乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      x264中的NAL流程

       lyz1985 2010-07-06
      x264中的NAL流程
       
      目前,主要是在分析NAL,做抓包實(shí)驗(yàn),所以對(duì)NAL的格式要求比較高,這個(gè)過(guò)程中讀了《新一代視頻編碼》,以前也讀過(guò),這是沒(méi)有遇到實(shí)際的問(wèn)題,讀的時(shí)候也是似懂非懂的,囫圇吞棗,現(xiàn)在要分析,要用了才知道這些相關(guān)文檔是要好好讀的,ES流也是要好好分析的。在上一篇中關(guān)于函數(shù)指針和指針函數(shù)的理論知識(shí)中,我主要是來(lái)看看x264中的NAL是怎么在封裝的。
      在x264中使用的函數(shù)指針,關(guān)于NAL部分的下面的一些:
      static int (*p_write_nalu)( hnd_t handle, uint8_t *p_nal, int i_size );,在這里可以看到p_write_nalu)是一個(gè)指針函數(shù),p_write_nalu = write_nalu_bsf;即對(duì)于p_write_nalu其所指向的函數(shù)write_nalu_bsf,類似的還有:
      p_write_nalu = write_nalu_mp4;
      p_write_nalu = write_nalu_mkv;
      //每一個(gè)NALU都是由header+payload組成的,在header的結(jié)構(gòu)是可以參考264的相關(guān)文檔
      enum nal_unit_type_e
      {
      NAL_UNKNOWN = 0,
      NAL_SLICE   = 1,
      NAL_SLICE_DPA   = 2,
      NAL_SLICE_DPB   = 3,
      NAL_SLICE_DPC   = 4,
      NAL_SLICE_IDR   = 5,    /* ref_idc != 0 */
      NAL_SEI         = 6,    /* ref_idc == 0 */
      NAL_SPS         = 7,
      NAL_PPS         = 8,
      NAL_AUD         = 9,
      /* ref_idc == 0 for 6,9,10,11,12 */
      };
      enum nal_priority_e
      {
      NAL_PRIORITY_DISPOSABLE = 0,
      NAL_PRIORITY_LOW        = 1,
      NAL_PRIORITY_HIGH       = 2,
      NAL_PRIORITY_HIGHEST    = 3,
      };
      //NAL結(jié)構(gòu)
      typedef struct
      {
      int i_ref_idc;  /* nal_priority_e */
      int i_type;     /* nal_unit_type_e */
      /* Size of payload in bytes. */
      int     i_payload;   //負(fù)載的大小
      /* If param->b_annexb is set, Annex-B bytestream with 4-byte startcode.
      * Otherwise, startcode is replaced with a 4-byte size.
      * This size is the size used in mp4/similar muxing; it is equal to i_payload-4 */
      uint8_t *p_payload;//如果是字節(jié)流格式的NAL時(shí)所用到的前綴4bytes
      } x264_nal_t;

      下面主要是跟蹤x264,得到NAL的封裝流程,如下:
      1. 
      //NAL
      static void x264_nal_start( x264_t *h, int i_type, int i_ref_idc )
      {
      x264_nal_t *nal = &h->out.nal[h->out.i_nal];
      nal->i_ref_idc = i_ref_idc;
      nal->i_type    = i_type;
      nal->i_payload= 0;
      nal->p_payload= &h->out.p_bitstream[bs_pos( &h->out.bs ) / 8];
      }
      //下面是對(duì)bs_pos函數(shù)的注解
      static inline int bs_pos( bs_t *s )
      {
      return( 8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left );  / /獲取當(dāng)前的NALU的地址?????????- s->i_left
      }
      //bs_s的結(jié)構(gòu)
      typedef struct bs_s
      {
      uint8_t *p_start;
      uint8_t *p;
      uint8_t *p_end;
      intptr_t cur_bits;
      int     i_left;    /* i_count number of available bits */
      int     i_bits_encoded; /* RD only */
      } bs_t;

      2.
      static int x264_encoder_encapsulate_nals( x264_t *h )   //NAL封裝
      {
      int nal_size = 0, i;
      uint8_t *nal_buffer;
      for( i = 0; i < h->out.i_nal; i++ )
      nal_size += h->out.nal[i].i_payload;
      /* Worst-case NAL unit escaping: reallocate the buffer if it's too small. */
      if( h->nal_buffer_size < nal_size * 3/2 + h->out.i_nal * 4 )
      {
      uint8_t *buf = x264_malloc( nal_size * 2 + h->out.i_nal * 4 );
      if( !buf )
      return -1;
      x264_free( h->nal_buffer );
      h->nal_buffer = buf;
      }
      nal_buffer = h->nal_buffer;
      for( i = 0; i < h->out.i_nal; i++ )
      {
      int size = x264_nal_encode( nal_buffer, h->param.b_annexb, &h->out.nal[i] );
      h->out.nal[i].i_payload = size;
      h->out.nal[i].p_payload = nal_buffer;
      nal_buffer += size;
      }
      return nal_buffer - h->nal_buffer;
      }
      3.在2.中有:
      int x264_nal_encode( uint8_t *dst, int b_annexb, x264_nal_t *nal )
      {
      uint8_t *src = nal->p_payload; //為了同意結(jié)構(gòu)還是將字節(jié)流格式的前綴作為指針的初始值
      uint8_t *end = nal->p_payload + nal->i_payload;
      uint8_t *orig_dst = dst;
      int i_count = 0, size;
      /* long nal start code (we always use long ones) */
      if( b_annexb )       //這里是進(jìn)行字節(jié)流格式的碼流編碼,有開(kāi)始前綴碼,對(duì)于RTP封裝則不需要前綴碼
      {
      *dst++ = 0x00;
      *dst++ = 0x00;
      *dst++ = 0x00;
      *dst++ = 0x01;
      }
      else /* save room for size later */
      dst += 4;
      /* nal header */
      *dst++ = ( 0x00 << 7 ) | ( nal->i_ref_idc << 5 ) | nal->i_type;//第一個(gè)bit的設(shè)置是由編碼器自己控制的
      while( src < end )
      {
      if( i_count == 2 && *src <= 0x03 )
      {
      *dst++ = 0x03;//偽起始碼
      i_count = 0;
      }
      if( *src == 0 )
      i_count++;
      else
      i_count = 0;
      *dst++ = *src++;
      }
      size = (dst - orig_dst) - 4;  //減4主要是前面的前綴碼所占的字節(jié)
      /* Write the size header for mp4/etc */
      if( !b_annexb )
      {
      /* Size doesn't include the size of the header we're writing now. */
      orig_dst[0] = size>>24;
      orig_dst[1] = size>>16;
      orig_dst[2] = size>> 8;
      orig_dst[3] = size>> 0;
      }
      return size+4;      //+4
      }
       

      4.
      static int x264_nal_end( x264_t *h )
      {
      x264_nal_t *nal = &h->out.nal[h->out.i_nal];
      nal->i_payload = &h->out.p_bitstream[bs_pos( &h->out.bs )/ 8] - nal ->p_payload;
      h->out.i_nal++;
      /* if number of allocated nals is not enough, re-allocate a larger one. */
      if( h->out.i_nal >= h->out.i_nals_allocated )
      {
      x264_nal_t *new_out = x264_malloc( sizeof(x264_nal_t) * (h->out.i_nals_allocated*2) );
      if( !new_out )
      return -1;
      memcpy( new_out, h->out.nal, sizeof(x264_nal_t) * (h->out.i_nals_allocated) );
      x264_free( h->out.nal );
      h->out.nal = new_out;
      h->out.i_nals_allocated *= 2;
      }
      return 0;
      }

      5.p_write_nalu
      int write_nalu_bsf( hnd_t handle, uint8_t *p_nalu, int i_size )
      {
      if( fwrite( p_nalu, i_size, 1, (FILE*)handle ) > 0 )  //就是把p_nalu里面的1*i_size的字節(jié)輸出到handle里面
      return i_size;
      return -1;
      }
       

      實(shí)驗(yàn)跟蹤:
      在編碼第一個(gè)I幀的時(shí)候,要編碼的NALU的個(gè)數(shù)為4個(gè),這里主要是指編碼的類型為:SEI,SPS,PPS,I幀的NAL的編碼,對(duì)于一個(gè)I幀,也就是對(duì)這個(gè)GOP中的圖像序列參數(shù),圖像參數(shù)進(jìn)行編碼,即有如下:
      /* Write SPS and PPS */
      if( i_nal_type == NAL_SLICE_IDR && h->param.b_repeat_headers )
      {
      if( h->fenc->i_frame == 0 )
      {
      /* identify ourself */
      x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
      if( x264_sei_version_write( h, &h->out.bs ) )
      return -1;
      if( x264_nal_end( h ) )
      return -1;
      overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
      }
      /* generate sequence parameters */
      x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );
      x264_sps_write( &h->out.bs, h->sps );
      if( x264_nal_end( h ) )
      return -1;
      overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
      /* generate picture parameters */
      x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST );
      x264_pps_write( &h->out.bs, h->pps );
      if( x264_nal_end( h ) )
      return -1;
      overhead += h->out.nal[h->out.i_nal-1].i_payload + NALU_OVERHEAD;
      }

      int x264_encoder_headers( x264_t *h, x264_nal_t **pp_nal, int *pi_nal )
      {
      int frame_size = 0;
      /* init bitstream context */
      h->out.i_nal = 0;
      bs_init( &h->out.bs, h->out.p_bitstream, h->out.i_bitstream );
      /* Write SEI, SPS and PPS. */
      x264_nal_start( h, NAL_SEI, NAL_PRIORITY_DISPOSABLE );
      if( x264_sei_version_write( h, &h->out.bs ) )
      return -1;
      if( x264_nal_end( h ) )
      return -1;
      /* generate sequence parameters */
      x264_nal_start( h, NAL_SPS, NAL_PRIORITY_HIGHEST );
      x264_sps_write( &h->out.bs, h->sps );
      if( x264_nal_end( h ) )
      return -1;
      /* generate picture parameters */
      x264_nal_start( h, NAL_PPS, NAL_PRIORITY_HIGHEST );
      x264_pps_write( &h->out.bs, h->pps );
      if( x264_nal_end( h ) )
      return -1;
      bs_flush( &h->out.bs );
      frame_size = x264_encoder_encapsulate_nals( h );
      /* now set output*/
      *pi_nal = h->out.i_nal;
      *pp_nal = &h->out.nal[0];
      h->out.i_nal = 0;
      return frame_size;
      }
       
      總結(jié)一下:對(duì)于NALU,并不是所謂的一幀對(duì)應(yīng)一個(gè)NALU,而是對(duì)于SLICE而言,一個(gè)slice就封裝層一個(gè)nal,具體一幀中有幾個(gè)nalu則是可以再pps中參數(shù)中進(jìn)行設(shè)定的,每遇到一個(gè)IDR,則此時(shí)就將對(duì)應(yīng)的SPS,PPS進(jìn)行一個(gè)更新,NAL的生成過(guò)程:先是對(duì)header里面的8個(gè)bits進(jìn)行設(shè)定,然后是Payload,中間的細(xì)節(jié),過(guò)于復(fù)雜,目前還不能夠鉆的很深,就先理解到這里。只是把大概的流程疏通。對(duì)下一步NALU的提取準(zhǔn)備。

      本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/adixia/archive/2010/01/21/5221957.aspx

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多