ios - 在 WWDC2014 中使用 VTCompressionSession

标签 ios swift core-media video-toolbox

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

目标:我需要 H264 编码(最好同时使用音频和视频,但只有视频就可以了,我会玩几天让音频也能正常工作),这样我就可以将它传递到 MPEG 传输流中。

我有什么:我有一个记录和输出样本缓冲区的相机。输入是相机背面和内置麦克风。

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

此处的代码(如果需要,请索取更多;我只放了 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 session 并设置其属性

    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);

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

关于ios - 在 WWDC2014 中使用 VTCompressionSession,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31467571/

相关文章:

ios - 检查 iOS 是否正在播放音乐 ("Is button in control center Pause?")

swift - Mac 托盘应用程序的全局键盘快捷键

SwiftUI 如何从所有 View 中查看类

objective-c - 如何使用 AVAssetReader 添加到 AudioBufferList?

ios - 在 iOS 上使用 CoreMedia.framework 解码视频

iOS:保留计数因分配方式而异

ios - 无法很好地解码 NSString

ios - 如何检测 Swift 4 中计划通知何时被触发

ios - 更改 View 的父级

ios - 如何在 Swift 中将 CMSampleBuffer 转换为数据?