I have a video file and an audio file. Is it possible to merge it to one video with with sound file. I think AVMutableComposition should help me, but I still dont understand how. any advices?
Asked
Active
Viewed 1.3k times
3 Answers
19
Thanks Daniel. I figured it out, its easy.
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, videoAsset.duration)
ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:kCMTimeZero error:nil];
AVAssetExportSession* _assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition
presetName:AVAssetExportPresetPassthrough];
NSString* videoName = @"export.mov";
NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
{
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
}
_assetExport.outputFileType = @"com.apple.quicktime-movie";
DLog(@"file type %@",_assetExport.outputFileType);
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
// your completion code here
}
}
];

Steve
- 970
- 3
- 8
- 19
-
acutually this peice of code is not working properly..when i implement this code into my project then there will be crashed on [compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration) ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil]; and shows there is no object at index zero.. – Swastik Mar 21 '12 at 06:09
-
@Swastik I run into the same problem on occassion, especially when working with files from the iCloud. The fix for me has been to do 2 things. 1) verify that the file I am trying to use is valid for the media type I'm trying to use it as and 2) make sure the file actually has data with it (which it sometimes doesn't with the iCloud) – nick Jul 02 '12 at 17:30
-
hi Steve, I'm only merging a single audio/video file. The problem is that, my video file of 40 seconds and audio file is of 28 seconds. So for remaining 12 (40-28) seconds – I want repeat it from 0 seconds in Audio file. How do I that? Is there a direct way to do this? – Hemang Jun 18 '15 at 11:23
-
same issue...... crashed on [[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] there is no object at index zero, any one find solution? – Jayesh Lathiya Sep 25 '15 at 09:54
-
@jayeshlathiya Did you find any solution ?? – iOS.Lover Jan 01 '16 at 20:34
6
Yes it is possible, here is a snippet of code that is used to add audio to an existing composition, i grabbed this from apples sample code, you should probably view the whole project, youll find it very useful, the project is AVEditDemo and you can find it in the WWDC 2010 material that they posted here developer.apple.com/videos/wwdc/2010. Hope that helps
- (void)addCommentaryTrackToComposition:(AVMutableComposition *)composition withAudioMix:(AVMutableAudioMix *)audioMix
{
NSInteger i;
NSArray *tracksToDuck = [composition tracksWithMediaType:AVMediaTypeAudio]; // before we add the commentary
// Clip commentary duration to composition duration.
CMTimeRange commentaryTimeRange = CMTimeRangeMake(self.commentaryStartTime, self.commentary.duration);
if (CMTIME_COMPARE_INLINE(CMTimeRangeGetEnd(commentaryTimeRange), >, [composition duration]))
commentaryTimeRange.duration = CMTimeSubtract([composition duration], commentaryTimeRange.start);
// Add the commentary track.
AVMutableCompositionTrack *compositionCommentaryTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionCommentaryTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, commentaryTimeRange.duration) ofTrack:[[self.commentary tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:commentaryTimeRange.start error:nil];
NSMutableArray *trackMixArray = [NSMutableArray array];
CMTime rampDuration = CMTimeMake(1, 2); // half-second ramps
for (i = 0; i < [tracksToDuck count]; i++) {
AVMutableAudioMixInputParameters *trackMix = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:[tracksToDuck objectAtIndex:i]];
[trackMix setVolumeRampFromStartVolume:1.0 toEndVolume:0.2 timeRange:CMTimeRangeMake(CMTimeSubtract(commentaryTimeRange.start, rampDuration), rampDuration)];
[trackMix setVolumeRampFromStartVolume:0.2 toEndVolume:1.0 timeRange:CMTimeRangeMake(CMTimeRangeGetEnd(commentaryTimeRange), rampDuration)];
[trackMixArray addObject:trackMix];
}
audioMix.inputParameters = trackMixArray;
}

Daniel
- 22,363
- 9
- 64
- 71
-
1Where is this demo ? I can not find a download for it anywhere. – The Lazy Coder Aug 18 '11 at 20:48
-
I'm only merging a single audio/video file. The problem is that, my video file of 40 seconds and audio file is of 28 seconds. So for remaining 12 (40-28) seconds – I want repeat it from 0 seconds in Audio file. How do I that? Is there a direct way to do this? – Hemang Jun 18 '15 at 11:26
0
Here is the swift version:
func mixAudio(audioURL audioURL: NSURL, videoURL: NSURL) {
let audioAsset = AVURLAsset(URL: audioURL)
let videoAsset = AVURLAsset(URL: videoURL)
let mixComposition = AVMutableComposition()
let compositionCommentaryTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)
// add audio
let timeRange = CMTimeRangeMake(kCMTimeZero, audioAsset.duration)
let track = audioAsset.tracksWithMediaType(AVMediaTypeAudio)[0]
do {
try compositionCommentaryTrack.insertTimeRange(timeRange, ofTrack: track, atTime: kCMTimeZero)
}
catch {
print("Error insertTimeRange for audio track \(error)")
}
// add video
let compositionVideoTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)
let timeRangeVideo = CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
let trackVideo = videoAsset.tracksWithMediaType(AVMediaTypeVideo)[0]
do {
try compositionVideoTrack.insertTimeRange(timeRangeVideo, ofTrack: trackVideo, atTime: kCMTimeZero)
}
catch {
print("Error insertTimeRange for video track \(error)")
}
// export
let assetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetPassthrough)
let videoName = "export.mov"
exportPath = "\(NSTemporaryDirectory())/\(videoName)"
let exportURL = NSURL(fileURLWithPath: exportPath!)
if NSFileManager.defaultManager().fileExistsAtPath(exportPath!) {
do {
try NSFileManager.defaultManager().removeItemAtPath(exportPath!)
}
catch {
print("Error deleting export.mov: \(error)")
}
}
assetExportSession?.outputFileType = "com.apple.quicktime-movie"
assetExportSession?.outputURL = exportURL
assetExportSession?.shouldOptimizeForNetworkUse = true
assetExportSession?.exportAsynchronouslyWithCompletionHandler({
print("Mixed audio and video!")
dispatch_async(dispatch_get_main_queue(), {
print(self.exportPath!)
})
})
}

RawMean
- 8,374
- 6
- 55
- 82