【问题标题】:Putting an H.264 I frame to AVSampleBufferDisplayLayer but no video image is displayed将 H.264 I 帧放入 AVSampleBufferDisplayLayer 但不显示视频图像
【发布时间】:2014-09-28 01:48:47
【问题描述】:

在详细回顾了 WWDC2014,Session513 之后,我尝试在 IOS8.0 上编写我的应用程序来解码和显示一个实时 H.264 流。首先,我成功构建了一个H264参数集。当我得到一个带有 4 位起始码的 I 帧时,就像“0x00 0x00 0x00 0x01 0x65 ...”一样,我将它放入 CMblockBuffer 中。然后我使用预览 CMBlockBuffer 构造一个 CMSampleBuffer。之后,我将 CMSampleBuffer 放入了 AVSampleBufferDisplayLayer。一切正常(我检查了返回的值),除了 AVSampleBufferDisplayLayer 不显示任何视频图像。由于这些 API 对每个人来说都是相当新的,所以我找不到任何可以解决这个问题的机构。

我将提供以下关键代码,如果您能帮助找出视频图像无法显示的原因,我将不胜感激。非常感谢。

(1) AVSampleBufferDisplayLayer 已初始化。 dsplayer 是我的主视图控制器的 objc 实例。

    @property(nonatomic,strong)AVSampleBufferDisplayLayer *dspLayer;

if(!_dspLayer)
{
    _dspLayer = [[AVSampleBufferDisplayLayer alloc]init];
    [_dspLayer setFrame:CGRectMake(90,551,557,389)];
    _dspLayer.videoGravity = AVLayerVideoGravityResizeAspect;
   _dspLayer.backgroundColor = [UIColor grayColor].CGColor;
    CMTimebaseRef tmBase = nil;
    CMTimebaseCreateWithMasterClock(NULL,CMClockGetHostTimeClock(),&tmBase);
    _dspLayer.controlTimebase = tmBase;
    CMTimebaseSetTime(_dspLayer.controlTimebase, kCMTimeZero);
    CMTimebaseSetRate(_dspLayer.controlTimebase, 1.0);

     [self.view.layer addSublayer:_dspLayer];

}

(2)在另一个线程中,我得到一个 H.264 I 帧。 //构造h.264参数集ok

    CMVideoFormatDescriptionRef formatDesc;
    OSStatus formatCreateResult =
    CMVideoFormatDescriptionCreateFromH264ParameterSets(NULL, ppsNum+1, props, sizes, 4, &formatDesc);
    NSLog([NSString stringWithFormat:@"construct h264 param set:%ld",formatCreateResult]);

//构造cmBlockbuffer . //databuf 指向 H.264 数据。以“0x00 0x00 0x00 0x01 0x65 ........”开头

    CMBlockBufferRef blockBufferOut = nil;
    CMBlockBufferCreateEmpty (0,0,kCMBlockBufferAlwaysCopyDataFlag, &blockBufferOut);
    CMBlockBufferAppendMemoryBlock(blockBufferOut,
                                    dataBuf,
                                    dataLen,
                                    NULL,
                                    NULL,
                                    0,
                                    dataLen,
                                    kCMBlockBufferAlwaysCopyDataFlag);

//构造cmsamplebuffer ok

    size_t sampleSizeArray[1] = {0};
    sampleSizeArray[0] = CMBlockBufferGetDataLength(blockBufferOut);
    CMSampleTiminginfo tmInfos[1] = {
        {CMTimeMake(5,1), CMTimeMake(5,1), CMTimeMake(5,1)}
    };
    CMSampleBufferRef sampBuf = nil;
    formatCreateResult = CMSampleBufferCreate(kCFAllocatorDefault,
                         blockBufferOut,
                         YES,
                         NULL,
                         NULL,
                         formatDesc,
                         1,
                         1,
                         tmInfos,
                         1,
                         sampleSizeArray,
                         &sampBuf);

//放到AVSampleBufferdisplayLayer,就一帧。但是我的视图中看不到任何视频帧

    if([self.dspLayer isReadyForMoreMediaData])
    {
    [self.dspLayer enqueueSampleBuffer:sampBuf];
    }
    [self.dspLayer setNeedsDisplay];

【问题讨论】:

  • Scythe42 answer 可能会解决您遇到的问题。我在让它工作时也遇到了一些问题。但最后我做到了。你应该take a look
  • 这里也一样。有一个 vail & ready CMSampleBuffer 但它不会显示在屏幕上... :(

标签: iphone video ios8 h.264


【解决方案1】:

您的 NAL 单元起始码 0x00 0x00 0x01 或 0x00 0x00 0x00 0x01 需要替换为长度标头。

这在您所指的 WWDC 会话中明确指出,附件 B 起始代码需要替换为符合 AVCC 的长度标头。你基本上是在这里从附件 B 流格式重新转换为 MP4 文件格式(当然是简化的描述)。

为此,您在创建参数集时的调用是“4”,因此您需要为您的 VCL NAL 单元添加一个 4 字节长度的前缀。这就是为什么您将其指定为 AVCC 格式的长度标头可以更短。

无论你在 CMSampleBuffer 中放什么都可以,没有完整性检查内容是否可以解码,只是你满足了作为任意数据与时序信息和参数集组合所需的参数。

基本上你输入的数据说 VCL NAL 单元是 1 字节长。解码器没有得到完整的 NAL 单元并在出现错误时退出。

还要确保当您使用创建参数集时,PPS/SPS 没有添加长度字节,并且附件 B 起始代码也被剥离。

此外,我建议不要使用 AVSampleBufferDisplayLayer,而是通过 VTDecompressionSession,这样您就可以在像素着色器中执行颜色校正或其他需要的操作。

【讨论】:

  • 还需要注意的是,NAL 长度代码需要采用 big-endian 字节顺序。
【解决方案2】:

最初使用 DecompressionSessionDecode Frame 可能是一个想法,因为这将为您提供有关解码成功的一些反馈。如果解码存在问题,AVSampleBufferDisplay 层不会告诉您它只是不显示任何内容。如果需要,我可以给你一些代码来帮助你,让我知道你是怎么做的,因为我正在尝试同样的事情:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-27
    相关资源
    最近更新 更多