iOS实现视频播放,原生代码播放视频更多的使用AVPlayer和AVPlayerViewController进行播放。
其中,
- AVPlayer不能单独进行播放,仅使用AVPLayer的话,还需要将其添加到AVPlayerLayer上进行播放,不含播放控制控件,需要自定义添加;
- AVPlayerViewController也是在AVPlayer的基础上集成的播放控件。包含完整的播放,暂停,进度拖动等控制控件。
所需库
- 使用AVPlayer和AVPlayerViewController需要添加库文件:AVKit.framework
- 获取时间(CMTimeGetSeconds)等等需要添加库文件:CoreMedia.framework
引用头文件
#import <AVKit/AVKit.h>
#import <AVFoundation/AVFoundation.h>
实现播放(代码)
1. AVPlayer
仅使用AVPlayer和AVPlayerLayer创建播放
//生成播放url
本地
NSString* localFilePath=[[NSBundle mainBundle]pathForResource:@"aaa" ofType:@"mp4"];
NSURL *videoUrl = [NSURL fileURLWithPath:localFilePath];
//网络
NSString *webVideoPath = @"http://122.144.137.20:81/2018/12/video/d63797a1912a4f529d8cffab862d8747.mp4";
NSURL *videoUrl = [NSURL URLWithString:webVideoPath];
//创建播放单元
AVPlayerItem* item = [AVPlayerItem playerItemWithURL:[NSURL URLWithString:videoUrl]]; //通过url生成
//创建播放器
AVPlayer* player = [AVPlayer playerWithPlayerItem:item]; //使用播放单元生成相应的播放器
或者
AVPlayer* player = [AVPlayer playerWithURL:videoUrl]; //直接使用播放URL生成
//切换播放内容时
[player replaceCurrentItemWithPlayerItem:item];
//创建播放层,将playerLayer添加到view上即可播放
AVPlayerLayer* playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.myPlayer];
2. AVPlayerViewController
AVPlayerViewController 在生成播放器player的基础上,进行下一步调用:
AVPlayerViewController* playerVC = [[AVPlayerViewController alloc] init];
//设置播放器
playerVC.player = player;
//设置播放范围
playerVC.view.frame = CGRectMake(0, 0, 700, 300);
/** 设置所播放视频的适配显示范围
* AVLayerVideoGravityResizeAspectFill : 显示尺寸适配,保证适配内容不变形的情况下铺满显示区域,画面可能会有截断
* AVLayerVideoGravityResizeAspect : 保证视频不变形,画面全部显示,可能不能铺满显示区域
* AVLayerVideoGravityResize : 保证视频铺满显示区域,画面全部显示,但视频内容可能会有变形
*/
playerVC.videoGravity = AVLayerVideoGravityResizeAspectFill;
//显示播放开始,播放进度条等控件
playerVC.showsPlaybackControls = YES;
通过[self presentViewController:playerVC animated:YES completion:nil];进行调用
播放相关监听
- status属性
播放单元playerItem可以通过添加status属性的监听来获取视频加载的状态。
/** 观察status属性, 一共有三种属性
* AVPlayerStatusReadyToPlay : 可以播放
* AVPlayerItemStatusFailed : 加载失败
* AVPlayerItemStatusUnknown : 未知错误
*/
[self.playerItem addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionNew) context:nil];
- loadedTimeRanges属性
播放单元playerItem还可以添加loadedTimeRanges属性。
[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
以上两种属性均在如下代码中返回监听结果:(这里的代码直接引用了简书作者的代码)
作者:梧雨北辰
链接:https://www.jianshu.com/p/b304694af77a
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
AVPlayerItem *playerItem = (AVPlayerItem *)object;
if ([keyPath isEqualToString:@"status"]) {
//获取playerItem的status属性最新的状态
AVPlayerStatus status = [[change objectForKey:@"new"] intValue];
switch (status) {
case AVPlayerStatusReadyToPlay:{
//获取视频长度
CMTime duration = playerItem.duration;
//更新显示:视频总时长(自定义方法显示时间的格式)
self.totalNeedPlayTimeLabel.text = [self formatTimeWithTimeInterVal:CMTimeGetSeconds(duration)];
//开启滑块的滑动功能
self.sliderView.enabled = YES;
//关闭加载Loading提示
[self showaAtivityInDicatorView:NO];
//开始播放视频
[self.player play];
break;
}
case AVPlayerStatusFailed:{//视频加载失败,点击重新加载
[self showaAtivityInDicatorView:NO];//关闭Loading视图
self.playerInfoButton.hidden = NO; //显示错误提示按钮,点击后重新加载视频
[self.playerInfoButton setTitle:@"资源加载失败,点击继续尝试加载" forState: UIControlStateNormal];
break;
}
case AVPlayerStatusUnknown:{
NSLog(@"加载遇到未知问题:AVPlayerStatusUnknown");
break;
}
default:
break;
}
} else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
//获取视频缓冲进度数组,这些缓冲的数组可能不是连续的
NSArray *loadedTimeRanges = playerItem.loadedTimeRanges;
//获取最新的缓冲区间
CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];
//缓冲区间的开始的时间
NSTimeInterval loadStartSeconds = CMTimeGetSeconds(timeRange.start);
//缓冲区间的时长
NSTimeInterval loadDurationSeconds = CMTimeGetSeconds(timeRange.duration);
//当前视频缓冲时间总长度
NSTimeInterval currentLoadTotalTime = loadStartSeconds + loadDurationSeconds;
//NSLog(@"开始缓冲:%f,缓冲时长:%f,总时间:%f", loadStartSeconds, loadDurationSeconds, currentLoadTotalTime);
//更新显示:当前缓冲总时长
_currentLoadTimeLabel.text = [self formatTimeWithTimeInterVal:currentLoadTotalTime];
//更新显示:视频的总时长
_totalNeedLoadTimeLabel.text = [self formatTimeWithTimeInterVal:CMTimeGetSeconds(self.player.currentItem.duration)];
//更新显示:缓冲进度条的值
_progressView.progress = currentLoadTotalTime/CMTimeGetSeconds(self.player.currentItem.duration);
}
}
- 监听播放进度
播放器player可以添加时间观察来管理播放进度
__weak __typeof(self) weakSelf = self;
[self.playerVC.player addPeriodicTimeObserverForInterval:CMTimeMake(1, 1) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
//当前播放的时间
NSTimeInterval currentTime = CMTimeGetSeconds(time);
//视频的总时间
NSTimeInterval totalTime = CMTimeGetSeconds(weakSelf.playerVC.player.currentItem.duration);
if (currentTime == totalTime) {
//[weakSelf dismissViewControllerAnimated:YES completion:nil]; //播放完成退出播放界面
}
}];
以上为目前使用iOS视频播放功能的整理。