核心类
AVAsset--视频资源对象,需要传入本地或网络的URL
AVPlayerItem--获取视频时长及各种状态,需要传入创建好的AVAsset对象
AVPlayer--视频播放类,需要传入创建好的AVPlayerItem对象
AVPlayerLayer--视频显示layer,可以替换或插入到视图树中
AVAssetImageGenerator--获取视频某一帧的缩略图,可以获取某个时间的,也可以批量获取
第一步:初始化
1.创建AVAsset
_asset = [AVAsset assetWithURL:assetURL];
2.创建AVPlayerItem,可以传入所需要监听的属性,例如视频时长duration
NSArray *keys = @[
@"tracks",
@"duration",
@"commonMetadata",
@"availableMediaCharacteristicsWithMediaSelectionOptions"
];
self.playerItem = [AVPlayerItem playerItemWithAsset:self.asset automaticallyLoadedAssetKeys:keys];
3.通过KVO给AVPlayerItem添加视频播放状态的监听
[self.playerItem addObserver:self forKeyPath:@"status" options:0 context:&PlayerItemStatusContext];
4.创建AVPlayer
self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
5.创建显示视频用的AVPlayerLayer,并设置之前创建好的AVPlayer为视频播放器,插入到当前视图树中
AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:player];
第二步:首次播放
[self.player play];
【更多音视频学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击领取→音视频开发基础知识和资料包
在第一步的KVO监听中监听到AVPlayerItem的播放状态为AVPlayerItemStatusReadyToPlay,调用AVPlayer的play方法开始播放,这里还写了其它方法,例如监听当前播放时长,批量获取缩略图等,后面会放具体实现
if (context == &PlayerItemStatusContext) {
dispatch_async(dispatch_get_main_queue(), ^{
//移除监听
[self.playerItem removeObserver:self forKeyPath:@"status"];
if (self.playerItem.status == AVPlayerItemStatusReadyToPlay) {
//添加视频当前播放时间的监听
[self addPlayerItemTimeOberver];
//视频总时长
CMTime duration = self.playerItem.duration;
[self.delegate playerDidChangeTime:CMTimeGetSeconds(kCMTimeZero) withAssertDuration:CMTimeGetSeconds(duration)];
//播放
[self.player play];
//批量获取缩略图
[self generateThumbnails];
}
});
}
第三步:暂停
[self.player pause];
第四步:暂停后继续播放,如果设置了倍速,暂停后会重置,这里需要重新设置一下速率,而且一定要放在play方法之后,不然不会生效
[self.player play]; self.player.rate = _playRate
第五步:获取当前播放时间,在初始化的KVO监听中调用AVPlayer的如下方法
- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block
- (void)addPlayerItemTimeOberver
{
CMTime interval = CMTimeMakeWithSeconds(0.5f, NSEC_PER_SEC);
dispatch_queue_t queue = dispatch_get_main_queue();
__weak typeof(self)weakSelf = self;
self.timeObserver = [self.player addPeriodicTimeObserverForInterval:interval queue:queue usingBlock:^(CMTime time) {
NSTimeInterval currentTime = CMTimeGetSeconds(time);
NSTimeInterval duration = CMTimeGetSeconds(weakSelf.playerItem.duration);
[weakSelf.delegate playerDidChangeTime:currentTime withAssertDuration:duration];
}];
}
第六步:速率播放,设置AVPlayer的rate属性
self.player.rate = playRate
第七步:移动到某个时间点进行播放,这里有一个细节,当手指按下的时候,需要停止播放并移除播放时长通知,当手指离开,继续播放与监听当前播放时长
[self.player seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC)];
//手指按下
- (void)progressSliderDidStartChange
{
[self.player pause];
[self.player removeTimeObserver:self.timeObserver];
self.timeObserver = nil;
}
//开始移动
- (void)progressSliderSeekToTime:(NSTimeInterval)time
{
[self.playerItem cancelPendingSeeks];
[self.player seekToTime:CMTimeMakeWithSeconds(time, NSEC_PER_SEC)];
}
//手指离开
- (void)progressSliderDidEnd
{
[self addPlayerItemTimeOberver];
[self.player play];
self.player.rate = _playRate;
}
第八步:批量获取缩略图,创建可视化进度条
创建AVAssetImageGenerator,传入AVAsset类型
AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:self.asset];
批量获取缩略图方法
- (void)generateCGImagesAsynchronouslyForTimes:(NSArray<NSValue *> *)requestedTimes completionHandler:(AVAssetImageGeneratorCompletionHandler)handler
获取某个时间点的缩略图
- (nullable CGImageRef)copyCGImageAtTime:(CMTime)requestedTime actualTime:(nullable CMTime *)actualTime error:(NSError * _Nullable * _Nullable)outError
【更多音视频学习资料,点击下方链接免费领取↓↓,先码住不迷路~】
点击领取→音视频开发基础知识和资料包
- (void)generateThumbnails
{
AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:self.asset];
imageGenerator.maximumSize = CGSizeMake(200, 0);
CMTime duration = self.asset.duration;
NSMutableArray *times = [NSMutableArray array];
CMTimeValue increment = duration.value / 20;
CMTimeValue currentValue = 2.0 * duration.timescale;
while (currentValue <= duration.value) {
CMTime time = CMTimeMake(currentValue, duration.timescale);
[times addObject:[NSValue valueWithCMTime:time]];
currentValue += increment;
}
__block NSInteger imageCount = times.count;
__block NSMutableArray *images = [NSMutableArray array];
[imageGenerator generateCGImagesAsynchronouslyForTimes:times completionHandler:^(CMTime requestedTime, CGImageRef _Nullable imageRef, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
if (result == AVAssetImageGeneratorSucceeded) {
UIImage *image = [UIImage imageWithCGImage:imageRef];
QXThumbnail *thumbnail = [QXThumbnail thumbilWithImage:image time:actualTime];
[images addObject:thumbnail];
} else {
NSLog(@"Error:%@",error.localizedDescription);
}
if (--imageCount == 0) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.delegate playerDidGenerateThumbnails:[images copy]];
});
}
}];
}
到此,一个简易的视频播放器就完成了,当然了,还有很多的细节需要去处理,这个就需要小伙伴们自己去捉摸了,学习音视频一定是一个漫长又有趣的路,加油!
如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!
版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除