1

I am merging multiple videos and playing it in AVPlayer. Video starts fine, but after sometime video freezes and only audio plays. I have a UISlider which helps to go forward or backward in video using seekToTime:.

So the weird part is that after video freezes, if I use the slider to go forward or backward, video starts playing perfectly fine. I have tried my app in multiple devices.

So basically I have to use seekToTime: method to give the video a nudge every time it freezes.

My code for merging video and playing back is following:

AVAsset *asset0 = [self currentAsset:0];
AVAsset *asset1 = [self currentAsset:1];
AVAsset *asset2 = [self currentAsset:2];
AVAsset *asset3 = [self currentAsset:3];
AVAsset *asset4 = [self currentAsset:4];

NSArray *assets = @[asset0, asset1, asset2, asset3, asset4];

AVMutableComposition *mutableComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                                   preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                                   preferredTrackID:kCMPersistentTrackID_Invalid];

NSMutableArray *instructions = [NSMutableArray new];
CGSize size = CGSizeZero;

CMTime time = kCMTimeZero;
for (AVAsset *asset in assets)
{
    AVAssetTrack *assetTrack = [asset tracksWithMediaType:AVMediaTypeVideo].firstObject;
    AVAssetTrack *audioAssetTrack = [asset tracksWithMediaType:AVMediaTypeAudio].firstObject;

    NSError *error;
    [videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, assetTrack.timeRange.duration)
                                   ofTrack:assetTrack
                                    atTime:time
                                     error:&error];
    if (error) {
        NSLog(@"Error - %@", error.debugDescription);
    }

    [audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, assetTrack.timeRange.duration)
                                   ofTrack:audioAssetTrack
                                    atTime:time
                                     error:&error];
    if (error) {
        NSLog(@"Error - %@", error.debugDescription);
    }

    AVMutableVideoCompositionInstruction *videoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    videoCompositionInstruction.timeRange = CMTimeRangeMake(time, assetTrack.timeRange.duration);
    videoCompositionInstruction.layerInstructions = @[[AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack]];
    [instructions addObject:videoCompositionInstruction];

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

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

AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition];
mutableVideoComposition.instructions = instructions;

mutableVideoComposition.frameDuration = CMTimeMake(1, 30);
mutableVideoComposition.renderSize = size;

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

player = [AVPlayer playerWithPlayerItem:[[CameraEngine engine] pi]];

player.volume = 0.75;
playerLayer = [AVPlayerLayer playerLayerWithPlayer: player];

playerLayer.frame = self.bounds;
[self.layer addSublayer: playerLayer];
[playerLayer setNeedsDisplay];
[player play];

UPDATE : Found out this link which describes similar problem. But his solution is not well understood.

Community
  • 1
  • 1
blancos
  • 1,576
  • 2
  • 16
  • 38
  • "But his solution is not well understood." What do you mean by that? It seems clear enough. Do you mean _you_ don't understand it? – matt Apr 03 '15 at 18:48
  • Also, can you explain what you are doing with AVMutableVideoCompositionInstruction? – matt Apr 03 '15 at 18:50
  • Can you please comment the videoCompositionInstruction in your code and try the same. may be there is something wrong with that – Nitheesh George Apr 03 '15 at 19:00

1 Answers1

0

Why do you call [AVPlayer playerWithPlayerItem:[[CameraEngine engine] pi]] instead of [AVPlayer playerWithPlayerItem:pi]? Your construct your composition and assign it to pi while it is not used anywhere. Try to use [AVPlayer playerWithPlayerItem:pi] instead.

If this will not help try to change your videoComposition generation. Try to do the following:

AVMutableVideoCompositionInstruction *videoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
videoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, mutableComposition.timeRange.duration);
videoCompositionInstruction.layerInstructions = @[[AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:[mutableComposition tracksWithMediaType:AVMediaTypeVideo].firstObject]];

AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition];
mutableVideoComposition.instructions = @[videoCompositionInstruction];

mutableVideoComposition.frameDuration = CMTimeMake(1, 30);
mutableVideoComposition.renderSize = size;

after your for loop. Hope this helps!

Nikita Arkhipov
  • 1,208
  • 4
  • 11
  • 28