6
我試圖在播放過程中更改視頻合成的佈局(即其組件幀轉換)。看起來有時候這種方式會起作用,而且視頻組合會無縫地更改爲新的變換集合,但有時它會凍結並保留當前的變換。 AVPlayer實例沒有狀態碼更改,播放器或播放器項目上也沒有錯誤。在播放過程中更改AVPlayerItem的videoComposition屬性(AVMutableVideoComposition)
有沒有人經歷過這個?任何建議,爲什麼發生這種情況,或如何解決它,將不勝感激。
部分代碼如下所示。重要的是'playerItem.videoComposition = videoComposition',這是在點擊視頻時觸發的(用於測試目的)。
此問題的另一個解決方案是將視頻顯示在單獨的圖層上,但視頻同步是非常必要的,因此構圖似乎是實現此目的的唯一方法。
@implementation VideoView
{
CGSize _videoSize;
CMTimeRange _videoFullRange;
AVMutableCompositionTrack * _compositionTrackVideoA;
AVMutableCompositionTrack * _compositionTrackVideoB;
}
+ (Class)layerClass
{
return [AVPlayerLayer class];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
NSString * videoAPath = [[NSBundle mainBundle] pathForResource:@"cam09v2" ofType:@"mp4"];
NSString * videoBPath = [[NSBundle mainBundle] pathForResource:@"cam10v2_b" ofType:@"mp4"];
AVURLAsset * videoAAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoAPath] options:nil];
AVURLAsset * videoBAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:videoBPath] options:nil];
AVAssetTrack * videoATrack = [[videoAAsset tracksWithMediaType:AVMediaTypeVideo] lastObject];
AVAssetTrack * videoBTrack = [[videoBAsset tracksWithMediaType:AVMediaTypeVideo] lastObject];
AVAssetTrack * audioTrack = [[videoAAsset tracksWithMediaType:AVMediaTypeAudio] lastObject];
_videoSize = [videoATrack naturalSize];
CMTime videoDuration = videoAAsset.duration;
_videoFullRange = CMTimeRangeMake(kCMTimeZero, videoDuration);
AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableCompositionTrack * compositionTrackVideoA = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack * compositionTrackVideoB = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack * compositionTrackAudio = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
compositionTrackVideoA.preferredTransform = videoATrack.preferredTransform;
NSError * error = nil;
if (! [compositionTrackVideoA insertTimeRange:_videoFullRange ofTrack:videoATrack atTime:kCMTimeZero error:&error])
NSLog(@"%@", error);
if (! [compositionTrackVideoB insertTimeRange:_videoFullRange ofTrack:videoBTrack atTime:kCMTimeZero error:&error])
NSLog(@"%@", error);
if (! [compositionTrackAudio insertTimeRange:_videoFullRange ofTrack:audioTrack atTime:kCMTimeZero error:&error])
NSLog(@"%@", error);
_compositionTrackVideoA = [compositionTrackVideoA copy];
_compositionTrackVideoB = [compositionTrackVideoB copy];
AVPlayerItem * playerItem = [AVPlayerItem playerItemWithAsset:composition];
AVPlayer * player = [AVPlayer playerWithPlayerItem:playerItem];
[(AVPlayerLayer *)self.layer setPlayer:player];
[player play];
[player addObserver:self forKeyPath:@"status" options:0 context:0];
[self updateCompositionForPlayerItem:playerItem];
UITapGestureRecognizer * tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTap:)];
[self addGestureRecognizer:tapGesture];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"status"])
NSLog(@"STATUS %d", ((AVPlayer *)object).status);
}
- (void)updateCompositionForPlayerItem:(AVPlayerItem *)playerItem
{
AVMutableVideoComposition * videoComposition = [AVMutableVideoComposition videoComposition];
AVMutableVideoCompositionInstruction *videoInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
videoInstruction.enablePostProcessing = NO;
videoInstruction.timeRange = _videoFullRange;
AVMutableVideoCompositionLayerInstruction * layerInstructionA = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:_compositionTrackVideoA];
CGAffineTransform transformA = CGAffineTransformMakeScale(0.5, 0.5);
[layerInstructionA setTransform:transformA atTime:kCMTimeZero];
AVMutableVideoCompositionLayerInstruction * layerInstructionB = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:_compositionTrackVideoB];
CGAffineTransform transformB = CGAffineTransformMakeScale(0.5, 0.5);
static int i = 0;
transformB = CGAffineTransformTranslate(transformB, (i++ % 2 == 0) ? _videoSize.width : 0, _videoSize.height);
[layerInstructionB setTransform:transformB atTime:kCMTimeZero];
videoInstruction.layerInstructions = [NSArray arrayWithObjects:layerInstructionA, layerInstructionB, nil];
videoComposition.instructions = [NSArray arrayWithObject:videoInstruction];
videoComposition.frameDuration = CMTimeMake(1, 30); // 30 fps
videoComposition.renderSize = _videoSize;
playerItem.videoComposition = videoComposition;
}
- (void)didTap:(UITapGestureRecognizer *)tapGesture
{
[self updateCompositionForPlayerItem:((AVPlayerLayer *)self.layer).player.currentItem];
}
@end