Iphone 将H.264 I帧放入AVSampleBufferDisplayLayer,但不显示视频图像
在详细回顾了WWDC2014 Session513之后,我尝试在IOS8.0上编写我的应用程序来解码和显示一条实时H.264流。首先,我成功地构造了一个H264参数集。当我得到一个具有4位开始代码的I帧时,就像“0x00 0x00 0x00 0x00 0x01 0x65…”,我将其放入CMblockBuffer。然后,我使用预览CMBlockBuffer构建了一个CMSampleBuffer。之后,我将CMSampleBuffer放入AVSampleBufferDisplayLayer中。一切正常(我检查了返回的值),除了AVSampleBufferDisplayLayer没有显示任何视频图像。因为这些API对每个人来说都是相当新的,所以我找不到任何人能够解决这个问题 我会给关键代码如下,我真的很感激如果你能帮助找出为什么视频图像不能显示。非常感谢 (1) AVSampleBufferDisplayLayer已初始化。 dsplayer是我的主视图控制器的objc实例Iphone 将H.264 I帧放入AVSampleBufferDisplayLayer,但不显示视频图像,iphone,video,ios8,h.264,Iphone,Video,Ios8,H.264,在详细回顾了WWDC2014 Session513之后,我尝试在IOS8.0上编写我的应用程序来解码和显示一条实时H.264流。首先,我成功地构造了一个H264参数集。当我得到一个具有4位开始代码的I帧时,就像“0x00 0x00 0x00 0x00 0x01 0x65…”,我将其放入CMblockBuffer。然后,我使用预览CMBlockBuffer构建了一个CMSampleBuffer。之后,我将CMSampleBuffer放入AVSampleBufferDisplayLayer中。一切正
@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……”开头
//构造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];
您的NAL单元起始代码0x00 0x00 0x01或0x00 0x00 0x00 0x01需要替换为长度标头 您所指的WWDC会议中明确指出,附件B的起始代码需要替换为符合AVCC的长度标题。你基本上是从附件B中的流格式恢复到MP4文件格式(当然是简化的描述) 为此,在创建参数集时,您的调用为“4”,因此需要使用4字节长度前缀为VCL NAL单元添加前缀。这就是为什么您指定它为AVCC格式,长度标题可以更短 无论您在CMSampleBuffer中放入什么都可以,如果内容可以解码,则没有健全性检查,只是您满足了将时间信息和参数集组合在一起的任意数据所需的参数 基本上,根据你输入的数据,你说VCL NAL单位是1字节长。解码器没有得到完整的NAL单元,并在出现错误时退出 还应确保在使用创建参数集时,PPS/SPS未添加长度byted,且附录B的起始代码也已删除
另外,我建议不要使用AVSampleBufferDisplayLayer,而是进行VTDecompressionSession,这样您就可以在像素着色器中执行颜色校正或其他需要的操作。最初使用DecompressionSessionDecode Frame可能是一个好主意,因为这将为您提供一些解码成功的反馈。如果解码有问题,AVSampleBufferDisplay层不会告诉您它只是不显示任何内容。如果需要的话,我可以给你一些代码来帮助你,让我知道你的情况,因为我正在尝试同样的事情:)Scythe42答案可能会解决你的问题。我也有一些问题,让它工作。但最后我做到了。你应该,这里也一样。获得了一个vail&ready CMSampleBuffer,但它不会显示在屏幕上…:(还需要注意的是,NAL长度代码需要采用大端字节顺序。
if([self.dspLayer isReadyForMoreMediaData])
{
[self.dspLayer enqueueSampleBuffer:sampBuf];
}
[self.dspLayer setNeedsDisplay];