Я все еще очень новичок в swift (и программировании), и я пытаюсь вывести CVPixelbuffer, который я получаю из ARFrame, в видео в реальном времени (без 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]
}
}