H264码流分析详解

Posted 老樊Lu码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了H264码流分析详解相关的知识,希望对你有一定的参考价值。

一、H264概念     

        H.264 是一次概念的革新,它打破常规,完全没有 I 帧、P帧、B 帧的概念,也没有 IDR帧的概念

        H264和H265的每一个NALU前缀码也是一样的,即“0x00 00 00 01”或者 “0x00 00 01”。

分析一下H264码流,nal单元如何分割,类型:

  

  二、 H.264 NAL 类型分析type

   类型枚举定义: 

typedef enum {

 NALU_TYPE_SLICE    = 1,

 NALU_TYPE_DPA      = 2,

 NALU_TYPE_DPB      = 3,

 NALU_TYPE_DPC      = 4,

 NALU_TYPE_IDR      = 5,

 NALU_TYPE_SEI      = 6,

 NALU_TYPE_SPS      = 7,

 NALU_TYPE_PPS      = 8,

 NALU_TYPE_AUD      = 9,

 NALU_TYPE_EOSEQ    = 10,

 NALU_TYPE_EOSTREAM = 11,

 NALU_TYPE_FILL     = 12,

#if (MVC_EXTENSION_ENABLE)

 NALU_TYPE_PREFIX   = 14,

 NALU_TYPE_SUB_SPS  = 15,

 NALU_TYPE_SLC_EXT  = 20,

 NALU_TYPE_VDRD     = 24  // View and Dependency Representation Delimiter NAL Unit

#endif

} NaluType;

三、帧类型判断

unsigned char * pBS = (unsigned char *)pBSBuf;
int nType = pBS[4] & 0x1F;  // NAL类型在固定的位置上 
if ( nType <= H264NT_PPS )
    return nType;// nTYPE  为5  表示关键帧

四、其它细节

        对于 H.264中出现的一些概念从大到小排序依次是:序列、图像、片组、片、NALU、宏块、亚宏块、块、像素。这里有几点值得说明:
        (1).在 H.264协议中图像是个集合概念,顶场、底场、帧都可以称为图像(本文图像概念时都是集合概念)。因此我们可以知道,对于H.264 协议来说,我们平常所熟悉的那些称呼,例如:I 帧、P 帧、B帧等等,实际上都是我们把图像这个概念具体化和细小化了。我们在 H.264里提到的“帧”通常就是指不分场的图像;
        (2).如果不采用FMO(灵活宏块排序) 机制,则一幅图像只有一个片组
        (3).如果不使用多个片,则一个片组只有一个片
        (4).如果不采用DP(数据分割)机制,则一个片就是一个NALU一个 NALU 也就是一个片

      否则,一个片由 三个 NALU 组成(即标准“表7-1”中 nal_unit_type 值为2、3、4 的三个 NALU 属于 一个片);  

   2 编码条带数据分割块A  slice_data_partition_a_layer_rbsp()

   3 编码条带数据分割块Bslice_data_partition_b_layer_rbsp( )

   4 编码条带数据分割块Cslice_data_partition_c_layer_rbsp( )

        (5).以上所述的片和 NALU的大小关系并不是抽象概念上的从属关系。从概念的从属关系上来看,NALU其实又是片的一个集合概念,例如:标准“表7-1”中nal_unit_type 值为 5 的 NALU 包括 I 片或者 SI片。

   一幅图像根据组成它的片类型来分,可以分为标准“表7-5”中的 8种类型。我们平常应用中所最常见到的其实是这些类型的特例。例如:我们平常所谓的“I帧”和“IDR 帧”,其实是 primary_pic_type 值为 0的图像,我们平常所谓的“P帧”其实是 primary_pic_type 值为 1的图像的特例我们平常所谓的“B帧”其实是 primary_pic_type 值为 2的图像的特例。

在收到h264码流的每个NAL数据(Buffer指针)时,对于如下代码的理解:
if((*(Buffer) == 0) && (*(Buffer+1) == 0) && (*(Buffer+2) == 0) && (*(Buffer+3) == 1)) //NAL头的0x00 00 00 01起始码
  {

   if(*(Buffer+4) == SPS_FRAME)

   {  //ox67为 0110 0111(nal_unit_type为低5位,u(5)= 0 0111 = 7)
    frame_type = SPS_FRAME;

   }

   else if(*(Buffer+4) == PPS_FRAME)

   {  //ox68为 0110 1000 (nal_unit_type为低5位,u(5)= 0 1000 = 8)
    frame_type = PPS_FRAME;

   }

   else if(*(Buffer+4) == I_FRAME)

   { //ox65为 0110 0101 (nal_unit_type为低5位,u(5)= 0 0101 = 5)

    frame_type = I_FRAME;

   }

   else

   { //0x41为0100 00001 (nal_ref_idc是参考级别,代表被其它帧参考情况,u(2)= 10 = 2; nal_unit_type为低5位,u(5)= 0 0001 = 1)
    frame_type = P_FRAME;

   }

   if((*(Buffer+5) & 0x80) == 0x80)

   {

    start_frame = 1;

   }

  }

以上是关于H264码流分析详解的主要内容,如果未能解决你的问题,请参考以下文章

H264码流中SPS PPS详解

RK3588平台开发系列讲解(视频篇)RTP H264 码流打包详解

PS封装H264码流分析

FFmpeg解码H264及swscale缩放详解

Android音视频 H264码流结构

音视频压缩:H264码流层次结构和NALU详解