问题描述
我正在尝试使用AVFoundation合并多个视频。当我仅添加两个视频时,效果很好。但是,当我尝试添加3个视频时,第二个视频轨道为空,但是导出的视频的总时长是正确的。
这是我的示例代码:
添加视频的代码:
func addVideo(videoAsset: AVAsset,isLast: Bool = false)
{
// Add video track
guard let videoTrack = self.mixComposition.addMutableTrack(
withMediaType: .video,preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
else { return }
do
{
try videoTrack.insertTimeRange(
CMTimeRangeMake(start: .zero,duration: videoAsset.duration),of: videoAsset.tracks(withMediaType: .video)[0],at: totalVideoTrackDuration)
// Add instruction for this track
// video helper fixes the video orientation
let instruction = VideoHelper.videoCompositionInstruction(videoTrack,asset: videoAsset)
if !isLast
{
// hide this clip when its done rendering
instruction.setOpacity(0.0,at: videoAsset.duration)
}
// add to layer instruction
self.instructions.append(instruction)
// get the sum of all added track durations
self.totalVideoTrackDuration = CMTimeAdd(self.totalVideoTrackDuration,videoAsset.duration)
}
catch
{
print("Failed to load track")
return
}
}
以下是导出视频的代码:
func export()
{
// 6
let mainInstruction = AVMutableVideoCompositionInstruction()
// set time range
mainInstruction.timeRange = CMTimeRangeMake(
start: .zero,duration: self.totalVideoTrackDuration
)
mainInstruction.layerInstructions = self.instructions
let mainComposition = AVMutableVideoComposition()
mainComposition.instructions = [mainInstruction]
mainComposition.frameDuration = CMTimeMake(value: 1,timescale: self.timeScale)
mainComposition.renderSize = self.videoSize
guard let documentDirectory = FileManager.default.urls(
for: .documentDirectory,in: .userDomainMask).first
else { return }
// file name
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .long
dateFormatter.timeStyle = .short
let date = Date().format(format: "mm-dd-yy-HH-mm-ss")!
let url = documentDirectory.appendingPathComponent("mergeVideo-\(date).mov")
guard let exporter = AVAssetExportSession(
asset: self.mixComposition,presetName: AVAssetExportPresetHighestQuality)
else { return }
exporter.outputURL = url
exporter.outputFileType = AVFileType.mov
exporter.shouldOptimizeForNetworkUse = true
exporter.videoComposition = mainComposition
exporter.exportAsynchronously {
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.
creationRequestForAssetFromVideo(
atFileURL: exporter.outputURL!)
}){
saved,error in
if saved
{
print("Export successful")
}
else
{
print("video erro: \(error)")
}
}
}
}
这是我调用addVideo
函数的方式:
// 4-second video
self.addVideo(videoAsset: asset1)
// 3-second video
self.addVideo(videoAsset: asset2)
// 4-second video
self.addVideo(videoAsset: asset3,isLast: true)
// export
self.export()
// the total duration of the exported video is 11 seconds. But the middle part,is blank.
解决方法
原来有问题的行是:
if !isLast
{
// hide this clip when its done rendering
instruction.setOpacity(0.0,at: videoAsset.duration)
}
// get the sum of all added track durations
self.totalVideoTrackDuration = CMTimeAdd(self.totalVideoTrackDuration,videoAsset.duration)
应该是:
// get the sum of all added track durations
self.totalVideoTrackDuration = CMTimeAdd(self.totalVideoTrackDuration,videoAsset.duration)
if !isLast
{
instruction.setOpacity(0.0,at: self.totalVideoTrackDuration)
}
setOpacity
的文档有些混乱。我以为at
参数是该特定视频时间范围内的时间。