0

我对 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]
    }

}
4

0 回答 0