Goz
Goz

Reputation: 62323

ios playing 3 videos one after another

I am trying to start a new video with no delay as soon as the first video ends. I tried using the AVQueuePlayer but there is some delay when the first video ends and the second starts.

I need this to be sample synchronous. ie if video 1 is 10.25 seconds long then when I have been playing for 11.5 seconds video 2 should be 1.25 seconds in.

I have been experimenting with keeping 3 AVPlayer objects where I preRoll each player using the same master clock. I am then trying to intercept the AVPlayerItemDidPlayToEndTimeNotification and then calling setRate:time:atHostTime: to start the next video going. However I'm not getting any video playing.

I pre-roll my videos using the following code:

- (void) preRollPlayer: (AVPlayer*) pPlayer withMasterClock: (CMClockRef) masterClock atTime: (NSTimeInterval) time
{
    [pPlayer setRate: 0.0f];
    [pPlayer play];

    [pPlayer seekToTime: CMTimeMakeWithSeconds( time, 1000000 ) toleranceBefore: kCMTimeZero toleranceAfter: kCMTimeZero];
    [pPlayer setMasterClock: masterClock];

    __block volatile int32_t completed  = 0;
    [pPlayer prerollAtRate: 1.0f completionHandler: ^( BOOL finished )
        {
            OSAtomicIncrement32( &completed );
        }];

    while( completed == 0 )
    {
        [NSThread sleepForTimeInterval: 0.01];
    }
}


I then call preRoll as follows:

if ( pAudioVideoEntry.beforeVideoReader )
{
    [self preRollPlayer: pAudioVideoEntry.beforeVideoReader.player  withMasterClock: hostClock atTime: currentTime];
}

{
    [self preRollPlayer: pAudioVideoEntry.videoReader.player        withMasterClock: hostClock atTime: currentTime];
}
if ( pAudioVideoEntry.afterVideoReader )
{
    [self preRollPlayer: pAudioVideoEntry.afterVideoReader.player   withMasterClock: hostClock atTime: currentTime];
}


I finally start the video as follows:

[pAudioVideoEntry.beforeVideoReader.player  setRate: 1.0f time: kCMTimeZero atHostTime: syncTime];
    pAudioVideoEntry.playingPlayer  = pAudioVideoEntry.beforeVideoReader.player;

[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector( beforeVideoEnded: )
                                             name: AVPlayerItemDidPlayToEndTimeNotification
                                           object: pAudioVideoEntry.beforeVideoReader.playerItem];

What is odd is that I do not hear the audio, the notification is never sent and every call to my AVPlayerItem's output AVPlayerItemVideoOutput's hasNewPixelBufferForItemTime returns false. So I'm guessing the video has not started. Any ideas why?

Upvotes: 2

Views: 573

Answers (1)

Goz
Goz

Reputation: 62323

So in classic style around an hour after I post this (having spent most of the day battling over it) I find a simple solution here: https://stackoverflow.com/a/11337690/131140

Using an AVMutableCompositionI can add each video in sequence into the composition and I get perfect playback:

    // Fill in the assets that make up the composition
    CMTime time             = kCMTimeZero;
    for( AVAsset* pThisAsset in pAssets )
    {
        CMTimeRange timeRange   = CMTimeRangeMake( kCMTimeZero, pThisAsset.duration );
        [pComposition insertTimeRange: timeRange ofAsset: pThisAsset atTime: time error: nil];

        time        = CMTimeAdd( time, pThisAsset.duration );
    }

I'm having a slight bug with the video images playing back out of sync with the audio but the audio is performing perfectly. Massively simplified my code as well!

Upvotes: 1

Related Questions