SceneKIt+ AVFoundation 打造VR播放器(3)

下面是我写的播放器

SceneKIt+ AVFoundation 打造VR播放器(1)
SceneKIt+ AVFoundation 打造VR播放器(2)
支持VR,全景,视频缩放,本地,网络视频播放,实时获取视频帧,获取播放时间,获取缓存时间,播放,暂停

2017-06-22 17_47_06.gif

要想完成一个Vr播放器,需要完成两个功能

1、写一个可以实时获取视频帧的播放器
2、写一个可以渲染每一帧图片为全景图片的view

前面已经写好了两个类,现在调用就可以了

//
//  HelloViewController.m
//  SCN3DPlayer
//
//  Created by 俞涛涛 on 16/11/11.
//  Copyright © 2016年 俞涛涛. All rights reserved.
//

#import "HelloViewController.h"
#import "SCN3DPlayerView.h"
#import "SCN3DVideoAdatper.h"
#import "HelloViewController.h"
#import "Masonry.h"

@interface HelloViewController ()<SCN3DVideoAdatperDelegate>{
    

}
@property (nonatomic,strong)SCN3DPlayerView *scn3DPlayerView;
@property (nonatomic,strong)SCN3DVideoAdatper *scn3dVideo;


@property (strong, nonatomic)  UIButton *playAndStop;
@property (strong, nonatomic)  UILabel *curTimeLabel;
@property (strong, nonatomic)  UILabel *allTimeLabel;
@property (strong, nonatomic)  UIProgressView *progressView;
@property (strong, nonatomic)  UISlider *timeSlider;
@property (strong, nonatomic)  UIView *upView;
@property (strong, nonatomic)  UIView *videoView;

@property (nonatomic, assign) CGSize displaySize;
@property (nonatomic, assign) float aspect;

@end


@implementation HelloViewController

-(void)viewWillDisappear:(BOOL)animated{
    [self.scn3dVideo pause];
    [self.scn3dVideo removeDisplaylink];
    [self.scn3DPlayerView removeFromSuperview];
     self.scn3DPlayerView = nil;

}

-(void)viewWillAppear:(BOOL)animated{
//    self.scn3DPlayerView.frame = self.videoView.bounds;

}
-(void)viewDidAppear:(BOOL)animated{
    self.scn3DPlayerView.frame = self.view.frame;
    

    


}
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    // Do any additional setup after loading the view, typically from a nib.

    [self initSCN3DPlayerView];
    [self setSlider];
    [self initBtn];
    [self initVideo];
    
    
    }

-(void)initSCN3DPlayerView{
     self.scn3DPlayerView  = [[SCN3DPlayerView alloc]initWithFrame:self.view.frame];
    [self.view addSubview:self.scn3DPlayerView];
    [self.scn3DPlayerView  setInteractiveMode:SCN3DInteractive_MotionAndTouch];//设置重力触摸模式
//    [self.scn3DPlayerView setVideoAspectRatio:2.0];//设置视频宽高比
    [self.scn3DPlayerView setVideoDisplayMode:SCN3DDisplayMode_Plane_Normal];//初始化设置普通模式
    [self.scn3DPlayerView setHorizontalEnabled:YES verticalEnabled:YES];//设置触摸开关
    [self.scn3DPlayerView setPinchScaleEnabled:YES];//设置允许缩放
    [self.scn3DPlayerView setMinScale:1 maxScale:2.0];//设置缩放比例范围
    [self.scn3DPlayerView setCurrentScale:1.0]; //设置当前缩放比例


}
-(void)setSlider{
    _upView = [[UIView alloc]init];
    [self.view addSubview:_upView];
    _upView.backgroundColor = [UIColor grayColor];
    
    _playAndStop = [[UIButton alloc]init];
    
    [self.upView addSubview:_playAndStop];
    [_playAndStop setImage:[UIImage imageNamed:@"play_nor"] forState:UIControlStateNormal];
    [_playAndStop setImage:[UIImage imageNamed:@"pause_nor"] forState:UIControlStateSelected];
    [_playAndStop addTarget:self action:@selector(playAndstopClick:) forControlEvents:UIControlEventTouchUpInside];
    
    _curTimeLabel =[[UILabel alloc]init];
    [self.upView addSubview:_curTimeLabel];
    _curTimeLabel.text = @"00:00:00";
    _curTimeLabel.font =[UIFont systemFontOfSize:13];
    
    _allTimeLabel = [[UILabel alloc]init];
    [self.upView addSubview:_allTimeLabel];
    _allTimeLabel.text = @"00:00:00";
    _allTimeLabel.font = [UIFont systemFontOfSize:13];
    
    _progressView = [[UIProgressView alloc]init];
    [self.upView addSubview:_progressView];
    _progressView.progress = 0.0 ;
    
    _timeSlider = [[UISlider alloc]init];
    [self.upView addSubview:_timeSlider];
    _timeSlider.value = 0;
    [_timeSlider addTarget:self action:@selector(timeSliderValueChanged:) forControlEvents: UIControlEventValueChanged];
 
    
    
    __weak typeof(self) weakSelf = self;
    
    [self.upView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.and.trailing.equalTo(weakSelf.view).offset(0);
        make.bottom.equalTo(weakSelf.view).offset(0);
        make.height.equalTo(@60);
    }];
    
    [self.playAndStop mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.equalTo(weakSelf.upView);
        make.centerY.equalTo(weakSelf.upView);
        make.height.and.width.equalTo(@40);

    }];
    
    [self.curTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.equalTo(weakSelf.playAndStop.mas_trailing).offset(0);
        make.centerY.equalTo(weakSelf.upView);
        make.width.equalTo (@60);
        
    }];
    [self.allTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.trailing.equalTo(weakSelf.upView.mas_trailing).offset(-5);
        make.centerY.equalTo(weakSelf.upView);
        make.width.equalTo (@60);
        
    }];
    
    [self.timeSlider mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.equalTo(weakSelf.curTimeLabel.mas_trailing).offset(0);
        make.trailing.equalTo(weakSelf.allTimeLabel.mas_leading).offset(-8);
        make.centerY.equalTo(weakSelf.upView);
    }];
    
    [self.progressView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.leading.equalTo(weakSelf.curTimeLabel.mas_trailing).offset(0);
        make.trailing.equalTo(weakSelf.allTimeLabel.mas_leading).offset(-8);
        make.centerY.equalTo(weakSelf.upView);
    }];
    
    
    
    
    
    [self.timeSlider setThumbImage:[UIImage imageNamed:@"ic_circle@2x"] forState:UIControlStateNormal];
    [self.timeSlider setThumbImage:[UIImage imageNamed:@"ic_circle@2x"] forState:UIControlStateHighlighted];
    UIGraphicsBeginImageContextWithOptions((CGSize){ 1, 1 }, NO, 0.0f);
    UIImage *transparentImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    [self.timeSlider setMinimumTrackImage:transparentImage forState:UIControlStateNormal];
    [self.timeSlider setMaximumTrackImage:transparentImage forState:UIControlStateNormal];
}

-(void)initBtn{
    UIButton * btn0 = [[UIButton alloc]initWithFrame:CGRectMake(100, 50, 70, 40)];
    [btn0 setTitle:@"正常" forState:UIControlStateNormal];
    [btn0 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn0];
     btn0.alpha = 0.5;
     btn0.tag = SCN3DDisplayMode_Plane_Normal;
    [btn0 addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    
    
    
    UIButton * btn = [[UIButton alloc]initWithFrame:CGRectMake(100, 100, 70, 40)];
    [btn setTitle:@"平面180" forState:UIControlStateNormal];
    [btn setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn];
     btn.alpha = 0.5;
     btn.tag = SCN3DDisplayMode_Plane_Slide;
    [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    
    
    
    UIButton * btn2 = [[UIButton alloc]initWithFrame:CGRectMake(100, 150, 70, 40)];
    [btn2 setTitle:@"圆柱" forState:UIControlStateNormal];
    [btn2 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn2];
     btn2.alpha = 0.5;
     btn2.tag = SCN3DDisplayMode_Tube;
    [btn2 addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    
    
    
    UIButton * btn3 = [[UIButton alloc]initWithFrame:CGRectMake(100, 200, 70, 40)];
    [btn3 setTitle:@"圆" forState:UIControlStateNormal];
    [btn3 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn3];
    btn3.alpha = 0.5;
    btn3.tag = SCN3DDisplayMode_Sphere;
    [btn3 addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    
    
    UIButton * btn4 = [[UIButton alloc]initWithFrame:CGRectMake(100, 250, 70, 40)];
    [btn4 setTitle:@"全景" forState:UIControlStateNormal];
    [btn4 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn4];
    btn4.alpha = 0.5;
    btn4.tag = SCN3DDisplayMode_VR360;
    [btn4 addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    
    
    UIButton * btn5 = [[UIButton alloc]initWithFrame:CGRectMake(100, 300, 70, 40)];
    [btn5 setTitle:@"VR" forState:UIControlStateNormal];
    [btn5 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn5];
    btn5.alpha = 0.5;
    btn5.tag = SCN3DDisplayMode_VRGlass;
    [btn5 addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
    
    
    
    UIButton * btn6 = [[UIButton alloc]initWithFrame:CGRectMake(10, 10, 50, 50)];
    [btn6 setTitle:@"返回" forState:UIControlStateNormal];
    [btn6 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn6];
    btn6.alpha = 0.5;
    [btn6 addTarget:self action:@selector(backClick:) forControlEvents:UIControlEventTouchUpInside];
    
    UIButton * btn7 = [[UIButton alloc]initWithFrame:CGRectMake(80, 10, 50, 50)];
    [btn7 setTitle:@"+" forState:UIControlStateNormal];
    [btn7 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn7];
    btn7.alpha = 0.5;
    [btn7 addTarget:self action:@selector(addvoluem:) forControlEvents:UIControlEventTouchUpInside];
    UIButton * btn8 = [[UIButton alloc]initWithFrame:CGRectMake(150, 10, 50, 50)];
    [btn8 setTitle:@"-" forState:UIControlStateNormal];
    [btn8 setBackgroundColor:[UIColor blueColor]];
    [self.view addSubview: btn8];
    btn8.alpha = 0.5;
    
    [btn8 addTarget:self action:@selector(subvoluem:) forControlEvents:UIControlEventTouchUpInside];
    
    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapClick)];
    [self.view addGestureRecognizer:tap];
   

}

-(void)btnClick:(UIButton*)btn{
    
    if (btn.tag == SCN3DDisplayMode_Plane_Normal) {
        [self.scn3DPlayerView setVideoDisplayMode:SCN3DDisplayMode_Plane_Normal];
        
    }else if (btn.tag == SCN3DDisplayMode_Plane_Slide) {
        [self.scn3DPlayerView setVideoDisplayMode:SCN3DDisplayMode_Plane_Slide];
        [self.scn3DPlayerView setHorizontalEnabled:YES verticalEnabled:NO];//设置水平垂直是否启用
        [self.scn3DPlayerView setPinchScaleEnabled:YES];



    }else if (btn.tag == SCN3DDisplayMode_Tube){
        [self.scn3DPlayerView setVideoDisplayMode:SCN3DDisplayMode_Tube];
        [self.scn3DPlayerView setHorizontalEnabled:YES verticalEnabled:YES];
        [self.scn3DPlayerView setVerticalMinRotate:-60 maxRotate:60];


    }else if (btn.tag == SCN3DDisplayMode_Sphere){
        [self.scn3DPlayerView setVideoDisplayMode:SCN3DDisplayMode_Sphere];
        [self.scn3DPlayerView setHorizontalEnabled:YES verticalEnabled:YES];//设置水平垂直是否启用

    }else if (btn.tag == SCN3DDisplayMode_VR360){
        
        [self.scn3DPlayerView setVideoDisplayMode:SCN3DDisplayMode_VR360];
        [self.scn3DPlayerView setVerticalMinRotate:30 maxRotate:90];
        [self.scn3DPlayerView setCurrentRotateX:30 rotateY:0];
         self.scn3DPlayerView.cameraNode.position = SCNVector3Make(0, 0.1, 1.0);
        [self.scn3DPlayerView setHorizontalEnabled:YES verticalEnabled:YES];
        [self.scn3DPlayerView setGSensorMotionEnabled:YES];
        [self.scn3DPlayerView setPinchScaleEnabled:YES];

        
    }else if (btn.tag == SCN3DDisplayMode_VRGlass){
        
        [self.scn3DPlayerView setVideoDisplayMode:SCN3DDisplayMode_VRGlass];
        [self.scn3DPlayerView setHorizontalEnabled:YES verticalEnabled:YES];
        [self.scn3DPlayerView setGSensorMotionEnabled:YES];
        [self.scn3DPlayerView setPinchScaleEnabled:YES];

    }


}

-(void)tapClick{
    dispatch_async(dispatch_get_main_queue(), ^{
        [UIView animateWithDuration:0.3 animations:^{
            self.upView.alpha = 1.0;
            self.upView.alpha = 1.0;
        }];
        
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(6 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [UIView animateWithDuration:1.0 animations:^{
            self.upView.alpha = 0.0;
            self.upView.alpha = 0.0;
        }];
        
    });



}
-(void)initVideo{
    self.scn3dVideo = [[SCN3DVideoAdatper alloc]init];
        
    NSString * urlString = [[NSBundle mainBundle]pathForResource:@"abc" ofType:@"mp4"];
//    NSString * urlString = @"http://cache.utovr.com/aa38e1ffef5d4b9baaf393777dbc9342/L2_gx91akbix0qkiacw.mp4";
    
    
    NSURL *videoURL;
    
    if ([self checkPathIsHTTPURL:urlString]) {
        videoURL = [NSURL URLWithString:urlString]; //网络视频

    }
    else {
        videoURL = [NSURL fileURLWithPath:urlString];//本地视频

    }
    //播放方法一
    [self.scn3dVideo setURL:videoURL];
    
    //播放方法二
//    AVPlayerItem *playerItem = [[AVPlayerItem alloc] initWithURL:url];
//    [self.scn3dVideo setPlayerItem:playerItem];
    
    //方法三
//    AVAsset * asset = [AVAsset assetWithURL:url];
//    [self.scn3dVideo setAsset:asset];
    
    
     self.scn3dVideo.delegate = self;
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
}
    
    
    
    
    
- (void)videoPlayerIsReadyToPlayVideo:(SCN3DVideoAdatper *)videoAdatper{
    NSLog(@"准备播放====================");
    [self.scn3dVideo addDisplaylink];
    [self.scn3dVideo play];
     self.playAndStop.selected = YES;
    int totalTime = CMTimeGetSeconds(videoAdatper.playerItem.duration);
    self.timeSlider.maximumValue = totalTime;
    self.allTimeLabel.text = [self getVideoTimeString:totalTime];
    NSLog(@"time =========%d",totalTime);

}

- (void)videoPlayerDidReachEnd:(SCN3DVideoAdatper *)videoAdatper{
    NSLog(@"播放结束 ==============");
    [self.scn3dVideo pause];
   
        
}

- (void)videoPlayer:(SCN3DVideoAdatper *)videoAdatper timeDidChange:(CMTime)cmTime{
   
    int curTime = CMTimeGetSeconds(cmTime);
    self.timeSlider.value = curTime;
    self.curTimeLabel.text = [self getVideoTimeString:curTime];
}

- (void)videoPlayer:(SCN3DVideoAdatper *)videoAdatper loadedTimeRangeDidChange:(float)duration{
    
    // 视频缓冲长度
    int totalTime = CMTimeGetSeconds(videoAdatper.playerItem.duration);
    if (totalTime != 0) {
        self.progressView.progress = duration / totalTime;

    
    }
}
- (void)videoPlayer:(SCN3DVideoAdatper *)videoAdatper didFailWithError:(NSError *)error{
    NSLog(@"error====================%@",error);
}
    
- (void)videoPlayer:(SCN3DVideoAdatper *)videoAdatper displaylinkCallbackImage:(UIImage *)videoImage{
    //获取视频的每一帧
    [self.scn3DPlayerView setFramesPerVideoImage:videoImage];
    _aspect = videoImage.size.width/videoImage.size.height;
    
        
}

- (NSString *)getVideoTimeString:(int)time {
    int hou = time / 3600;
    int min = (time - hou * 60) / 60;
    int sec = time - hou * 3600 - min * 60;
    return [NSString stringWithFormat:@"%02d:%02d:%02d", hou, min, sec];
}

//支持的方向
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
        
    return UIInterfaceOrientationMaskAll;
        
}
    
//是否可以旋转
-(BOOL)shouldAutorotate{
    
    return YES;
}
// 横竖屏适配.
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
    
    [self relayout];
}
    
- (void)relayout
{
    if(self.view.frame.size.width>self.view.frame.size.height) {
        self.scn3DPlayerView .frame = self.view.frame;
            
    } else {
        self.scn3DPlayerView.frame = self.view.frame;
    }
}

- (BOOL)checkPathIsHTTPURL:(NSString *)path {
    NSString *head = [path substringWithRange:NSMakeRange(0, 4)];
    NSStringCompareOptions options = NSCaseInsensitiveSearch | NSNumericSearch;
    if ([head compare:@"http" options:options] == NSOrderedSame) {
        return YES;
    }
    return NO;
}
- (void)playAndstopClick:(UIButton *)sender {
    if (self.scn3dVideo.isPlaying) {
        [self.scn3dVideo pause];
        self.playAndStop.selected = NO;
    }else{
        [self.scn3dVideo play];
        self.playAndStop.selected = YES;
    }
}

- (void)timeSliderValueChanged:(UISlider*)sender {  // 滑动播放进度
    float seekTime = sender.value;
    if (self.scn3dVideo.isPlaying) {
        [self.scn3dVideo pause];
    }
    if (self.playAndStop.selected == YES) {
        [self.scn3dVideo play];
    }

    [self.scn3dVideo seekToTime:seekTime completion:nil];
}
- (void)backClick:(UIButton *)sender {
    
    [self dismissViewControllerAnimated:YES completion:nil];
}

-(void)subvoluem:(UIButton *)sender{
    
    [self.scn3dVideo fadeOutVolume];
}
-(void)addvoluem:(UIButton *)sender{
    
    [self.scn3dVideo  fadeInVolume];
}

@end

源代码下载
如果喜欢的话,就点个赞,star一下,本文里面有误的地方,请大家指教

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容