使用视频工具箱解码iOS 8中的h264

时间:2014-09-24 08:30:07

标签: video-streaming ios8 h.264

需要解码h264流并获取像素缓冲区

我知道在iOS 8上可以使用视频工具箱

1.如何将h264流转换为CMSampleBufferRef

2.如何使用视频工具箱进行解码?

2 个答案:

答案 0 :(得分:7)

我假设您获得附件B格式的流,如果它已经是AVCC格式(读取MP4),那么您可以使用AssetReader并且不需要做太多。

对于附件B流(这是ppl。通常称为原始h264流)。

  1. 提取SPS / PPS NAL单位并从此创建参数集。你定期收到它们。它们包含解码帧应如何解码的信息。

  2. 创建具有持续时间的TimingInfo数组(您可以从解析SPS的VUI部分获取它)以及呈现时间戳和解码时间戳。如果以MPEG2 TS接收流,则从PESr获取时间戳。如果不只是根据您的计算提供缺失的信息。

  3. 将VLC NAL单元包装在CMBlockBuffer中。你可以把多于一个。如果您通过RTP收到可能使NAL单元分段的流,请确保每个NAL单元都已完成。

  4. 将NAL单元包装在CMBlock缓冲区中时,用长度标题替换3或4字节的起始码。

  5. 将信息提供给CMSampleBufferCreate,您可以在VTDecompressionSession中解码帧

  6. WWDC提供了预设功能,可以更详细地解释这些步骤,并提供示例代码。

答案 1 :(得分:3)

尝试使用此代码。将编码后的CMSampleBufferRef提供给sampleBuffer。

if(!decompressionSession)
    {
    CMFormatDescriptionRef formatDescription=CMSampleBufferGetFormatDescription(sampleBuffer);
    decompressionSession = NULL;
    VTDecompressionOutputCallbackRecord callBackRecord;
    callBackRecord.decompressionOutputCallback=didDecompress;
    callBackRecord.decompressionOutputRefCon = (__bridge void *)self;
    OSStatus status1= VTDecompressionSessionCreate(kCFAllocatorDefault, formatDescription, NULL, NULL, &callBackRecord, &decompressionSession);
    }
    else
    {
        VTDecodeFrameFlags flags = kVTDecodeFrame_EnableAsynchronousDecompression;
        VTDecodeInfoFlags flagOut;
        VTDecompressionSessionDecodeFrame(decompressionSession, sampleBuffer, flags, NULL, &flagOut);
        VTDecompressionSessionWaitForAsynchronousFrames(decompressionSession);

    }



Decompression all back

static void didDecompress( void *decompressionOutputRefCon, void *sourceFrameRefCon, OSStatus status, VTDecodeInfoFlags infoFlags, CVImageBufferRef imageBuffer, CMTime presentationTimeStamp, CMTime presentationDuration ){
 if(status==noErr)
    {
        NSLog(@"SUCCESS PROCEED FROM HERE !!!!");
    }
}

//请记住,您在编码时提供正确的演示时间。我在为您提供编码详细信息..

//ENCODING-------------------ENCODING---------------ENCODING
if(!_compression_session)
{
  NSDictionary* pixelBufferOptions = @{
                                          (NSString*) kCVPixelBufferWidthKey : @(widthOFCaptureImage),
                                          (NSString*) kCVPixelBufferHeightKey : @(heightOFCaptureImage),
                                          (NSString*) kCVPixelBufferOpenGLESCompatibilityKey : @YES,
                                          (NSString*) kCVPixelBufferIOSurfacePropertiesKey : @{}};
_compression_session=NULL;
 CFMutableDictionaryRef encoderSpecifications = NULL;
  err = VTCompressionSessionCreate(
                                     kCFAllocatorDefault,
                                     widthOFCaptureImage,
                                     heightOFCaptureImage,
                                     kCMVideoCodecType_H264,
                                     encoderSpecifications,
                                     (__bridge CFDictionaryRef)pixelBufferOptions,
                                     NULL,
                                     compressionCallback,
                                     (__bridge void *)self,
                                     &_compression_session);
}
else
{


 CMTime presentationTimeStamp = CMSampleBufferGetPresentationTimeStamp(sampleBufferIs);
  CVPixelBufferRef pixelbufferPassing= CMSampleBufferGetImageBuffer(sampleBufferIs);
          OSStatus status1= VTCompressionSessionEncodeFrame(_compression_session, pixelbufferPassing, presentationTimeStamp, kCMTimeInvalid, NULL, NULL, NULL);
 VTCompressionSessionEndPass(_compression_session, NO, NULL);
}

// ENCODING CALL BACK ----------------------------------------- < / p>

  static void compressionCallback(void *outputCallbackRefCon,
                             void *sourceFrameRefCon,
                             OSStatus status,
                             VTEncodeInfoFlags infoFlags,
                             CMSampleBufferRef sampleBuffer ){
    }

//祝福:)快乐的编码:)