在对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 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];
答案 0 :(得分:5)
您的NAL单元起始码0x00 0x00 0x01或0x00 0x00 0x00 0x01需要用长度标头替换。
在WWDC会议中明确指出,附件B起始码需要由符合AVCC标准的lengh标头替换。您现在基本上可以从附件B流格式中复制到MP4文件格式(当然简化说明)。
创建参数集时,您的呼叫为“4”,因此您需要为VCL NAL单元添加前缀为4字节的前缀。这就是为什么你用AVCC格式指定它的长度标题可以更短。
无论你放在CMSampleBuffer中什么都没关系,没有完整性检查是否可以解码内容,只是你遇到了与定时信息和参数集结合的任意数据所需的参数。
基本上,您输入的数据表示VCL NAL单位长度为1个字节。解码器没有得到完整的NAL单元并且出错了。
同时确保在使用时创建参数集,使PPS / SPS没有添加长度,并且附件B起始码也被剥离。
另外,我建议不要使用AVSampleBufferDisplayLayer,而是通过VTDecompressionSession,这样你就可以做像色彩校正或像素着色器中需要的其他东西。
答案 1 :(得分:0)
最初使用DecompressionSessionDecode Frame可能是一个想法,因为这将为您提供有关解码成功的一些反馈。如果解码存在问题,AVSampleBufferDisplay图层不会告诉您它只是没有显示任何内容。如果需要的话,我可以给你一些代码来帮助解决这个问题,让我知道你是如何继续的,因为我正在尝试同样的事情:)