Daniel Norman
Daniel Norman

Reputation: 151

Merging Audio with Video Objective-C

I'm attempting to merge an audio file with a video file using:

+ (void)CompileFilesToMakeMovie:(NSString *) audioPath {
NSLog(@"a");
AVMutableComposition* mixComposition = [AVMutableComposition composition];
NSURL *audio_inputFileUrl = [[NSURL alloc] initFileURLWithPath:audioPath];



NSString *videoPath = [[NSBundle bundleForClass:[self class]] pathForResource:@"input" ofType:@"mov"];
NSURL*    video_inputFileUrl = [NSURL fileURLWithPath:videoPath];

NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
NSString *outputFilePath = [docsDir stringByAppendingPathComponent:@"OutputFile.mov"];
NSURL*    outputFileUrl = [NSURL fileURLWithPath:outputFilePath];

if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
    [[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];
NSLog(@"b");


CMTime nextClipStartTime = kCMTimeZero;

AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:video_inputFileUrl options:nil];
CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
AVMutableCompositionTrack *a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[a_compositionVideoTrack insertTimeRange:video_timeRange ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:nextClipStartTime error:nil];

 NSLog(@"c");
AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil];
CMTimeRange audio_timeRange = CMTimeRangeMake(kCMTimeZero, 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];
 NSLog(@"d");


AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
_assetExport.outputFileType = @"com.apple.quicktime-movie";
_assetExport.outputURL = outputFileUrl;

[_assetExport exportAsynchronouslyWithCompletionHandler:
 ^(void ) {
     UISaveVideoAtPathToSavedPhotosAlbum(outputFilePath, nil, nil, nil);
 }       
 ];


}

But I am getting an error after "c" is logged for 'NSRangeException', reason:

* -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'.

The audio file is located at

  NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *docsDir = [dirPaths objectAtIndex:0];
  NSString *soundFilePath = [docsDir stringByAppendingPathComponent:@"%1.iaff"];

Any tips? Thanks.

Upvotes: 2

Views: 3952

Answers (2)

Ackman
Ackman

Reputation: 1592

This is happening because the audio or the video file has yet not been completely written and you are trying to merge them. Make sure you use completion handlers to make sure audio and video file at the specific path is written completely.

Upvotes: 0

Thilina Chamath Hewagama
Thilina Chamath Hewagama

Reputation: 9040

First of all I should say the audio format you have given is incorrect,

NSString *soundFilePath = [docsDir stringByAppendingPathComponent:@"%1.iaff"];

make that aiff NSString *soundFilePath = [docsDir stringByAppendingPathComponent:@"1.aiff"];

If you are not sure of the code you used, This code works for me,

    -(void) mergeAudio:(NSURL *) audioURL withVideo:(NSURL *) videoURL andSaveToPathUrl:(NSString *) savePath{

 AVURLAsset* audioAsset = [[AVURLAsset alloc]initWithURL:audioURL options:nil];
 AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:videoURL options:nil];

 AVMutableComposition* mixComposition = [AVMutableComposition composition];

 AVMutableCompositionTrack *compositionCommentaryTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
 preferredTrackID:kCMPersistentTrackID_Invalid];
 [compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration)
 ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]
 atTime:kCMTimeZero error:nil];

 AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
 preferredTrackID:kCMPersistentTrackID_Invalid];
 [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration)
 ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
 atTime:kCMTimeZero error:nil];

 AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition
 presetName:AVAssetExportPresetPassthrough];

 NSURL    *savetUrl = [NSURL fileURLWithPath:savePath];

 if ([[NSFileManager defaultManager] fileExistsAtPath:savePath])
 {
 [[NSFileManager defaultManager] removeItemAtPath:savePath error:nil];
 }

 _assetExport.outputFileType = @"com.apple.quicktime-movie";


 _assetExport.outputURL = savetUrl;
 _assetExport.shouldOptimizeForNetworkUse = YES;

 [_assetExport exportAsynchronouslyWithCompletionHandler:
 ^(void ) {
 NSLog(@"fileSaved !");
 }
 ];


 }

Pass the videoURL, audioURL and save path of the final file

Upvotes: 11

Related Questions