ffmpeg解複用視頻文件

轉自:http://blog.chinaunix.net/uid-24922718-id-3692670.html

 

 解複用視頻文件:就是提取出音頻文件和視頻文件的ES流數據。而對於aac和h264來說,提取出來的數據直接保存並不能成功的播放,原因就在ffmpeg解出的ES數據比較純淨,沒有ADTS頭,而很多解碼器都是需要ADTS頭信息來進行解碼的,所以就要對aac數據進行頭部adts結構的添加。
     對於h264文件來說,h264有兩種封裝,
一種是annexb模式,傳統模式,有startcode,SPS和PPS是在ES中
一種是mp4模式,一般mp4 mkv會有,沒有startcode,SPS和PPS以及其它信息被封裝在container中,每一個frame前面是這個frame的長度
很多解碼器只支持annexb這種模式,因此需要將mp4做轉換:
在ffmpeg中用h264_mp4toannexb_filter可以做轉換
實現:
註冊filter
avcbsfc = av_bitstream_filter_init("h264_mp4toannexb");
轉換bitstream
av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc,
AVCodecContext *avctx, const char *args,
uint8_t **poutbuf, int *poutbuf_size,
const uint8_t *buf, int buf_size, int keyframe)

核心代碼:

點擊(此處)摺疊或打開

  1. #include <libavformat/avformat.h>
  2. #include <libavcodec/avcodec.h>
  3. #include <stdio.h>
  4. static int audioindex = -1;
  5. static int videoindex = -1;
  6. static int isaaccodec = -1;
  7. int main(int argc ,char **argv)
  8. {
  9.     av_register_all();
  10.     FILE *= NULL;
  11.     FILE *= NULL;
  12.     f = fopen("audio","wb");
  13.     g = fopen("video","wb");
  14.     if(!|| !g)
  15.     {
  16.         printf("open write file errorn");
  17.         return 0;
  18.     }
  19.     AVFormatContext *fmtctx = NULL;
  20.     AVPacket audiopack;
  21.     if(avformat_open_input(&fmtctx,argv[1],NULL,NULL) < 0)
  22.     {
  23.         printf("open fmtctx errorn");
  24.         return 0;
  25.     }
  26.     if(avformat_find_stream_info(fmtctx,NULL) < 0)
  27.     {
  28.         printf("find stream info n");
  29.         return 0;
  30.     }
  31.     int streamnum = fmtctx->nb_streams;
  32.     printf("stream num is %dn",streamnum);
  33.     int i=0;
  34.     for(;i<streamnum;i++)
  35.     {
  36.         if(fmtctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audioindex == -1)
  37.         {
  38.             audioindex = i; 
  39.         }
  40.         else if(fmtctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && videoindex == -1)
  41.         {
  42.             videoindex = i;
  43.         }
  44.     }
  45.     printf("audioindex is %dn",audioindex);
  46.     printf("videoindex is %dn",videoindex);
  47.     AVCodecContext *codecctx = fmtctx->streams[videoindex]->codec;
  48.     AVCodec *decode = avcodec_find_decoder(codecctx->codec_id);
  49.     AVCodecContext *audioCodecCtx = fmtctx->streams[audioindex]->codec;
  50.     AVCodec *audiodecode = avcodec_find_decoder(audioCodecCtx->codec_id);
  51.     if(audiodecode->id == AV_CODEC_ID_AAC)
  52.     {
  53.         isaaccodec = 1;
  54.     }
  55.     if(avcodec_open2(codecctx,decode,NULL) < 0)
  56.     {
  57.         return -1;
  58.     }
  59.     if(avcodec_open2(audioCodecCtx,audiodecode,NULL) < 0)
  60.     {
  61.         return -1;
  62.     }
  63.     printf("extradata size is %dn",audioCodecCtx->extradata_size);
  64.     AVBitStreamFilterContext* bsfc = av_bitstream_filter_init("h264_mp4toannexb");
  65.     AVBitStreamFilterContext* aacbsfc = av_bitstream_filter_init("aac_adtstoasc");
  66.     if(!bsfc || !aacbsfc)
  67.     {
  68.         return 0;
  69.     }
  70.     AVFrame picture;
  71.     while(!(av_read_frame(fmtctx,&audiopack)))
  72.     {
  73.         if(audiopack.stream_index == 1)
  74.         {
  75.             if(isaaccodec == 1)
  76.             {
  77.                 char bits[7] = {0};
  78.                 int sample_index = 0 , channel = 0;
  79.                 char temp = 0;
  80.                 int length = 7 + audiopack.size;
  81.                 sample_index = (audioCodecCtx->extradata[0] & 0x07) << 1;
  82.                 temp = (audioCodecCtx->extradata[1]&0x80);
  83.                 switch(audioCodecCtx->sample_rate)
  84.                 {
  85.                     case 44100:
  86.                         {
  87.                             sample_index = 0x7;
  88.                         }break;
  89.                     default:
  90.                         {
  91.                             sample_index = sample_index + (temp>>7);
  92.                         }break;
  93.                 }
  94.                 channel = ((audioCodecCtx->extradata[1] - temp) & 0xff) >> 3;
  95.                 bits[0] = 0xff;
  96.                 bits[1] = 0xf1;
  97.                 bits[2] = 0x40 | (sample_index<<2) | (channel>>2);
  98.                 bits[3] = ((channel&0x3)<<6) | (length >>11);
  99.                 bits[4] = (length>>3) & 0xff;
  100.                 bits[5] = ((length<<5) & 0xff) | 0x1f;
  101.                 bits[6] = 0xfc;
  102.                 fwrite(bits,1,7,f);
  103.             }
  104.             fwrite(audiopack.data,1,audiopack.size,f);
  105.             printf("audio pts is %fn",audiopack.pts*av_q2d(fmtctx->streams[audioindex]->time_base));
  106.         }
  107.         else if(audiopack.stream_index == videoindex){
  108.             AVPacket pkt = audiopack;
  109.             
  110.             int a = av_bitstream_filter_filter(bsfc, codecctx, NULL, &pkt.data, &pkt.size, audiopack.data, audiopack.size, audiopack.flags & AV_PKT_FLAG_KEY);
  111.             if(> 0)
  112.             {
  113.                 audiopack = pkt;
  114.             }
  115.             fwrite(audiopack.data,1,audiopack.size,g);
  116.             int gotfinished = 0;
  117.             if(avcodec_decode_video2(codecctx,&picture,&gotfinished,&audiopack) < 0)
  118.             {
  119.                 printf("decode video errorn");
  120.             }
  121.             if(picture.key_frame)
  122.             {
  123.                 //printf("key framen");
  124.             }
  125.             else{
  126.                 //printf("frame num is %dn",picture.pict_type);
  127.             }
  128.             //printf("video pts is %f, %dn",picture.pkt_dts * av_q2d(fmtctx->streams[videoindex]->codec->time_base),picture.pts );
  129.         }
  130.         av_free_packet(&audiopack);
  131.     }
  132.     fclose(f);
  133. }


最後就可以用vlc 或ffplay來查看解析出來的音頻aac文件和264文件,本套代碼是通用解析器,任何視頻文件都可以解析,只是對於264和aac單獨做了處理。
貼上最後的效果圖:

發佈了340 篇原創文章 · 獲贊 4 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章