I'm trying to merge a pre-existing video with a newly recorded audio voiceover track. User can set the relative sound volume for the two audio tracks (audio belonging to video, and new audio).
This code works in terms of merging it into one new video file, however I can't figure out how to adjust track volume. I tried some code (commented out) but don't understand how to use AVMutableAudioMixInputParameters with the code I already have.
static func mergeFilesWithUrl(videoUrl: URL, videoVolume: Float, audioUrl: URL, audioVolume: Float, completion: @escaping (URL?, Error?) -> Void) {
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: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)!)
mutableCompositionAudioTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)!)
mutableCompositionAudioOfVideoTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)!)
let aAudioOfVideoTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaType.audio)[0]
let aVideoAssetTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaType.video)[0]
let aAudioAssetTrack: AVAssetTrack = aAudioAsset.tracks(withMediaType: AVMediaType.audio)[0]
do {
try mutableCompositionAudioOfVideoTrack[0].insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aAudioOfVideoTrack, at: CMTime.zero)
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)
} catch {
}
//TODO: how to set audio track volume
// let audioMixInputParams = AVMutableAudioMixInputParameters()
// audioMixInputParams.trackID = aAudioAssetTrack.trackID
// audioMixInputParams.setVolume(0.0, at: CMTime.zero)
// aAudioAssetTrack.inputParameters.append(audioMixInputParams)
totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration)
let mutableVideoComposition: AVMutableVideoComposition = AVMutableVideoComposition()
mutableVideoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
mutableVideoComposition.renderSize = CGSize(width: 720, height: 1280)//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 = AVFileType.mp4
assetExport.outputURL = savePathUrl as URL
assetExport.shouldOptimizeForNetworkUse = true
assetExport.exportAsynchronously {
switch assetExport.status {
case AVAssetExportSessionStatus.completed:
print("success")
completion(assetExport.outputURL, nil)
case AVAssetExportSessionStatus.failed:
print("failed \(String(describing: assetExport.error))")
completion(nil, assetExport.error)
case AVAssetExportSessionStatus.cancelled:
print("cancelled \(String(describing: assetExport.error))")
completion(nil, assetExport.error)
default:
print("complete")
}
}
}
Here is the code I used to change volume of a track:
let audioMix: AVMutableAudioMix = AVMutableAudioMix()
var audioMixParam: [AVMutableAudioMixInputParameters] = []
let assetAudioFromVideo: AVAssetTrack = videoAsset.tracks(withMediaType: AVMediaType.audio)[0]
let videoParam: AVMutableAudioMixInputParameters = AVMutableAudioMixInputParameters(track: assetAudioFromVideo)
videoParam.trackID = videoAudioTrack!.trackID
videoParam.setVolume(inputs.levels.videoVolume, at: CMTime.zero)
audioMixParam.append(videoParam)
audioMix.inputParameters = audioMixParam
//...
let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)!
assetExport.outputFileType = AVFileType.mp4
assetExport.outputURL = savePathUrl as URL
assetExport.shouldOptimizeForNetworkUse = true
assetExport.audioMix = audioMix
assetExport.videoComposition = videoComposition
assetExport.exportAsynchronously { //...