kaanmijo
kaanmijo

Reputation: 703

AVAssetExportSession, AVMutableComposition w/ AudioMix fade out not working

I'm building a app that combines a couple of videos, merges them into one and puts a custom audiotrack in the video. This all works flawlessly. Now I want to fade out my audio. This on the other hand, does not work, and I have no idea why. This is my code:

let duration = composition.duration
let durationInSeconds = CMTimeGetSeconds(duration) * 10
let composition = AVMutableComposition()

let item = AVPlayerItem(asset: composition)
let params = AVMutableAudioMixInputParameters(track: composition.tracks.first! as AVAssetTrack)

let lastSecond = CMTimeRangeMake(CMTimeMakeWithSeconds(durationInSeconds-10, 10), CMTimeMakeWithSeconds(1, 1))

params.setVolumeRamp(fromStartVolume: 1, toEndVolume: 0, timeRange: lastSecond)

let mix = AVMutableAudioMix()
mix.inputParameters = [params]

item.audioMix = mix

// Put the track under the video
do {
    try audioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, current), of: backgroundAudio.tracks(withMediaType: AVMediaTypeAudio)[0], at: kCMTimeZero)
} catch _ {
    print("Failed to load Audio track")
}

guard let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else { return }
exporter.audioMix = mix
exporter.outputURL = URL(fileURLWithPath: finalVideoPath)
exporter.outputFileType = AVFileTypeMPEG4
exporter.shouldOptimizeForNetworkUse = true

And after this block of code it continues to another method where the video itself is rendered. Could someone explain me why this does not work and how to fix this?

Thanks in advance!

Upvotes: 4

Views: 1228

Answers (2)

Bokoskokos
Bokoskokos

Reputation: 512

It's a bit unclear where your "audioTrack" comes from in the code snippet, but make sure you're getting the right composition track for the

AVMutableAudioMixInputParameters

e.g.

let compositionAudioTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)
let params = AVMutableAudioMixInputParameters(track: compositionAudioTrack)

It may just be that

composition.tracks.first!

is referencing one of your video tracks

Upvotes: 1

Vivek Goswami
Vivek Goswami

Reputation: 432

Here is a code for add Video and audio url and set volume of both. Your result video will be fade in and fade out effect.

 func mergeVideoAndMusicWithVolume(videoURL: NSURL, audioURL: NSURL, startAudioTime: Float64, volumeVideo: Float, volumeAudio: Float, complete: ((NSURL?)) -> Void) -> Void {

    //The goal is merging a video and a music from iPod library, and set it a volume

    //Get the path of App Document Directory
    let dirPaths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
    let docsDir = dirPaths[0] as String

    //Create Asset from record and music
    let assetVideo: AVURLAsset = AVURLAsset(URL: videoURL)
    let assetMusic: AVURLAsset = AVURLAsset(URL: audioURL)

    let composition: AVMutableComposition = AVMutableComposition()
    let compositionVideo : AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: CMPersistentTrackID())
    let compositionAudioVideo: AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())
    let compositionAudioMusic: AVMutableCompositionTrack = composition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID())

    //Add video to the final record

    do {
        try compositionVideo.insertTimeRange(CMTimeRangeMake(kCMTimeZero, assetVideo.duration), ofTrack:assetVideo.tracksWithMediaType(AVMediaTypeVideo)[0], atTime: kCMTimeZero)
    } catch _ {
    }

    //Extract audio from the video and the music
    let audioMix: AVMutableAudioMix = AVMutableAudioMix()
    var audioMixParam: [AVMutableAudioMixInputParameters] = []

    let assetVideoTrack: AVAssetTrack = assetVideo.tracksWithMediaType(AVMediaTypeAudio)[0]
    let assetMusicTrack: AVAssetTrack = assetMusic.tracksWithMediaType(AVMediaTypeAudio)[0]

    let videoParam: AVMutableAudioMixInputParameters = AVMutableAudioMixInputParameters(track: assetVideoTrack)
    videoParam.trackID = compositionAudioVideo.trackID

    let musicParam: AVMutableAudioMixInputParameters = AVMutableAudioMixInputParameters(track: assetMusicTrack)
    musicParam.trackID = compositionAudioMusic.trackID

    //Set final volume of the audio record and the music
    videoParam.setVolume(volumeVideo, atTime: kCMTimeZero)
    musicParam.setVolume(volumeAudio, atTime: kCMTimeZero)

    //Add setting
    audioMixParam.append(musicParam)
    audioMixParam.append(videoParam)

    //Add audio on final record
    //First: the audio of the record and Second: the music
    do {
    try compositionAudioVideo.insertTimeRange(CMTimeRangeMake(kCMTimeZero, assetVideo.duration), ofTrack: assetVideoTrack, atTime: kCMTimeZero)
    } catch _ {
    assertionFailure()
    }

    do {
    try compositionAudioMusic.insertTimeRange(CMTimeRangeMake(CMTimeMake(Int64(startAudioTime * 10000), 10000), assetVideo.duration), ofTrack: assetMusicTrack, atTime: kCMTimeZero)
    } catch _ {
    assertionFailure()
    }

    //Add parameter
    audioMix.inputParameters = audioMixParam

    //Remove the previous temp video if exist
    let filemgr = NSFileManager.defaultManager()
        do {
            if filemgr.fileExistsAtPath("\(docsDir)"){
                try filemgr.removeItemAtPath("\(docsDir)/movie-merge-music.mp4")
            } else {
            }
            } catch _ {
        }
    //Exporte the final record’
    let completeMovie = "\(docsDir)/\(randomString(5)).mp4"
    let completeMovieUrl = NSURL(fileURLWithPath: completeMovie)
    let exporter: AVAssetExportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality)!

    exporter.outputURL = completeMovieUrl
    exporter.outputFileType = AVFileTypeMPEG4
    exporter.audioMix = audioMix
    exporter.exportAsynchronouslyWithCompletionHandler({ 

    switch exporter.status {

    case AVAssetExportSessionStatus.Completed:
        print("success with output url \(completeMovieUrl)")
        case  AVAssetExportSessionStatus.Failed:
            print("failed \(String(exporter.error))")
        case AVAssetExportSessionStatus.Cancelled:
            print("cancelled \(String(exporter.error))")
        default:
            print("complete")
        }            
    })
}

Upvotes: 1

Related Questions