【问题标题】:Composing Video and Audio - Video's audio is gone编写视频和音频 - 视频的音频消失了
【发布时间】:2017-12-31 23:49:36
【问题描述】:

我的问题是,我正在使用下面的功能来编写视频和音频。我想保留视频的原始声音,但不知何故消失了,我没有任何线索。

我从this answer得到这个功能

我尝试在添加 AVMutableCompositionTracks 后立即更改音量,但没有成功

例如;

mutableVideoCompositionTrack.prefferedVolume = 1.0
mutableAudioCompositionTrack.prefferedVolume = 0.05

但是,您仍然只能听到音频文件。

函数;

private func mergeAudioAndVideo(audioUrl: URL, videoUrl: URL, completion: @escaping (Bool)->Void){

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

    let videoAsset = AVAsset(url: videoUrl)
    let audioAsset = AVAsset(url: audioUrl)

    mutableCompositionVideoTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid))
    mutableCompositionAudioTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid))
    mutableCompositionAudioTrack[0].preferredVolume = 0.05
    mutableCompositionVideoTrack[0].preferredVolume = 1.0        


    let videoAssetTrack = videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0]
    let audioAssetTrack = audioAsset.tracks(withMediaType: AVMediaTypeAudio)[0]

    do {
        try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAssetTrack.timeRange.duration), of: videoAssetTrack, at: kCMTimeZero)
        try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAssetTrack.timeRange.duration), of: audioAssetTrack, at: kCMTimeZero)
    }catch{
        print("ERROR#1")
    }

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

    let mutableVideoComposition = AVMutableVideoComposition()
    mutableVideoComposition.frameDuration = CMTimeMake(1, 30)
    mutableVideoComposition.renderSize = CGSize(width: 1280, height: 720)

    //exporting

    savePathUrl = try! FileManager.default.url(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("merged").appendingPathExtension("mov")

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

    do {
        try FileManager.default.removeItem(at: savePathUrl)
    }catch {
        print(error)
    }

    assetExport.exportAsynchronously { 
        switch assetExport.status{
        case .completed:
            print("completed")
            completion(true)
        default:
            print("failed \(assetExport.error!)")
            completion(false)
        }
    }

}

【问题讨论】:

    标签: swift avfoundation avmutablecomposition avkit


    【解决方案1】:

    我想通了。加载视频的AVAsset 似乎将音频和视频分开保存。所以你可以联系他们写作``

    videoAsset.tracks(withMediaType: AVMediaTypeAudio)[0] //audio of a video
    videoAsset.tracks(withMediaType: AVMediaTypeVideo)[0] //video of a video(without sound)
    

    所以我将这些行添加到代码中并且它起作用了!

    var mutableCompositionBackTrack : [AVMutableCompositionTrack] = []
    
    mutableCompositionBackTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)) 
    
    try mutableCompositionBackTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, videoAssetTrack.timeRange.duration), of: backAssetTrack, at: kCMTimeZero)
    

    还有一点我不知道该怎么做,那就是设置这些音频资产的音量。一旦我弄清楚如何,我会更新这个答案。

    【讨论】:

    • 我想将视频的音频与我的自定义声音保存在一个文件中,以便在播放最终视频时播放两种音频。这个功能可以实现吗?
    • 这正是我在这里所做的。但正如我所说,我不知道如何更改每个音频的音量。 @parth
    • @FarukWell 在将视频合并为一个视频后,我也面临同样的调整视频的音量问题。你能帮我实现这个目标吗?谢谢!
    • 显然,问题不在于音量,而在于声音本身实际上丢失了。assetVideo.tracksWithMediaType(AVMediaTypeAudio)[0] 这段代码返回一个分别包含视频和音频的数组。所以你应该提取两个视频文件和你想要合成的声音文件。之后,一切都与合并有关。请仔细检查问题中的代码和@Vivek Goswami 的答案。
    【解决方案2】:

    你可以单独调整视频和音频的音量@Faruk,这里有一点代码。

            //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
    
    let completeMovie = "\(docsDir)/\(randomString(5)).mp4"
    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.Completed:
        print("success with output url \(completeMovieUrl)")
        case  AVAssetExportSessionStatus.Failed:
            print("failed \(String(exporter.error))")
        case AVAssetExportSessionStatus.Cancelled:
            print("cancelled \(String(exporter.error))")
        default:
            print("complete")
        }            
    })
    

    }

    【讨论】:

    • 这是一个很好的答案。感谢您抽出宝贵的时间。对于其他人,请注意这不是 Swift 4,但它很容易自我更新。
    【解决方案3】:

    这是所有答案的组合代码。我花了一些时间来解码这些答案,所以我决定在这里为任何未来的用户添加它:

    斯威夫特 5:

    enum MixError: Error {
       case TimeRangeFailure
       case ExportFailure
    }
    
    var selectedVideoLevel = 1.0
    var selectedMusicLevel = 1.0
    
    func mix(videoUrl: URL, musicUrl: URL, completion: ((Result<URL, Error>) -> Void)?) {
        let videoAsset = AVAsset(url: videoUrl)
        let musicAsset = AVAsset(url: musicUrl)
    
        let audioVideoComposition = AVMutableComposition()
    
        let audioMix = AVMutableAudioMix()
        var mixParameters = [AVMutableAudioMixInputParameters]()
    
        let videoCompositionTrack = audioVideoComposition
          .addMutableTrack(withMediaType: .video, preferredTrackID: .init())!
    
        let audioCompositionTrack = audioVideoComposition
          .addMutableTrack(withMediaType: .audio, preferredTrackID: .init())!
    
        let musicCompositionTrack = audioVideoComposition
          .addMutableTrack(withMediaType: .audio, preferredTrackID: .init())!
    
        let videoAssetTrack = videoAsset.tracks(withMediaType: .video)[0]
        let audioAssetTrack = videoAsset.tracks(withMediaType: .audio).first
        let musicAssetTrack = musicAsset.tracks(withMediaType: .audio)[0]
    
        let audioParameters = AVMutableAudioMixInputParameters(track: audioAssetTrack)
        audioParameters.trackID = audioCompositionTrack.trackID
    
        let musicParameters = AVMutableAudioMixInputParameters(track: musicAssetTrack)
        musicParameters.trackID = musicCompositionTrack.trackID
    
        audioParameters.setVolume(selectedVideoLevel, at: .zero)
        musicParameters.setVolume(selectedMusicLevel, at: .zero)
    
        mixParameters.append(audioParameters)
        mixParameters.append(musicParameters)
    
        audioMix.inputParameters = mixParameters
    
        /// prevents video from unnecessary rotations
        videoCompositionTrack.preferredTransform = videoAssetTrack.preferredTransform
    
        do {
          let timeRange = CMTimeRange(start: .zero, duration: videoAsset.duration)
    
          try videoCompositionTrack.insertTimeRange(timeRange, of: videoAssetTrack, at: .zero)
    
          if let audioAssetTrack = audioAssetTrack {
            try audioCompositionTrack.insertTimeRange(timeRange, of: audioAssetTrack, at: .zero)
          }
    
          try musicCompositionTrack.insertTimeRange(timeRange, of: musicAssetTrack, at: .zero)
    
        } catch {
          completion?(.failure(MixError.TimeRangeFailure)
        }
    
    
        let exportUrl = FileManager.default
          .urls(for: .applicationSupportDirectory, in: .userDomainMask).first?
          .appendingPathComponent("\(Date().timeIntervalSince1970)-video.mp4")
    
        let exportSession = AVAssetExportSession(
          asset: audioVideoComposition,
          presetName: AVAssetExportPresetHighestQuality
        )
    
        exportSession?.audioMix = audioMix
        exportSession?.outputFileType = .m4v
        exportSession?.outputURL = exportUrl
    
        exportSession?.exportAsynchronously(completionHandler: {
          guard let status = exportSession?.status else { return }
    
          switch status {
          case .completed:
            completion?(.success(exportUrl!))
         case .failed:
            completion?(.failure(MixError.ExportError)
          default:
            print(status)
    
          }
    
        })
    
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-08
      • 2014-08-02
      • 1970-01-01
      相关资源
      最近更新 更多