在WWDC2014中使用VTCompressionSession

时间:2015-07-17 02:29:20

标签: ios swift core-media video-toolbox

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

目标:我需要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
    }
}

全部谢谢!

1 个答案:

答案 0 :(得分: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);

显然,您需要检查状态并返回值,但这应该使您朝正确的方向看。