【问题标题】:Swift Merge audio and video Swift3Swift 合并音视频 Swift3
【发布时间】:2019-05-24 13:50:06
【问题描述】:

我有一个视频,我正在将另一个音频合并到那个视频,所以现在我有两个音频和那个视频,一个是原始声音,另一个是视频自己的声音。现在的问题是我可以为视频自己的声音设置音量,但我无法设置外部音频的音量。我已经使用以下代码来做同样的事情。

func mergeAV(videoUrl: URL, audioUrl: URL, shouldFlipHorizontally: Bool = false) {
    print("\(#function)")
    process_merge.startAnimating()

    let mixComposition = AVMutableComposition()
    var mutableCompositionVideoTrack = [AVMutableCompositionTrack]()
    var mutableCompositionAudioTrack = [AVMutableCompositionTrack]()
    var mutableCompositionAudioOfVideoTrack = [AVMutableCompositionTrack]()

    let aVideoAsset = AVAsset(url: videoUrl)
    let aAudioAsset = AVAsset(url: audioUrl)

    let compositionAddVideo = mixComposition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)
    let compositionAddAudio = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)
    let compositionAddAudioOfVideo = mixComposition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)

    let aVideoAssetTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaType.video)[0]
    let aAudioOfVideoAssetTrack: AVAssetTrack? = aVideoAsset.tracks(withMediaType: AVMediaType.audio).first
    let aAudioAssetTrack: AVAssetTrack = aAudioAsset.tracks(withMediaType: AVMediaType.audio)[0]

    compositionAddVideo?.preferredTransform = aVideoAssetTrack.preferredTransform

    mutableCompositionVideoTrack.append(compositionAddVideo!)
    mutableCompositionAudioTrack.append(compositionAddAudio!)
    mutableCompositionAudioOfVideoTrack.append(compositionAddAudioOfVideo!)

    do {
        try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aVideoAssetTrack, at: CMTime.zero)

        try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: CMTime.zero)

        if let aAudioOfVideoAssetTrack = aAudioOfVideoAssetTrack {
            try mutableCompositionAudioOfVideoTrack[0].insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aAudioOfVideoAssetTrack, at: CMTime.zero)
        }

    } catch {
        print(error.localizedDescription)
    }

    // Exporting
    let fileManager = FileManager.default
    let documentsDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let savePathUrl = documentsDirectory.appendingPathComponent("MergeAudioVideo.mp4")

    do {
        // delete old video
        try FileManager.default.removeItem(at: savePathUrl)
    } catch {
        print(error.localizedDescription)
    }

    var videoVolume : Float = 0.0
    var audioVolume : Float = 0.0
    videoVolume = self.vol_Video.value
    audioVolume = self.vol_Audio.value

    let audioMix: AVMutableAudioMix = AVMutableAudioMix()
    var audioMixParam: [AVMutableAudioMixInputParameters] = []

    let videoParam: AVMutableAudioMixInputParameters = AVMutableAudioMixInputParameters(track: aVideoAssetTrack)
    videoParam.trackID = (compositionAddVideo?.trackID)!

    let musicParam: AVMutableAudioMixInputParameters = AVMutableAudioMixInputParameters(track: aAudioAssetTrack)
    musicParam.trackID = (compositionAddAudio?.trackID)!

    videoParam.setVolume(videoVolume, at: CMTime.zero)
    musicParam.setVolume(audioVolume, at: CMTime.zero)

    videoParam.setVolumeRamp(fromStartVolume: videoVolume, toEndVolume: videoVolume, timeRange: aVideoAssetTrack.timeRange)
    musicParam.setVolumeRamp(fromStartVolume: videoVolume, toEndVolume: audioVolume, timeRange: aAudioAssetTrack.timeRange)

    audioMixParam.append(musicParam)
    audioMixParam.append(videoParam)

    audioMix.inputParameters = [musicParam,videoParam]

    let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
    assetExport.outputFileType = AVFileType.mp4
    assetExport.outputURL = savePathUrl
    assetExport.shouldOptimizeForNetworkUse = true
    assetExport.audioMix = audioMix

    print("Export Action")
    assetExport.exportAsynchronously { () -> Void in
        self.process_merge.stopAnimating()

        switch assetExport.status {
        case AVAssetExportSession.Status.completed:
            print("Merge video+Audio URL : \(savePathUrl)")
            print("Export : success")
            self.showMess(strMess: "Success...\nMerge video+Audio URL: \(savePathUrl)", isAlert: false)
            break

        default:
            print("Error : unknown")
            self.showMess(strMess: "Something was wrong. Please try again.\nError: \(assetExport.error?.localizedDescription ?? "unknown")", isAlert: true)
            break
        }
    }
}

我该如何解决这个问题?请帮忙!

【问题讨论】:

  • 嗨@Khush,我在合并视频和音频时需要你的帮助...
  • 在我的情况下,我有包含音频但不知道为什么我得到空数组的视频资产?如果我制作一个视频 3 到 5 秒,那么我不会收到任何错误,因为数组不是空的,但是如果我创建一个超过 5、6 秒的视频并且这个视频也包含音频,那么在这种情况下,我会得到 EMPTY ARRAY(INDEX OUT OF BOUND) 并且它崩溃了......你能通过 mr.ahtazaz@gmail.com 帮助我吗?
  • 嘿@Mr.Ahtazaz 抱歉迟到了,你解决了吗?还是仍然面临这个问题?
  • 嗨@Khush。是的,它解决了。非常感谢...
  • 您能告诉我们崩溃的原因吗?

标签: ios audio video swift3 merge


【解决方案1】:
func mergeFilesWithUrl(videoUrl: URL, audioUrl: URL) {

    let mixComposition: AVMutableComposition = AVMutableComposition()

    var mutableCompositionVideoTrack: [AVMutableCompositionTrack] = []
    var mutableCompositionAudioTrack: [AVMutableCompositionTrack] = []
    var mutableCompositionAudioOfVideoTrack: [AVMutableCompositionTrack] = []
    let totalVideoCompositionInstruction: AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction()

    let aVideoAsset: AVAsset = AVAsset(url: videoUrl)
    let aAudioAsset: AVAsset = AVAsset(url: audioUrl)

    mutableCompositionVideoTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid))
    mutableCompositionAudioTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid))
    mutableCompositionAudioOfVideoTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid))

    let aAudioOfVideoTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaTypeAudio)[0]
    let aVideoAssetTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaTypeVideo)[0]
    let aAudioAssetTrack: AVAssetTrack = aAudioAsset.tracks(withMediaType: AVMediaTypeAudio)[0]

    do {
        try mutableCompositionAudioOfVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), of: aAudioOfVideoTrack, at: kCMTimeZero)
        try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), of: aVideoAssetTrack, at: kCMTimeZero)
        try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: kCMTimeZero)
    } catch {

    }

    totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration)

    let mutableVideoComposition: AVMutableVideoComposition = AVMutableVideoComposition()
    mutableVideoComposition.frameDuration = CMTimeMake(1, 30)

    mutableVideoComposition.renderSize = CGSize(width: 1280, height: 720)//CGSize(1280,720)

    //find your video on this URl
    let savePathUrl: NSURL = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/newVideo.mp4")

    do { // delete old video
        try FileManager.default.removeItem(at: savePathUrl as URL)
    } catch {
        print(error.localizedDescription)
    }

    let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
    assetExport.outputFileType = AVFileTypeMPEG4
    assetExport.outputURL = savePathUrl as URL
    assetExport.shouldOptimizeForNetworkUse = true

    assetExport.exportAsynchronously {
        switch assetExport.status {
        case AVAssetExportSessionStatus.completed:
            print("success")
        case AVAssetExportSessionStatus.failed:
            print("failed \(assetExport.error)")
        case AVAssetExportSessionStatus.cancelled:
            print("cancelled \(assetExport.error)")
        default:
            print("complete")
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    • 2018-12-03
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2018-12-27
    相关资源
    最近更新 更多