3

这个库的文档基本上不存在,所以我真的需要你的帮助。

目标:我需要 H264 编码(最好同时使用音频和视频,但只是视频就可以了,我只需播放几天就可以让音频工作)所以我可以将它传递到 MPEG 传输流中。

我所拥有的:我有一个记录和输出样本缓冲区的相机。输入是相机后盖和内置麦克风。

几个问题:A. 是否可以让相机以 H264 格式输出 CMSampleBuffers?我的意思是,2014 年的它是从 VTCompressionSessions 生成的,但是在编写我的 captureOutput 时,我看到我已经得到了一个 CMSampleBuffer... B.如何设置 VTCompressionSession?会话如何使用?一些关于此的总体顶级讨论可能会帮助人们了解这个几乎没有文档记录的库中实际发生的事情。

代码在这里(如果需要,请询问更多;我只放 captureOutput 因为我不知道其余代码的相关性):

func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {
    println(CMSampleBufferGetFormatDescription(sampleBuffer))
    var imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
    if imageBuffer != nil {
        var pixelBuffer = imageBuffer as CVPixelBufferRef
        var timeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBuffer as CMSampleBufferRef)
        //Do some VTCompressionSession stuff
    }
}

谢谢大家!

4

1 回答 1

0

首先初始化 VTCompression 会话并设置其属性

    NSDictionary* bAttributes= @{};

    VTCompressionSessionRef vtComp;
    OSStatus result = VTCompressionSessionCreate(NULL,
        trackSize.width,
        trackSize.height,
        kCMVideoCodecType_H264,
        NULL,
        (CFDictionaryRef)bAttributes,
        NULL,
        compressCallback,
        NULL,
        &vtComp);
    NSLog(@"create VTCS Status: %d",result);
    
    NSDictionary* compProperties = @{ 
        (id)kVTCompressionPropertyKey_ProfileLevel: (id)kVTProfileLevel_H264_High_AutoLevel,
        (id)kVTCompressionPropertyKey_H264EntropyMode: (id)kVTH264EntropyMode_CABAC,
        (id)kVTCompressionPropertyKey_Quality: @(0.95),
        (id)kVTCompressionPropertyKey_RealTime: @(YES),
        (id)kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder: @(YES),
        (id)kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder: @(YES)
    };

    result=VTSessionSetProperties(vtComp,(CFDictionaryRef)compProperties);

compressCallback是您在压缩数据可用时调用的方法。看起来像这样;

void compressCallback(void *outputCallbackRefCon, void *sourceFrameRefCon, OSStatus status, VTEncodeInfoFlags infoFlags, CMSampleBufferRef sampleBuffer)
{
    AVAssetWriterInput* aw = (AVAssetWriterInput*)sourceFrameRefCon;    
    [aw appendSampleBuffer:sampleBuffer];
}

然后你有你的读/压缩循环。您从 CMSample 缓冲区获取 CVImage 缓冲区并将其传递给压缩器。

        CVPixelBufferRef buffer = CMSampleBufferGetImageBuffer(cmbuf);
        VTEncodeInfoFlags encodeResult;

        result = VTCompressionSessionEncodeFrame (vtComp,
            buffer, 
            currentTime,
            frameDuration,
            NULL, // frameProperties
            writerInput, // opaque context to callback
            &encodeResult);

显然你需要检查状态和返回值,但这应该让你朝着正确的方向寻找。

于 2020-06-25T07:24:12.780 回答