iOS 9之后苹果推荐使用AVPlayer进行视频播放,AVPlayer相对于MPMediaPlayerViewController功能更加强大,有更多的灵活性,当然,也需要你去自定义构建UI。其他优势,例如其扩展的AVQueuePlayer,可以实现视频无缝队列播放、多视频同时播放、视频转换、编解码等功能。

1、简单的播放

 // 1、得到视频的URLNSURL *movieURL = [NSURL fileURLWithPath:filePath];// 2、根据URL创建AVPlayerItemself.playerItem   = [AVPlayerItem playerItemWithURL:movieURL];// 3、把AVPlayerItem 提供给 AVPlayerself.player     = [AVPlayer playerWithPlayerItem:self.playerItem];// 4、AVPlayerLayer 显示视频。AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];playerLayer.frame       = self.view.bounds;//设置边界显示方式playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;[self.view.layer addSublayer:playerLayer];self.player play];

2、监听视频加载状态/设置缓存进度

#pragma mark - 观察者、通知
- (void) addObserverAndNotification {// 观察status属性[_playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:(NSKeyValueObservingOptionNew) context:nil];[_playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];}#pragma mark - observe
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {AVPlayerItem *item = (AVPlayerItem *)object;if ([keyPath isEqualToString:@"status"]) {AVPlayerStatus status = [[change objectForKey:@"new"] intValue]; // 获取更改后的状态if (status == AVPlayerStatusReadyToPlay) {CMTime duration = item.duration; // 获取视频长度// 设置视频时间[self setMaxDuration:CMTimeGetSeconds(duration)];// 播放[self play];//监听播放进度[self monitoringPlayback:self.playerItem];} else if (status == AVPlayerStatusFailed) {NSLog(@"AVPlayerStatusFailed");} else {NSLog(@"AVPlayerStatusUnknown");}} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {NSTimeInterval timeInterval = [self availableDuration]; // 缓冲时间CGFloat totalDuration = CMTimeGetSeconds(_playerItem.duration); // 总时间CGFloat progress = timeInterval / totalDuration;//在这里设置缓存进度[self.progressView setProgress:progress animated:YES]; // 更新缓冲条}
}

3、监听播放进度

#pragma mark - 观察播放进度
- (void)monitoringPlayback:(AVPlayerItem *)item {__weak typeof(self)WeakSelf = self;// 观察间隔, CMTime 为30分之一秒_playTimeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 30.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {// 获取 item 当前播放秒float currentPlayTime = (double)item.currentTime.value/ item.currentTime.timescale;[WeakSelf updateVideoSlider:currentPlayTime];// 更新slider, 如果正在滑动则不更新if (_isSliding == NO) {[WeakSelf updateVideoSlider:currentPlayTime];}}];
}

4、设置进度

- (void)playerSliderValueChanged {_isSliding = YES;[self pause];    // 跳转到拖拽秒处CMTime changedTime = CMTimeMakeWithSeconds(self.slider.value, 1.0);[_playerItem seekToTime:changedTime completionHandler:^(BOOL finished) {
//        // 跳转完成后
//        _isSliding = NO;
//        [self play];}];
}

完整demo

@import AVFoundation;
@import MediaPlayer;
@interface ViewController ()
@property(nonatomic,strong) AVPlayer *player;
@property(nonatomic,strong) AVPlayerItem *playerItem;
@property(nonatomic,strong) id playTimeObserver;
@property(nonatomic,assign) BOOL isSliding; //是否正在滑动
/***  视频总秒数*/
@property (nonatomic, assign) NSInteger totalSeconds;
@property (nonatomic, weak) UISlider *slider;
@property (nonatomic, weak) UIProgressView *progressView;
@end
- (void)viewDidLoad {[super viewDidLoad];NSString *path = [[NSBundle mainBundle]pathForResource:@"loginmovie" ofType:@".mp4"];//    NSURL *url     = [NSURL fileURLWithPath:path];[self createAVPlayer:path];UIProgressView *progressView = [[UIProgressView alloc]initWithFrame:CGRectMake(5, 510,[UIScreen mainScreen].bounds.size.width-10, 0)];//进度条背景色progressView.trackTintColor = [UIColor lightGrayColor];//进度条缓存颜色progressView.progressTintColor = [UIColor greenColor];self.progressView = progressView;[self.view addSubview:progressView];//添加slideUISlider *slider = [[UISlider alloc]initWithFrame:CGRectMake(0, 500,[UIScreen mainScreen].bounds.size.width, 21)];slider.minimumTrackTintColor = [UIColor redColor];slider.maximumTrackTintColor = [UIColor clearColor];self.slider      = slider;[slider addTarget:self action:@selector(playerSliderValueChanged) forControlEvents:UIControlEventValueChanged];[self.view addSubview:slider];
}#pragma mark - MPMoviePlayerController
- (void)createAVPlayer:(NSString *)filePath {//在使用 AVPlayer 播放视频时,提供视频信息的是 AVPlayerItem,一个 AVPlayerItem 对应着一个URL视频资源// 1、得到视频的URLNSURL *movieURL = [NSURL fileURLWithPath:filePath];// 2、根据URL创建AVPlayerItemself.playerItem   = [AVPlayerItem playerItemWithURL:movieURL];// 3、把AVPlayerItem 提供给 AVPlayerself.player     = [AVPlayer playerWithPlayerItem:self.playerItem];// 4、AVPlayerLayer 显示视频。AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];playerLayer.frame       = self.view.bounds;//设置边界显示方式playerLayer.videoGravity = AVLayerVideoGravityResizeAspect;[self.view.layer addSublayer:playerLayer];// 注册观察者,通知[self addObserverAndNotification];
}#pragma mark - 更新视频
- (void)updatePlayerWithURL:(NSURL *)url {_playerItem = [AVPlayerItem playerItemWithURL:url]; // create item[_player  replaceCurrentItemWithPlayerItem:_playerItem]; // replaceCurrentItem[self addObserverAndNotification]; // 注册观察者,通知
}#pragma mark - 观察者、通知
- (void) addObserverAndNotification {// 观察status属性[_playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:(NSKeyValueObservingOptionNew) context:nil];[_playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];}#pragma mark - observe
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {AVPlayerItem *item = (AVPlayerItem *)object;if ([keyPath isEqualToString:@"status"]) {AVPlayerStatus status = [[change objectForKey:@"new"] intValue]; // 获取更改后的状态if (status == AVPlayerStatusReadyToPlay) {CMTime duration = item.duration; // 获取视频长度// 设置视频时间[self setMaxDuration:CMTimeGetSeconds(duration)];// 播放[self play];//监听播放进度[self monitoringPlayback:self.playerItem];} else if (status == AVPlayerStatusFailed) {NSLog(@"AVPlayerStatusFailed");} else {NSLog(@"AVPlayerStatusUnknown");}} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {NSTimeInterval timeInterval = [self availableDuration]; // 缓冲时间CGFloat totalDuration = CMTimeGetSeconds(_playerItem.duration); // 总时间CGFloat progress = timeInterval / totalDuration;//在这里设置缓存进度[self.progressView setProgress:progress animated:YES]; // 更新缓冲条}
}#pragma mark - 设置视频时间总秒数
- (void) setMaxDuration:(CGFloat)seconds{self.slider.minimumValue = 0;self.slider.maximumValue = seconds;self.totalSeconds = seconds;NSLog(@"总秒数===%f",seconds);
}#pragma mark - 播放
- (void) play{[self.player play];
}#pragma mark - 暂停
- (void) pause{[self.player pause];
}#pragma mark - 观察播放进度
- (void)monitoringPlayback:(AVPlayerItem *)item {__weak typeof(self)WeakSelf = self;// 观察间隔, CMTime 为30分之一秒_playTimeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMake(1, 30.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {// 获取 item 当前播放秒float currentPlayTime = (double)item.currentTime.value/ item.currentTime.timescale;[WeakSelf updateVideoSlider:currentPlayTime];// 更新slider, 如果正在滑动则不更新if (_isSliding == NO) {[WeakSelf updateVideoSlider:currentPlayTime];}}];
}- (void)playerSliderValueChanged {_isSliding = YES;[self pause];    // 跳转到拖拽秒处CMTime changedTime = CMTimeMakeWithSeconds(self.slider.value, 1.0);[_playerItem seekToTime:changedTime completionHandler:^(BOOL finished) {
//        // 跳转完成后
//        _isSliding = NO;
//        [self play];}];
}#pragma mark - 获取缓存进度
- (NSTimeInterval)availableDuration {NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 获取缓冲区域float startSeconds = CMTimeGetSeconds(timeRange.start);float durationSeconds = CMTimeGetSeconds(timeRange.duration);NSTimeInterval result = startSeconds + durationSeconds;// 计算缓冲总进度return result;
}- (NSString *)convertTime:(CGFloat)second{NSDate *d = [NSDate dateWithTimeIntervalSince1970:second];NSDateFormatter *formatter = [[NSDateFormatter alloc] init];if (second/3600 >= 1) {[formatter setDateFormat:@"HH:mm:ss"];} else {[formatter setDateFormat:@"mm:ss"];}NSString *showtimeNew = [formatter stringFromDate:d];return showtimeNew;
}#pragma mark - 设置播放seconds
- (void) updateVideoSlider:(float) time{NSLog(@"time=%f",time);self.slider.value = time;
}#pragma mark - 播放完成后
- (void)playbackFinished:(NSNotification *)notification {NSLog(@"视频播放完成通知");_playerItem = [notification object];[_playerItem seekToTime:kCMTimeZero]; // item 跳转到初始//[_player play]; // 循环播放
}#pragma mark - 释放资源
- (void)dealloc {[self removeObserveAndNOtification];
}#pragma mark - 移除通知和观察者
- (void)removeObserveAndNOtification{[[NSNotificationCenter defaultCenter]removeObserver:self];[_player removeTimeObserver:_playTimeObserver]; // 移除playTimeObserver}[_player removeObserver:self forKeyPath:@"loadedTimeRanges"];[_player removeObserver:self forKeyPath:@"status"];
}

效果图:

iOS 视频播放从零开始(二)相关推荐

  1. iOS 视频播放从零开始(一)

    之前很少有时间看视频这块,赶在现在比较闲,从零开始拾起. iOS 中关于视频播放框架已更新换代多次,先从最开始的走起. iOS9之前,iOS播放视频文件一般使用MPMoviePlayerViewCon ...

  2. iOS视频播放的基本方法

    本文总结了iOS中最常见的视频播放方法,不同的方法都各具特点,我希望能够总结它们的不同,方便在开发中选择合适的技术方案. Apple为我们提供了多种方法来实现视频播放,包括MPMoviePlayerC ...

  3. iOS: ios视频播放(MPMediaPlayerController,AVPlayer,AVPlayerViewcontroller、ffmpeg-AVPlayer)...

    介绍: 和音频播放一样,ios也提供个很多的API.如mediaPlayer.framework下的MPMediaPlayerController.AVFounditon.framework下的AVP ...

  4. iOS原生实现二维码扫描

    iOS原生实现二维码扫描 最近项目上需要开发扫描二维码进行签到的功能,主要用于开会签到的场景,所以为了避免作弊,我们再开发时只采用直接扫描的方式,并且要屏蔽从相册读取图片,此外还在二维码扫描成功签到时 ...

  5. iOS 视频播放器开发

    需求设计 做一个小学生教育辅导视频播放器. 参考小猿搜题视频播放器 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-L0GsyFSt-1675164972791)(htt ...

  6. 基于libVLC的视频播放器之二:使用VLC-Qt播放RTSP流

    此篇是 使用VLC浏览器插件播放RTSP流的姊妹篇. 一.直接使用libVLC libVLC是VLC media player多媒体框架的核心引擎和接口,开发者使用它能轻松的创建大量具有VLC特性的应 ...

  7. ios内购二次验证安全性问题_苹果IOS内购二次验证返回state为21002的坑

    项目是三四年前的老项目,之前有IOS内购二次验证的接口,貌似很久都没用了,然而最近IOS的妹子说接口用不了,让我看看啥问题.接口流程时很简单的,就是前端IOS在购买成功之后,接收到receipt后进行 ...

  8. iOS相册图片二维码识别

    前言:最近客户要求开发一个功能,类似微信长按图片识别图片中的二维码,一开始我使用了ZXingObjC,但是完成后被测试出有些二维码识别不了,所以只能另寻它法,之后更换为苹果系统自带的识别图片二维码的功 ...

  9. 小米手环iOS开发实战(二):开发Demo让你的手环振动起来

    小米手环iOS开发实战(二):开发Demo让你的手环振动起来 上一节讲了CoreBluetooth的使用,理论知识很枯燥,那么现在先利用上一节讲的内容,做一个简易手环应用,实现连接/断开手环,查看手环 ...

最新文章

  1. 车道线检测--End-to-end Lane Detection through Differentiable Least-Squares Fitting
  2. linux命令:groupadd
  3. python - 条件语句
  4. c3p0 参数 模糊查询_MySQL模糊查询用法大全(正则、通配符、内置函数等)
  5. 通过php extension使disable_function支持通配符
  6. ElasticSearch评分分析 explian 解释和一些查询理解
  7. [Android开源项目] GitHub开源项目总结 (转)
  8. 图论 —— 环与块 —— DAG 图判定
  9. MySQL常用命令_vortex_新浪博客
  10. 从王者荣耀看设计模式(六.状态模式)
  11. java抽象类泛型_java-使用泛型定义抽象方法
  12. windows系统下帧率获取工具--fraps
  13. 标签打印软件中标签间距以及边距如何设置
  14. ubuntu20.04WPS解决缺失字体的问题
  15. linux vga 驱动,Linux VGA驱动移植实验【转】
  16. 埃尔米特插值及其代码
  17. r语言中which的使用_R语言绘图 | 使用pheatmap快速绘制热图
  18. DSDS/DSDA/DR-DSDS/DR-DSDA场景介绍和关键Log分析
  19. 易优CMS:user 登录注册入口标签
  20. 学会不被洗脑 很重要!

热门文章

  1. GTX 770 (GK 104)
  2. Python标准-模块版本号命名-PEP-396PEP-386
  3. 电机磁链和反电动势系数辨识
  4. 梳理一些近期关于编程和其他一些感想
  5. 【约瑟夫环】Java实现:100个人开始从1开始报数,每当报数到3,报数3的人离开,求最后留下来人的位置。
  6. bootstrap的tooltip
  7. java常用英文单词发音_java常用英语单词(带音标)
  8. GC8871一款带内部电流感测功能的刷式直流电机驱动芯片(可替代DRV8871)
  9. 求0—7所能组成的奇数个数。
  10. 计算机生成全息投影代码,常见的投影控制代码 汇总 1