AVFoundation-实现一个简易的视频播放器

发布一下 0 0

核心类

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]];

});

}

}];

}


到此,一个简易的视频播放器就完成了,当然了,还有很多的细节需要去处理,这个就需要小伙伴们自己去捉摸了,学习音视频一定是一个漫长又有趣的路,加油!

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

版权声明:内容来源于互联网和用户投稿 如有侵权请联系删除

本文地址:http://0561fc.cn/184303.html