Jesse Black
Jesse Black

Reputation: 7976

AVAssetExportSession creates movie successfully, but the duration is off

I have been attempting to combine a video with background audio. I was able to create a video with 1 video and 1 audio file, (which I thankfully found on SO), but I am having difficulty extending it to use 2 or more audio files. The background audio can come from multiple files and I want to add them sequentially to the video.

Ex. audio-1.caf is 2 seconds long, audio-2.caf is 2 seconds long, video-1.mov is 4 seconds long.

I would like audio-1 to be at time interval 0-2 seconds and audio-2 to be at time interval 2-4 seconds. Unfortunately the code I have been creates a 2 second movie with the first audio-1 and the rest of the movie and audio are not included.

I simplified the problem down so I could ask for help here. The code below attempts to create a blank video with 2 audio sources. (My previous implementation was dynamic and looped through all audio sources)

-(void)writeAudio
{
  AVMutableComposition* mixComposition = [AVMutableComposition composition];

  NSDictionary * assetOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];

  NSString * outputFilePath = NSHomeDirectory();
  outputFilePath = [outputFilePath stringByAppendingPathComponent:@"Library"];
  outputFilePath = [outputFilePath stringByAppendingPathComponent:@"temp.mov"];
  NSURL * outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
  [[NSFileManager defaultManager] removeItemAtURL:outputFileUrl error:nil];

  CMTime nextClipStartTime = kCMTimeZero;
  NSURL * audioURL /* = kSomeValidURL */;
  NSURL * audio2URL /* = kSomeOtherValidURL */;

  AVURLAsset* audioAsset = [[AVURLAsset alloc] initWithURL:audioURL options:assetOptions];
  CMTimeRange audio_timeRange = CMTimeRangeMake(nextClipStartTime, audioAsset.duration);
  AVMutableCompositionTrack *b_compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
  [b_compositionAudioTrack insertTimeRange:audio_timeRange ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:nextClipStartTime error:nil];
  nextClipStartTime = CMTimeAdd(nextClipStartTime, audio_timeRange.duration);

  AVURLAsset* audio2Asset = [[AVURLAsset alloc] initWithURL:audio2URL options:assetOptions];
  CMTimeRange audio2_timeRange = CMTimeRangeMake(nextClipStartTime, audio2Asset.duration);
  AVMutableCompositionTrack *b_compositionAudio2Track = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
  [b_compositionAudio2Track insertTimeRange:audio2_timeRange ofTrack:[[audio2Asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:nextClipStartTime error:nil];
  nextClipStartTime = CMTimeAdd(nextClipStartTime, audio2_timeRange.duration);

  AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];   
  _assetExport.outputFileType = @"com.apple.quicktime-movie";
  _assetExport.outputURL = outputFileUrl;
  [_assetExport exportAsynchronouslyWithCompletionHandler:
   ^(void ) {
     NSLog(@"audio was completed???");
   }       
   ];


}

The problem remains the same, the new video consists of the first audioURL's contents and is the duration of the first audioURL's contents.

Upvotes: 1

Views: 1322

Answers (1)

Jesse Black
Jesse Black

Reputation: 7976

My issue stemmed from not understanding the AVFoundation fully (I still don't).

My time intervals, still need to start at 0 and last the durations of the audio assets, then be inserted at the time I want them to start at.

I changed the code that initializes the audio_timeRanges.

From

CMTimeRange audio_timeRange = CMTimeRangeMake(nextClipStartTime, audioAsset.duration);

To

CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration);

and From

CMTimeRange audio2_timeRange = CMTimeRangeMake(nextClipStartTime, audio2Asset.duration);

To

CMTimeRange audio2_timeRange = CMTimeRangeMake(kCMTimeZero, audio2Asset.duration);

Upvotes: 1

Related Questions