AVMutableAudioMixInputParameters:setVolume() 不适用于 iOS 9 的音频文件

Posted

技术标签:

【中文标题】AVMutableAudioMixInputParameters:setVolume() 不适用于 iOS 9 的音频文件【英文标题】:AVMutableAudioMixInputParameters: setVolume() doesn't work with audio file iOS 9 【发布时间】:2015-10-26 13:41:27 【问题描述】:

我尝试将视频记录与设备 iPod 库中的音频文件混合。

我想设置每个音频(视频的音频和音频文件的音频)的音量。

我尝试将AVMutableAudioMixInputParameters 对象与setVolume() 方法一起使用。

我对视频的音量没有任何问题,但最终录制的音频文件的音量总是设置为最大。我尝试更改音频文件以使用视频进行测试,并仅获取该视频的音轨,并且效果很好。

import UIKit
import AVFoundation

class AVTools: NSObject 

    /**
    volume: between 1.0 and 0.0
    */
    class 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 = assetVideoTrack.trackID

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

        //Set final volume of the audio record and the music
        videoParam.setVolume(volumeVideo, atTime: kCMTimeZero)
        musicParam.setVolume(volumeAudio, atTime: kCMTimeZero) // <----- This doesn't work on audio file

        //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)/movie-merge-music.mov") 
                try filemgr.removeItemAtPath("\(docsDir)/movie-merge-music.mov")
             else 
            
         catch _ 
        

        //Exporte the final record’
        let completeMovie = "\(docsDir)/movie-merge-music.mov"
        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.Failed:
                print("failed \(exporter.error)")
                complete(nil)
            case AVAssetExportSessionStatus.Cancelled:
                print("cancelled \(exporter.error)")
                complete(nil)
            default:
                print("complete")
                complete(completeMovieUrl)
            
        )
    

【问题讨论】:

您找到解决方案了吗?! 还没有...任何更新暂时修复它 这实际上不是我的问题。我只是忘记在exporter.audioMix = audioMix周围复制+粘贴代码时将混合添加到导出会话中@ 【参考方案1】:

好的,我找到了问题所在。 问题是我分配了资产的 trackID 而不是组合的 trackID。 要修复它,只需替换:

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

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

到:

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

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

最终结果:

    /**
 volume: between 1.0 and 0.0
 */
class 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)/movie-merge-music.mov") 
            try filemgr.removeItemAtPath("\(docsDir)/movie-merge-music.mov")
         else 
        
     catch _ 
    

    //Exporte the final record’
    let completeMovie = "\(docsDir)/movie-merge-music.mov"
    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.Failed:
            print("failed \(exporter.error)")
            complete(nil)
        case AVAssetExportSessionStatus.Cancelled:
            print("cancelled \(exporter.error)")
            complete(nil)
        default:
            print("complete")
            complete(completeMovieUrl)
        
    )

【讨论】:

以上是关于AVMutableAudioMixInputParameters:setVolume() 不适用于 iOS 9 的音频文件的主要内容,如果未能解决你的问题,请参考以下文章