我正在尝试使用从另一个视频中获取的样本缓冲区来创建和保存视频。我正在使用Swift Playground,并启用了以下设置,以便Dispatch可以正常工作。
PlaygroundPage.current.needsIndefiniteExecution = true
然后声明资产读取器,并将其用于读取样本缓冲区。样本缓冲区是有效的(将随机缓冲区转换为UIImage并显示它会显示正确的帧)。
// A sample buffer array is populated from a source video.
// Source video is just a three seconds 720p video at 30fps (m4v).
var sampleBuffer: CMSampleBuffer? = assetReaderOutput.copyNextSampleBuffer()
var sourceSampleBufferArray = [CMSampleBuffer]()
while (sampleBuffer != nil) {
sampleBuffer = assetReaderOutput.copyNextSampleBuffer()
if (sampleBuffer != nil) {
sourceSampleBufferArray.append(sampleBuffer!)
}
}
现在,我正在尝试使用AVAssetWriter将样本缓冲区另存为新视频。
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
let videoOutputURL = URL(fileURLWithPath: documentsPath.appendingPathComponent("AssembledVideo.m4v"))
do {
try FileManager.default.removeItem(at: videoOutputURL as URL)
}
catch {}
let assetWriter = try AVAssetWriter(outputURL: videoOutputURL as URL, fileType: AVFileTypeAppleM4V)
let outputSettings: Dictionary<String, AnyObject> = [
AVVideoCodecKey : AVVideoCodecH264 as AnyObject,
AVVideoWidthKey : 1280 as AnyObject,
AVVideoHeightKey : 720 as AnyObject
];
let assetWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: outputSettings)
assetWriter.add(assetWriterInput)
let mediaQueue = DispatchQueue(label: "DispatchQueue")
if assetWriter.startWriting() {
var counter = sourceSampleBufferArray.count
assetWriter.startSession(atSourceTime: kCMTimeZero)
assetWriterInput.requestMediaDataWhenReady(on: mediaQueue) {
while assetWriterInput.isReadyForMoreMediaData {
if counter > 0 {
assetWriterInput.append(sourceSampleBufferArray[counter - 1])
counter = counter - 1
}
else {
assetWriterInput.markAsFinished()
assetWriter.finishWriting(completionHandler: {
print(assetWriter.outputURL)
})
break
}
}
}
}
我没有收到任何错误,并且代码似乎可以正常运行,只是创建的视频为零字节。任何建议或帮助弄清楚为什么视频未正确保存的原因将不胜感激。谢谢:)
每个帧/样本缓冲区都有其自己的显示时间戳。将其移植到新视频中时,这些可能不正确。您可以使用
检查时间戳记let timestamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer)
如果您仅将一个视频插入输出视频中,则解决方案就像通过以下方法更改输出视频的时间轴原点一样简单:
let startTime = CMSampleBufferGetPresentationTimeStamp(firstInputSampleBuffer)
assetWriter.startSession(atSourceTime: startTime)
如果要插入多个时间间隔不兼容的多部视频,则需要使用您计算出的正确演示时间戳来复制(浅!)单个样本缓冲区的副本>
CMSampleBufferCreateCopyWithNewTiming()