コアクラス
AVAsset
-ビデオリソースオブジェクト、ローカルまたはネットワークのURLを渡す必要があります
AVPlayerItem
-ビデオの長さとさまざまな状態を取得します。作成したAVAssetオブジェクトを渡す必要があります
AVPlayer
-ビデオ再生クラス。作成したAVPlayerItemオブジェクトを渡す必要があります
AVPlayerLayer
-ビデオ表示レイヤー。ビューツリーに置き換えたり挿入したりできます。
AVAssetImageGenerator
-ビデオの特定のフレームのサムネイルを取得するか、特定の時間に取得するか、バッチで取得することができます
ステップ1:初期化
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];
复制代码
ステップ2:初めてプレイする
[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];
}
});
}
复制代码
ステップ3:一時停止
[self.player pause];
ステップ4:一時停止後も再生を続行します。倍速が設定されている場合は、一時停止後にリセットされます。ここで速度をリセットする必要があり、再生方法の後に配置する必要があります。そうしないと、効果がありません。
[self.player play];
self.player.rate = _playRate
ステップ5:現在の再生時間を取得し、初期化された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];
}];
}
复制代码
ステップ6:再生を評価し、AVPlayerのレート属性を設定します
self.player.rate = playRate
ステップ7:再生する特定の時点に移動します。詳細は次のとおりです。指を押すと、再生を停止して再生時間の通知を削除する必要があります。指を離すと、再生を続行し、現在の再生を監視します。間隔
[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;
}
复制代码
ステップ8:サムネイルをバッチで取得し、視覚的なプログレスバーを作成します
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]];
});
}
}];
}
复制代码
この時点で、簡単なビデオプレーヤーが完成します。もちろん、対処すべき詳細はまだたくさんあります。これは、友人が理解する必要があります。オーディオとビデオの学習は、長くて興味深い道である必要があります。