在
Media SDK H.264解码器的子类型
中,笔者讲述了AVC,H.264,X264之间的有无开始码的差别。因为这种差别的存在,会导致Splitter和Decoder之间互联和解码的失败。本篇博客在此基础上着重讨论SPS和PPS,它的存在也将会导致解码器的失败。
对于H.264的NAL结构,一般是如图1格式:
图1 NAL 结构图
Media SDK的Decoder是按照H.264标准的NAL结构来解析数据的。如果Splitter过来的数据没有相关的Start Code,那么为了使Sample H.264 DShower filter工作,必须在对应的数据前面插入Start Code。H.264码流中,有时候会包含一些关于序列或者图像的参数,比如SPS和PPS。对于Media SDK的H.264解码器而言,这些信息是需要的。如果Spiltter丢弃了这个部分信息,那么需要手动的添加入头部信息,如图2所示:
图2 SPS和PPS结构图
那么如何才能够获知是否存在SPS或PPS呢?MPEG2VIDEOINFO结构包含了这个信息的旗帜位,即cbSequenceHeader。
typedef struct tagMPEG2VIDEOINFO {
VIDEOINFOHEADER2 hdr;
DWORD dwStartTimeCode; // ?? not used for DVD ??
DWORD cbSequenceHeader; // is 0 for DVD (no sequence header)
DWORD dwProfile; // use enum MPEG2Profile
DWORD dwLevel; // use enum MPEG2Level
DWORD dwFlags; // use AMMPEG2_* defines. Reject connection if undefined bits are not 0
DWORD dwSequenceHeader[1]; // DWORD instead of Byte for alignment purposes
// For MPEG-2, if a sequence_header is included, the sequence_extension
// should also be included
} MPEG2VIDEOINFO;
当cbSequenceHeader > 0的时候,SPS或者PPS存在,我们需要将其添加入数据头中。
在加入Start Code和SPS、PSS后,如果再次调用DecoderHeader()函数,你会发现什么呢?呵呵,成功了吧!
对于H.264的NAL结构,一般是如图1格式:
图1 NAL 结构图
Media SDK的Decoder是按照H.264标准的NAL结构来解析数据的。如果Splitter过来的数据没有相关的Start Code,那么为了使Sample H.264 DShower filter工作,必须在对应的数据前面插入Start Code。H.264码流中,有时候会包含一些关于序列或者图像的参数,比如SPS和PPS。对于Media SDK的H.264解码器而言,这些信息是需要的。如果Spiltter丢弃了这个部分信息,那么需要手动的添加入头部信息,如图2所示:
图2 SPS和PPS结构图
那么如何才能够获知是否存在SPS或PPS呢?MPEG2VIDEOINFO结构包含了这个信息的旗帜位,即cbSequenceHeader。
typedef struct tagMPEG2VIDEOINFO {
VIDEOINFOHEADER2 hdr;
DWORD dwStartTimeCode; // ?? not used for DVD ??
DWORD cbSequenceHeader; // is 0 for DVD (no sequence header)
DWORD dwProfile; // use enum MPEG2Profile
DWORD dwLevel; // use enum MPEG2Level
DWORD dwFlags; // use AMMPEG2_* defines. Reject connection if undefined bits are not 0
DWORD dwSequenceHeader[1]; // DWORD instead of Byte for alignment purposes
// For MPEG-2, if a sequence_header is included, the sequence_extension
// should also be included
} MPEG2VIDEOINFO;
当cbSequenceHeader > 0的时候,SPS或者PPS存在,我们需要将其添加入数据头中。
在加入Start Code和SPS、PSS后,如果再次调用DecoderHeader()函数,你会发现什么呢?呵呵,成功了吧!