使用AVMutableVideoComposition时AVMutableComposition冻结的奇怪行为 [英] Weird behaviour of AVMutableComposition freezing while using AVMutableVideoComposition

查看:452
本文介绍了使用AVMutableVideoComposition时AVMutableComposition冻结的奇怪行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 AVMutableComposition 合并多个视频。我遇到的问题是每当我尝试添加任何 AVMutableVideoComposition 来应用任何指令时,我的播放都会在 AVPlayer 中冻结准确的6秒持续时间。



另一个有趣的事情是,如果我在使用相同的 videoComposition导出后在iPad的照片应用中播放它,它会正常播放。那么为什么它会在6秒内在 AVPlayer 中冻结?



代码:

  AVMutableComposition * mutableComposition = [AVMutableComposition composition]; 

AVMutableCompositionTrack * videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];

AVMutableCompositionTrack * audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];

for(AVURLAsset *资产中的资产)
{
AVAssetTrack * assetTrack;
assetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack * audioAssetTrack = [asset tracksWithMediaType:AVMediaTypeAudio] .firstObject;


NSError *错误;
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,assetTrack.timeRange.duration)
ofTrack:assetTrack
atTime:time
error:& error];

if(error){
NSLog(@asset url ::%@,assetTrack.asset);
NSLog(@Error1 - %@,error.debugDescription);
}

[audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,audioAssetTrack.timeRange.duration)
ofTrack:audioAssetTrack
atTime:time
error:& error ]。

if(error){
NSLog(@Error2 - %@,error.debugDescription);
}

time = CMTimeAdd(time,assetTrack.timeRange.duration);

if(CGSizeEqualToSize(size,CGSizeZero)){
size = assetTrack.naturalSize ;;
}
}

AVMutableVideoCompositionInstruction * mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
AVMutableVideoCompositionLayerInstruction * videoTrackLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];

mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,time);
mainInstruction.layerInstructions = [NSArray arrayWithObjects:videoTrackLayerInstruction,nil];
AVMutableVideoComposition * mainCompositionInst = [AVMutableVideoComposition videoComposition];
mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1,30);
mainCompositionInst.renderSize = size;

pi = [AVPlayerItem playerItemWithAsset:mutableComposition];
pi.videoComposition = mainCompositionInst;

此外,我知道问题主要是 videoComposition 因为如果我删除了 videoComposition ,那么它在 AVPlayer 上播放正常。



UPDATE 1 :我刚发现它在6秒后冻结,如果我向后或向前拖动滑块(即使用 seekToTime ),它再次开始正常播放而不再进一步冻结。



即使视频被冻结,音频也能保持正常播放。



更新2 :如果我继续使用 AVAssetExportSession 进行导出相同的 AVMutableComposition ,并从导出的视频加载资产,它工作正常。所以当我直接玩 AVMutableComposition 时,问题就出现了。

解决方案

最后,我得到了解决这个问题的解决方案。



你应该在playerItem的状态改为.ReadyToPlay之后玩。



<请参见下文。

  func startVideoPlayer(){
let playerItem = AVPlayerItem(asset:self.composition !)
playerItem.videoComposition = self.videoComposition!

让玩家= AVPlayer(playerItem:playerItem)
player.actionAtItemEnd = .None

videoPlayerLayer = AVPlayerLayer(玩家:玩家)
videoPlayerLayer!。 frame = self.bounds

/ * add playerItem的observer * /
player.addObserver(self,forKeyPath:player.currentItem.status,options:.New,context:nil)

NSNotificationCenter.defaultCenter()。addObserver(self,selector:playerItemDidReachEnd:,name:AVPlayerItemDidPlayToEndTimeNotification,object:playerItem);

self.layer.addSublayer(videoPlayerLayer!)
}

覆盖func observeValueForKeyPath(keyPath:String?,ofObject object:AnyObject ?, change:[String: AnyObject] ?, context:UnsafeMutablePointer< Void>){
if keyPath!= nil&&的keyPath! ==player.currentItem.status{
如果让newValue =更改?[NSKeyValueChangeNewKey] {
如果AVPlayerStatus(rawValue:newValue as!Int)== .ReadyToPlay {
playVideo() / *播放状态更改为.ReadyToPlay * /
}
}
} else {
super.observeValueForKeyPath(keyPath,ofObject:object,change:change,context:context )
}
}

func playerItemDidReachEnd(通知:NSNotification){
让playerItem = notification.object as! AVPlayerItem
playerItem.seekToTime(kCMTimeZero)

playVideo()
}

func playVideo(){
videoPlayerLayer?.player!。 play()
}


I am trying to merge multiple videos using AVMutableComposition. The problem I face is that whenever I try to add any AVMutableVideoComposition for applying any instructions, my playback freezes in AVPlayer at exact 6 seconds duration.

Another interesting thing is that it plays fine if I play it in Photos app of iPad after exporting using same videoComposition. So why does it freezes in AVPlayer at 6 seconds?

Code:

AVMutableComposition *mutableComposition = [AVMutableComposition composition];

    AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];

    AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                                       preferredTrackID:kCMPersistentTrackID_Invalid];

    for (AVURLAsset *asset in assets)
    {
            AVAssetTrack *assetTrack;
            assetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
            AVAssetTrack *audioAssetTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;


            NSError *error;
            [videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, assetTrack.timeRange.duration )
                                                   ofTrack:assetTrack
                                                    atTime:time
                                                     error:&error];

            if (error) {
                NSLog(@"asset url :: %@",assetTrack.asset);
                NSLog(@"Error1 - %@", error.debugDescription);
            }

            [audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAssetTrack.timeRange.duration)
                                               ofTrack:audioAssetTrack
                                                atTime:time
                                                 error:&error];

            if (error) {
                NSLog(@"Error2 - %@", error.debugDescription);
            }

            time = CMTimeAdd(time, assetTrack.timeRange.duration);

            if (CGSizeEqualToSize(size, CGSizeZero)) {
                size = assetTrack.naturalSize;;
            }
        }

        AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
        AVMutableVideoCompositionLayerInstruction *videoTrackLayerInstruction =  [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];

        mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, time);
        mainInstruction.layerInstructions = [NSArray arrayWithObjects:videoTrackLayerInstruction, nil];
        AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
        mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
        mainCompositionInst.frameDuration = CMTimeMake(1, 30);
        mainCompositionInst.renderSize = size;

        pi = [AVPlayerItem playerItemWithAsset:mutableComposition];
        pi.videoComposition = mainCompositionInst;

Also, I know problem is mostly videoComposition because if I remove the videoComposition, then it plays fine on AVPlayer.

UPDATE 1: I just found out that when it freezes after 6 seconds, if I drag the slider back or forward(i.e. use seekToTime), it starts playing normally again without any further freeze.

Also audio keeps on playing fine even when video is frozen.

UPDATE 2: If I just go ahead and export it using AVAssetExportSession with same AVMutableComposition, and load asset from of exported video, it works fine. So its just when I play AVMutableComposition directly, problem arises.

解决方案

Finally, I got the solution to fix this.

You should play after playerItem's status is changed to .ReadyToPlay.

Please see as below.

func startVideoPlayer() {
    let playerItem = AVPlayerItem(asset: self.composition!)
    playerItem.videoComposition = self.videoComposition!

    let player = AVPlayer(playerItem: playerItem)
    player.actionAtItemEnd = .None

    videoPlayerLayer = AVPlayerLayer(player: player)
    videoPlayerLayer!.frame = self.bounds

    /* add playerItem's observer */
    player.addObserver(self, forKeyPath: "player.currentItem.status", options: .New, context: nil)

    NSNotificationCenter.defaultCenter().addObserver(self, selector: "playerItemDidReachEnd:", name: AVPlayerItemDidPlayToEndTimeNotification, object: playerItem);

    self.layer.addSublayer(videoPlayerLayer!)
}

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
    if keyPath != nil && keyPath! == "player.currentItem.status" {
        if let newValue = change?[NSKeyValueChangeNewKey] {
            if AVPlayerStatus(rawValue: newValue as! Int) == .ReadyToPlay {
                playVideo() /* play after status is changed to .ReadyToPlay */
            }
        }
    } else {
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
}    

func playerItemDidReachEnd(notification: NSNotification) {
    let playerItem = notification.object as! AVPlayerItem
    playerItem.seekToTime(kCMTimeZero)

    playVideo()
} 

func playVideo() {
    videoPlayerLayer?.player!.play()
}       

这篇关于使用AVMutableVideoComposition时AVMutableComposition冻结的奇怪行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆