我对 swift(和编程)仍然很陌生,我正在尝试将从 ARFrame 获得的 CVPixelbuffer 实时输出到视频中(顶部没有 AR 的东西)。
我已经设置了 AVAssetWriter 和 Input,并在每一帧上尝试附加 CVPixelbuffer(转换为 CMSampleBuffer)。
该代码创建了一个 0 字节的文件并且没有给出任何错误。我不知道出了什么问题,而且文档对于我的级别来说相当神秘。
我很确定每帧的时间戳不正确。但我无法弄清楚每一帧是否需要时间,或者自视频开始以来的总时间。
然后是 cvPixelBuffer 的大小和格式。我也不知道我是否需要告诉 AVAssetwriter 即将到来的数据的大小和格式是什么,或者它是否可以自己解决。
感谢您的时间。
class VideoHandler
{
var videoWriter: AVAssetWriter?
var videoWriterInput: AVAssetWriterInput?
var videoURL = URL(fileURLWithPath: "")
let videoSize = CGSize(width: 1280, height: 720)
func start()
{
videoURL = getDocumentsDirectory().appendingPathComponent("Temp.mov")
do {
try FileManager.default.removeItem(at: videoURL)
} catch {}
do {
try videoWriter = AVAssetWriter(outputURL: videoURL, fileType: AVFileType.mov)
} catch let error as NSError {
print(error)
videoWriter = nil
}
let videoSettings: [String : AnyObject] = [
AVVideoCodecKey : AVVideoCodecType.h264 as AnyObject,
AVVideoWidthKey : videoSize.width as AnyObject,
AVVideoHeightKey : videoSize.height as AnyObject,
// AVVideoCompressionPropertiesKey : [
// AVVideoAverageBitRateKey : NSInteger(1000000),
// AVVideoMaxKeyFrameIntervalKey : NSInteger(16),
// AVVideoProfileLevelKey : AVVideoProfileLevelH264BaselineAutoLevel
// ]
]
videoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
videoWriterInput?.expectsMediaDataInRealTime = true
//TODO: Force unwrapping... so dangerous but don't know any other way.
if videoWriter!.canAdd(videoWriterInput!)
{
videoWriter!.add(videoWriterInput!)
}
else
{
print("Can't add videoWriterInput")
}
if videoWriter?.startWriting() ?? false
{
videoWriter?.startSession(atSourceTime: CMTime.zero)
}
print("Video writing started.")
}
func addFrame(buffer: CVPixelBuffer, timeStamp: Double)
{
if videoWriterInput?.isReadyForMoreMediaData ?? false
{
videoWriterInput?.append(getCMSampleBuffer(buffer: buffer, timeStamp: timeStamp))
}
}
func getCMSampleBuffer(buffer: CVPixelBuffer, timeStamp: Double) -> CMSampleBuffer
{
// Don't know yet how to set the time and timescale stuff properly.
var info = CMSampleTimingInfo()
// info.presentationTimeStamp = CMTime.zero
info.presentationTimeStamp = CMTime(seconds: timeStamp, preferredTimescale: 1)
// info.duration = CMTime.invalid
// info.decodeTimeStamp = CMTime.invalid
var formatDesc: CMFormatDescription? = nil
CMVideoFormatDescriptionCreateForImageBuffer(
allocator: kCFAllocatorDefault,
imageBuffer: buffer,
formatDescriptionOut: &formatDesc)
var sampleBuffer: CMSampleBuffer? = nil
CMSampleBufferCreateReadyWithImageBuffer(allocator: kCFAllocatorDefault,
imageBuffer: buffer,
formatDescription: formatDesc!,
sampleTiming: &info,
sampleBufferOut: &sampleBuffer);
return sampleBuffer!
}
func stop()
{
videoWriter?.finishWriting
{
print("Video writing finished.")
}
videoWriter = nil
}
func getDocumentsDirectory() -> URL
{
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
}