Strange AVMutableComposition hang behavior when using AVMutableVideoComposition

I am trying to combine multiple videos using AVMutableComposition . The problem I am facing is that whenever I try to add any AVMutableVideoComposition to apply any instructions, my playback freezes in AVPlayer with an accuracy of 6 seconds.

Another interesting thing: to play it perfectly if I play it in the Photos application of the iPad after exporting using the same videoComposition . So why does it freeze in AVPlayer after 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; 

In addition, I know that the problem is mainly videoComposition , because if I delete videoComposition , then it works fine on AVPlayer .

UPDATE 1 . I just found out that when it freezes after 6 seconds, if I dragged the slider back or forward (i.e. used seekToTime ), it will start playing normally again without further freezing.

Also, the sound continues to play well even when the video is frozen.

UPDATE 2 . If I just continue and export it using AVAssetExportSession with the same AVMutableComposition , and load the resource from the exported video, it works fine. So when I play AVMutableComposition directly, the problem arises.

+6
source share
1 answer

Finally, I got a solution to fix this.

You must play after the player status has changed to .ReadyToPlay.

See 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 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() } 
0
source

All Articles