Setting multiple Volumes to each Video tracks using AudioMixInputParameters AVFoundation is not working in Swift iOS

房东的猫 提交于 2019-11-28 09:37:14

问题


I am working on Video based Application in Swift. As per the requirement I have to select multiple Videos from Device Gallery, setting up different different CIFilter effects and Volume for each Video Asset and then merge all the Videos and have to Save the Final Video. As an output, when I will play the Final Video then Video sound volume should change accordingly.

I have already merged all the selected Video Assets into one with different different CIFilter effects but my problem is when I am trying to set Volume for each Video Clips then it's not working. I am getting the default Volume for my Final Video. Here is my code:

func addFilerEffectAndVolumeToIndividualVideoClip(_ assetURL: URL, video: VideoFileModel, completion : ((_ session: AVAssetExportSession?, _ outputURL : URL?) -> ())?){

        let videoFilteredAsset = AVAsset(url: assetURL)

        print(videoFilteredAsset)
        createVideoComposition(myAsset: videoFilteredAsset, videos: video)

        let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]

        let url = URL(fileURLWithPath: documentDirectory).appendingPathComponent("\(video.fileID)_\("FilterVideo").mov")

        let filePath = url.path
        let fileManager = FileManager.default

        do {
            if fileManager.fileExists(atPath: filePath) {
                print("FILE AVAILABLE")
                try fileManager.removeItem(atPath:filePath)
            } else {
                print("FILE NOT AVAILABLE")
            }
        } catch _ {
        }

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


        //Add video to the final record
        do {
            try compositionVideo.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoFilteredAsset.duration), of: videoFilteredAsset.tracks(withMediaType: AVMediaTypeVideo)[0], at: kCMTimeZero)
        } catch _ {
        }

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

        let assetVideoTrack: AVAssetTrack = videoFilteredAsset.tracks(withMediaType: AVMediaTypeAudio)[0]

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

        //Set final volume of the audio record and the music
        videoParam.setVolume(video.videoClipVolume, at: kCMTimeZero)

        //Add setting
        audioMixParam.append(videoParam)

        //Add audio on final record
        do {
            try compositionAudioVideo.insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoFilteredAsset.duration), of: assetVideoTrack, at: kCMTimeZero)

        } catch _ {
            assertionFailure()
        }

        //Fading volume out for background music
        let durationInSeconds = CMTimeGetSeconds(videoFilteredAsset.duration)

        let firstSecond = CMTimeRangeMake(CMTimeMakeWithSeconds(0, 1), CMTimeMakeWithSeconds(1, 1))
        let lastSecond = CMTimeRangeMake(CMTimeMakeWithSeconds(durationInSeconds-1, 1), CMTimeMakeWithSeconds(1, 1))

        videoParam.setVolumeRamp(fromStartVolume: 0, toEndVolume: video.videoClipVolume, timeRange: firstSecond)
        videoParam.setVolumeRamp(fromStartVolume: video.videoClipVolume, toEndVolume: 0, timeRange: lastSecond)

        //Add parameter
        audioMix.inputParameters = audioMixParam

        // Export part, left for facility
        let exporter = AVAssetExportSession(asset: videoFilteredAsset, presetName: AVAssetExportPresetHighestQuality)!
        exporter.videoComposition = videoFilterComposition
        exporter.outputURL = url
        exporter.outputFileType = AVFileTypeQuickTimeMovie

        exporter.audioMix = audioMix

        exporter.exportAsynchronously(completionHandler: { () -> Void in
            completion!(exporter, url)
        })

    }

After that again I am using a method to merge all the Video Clips using AVAssetExportSession, there I am not setting any AudioMixInputParameters.

Note: When I am setting up volume in final merging method using AVAssetExportSession's AudioMixInputParameters, then Volume is getting change for full Video.

My question: Is it possible to set multiple volume for each Video Clips. Please suggest. Thank you!


回答1:


Here is the working solution for my question:

func addVolumeToIndividualVideoClip(_ assetURL: URL, video: VideoFileModel, completion : ((_ session: AVAssetExportSession?, _ outputURL : URL?) -> ())?){

        //Create Asset from Url
        let filteredVideoAsset: AVAsset = AVAsset(url: assetURL)

        video.fileID = String(video.videoID)

        //Get the path of App Document Directory
        let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]

        let url = URL(fileURLWithPath: documentDirectory).appendingPathComponent("\(video.fileID)_\("FilterVideo").mov")

        let filePath = url.path
        let fileManager = FileManager.default

        do {
            if fileManager.fileExists(atPath: filePath) {
                print("FILE AVAILABLE")
                try fileManager.removeItem(atPath:filePath)
            } else {
                print("FILE NOT AVAILABLE")
            }
        } catch _ {
        }


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


        //Add video to the final record
        do {
             try compositionVideo.insertTimeRange(CMTimeRangeMake(kCMTimeZero, filteredVideoAsset.duration), of: filteredVideoAsset.tracks(withMediaType: AVMediaTypeVideo)[0], at: kCMTimeZero)
        } catch _ {
        }

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

        let assetVideoTrack: AVAssetTrack = filteredVideoAsset.tracks(withMediaType: AVMediaTypeAudio)[0]

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

        //Set final volume of the audio record and the music
        videoParam.setVolume(video.videoVolume, at: kCMTimeZero)

        //Add setting
        audioMixParam.append(videoParam)

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

        //Fading volume out for background music
        let durationInSeconds = CMTimeGetSeconds(filteredVideoAsset.duration)

        let firstSecond = CMTimeRangeMake(CMTimeMakeWithSeconds(0, 1), CMTimeMakeWithSeconds(1, 1))
        let lastSecond = CMTimeRangeMake(CMTimeMakeWithSeconds(durationInSeconds-1, 1), CMTimeMakeWithSeconds(1, 1))

        videoParam.setVolumeRamp(fromStartVolume: 0, toEndVolume: video.videoVolume, timeRange: firstSecond)
        videoParam.setVolumeRamp(fromStartVolume: video.videoVolume, toEndVolume: 0, timeRange: lastSecond)

        //Add parameter
        audioMix.inputParameters = audioMixParam

        //Remove the previous temp video if exist
        let filemgr = FileManager.default
        do {
            if filemgr.fileExists(atPath: "\(video.fileID)_\("FilterVideo").mov") {
                try filemgr.removeItem(atPath: "\(video.fileID)_\("FilterVideo").mov")
            } else {
            }
        } catch _ {
        }

        //Exporte the final record’
        let exporter: AVAssetExportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality)!
        exporter.outputURL = url
        exporter.outputFileType = AVFileTypeMPEG4
        exporter.audioMix = audioMix

        exporter.exportAsynchronously(completionHandler: { () -> Void in
            completion!(exporter, url)

           // self.saveVideoToLibrary(from: filePath)
        })
    }



回答2:


I found, that exporting an asset with preset of AVAssetExportPresetPassthrough doesn't have an impact on output volume. When I tried to use AVAssetExportPresetLowQuality, volume change successfully applied.

I wish it is better documented somewhere :(

The working code:

// Assume we have:
let composition: AVMutableComposition
var inputParameters = [AVAudioMixInputParameters]()

// We add a track
let trackComposition = composition.addMutableTrack(...)

// Configure volume for this track
let inputParameter = AVMutableAudioMixInputParameters(track: trackComposition)
inputParameter.setVolume(desiredVolume, at: startTime)

// It works even without setting the `trackID`
// inputParameter.trackID = trackComposition.trackID

inputParameters.append(inputParameter)

// Apply gathered `inputParameters` before exporting
let audioMix = AVMutableAudioMix()
audioMix.inputParameters = inputParameters

// I found it's not working, if using `AVAssetExportPresetPassthrough`,
// so try `AVAssetExportPresetLowQuality` first
let export = AVAssetExportSession(..., presetName: AVAssetExportPresetLowQuality)
export.audioMix = audioMix

Tested this with multiple assetTrack insertions to the same compositionTrack, setting different volume for each insertion. Seems to be working.



来源:https://stackoverflow.com/questions/54804888/setting-multiple-volumes-to-each-video-tracks-using-audiomixinputparameters-avfo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!