H.264 将构成一帧图像所有nalu 的集合称为一个AU,帧边界识别实际上就是识别AU。
因为H.264 取消帧级语法,所以无法简单地从码流中获取AU。解码器只有在解码的过
程中,通过某些语法元素的组合才能判断一帧图像是否结束。一般来说,解码器必须在
完成一帧新图像的第一个slice_header 语法解码之后,才能知道前一帧图像已经结束。
因此,最严谨的AU 识别步骤如下:
步骤 1 对码流实施“去03 处理”。
步骤 2 解析nalu 语法。
步骤 3 解析slice_header 语法。
步骤 4 综合判断前后两个nalu 以及对应的slice_header 中的若干个语法元素,看是否发生变化。
如果发生变化,则说明这两个nalu 属于不同的帧,否则说明这两个nalu 属于同一帧。
----结束
显然,在解码前完成上述的AU 识别消耗许多CPU 资源,因此不推荐使用AU 方式解码
为了提供一种简单的AU 识别方案,H.264 规定一种类型为09 的nalu,即编码器在每次完成一个AU 编码后,在码流中插入一个类型为09 的nalu,在这个前提下,解码器只需要从码流中搜索类型为09 的nalu 即可获得一个AU。
H.264 并不强制要求编码器插入类型为09 的nalu,因此并非所有的码流都具备这种特征。对于
编码器和解码器协同工作的应用场景,建议让编码器插入类型为09 的nalu,这样可以降低解码
器识别AU 的代价。
为了降低解码器在解码前识别AU 的代价,本文提出一种高效的AU 识别方法,其主要
思路是利用一帧图像的第一个slice_header 中的语法元素first_mb_in_slice 一般等于0 这
个特征(对于包含ASO 或者FMO 特性的码流,这个条件不一定成立)。
typedef struct ParseContext{
unsigned int FrameStartFound;
unsigned int iFrameLength;
} ParseContext;
signed int DecLoadAU(unsigned char* pStream, unsigned int iStreamLen, ParseContext *pc)
{
unsigned int i;
unsigned int state = 0xffffffff;
if( NULL == pStream )
{
return -1;
}
for( i = 0; i < iStreamLen; i++)
{
if( (state & 0xFFFFFF1F) == 0x101 || (state & 0xFFFFFF1F) == 0x105 )
{
if (i >= iStreamLen)
{
break;
}if( pStream[i] & 0x80)
{
if(pc->FrameStartFound)
{
pc->iFrameLength = i - 4;
pc->FrameStartFound = 0;
state = 0xffffffff;
return 0;
}
else
{
pc->FrameStartFound = 1;
}
}
}
if (i < iStreamLen)
{
state = (state << 8) | pStream[i];
}
}
pc->FrameStartFound = 0;
return -1;
}
解决了最关键的问题后, 下面就是将解码完的数据送去播放的问题了, 可以启动一个Timer, 定时去读取一帧的数据送去解码就可以。针对不同的帧率调整Timer的时间即可,当然最正规的做法是根据MP4或者AVI文件中的时间戳。
//------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------
这个要看你怎么理解了。和MPEG2、MPEG4相比,H.264字节流中帧的形式发生了变化。以视频帧为例,
MPEG2和MPEG4字节流在传输的时候提取帧的关键参数,将其封装入传输包首部,比如TS包或RTP包,
而包负载中的数据仍然是一个完整的图像帧。也就是说,你即使不使用包首部中所设置的关于包负载
的参数信息,也能够根据包负载中的帧数据本身进行正确的解码。
而H.264码流本身对图像数据就做了处理,将一个完整的图像帧进行分解,抽出序列参数集、
图像参数集等帧信息,放到各自对应的NAL中,而图像数据本身则封装进编码条带中。这样,
在NAL流中,仅仅根据编码条带NAL单元是解析不出图像来的,必须和序列参数集、
图像参数集NAL配合才能解出。也就是说,MPEG2、MPEG4编码的一帧数据,
被分解成了H.264中的多个NAL单元,H.264编码的抽象化程度更高了。
但是H.264码流在组织的时候仍然是以一帧数据为单位的,它并不会将多帧数据交织到一起,
只不过表现在形式上,需要用多个NAL单元才能组成一个完整的数据帧。
当然是可以的。这其实是一个协议分析过程,每一帧H264数据都是可以通过观察二进制码流分析出来的。
根据协议说明,每一帧图像一般在开头有一个单元分隔符NAL,
两个单元分隔符之间的数据包就是一帧图像。就是00 00 01 09,这个09就是单元分隔符的标志。
不过协议并没有说NAL流必须如此组织,可能还有其它的组织形式。我手头的H264文件都是这样组织的。
一帧可能有几个SLICE的!你要把所有的SLICE定位出来,然后再找到每个SLICE的起始宏块的地址,
地址为0的话就是一帧开始了!
http://blog.sina.com.cn/s/blog_76550fd70101gh1q.html