Using VTCompressionSession as in WWDC2014



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

目标:我需要H264编码(最好是音频和视频,但只是视频很好,我只是玩了几天,让音频工作太),所以我可以把它传递到MPEG传输流。

我有:我有一个相机记录和输出样本缓冲。输入为摄像头后置和内置麦克风。

几个问题:A.是否有可能让相机输出CMSampleBuffers在H264格式?我的意思是,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
    }
}

谢谢!

首先初始化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);

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

最新更新