ios - AVMutableAudioMixInputParameters : setVolume() doesn't work with audio file iOS 9

标签 ios iphone swift avfoundation

我尝试将视频记录与设备 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)
            }
        })
    }
}

最佳答案

好的,我找到问题了。 问题是我分配了 Assets 的 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)
        }
    })
}

关于ios - AVMutableAudioMixInputParameters : setVolume() doesn't work with audio file iOS 9,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33347256/

相关文章:

ios - 错误无法使 UICollectionElementKindCell 类型的 View 出列

iphone - 如何在 Xcode 4 中从断点操作打印字符串值?

iphone - 它会影响 map 加载速度/性能吗? addAnnotation 与 addAnnotations

iphone - 为什么我的 UITextView 中不显示键盘?

swift - NSURLErrorDomain 错误消息是否应该出现在 Xcode 控制台中?

ios - 每次我按下调试线调用 NSMakeRange 的单步执行按钮时,都会进入 NSMakeRange

iphone - iOS 拨号助手自动将本地号码格式化为美国号码

swift - 如何在当前类型 Swift 中使用泛型函数

swift - 使用 Storyboard和 swift 从 xib 打开 NSWindow

objective-c - 当 block 的参数数量和类型可能不同时,使用来自 va_list 的参数调用 block