解密H26四、AAC硬件解碼的關鍵擴展數據處理

    經過上一篇文章(http://my.oschina.net/u/2336532/blog/399058),咱們用ffmpeg分離出一個多媒體容器中的音視頻數據,可是極可能這些數據是不能被正確解碼的。爲何呢?由於在解碼這些數據以前,須要對解碼器作一些配置,典型的就是目前流行的高清編碼「黃金搭檔」組合H264 + AAC的搭配。本文將講述H264AAC的關鍵解碼配置參數的解析,若是沒有這些配置信息,數據幀每每不完整,致使瞭解碼器不能解碼。程序員

  • H264的配置信息解析微信

    前面咱們知道,ffmpegavformat_find_stream_info函數能夠取得音視頻媒體多種,好比播放持續時間、音視頻壓縮格式、音軌信息、字幕信息、幀率、採樣率等。在信息結果中有一項擴展數據描述(avcodec.h文件中):微信公衆平臺

          AVCodecContext定義以下:函數

    若是視頻流是H264,這個extradate裏面就包含了H264的配置信息,這個擴展數據有以下定義:編碼

    詳細解釋能夠參考ISO-14496-15 AVC file format文檔。裏面最重要的就是NAL長度和SPSPPS數據和對應的長度信息。對該數據的解析在ffmpeg裏面有現成的函數:ff_h264_decode_extradata,在個人項目裏面是本身寫的擴展數據解析。spa

  • AAC的配置信息解析及設置.net

    若是音頻數據是AAC流,在解碼時須要ADTS(Audio Data Transport Stream)頭部,無論是容器封裝仍是流媒體,沒有這個,通常都是不能播放的。不少朋友在作AAC流播放時遇到播不出聲音,極可能就是這個緣由致使。code

    ADTS所需的數據仍然是放在上面的擴展數據extradata中,咱們須要先解碼這個擴展數據,而後再從解碼後的數據信息裏面從新封裝成ADTS頭信息,加到每一幀AAC數據以前再送解碼器,這樣就能夠正常解碼了。orm

    extradate數據定義以下:視頻

     

        詳細信息及說明請參考「ISO-IEC-14496-3 (Audio)」的AudioSpecificConfig部分。裏面最重要的部分有采樣頻率、通道配置和音頻對象類型,這幾個通常都是AAC解碼器須要的配置參數。

        這個數據在ffmpeg中也有相應的解碼函數:avpriv_aac_parse_header。在個人項目中,我沒有使用這個函數,而是本身實現的:

  • typedef struct
    {
          int write_adts;
          int objecttype;
          int sample_rate_index;
          int channel_conf;
    }ADTSContext;

  • int aac_decode_extradata(ADTSContext *adts, unsigned char *pbuf, int bufsize)
    {
          int aot, aotext, samfreindex;
          int i, channelconfig;
          unsigned char *p = pbuf;
     
          if (!adts || !pbuf || bufsize<2)
          {
                return -1;
          }
          aot = (p[0]>>3)&0x1f;
          if (aot == 31)
          {
                aotext = (p[0]<<3 | (p[1]>>5)) & 0x3f;
                aot = 32 + aotext;
                samfreindex = (p[1]>>1) & 0x0f;
               
                if (samfreindex == 0x0f)
                {
                      channelconfig = ((p[4]<<3) | (p[5]>>5)) & 0x0f;
                }
                else
                {
                      channelconfig = ((p[1]<<3)|(p[2]>>5)) & 0x0f;
                }
          }
          else
          {
                samfreindex = ((p[0]<<1)|p[1]>>7) & 0x0f;
                if (samfreindex == 0x0f)
                {
                      channelconfig = (p[4]>>3) & 0x0f;
                }
                else
                {
                      channelconfig = (p[1]>>3) & 0x0f;
                }
          }
     
    #ifdef AOT_PROFILE_CTRL
          if (aot < 2) aot = 2;
    #endif
          adts->objecttype = aot-1;
          adts->sample_rate_index = samfreindex;
          adts->channel_conf = channelconfig;
          adts->write_adts = 1;
     
          return 0;
    }

           上面的pbuf就是extradata

    接下來,再用ADTSContext數據編碼爲ADTS頭信息插入每個AAC幀前面:

  • int aac_set_adts_head(ADTSContext *acfg, unsigned char *buf, int size)
    {       
          unsigned char byte;
     
          if (size < ADTS_HEADER_SIZE)
          {
                return -1;
          }
         
          buf[0] = 0xff;
          buf[1] = 0xf1;
          byte = 0;
          byte |= (acfg->objecttype & 0x03) << 6;
          byte |= (acfg->sample_rate_index & 0x0f) << 2;
          byte |= (acfg->channel_conf & 0x07) >> 2;
          buf[2] = byte;
          byte = 0;
          byte |= (acfg->channel_conf & 0x07) << 6;
          byte |= (ADTS_HEADER_SIZE + size) >> 11;
          buf[3] = byte;
          byte = 0;
          byte |= (ADTS_HEADER_SIZE + size) >> 3;
          buf[4] = byte;
          byte = 0;
          byte |= ((ADTS_HEADER_SIZE + size) & 0x7) << 5;
          byte |= (0x7ff >> 6) & 0x1f;
          buf[5] = byte;
          byte = 0;
          byte |= (0x7ff & 0x3f) << 2;
          buf[6] = byte;
     
          return 0;
    }

  這個頭部是固定的7字節長度,因此可提早空出這7個字節供ADTS佔用。

  經過以上對H264AAC的擴展數據處理,播放各類「黃金搭檔」的多媒體文件、流媒體、視頻點播等都應該沒有問題了。

 

  想第一時間得到更多原創文章,請關注我的微信公衆平臺:程序員互動聯盟(coder_online),掃一掃下方二維碼或者搜索微信號coder_online便可關注,裏面有大量AndroidChromiumLinux等相關文章等着您,咱們還能夠在線交流。

        如需轉載本文,請註明出處:http://my.oschina.net/u/2336532/blog

相關文章
相關標籤/搜索