h264帧边界识别

来源:互联网 发布:.net 桥接数据库 编辑:程序博客网 时间:2024/05/21 01:48

帧边界识别简介

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编码后,在码流中插入一个类型为09nalu,在这个前提下,解码器只需要从码流中搜索类型为09nalu 即可获得一个AU

H.264 并不强制要求编码器插入类型为09nalu,因此并非所有的码流都具备这种特征。对于编码器和解码器协同工作的应用场景,建议让编码器插入类型为09nalu,这样可以降低解码器识别AU的代价。

 

为了降低解码器在解码前识别AU 的代价,本文提出一种高效的AU 识别方法,其主要思路是利用一帧图像的第一个slice_header 中的语法元素first_mb_in_slice 一般等于0 这

个特征(对于包含ASO 或者FMO 特性的码流,这个条件不一定成立)。

  1. typedef struct ParseContext{  
  2.   
  3.     unsigned int FrameStartFound;   
  4.   
  5.     unsigned int iFrameLength;   
  6.   
  7. } ParseContext;  
  8.   
  9.   
  10. signed int  DecLoadAU(unsigned char* pStream, unsigned int iStreamLen, ParseContext *pc)  
  11.   
  12.     {  
  13.   
  14.         unsigned int i;  
  15.         unsigned int state = 0xffffffff;  
  16.         if( NULL == pStream )  
  17.         {  
  18.             return -1;  
  19.         }  
  20.   
  21.         for( i = 0; i < iStreamLen; i++)  
  22.         {  
  23.             /* 查找nal类型为1和5的nal头 */  
  24.             if( (state & 0xFFFFFF1F) == 0x101 || (state & 0xFFFFFF1F) == 0x105 )  
  25.             {  
  26.                 if (i >= iStreamLen) /* 到达Buffer尾部,退出查找循环 */  
  27.                 {  
  28.                     break;  
  29.                 }if( pStream[i] & 0x80) /* 查找first_mb_in_slice为0的slice头确定一幅图像的开始 */  
  30.                 {  
  31.                     if(pc->FrameStartFound) /* 查找到下一幅图像的开始就可以确定图像的起始和结束 */  
  32.                     {  
  33.                         pc->iFrameLength = i - 4;  
  34.                         pc->FrameStartFound = 0;  
  35.                         state = 0xffffffff;  
  36.                         return 0; /* 找到一幅图像的边界返回0 */  
  37.                     }  
  38.                     else  
  39.                     {  
  40.                         pc->FrameStartFound = 1;  
  41.                     }  
  42.                 }  
  43.             }  
  44.             if (i < iStreamLen)  
  45.             {  
  46.                 state = (state << 8) | pStream[i]; /* 从码流Buffer中读入1个字节 */  
  47.             }  
  48.         }  
  49.         pc->FrameStartFound = 0;  
  50.         return -1; /* 没有找到AU边界返回-1 */  
  51.     } 

0 0
原创粉丝点击