OC AVPlayerItem,AVPlayer,AVPlayerLayer的使用

Stella981
• 阅读 665

音量调节以及跳转到指定的秒数,停止和暂停,只是学习,没有封装

#import <Masonry.h>
#import <AVFoundation/AVFoundation.h>
@interface RecordVideoplayVC ()
@property(nonatomic,strong)AVPlayerItem *avPlayerItem;
@property(nonatomic,strong)AVPlayer *avPlayer;
@property (nonatomic ,strong) id playbackTimeObserver;
@end

@implementation RecordVideoplayVC

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
//    AVPlayerItem:提供视频信息,一个AVPlayerItem对应着你提供的一个视频Url资源,这个理解它的时候可以把它比作一个Model, 你初始化了AVPlayerItem之后,并不是马上就可以使用它了,因为凡是和Url网络扯上关系的,都需要时间,等AVPlayerItem加载好之后就可以使用它了,那这一步我们怎么处理呢?
//    答案是利用KVO观察statues属性为 AVPlayerStatusReadyToPlay,看看这个属性的定义:
    
//    @property (nonatomic, readonly) AVPlayerStatus status  它是一个只读属性,这点也需要注意,其实也就理解利用KVO的原因。
//
//    2>: 顺便总结要是你要显示当前视屏的缓存进度,你需要监测它的loadedTimeRanges属性。
//
//    2、AVPlayerLayer
//
//    它主要负责的就是视频的显示,继承自CALayer,其实你可以把它理解成我们的View。我们自定义的那些播放时候的控件就是添加在它上面的,比如我们能看到的播放按钮,停止按钮,或者播放进度条等等。
  
//    3、 AVPlayer
//
//    它主要负责的是管理视频播放,暂停等等,相当于一个视频管理器,要是类比的话他就是一个ViewController(当然不是真正的ViewController),这三者就基本含括了一个基本的视频播,基于着三者我们总结一下播放一个视频的基本的过程:
    
//    首先,得到视频的URL
//    根据URL创建AVPlayerItem
//    把AVPlayerItem 提供给 AVPlayer
//    AVPlayerLayer 显示视频。
//    AVPlayer 控制视频, 播放, 暂停, 跳转 等等。
//    播放过程中获取缓冲进度,获取播放进度。
//    视频播放完成后做些什么,是暂停还是循环播放,还是获取最后一帧图像。

//    4、AVPlayerViewController
//
//    它是Apple 帮我们封装好的可以一个视频播放控制器,它就有一个  @property (nonatomic, strong, nullable) AVPlayer *player 的属性,前面的AVPlayer也就像相应的需要赋值给它,它里面还有一些我们需要理解一下的属性,我们也把它写出来,具体代码我们下面再看:
//
//    player:                                    设置播放器
//    showsPlaybackControls:           设置是否显示媒体播放组件,默认YES
//    videoGravity:                           设置视频拉伸模式
//    allowsPictureInPicturePlayback: 设置是否允许画中画回放,默认YES
//    delegate:                                设置代理
//    5、AVPlayerViewControllerDelegate
//
//    这个代理就是前面说的AVPlayerViewController的协议,它主要的是为画中画的设置的代理,前面介绍 AVPlayerViewController 的时候有看到过一个是否允许画中画的属性,具体什么是画中画相信大家都了解,看过直接的朋友应该都看到了这个技术点的具体应用。我们看看它里面的饭法规主要都干了些什么?
//    // 1、即将开始画中画
//    - (void)playerViewControllerWillStartPictureInPicture:(AVPlayerViewController *)playerViewController;
//    // 2、开始画中画
//    - (void)playerViewControllerDidStartPictureInPicture:(AVPlayerViewController *)playerViewController;
//    // 3、画中画失败
//    - (void)playerViewController:(AVPlayerViewController *)playerViewController failedToStartPictureInPictureWithError:(NSError *)error;
//    // 4、即将结束画中画
//    - (void)playerViewControllerWillStopPictureInPicture:(AVPlayerViewController *)playerViewController;
//    // 5、结束画中画
//    - (void)playerViewControllerDidStopPictureInPicture:(AVPlayerViewController *)playerViewController;
    
    
    
    // Do any additional setup after loading the view.
    
    
    self.avPlayerItem   = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:MovieURL]];
    self.avPlayer       = [[AVPlayer alloc]initWithPlayerItem:self.avPlayerItem];
    AVPlayerLayer *avPlayerLayer  = [AVPlayerLayer playerLayerWithPlayer:self.avPlayer];
    avPlayerLayer.frame = CGRectMake(10, 100, 355, 200);
    [self.view.layer addSublayer:avPlayerLayer];

    //状态添加观察者
    [self.avPlayerItem  addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
    // 缓存进度添加观察者
    [self.avPlayerItem  addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    // 添加视频播放结束通知
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(moviePlayDidEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayerItem];
    
    
    
    self.avPlayer.volume = 0.5;//调节音量 0-1
    
}

- (void)moviePlayDidEnd:(NSNotification *)notification {
    NSLog(@"Play end");
    
    __weak typeof(self) weakSelf = self;
    [self.avPlayer seekToTime:kCMTimeZero completionHandler:^(BOOL finished) {
        //把进度跳转到0,
    }];
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    
    AVPlayerItem * avplayeritem = (AVPlayerItem *)object;
    if ([keyPath isEqualToString:@"status"]) {
        
        AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
        if (status == AVPlayerStatusReadyToPlay) {
            NSLog(@"准备好播放");
            CMTime duration = avplayeritem.duration;
            NSLog(@"视频总时长:%.2f",CMTimeGetSeconds(duration));//总时长
            // 播放
            [self.avPlayer play];
            [self monitoringPlayback];// 监听播放状态
           
        }else if (status == AVPlayerStatusFailed){
            NSLog(@"视频准备发生错误");
        }else{
            NSLog(@"位置错误");
        }
    }else if ([keyPath isEqualToString:@"loadedTimeRanges"]){
        
        // 可以自定义缓存进度
        NSTimeInterval timeInterval = [self alreadyCacheVideoProgress];
        NSLog(@"视频已经缓存的时长:%.2f",timeInterval);
    }
}

#pragma mark --
#pragma mark -- alreadyCacheVideoProgress
-(NSTimeInterval)alreadyCacheVideoProgress{
    // 先获取到它的缓存的进度
    NSArray * cacheVideoTime = [self.avPlayerItem loadedTimeRanges];
    // CMTimeRange 结构体 start duration 表示起始位置 和 持续时间
    // 获取缓冲区域
    CMTimeRange timeRange = [cacheVideoTime.firstObject CMTimeRangeValue];//NSValue
    float startSeconds    = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
   
    // 计算总缓冲时间 = start + duration
    NSTimeInterval result = startSeconds + durationSeconds;
    return result;
}



-(void)dealloc{
    [self.avPlayerItem removeObserver:self forKeyPath:@"status"];
    [self.avPlayerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.avPlayerItem];
    [self.avPlayer removeTimeObserver:self.playbackTimeObserver];
}

//监听播放状态
- (void)monitoringPlayback {
    /*
    CMTime CMTimeMake(
    int64_t value, //秒
    int32_t timescale)//次数
    */
 self.playbackTimeObserver = [self.avPlayer addPeriodicTimeObserverForInterval:CMTimeMake(1, 5) queue:NULL usingBlock:^(CMTime time) {
        CGFloat currentSecond = self.avPlayerItem.currentTime.value/self.avPlayerItem.currentTime.timescale;// 计算当前在第几秒
        //如果需要进度条的话,这里可以更新进度条
    }];
}
//跳转到指定的秒数
-(void)jumptoValue:(float)seconds{
     CMTime changedTime = CMTimeMakeWithSeconds(seconds, 1);
    [self.avPlayer seekToTime:changedTime completionHandler:^(BOOL finished) {
        [self.avPlayer play];
    }];

}


//

@end
点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
2年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Stella981 Stella981
2年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这