繁体   English   中英

将H.264 I帧放入AVSampleBufferDisplayLayer,但不显示视频图像

[英]Putting an H.264 I frame to AVSampleBufferDisplayLayer but no video image is displayed

在详细了解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参数集

    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确定

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

您的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,这样您就可以进行颜色校正或像素着色器中所需的其他操作。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM