简体   繁体   中英

Audio Mixing in iOS using AVFoundation doesnt work

I am trying to stitch a bunch of videos together and then add some music over the video in iOS. The audio is added using AVMutableAudioMix . However when the video is finally exported the audio mix is missing. Here is how the code looks like :

- (void)mergeVideos:(NSArray *)videos{
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
    AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    AVMutableCompositionTrack *audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                        preferredTrackID:kCMPersistentTrackID_Invalid];
    CMTime currentTime = kCMTimeZero;
    for (AVAsset *asset in videos) {
        // 2 - Video track
        [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                            ofTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:currentTime error:nil];
        [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                            ofTrack:[[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:currentTime error:nil];
        currentTime = CMTimeAdd(currentTime, asset.duration);
    }
        // 4 - Get path
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *myPathDocs =  [documentsDirectory stringByAppendingPathComponent:
                             [NSString stringWithFormat:@"mergeVideo-%d.mp4",arc4random() % 1000]];
    NSURL *url = [NSURL fileURLWithPath:myPathDocs]; 
    // 5 - Create exporter
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:mixComposition];
    NSString *quality = AVAssetExportPresetHighestQuality;
    //load the audio
    AVMutableAudioMix *audioMix = nil;
    NSURL *audioURL = [self loadAudioFile];// gives a url for a .caf file from the bundle
    if (audioURL) {
        AVURLAsset *audioAsset = [AVURLAsset assetWithURL:audioURL];
        AVAssetTrack *aTrack =  (AVAssetTrack *)[[audioAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];

        AVMutableAudioMixInputParameters *trackMix =
        [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:aTrack];

        [trackMix setVolumeRampFromStartVolume:0 toEndVolume:1 timeRange:
         CMTimeRangeMake(CMTimeMakeWithSeconds(0, 1), CMTimeMakeWithSeconds(3, 1))];
        [trackMix setVolume:1.0 atTime:kCMTimeZero];
        AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
        audioMix.inputParameters = [NSArray arrayWithObject:trackMix];
    }

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                      presetName:quality];
    if (audioMix) {
        exporter.audioMix = audioMix;
    }
    exporter.outputURL=url;
    exporter.outputFileType = AVFileTypeMPEG4;
    exporter.shouldOptimizeForNetworkUse = YES;
    [exporter exportAsynchronouslyWithCompletionHandler:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            [self exportDidFinish:exporter];
        });
    }];
}

There is no error while executing. Just that the music contained in the .caf file doesnt get mixed to the exported file. Any idea what is going on?

You haven't inserted the audio from the .caf file into any AVMutableCompositionTrack , so the audio mix associated with aTrack is not going to adjust the volume for the .caf file. If you'd like the audio from the .caf file to be included in the video with the associated audio mix, create another AVMutableCompositionTrack to hold the audio from the .caf file:

AVMutableCompositionTrack *audioTrackCAF = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
                                                                    preferredTrackID:kCMPersistentTrackID_Invalid];

(with the time ranges set to your liking):

[audioTrackCAF insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset.duration)
                            ofTrack:aTrack atTime:kCMTimeZero error:nil]

Additionally, is helpful to pass an NSError * (instead of nil ) to insertTimeRange:ofTrack:atTime:error to make sure you had valid time ranges and your media was inserted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM