ios - 使用 AudioMixInputParameters AVFoundation 为每个视频轨道设置多个音量在 Swift iOS 中不起作用

标签 ios swift audio avfoundation avassetexportsession

我正在 Swift 中开发基于VideoApplication。根据要求,我必须从 Device Gallery 中选择多个 Videos,设置不同的 CIFilter 效果和 Volume对于每个 Video Asset,然后合并所有 Videos 并且必须保存 Final Video。作为输出,当我播放 Final Video 时,Video 声音 volume 应该相应地改变。

我已经将所有选定的 Video Assets 合并到一个具有不同 CIFilter 效果的文件中,但我的问题是当我尝试设置 Volume 对于每个 Video Clips 然后它不工作。我正在为我的 Final Video 使用默认的 Volume。这是我的代码:

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)
        })

    }

在那之后,我再次使用一种方法使用 AVAssetExportSession 合并所有 Video Clips,我没有设置任何 AudioMixInputParameters

注意: 当我使用 AVAssetExportSession 的 AudioMixInputParameters 在最终合并方法中设置音量时,Volume 是获取完整 Video 的零钱。

我的问题:是否可以为每个 Video Clips 设置多个 volume。请建议。谢谢!

最佳答案

这是我的问题的有效解决方案:

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)
        })
    }

关于ios - 使用 AudioMixInputParameters AVFoundation 为每个视频轨道设置多个音量在 Swift iOS 中不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54804888/

相关文章:

Swift 将 NSManagedObject 转换为子类失败

swift - NSNull 转换为具有 NSDate 类型属性的 Struct

audio - 寻找富有表现力的音频编程语言或库

ios - AudioKit 4.0.1 - 类型 'AKSequencer' 的值没有成员 'avTracks'

ios - Restkit 简单的 NSDictionary 映射

ios - 尝试存档时自定义 NavigationStack 导致 `error: Segmentation fault: 11` 时的解决方法建议?

swift - tableview 到其他 View autoresize 问题 : swift

java - Android - 禁用启动屏幕上的声音

python - 如何使用 gst-python 生成音频流?

ios - 检查互联网连接类型 (iOS)