x264学习小总结

问题1:如何识别关键帧?

从x264的源代码中可以看到,如果某一帧为关键帧,这么这一帧的所携带的几个nalu中,必然有一个的type 必然为NAL_SLICE_IDR。

/* Set output picture properties */ if( h->sh.i_type == SLICE_TYPE_I ) pic_out->i_type = h->i_nal_type == NAL_SLICE_IDR ? X264_TYPE_IDR : X264_TYPE_I; else if( h->sh.i_type == SLICE_TYPE_P ) pic_out->i_type = X264_TYPE_P; else pic_out->i_type = X264_TYPE_B;

我的理解就是如果nalu的type为NAL_SLICE_IDR的话,那么这帧肯定就是关键帧了。

因此只需要判断每一帧的nalu的type中是否包还有type为NAL_SLICE_IDR的,如果有则是关键帧。

判断nalu的type的可用如下的方法。

for(int i=0; i

{

      uint8_t *ptr = nalu[i];

      int type = ptr[4]&0x1F;

      if(type == NAL_SLICE_IDR)

      {

        key_frame = true;

        break;

       }

}

 

判断nalu的type中用到int type = ptr[4]&0x1F; 为什么是0x1F呢,这得说说每个nalu的结构;

nalu有三部分组成。

起始码      nalu_header       data

起始码: 分为longcode 和  shortcode  ;

longcode :0x 00 00 00 01;

shortcode :0x 00 00 01;

nalu_header:有三个子域;

 

NALU 头由一个字节组成, 它的语法如下:

      +---------------+
      |0|1|2|3|4|5|6|7|
      +-+-+-+-+-+-+-+-+
      |F|NRI|  Type   |
      +---------------+

F: 1 个比特.
  forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.

NRI: 2 个比特.
  nal_ref_idc. 取 00 ~ 11, 似乎指示这个 NALU 的重要性, 如 00 的 NALU 解码器可以丢弃它而不影响图像的回放. 不过一般情

况下不太关心

这个属性.

Type: 5 个比特.
  nal_unit_type. 这个 NALU 单元的类型. 简述如下:

  0     没有定义
  1-23  NAL单元  单个 NAL 单元包.
  24    STAP-A   单一时间的组合包
  24    STAP-B   单一时间的组合包
  26    MTAP16   多个时间的组合包
  27    MTAP24   多个时间的组合包
  28    FU-A     分片的单元
  29    FU-B     分片的单元
  30-31 没有定义

大家可以看到,要获得type的话,就得将nalu起始码后面紧跟的第一个字节的内容与0x1F做与运算后得到。

 

问题2:如何判断每一帧的中nalu的起始和结束。

 数据在经过int x264_nal_encode( void *, int *, int b_annexeb, x264_nal_t *nal )后,会将数据组装成nalu的标准格式,即按照上面的格式:

起始码   nalu_header   data。

x264使用0x 00 00 00 01作为起始码(longcode)。int x264_nal_encode( void *, int *, int b_annexeb, x264_nal_t *nal )的作用就是使得数据流中不会再出现连续的两个以上的0。如果有的话就会插入一个0x03;

因此如果要还原一帧数据中的逻辑结构的话,可以遍历数据流,寻找0x00000001这样的特征代码。

这一点对于使用x264自带的mkv文件保存接口很是有用。因为我们接收到的网络数据可能没有没有带上详细的nalu分界信息和帧类型,需要自己重新还原。

你可能感兴趣的:(x264学习小总结)