首页 > 代码库 > FFmpeg SDK开发模型之三:muxer

FFmpeg SDK开发模型之三:muxer

简介
使用FFmpeg SDK实现的H.264码流合成MPEG2-TS文件

一、源代码
int main(int argc, char* argv[])                                                      
{                
  const char* input = NULL;
  const char* output= NULL;                                                           
      
  /* Obtain input params */                                                           
  if (argc <= 1) {                                                                    
    printf("Usage:\n");                                                               
    printf("%s <input_file.264> <output_file.ts>\n", argv[0]);                        
    return 0;
  }                                                                                   
  input = argv[1];                                                                    
  output= argv[2];
  
  AVInputFormat* ifmt  = NULL;
  AVOutputFormat* ofmt = NULL;                                                        
  AVFormatContext* ic  = NULL;                                                        
  AVFormatContext* oc  = NULL;                                                        
  AVStream* video_st   = NULL;                                                        
  AVStream* audio_st   = NULL;                                                        
  AVCodec* codec = NULL;                                                              
  AVDictionary* pAVDictionary = NULL;                                                 
                                                                                      
  avcodec_init();
  avcodec_register_all();                                                             
  av_register_all();                                                                  
  
  ifmt = av_find_input_format("avc");
  ic = avformat_alloc_context();                                                      
  if (!ic)
  {
    printf("Call avformat_alloc_context failed!\n");                                  
    return 0;                                                                         
  } 
    
  char szError[256] = {0};                                                            
  int nRet = avformat_open_input(&ic, input, ifmt, &pAVDictionary);                   
  if (nRet != 0)
  {
    av_strerror(nRet, szError, 256);                                                  
    printf(szError);
    printf("\n");
    printf("Call avformat_open_input function failed!\n");
    return 0;
  }


  if (avformat_find_stream_info(ic, NULL) < 0)
  {
    printf("Call av_find_stream_info function failed!\n");
    return 0;
  }
  ofmt = av_guess_format("mpegts", NULL, NULL);
  if (!ofmt)
  {
    printf("Call av_guess_format function failed!\n");
    return 0;
  }


  oc = avformat_alloc_context();
  if (!oc)
  {
    printf("Call av_guess_format function failed!\n");
    return 0;
  }
  oc->oformat = ofmt;


  int video_index = -1, audio_index = -1;
  unsigned int i;
  for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++)
  {
    switch (ic->streams[i]->codec->codec_type)
    {
      case AVMEDIA_TYPE_VIDEO:
        video_index = i;
        ic->streams[i]->discard = AVDISCARD_NONE;
        video_st = add_output_stream(oc, ic->streams[i]);
        break;
      case AVMEDIA_TYPE_AUDIO:
        audio_index = i;
        ic->streams[i]->discard = AVDISCARD_NONE;
        audio_st = add_output_stream(oc, ic->streams[i]);
        break;
      default:
        ic->streams[i]->discard = AVDISCARD_ALL;
        break;
    }
  }


  codec = avcodec_find_decoder(video_st->codec->codec_id);
  if (codec == NULL)
  {
    printf("Call avcodec_find_decoder function failed!\n");
    return 0;
  }


  if (avcodec_open(video_st->codec, codec) < 0)
  {
    printf("Call avcodec_open function failed !\n");
    return 0;
  }


  if (avio_open(&oc->pb, output, AVIO_FLAG_WRITE) < 0)
  {
    return 0;
  }
  if (avformat_write_header(oc, &pAVDictionary))
  {
    printf("Call avformat_write_header function failed.\n");
    return 0;
  }


  uint8_t *dummy = NULL;
  int dummy_size = 0;
  AVBitStreamFilterContext* bsfc =  av_bitstream_filter_init("h264_mp4toannexb");
  if(bsfc == NULL)
  {
    return -1;
  }


  int decode_done = 0;
  do
  {
    double segment_time = 0;
    AVPacket packet;
    decode_done = av_read_frame(ic, &packet);
    if (decode_done < 0)
    break;


    if (av_dup_packet(&packet) < 0)
    {
      printf("Call av_dup_packet function failed\n");
      av_free_packet(&packet);
      break;
    }


    static int nCount = 0;
    if (nCount++ < 20)
    {
      printf("The packet.stream_index is %ld\n", packet.stream_index);
    }


    if (packet.stream_index == video_index)
    {
      if (packet.pts != (u_int)AV_NOPTS_VALUE)
      {
        packet.pts      = av_rescale_q(packet.pts,ic->streams[video_index]->time_base,video_st->time_base);
      }


      if (packet.dts != (u_int)AV_NOPTS_VALUE)
      {
        packet.dts      = av_rescale_q(packet.dts,ic->streams[video_index]->time_base,video_st->time_base);
      }
    }
    nRet = av_interleaved_write_frame(oc, &packet);
    if (nRet < 0)
    {
      printf("Call av_interleaved_write_frame function failed\n");
    }
    else if (nRet > 0)
    {
      printf("End of stream requested\n");
      av_free_packet(&packet);
      break;
    }


    av_free_packet(&packet);
  }while(!decode_done);


  av_write_trailer(oc);


  av_bitstream_filter_close(bsfc);
  avcodec_close(video_st->codec);
  unsigned int k;
  for(k = 0; k < oc->nb_streams; k++)
  {
    av_freep(&oc->streams[k]->codec);
    av_freep(&oc->streams[k]);
  }


  av_free(ic);
  av_free(oc);
  getchar();
  return 0;
}


二、源码分析
01  avcodec_init();         初始化libavcodec
02  avcodec_register_all(); 注册所有的codec, 解析器、码流过滤器
03  av_register_all();      初始化libavformat并注册所有的muxer, demuxer和协议


/* 处理输入文件的格式 并初始化上下文 */
04  ifmt = av_find_input_format("avc");
05  ic = avformat_alloc_context();
06  avformat_open_input(&ic, input, ifmt, &pAVDictionary);
07  avformat_find_stream_info(ic, NULL);


/* 处理输出文件的格式 并初始化上下文 */
08  ofmt = av_guess_format("mpegts", NULL, NULL);
09  oc   = avformat_alloc_context();
10  oc->oformat = ofmt;


/* 将输入文件的音视频流映射到输出文件,并初始化 */
11  int video_index = -1, audio_index = -1;
12  unsigned int i;
13  for (i = 0; i < ic->nb_streams && (video_index < 0 || audio_index < 0); i++){
14    switch (ic->streams[i]->codec->codec_type){
15      case AVMEDIA_TYPE_VIDEO:
16        video_index = i;
17        ic->streams[i]->discard = AVDISCARD_NONE;
18        video_st = add_output_stream(oc, ic->streams[i]);
19        break;
20      case AVMEDIA_TYPE_AUDIO:
21        audio_index = i;
22        ic->streams[i]->discard = AVDISCARD_NONE;
23        audio_st = add_output_stream(oc, ic->streams[i]);
24        break;
25      default:
26        ic->streams[i]->discard = AVDISCARD_ALL;
27        break;
28    }
29  }


30  codec = avcodec_find_decoder(video_st->codec->codec_id); 查找输出视频流的解码器;
31  avcodec_open(video_st->codec, codec);    使用codec初始化上下文video_st->codec;  
32  avio_open(&oc->pb, output, AVIO_FLAG_WRITE);  打开输出文件
33  avformat_write_header(oc, &pAVDictionary);    将MPEG2-TS流的头写到输出文件
34  AVBitStreamFilterContext* bsfc =  av_bitstream_filter_init("h264_mp4toannexb"); 初始化流过滤器上下文


35  int decode_done = 0;
36  do{
      double segment_time = 0;
      AVPacket packet;
37    decode_done = av_read_frame(ic, &packet);   从输入文件中读取一帧
38    if (decode_done < 0)
        break;


39    if (av_dup_packet(&packet) < 0){            包数据空间扩展
        printf("Call av_dup_packet function failed\n");
        av_free_packet(&packet);
        break;
      }


40    static int nCount = 0;                      前20个包的流信息输出
      if (nCount++ < 20){
        printf("The packet.stream_index is %ld\n", packet.stream_index);
      }


41    if (packet.stream_index == video_index){    计算视频流的时间戳
42      if (packet.pts != (u_int)AV_NOPTS_VALUE){ 计算PTS值
          packet.pts      = av_rescale_q(packet.pts,ic->streams[video_index]->time_base,video_st->time_base);
        }


43      if (packet.dts != (u_int)AV_NOPTS_VALUE){ 计算DTS值
          packet.dts      = av_rescale_q(packet.dts,ic->streams[video_index]->time_base,video_st->time_base);
        }
      }


44    nRet = av_interleaved_write_frame(oc, &packet); 将数据包混合插入输出文件
45    if (nRet < 0){
        printf("Call av_interleaved_write_frame function failed\n");
      }
46    else if (nRet > 0)
      {
        printf("End of stream requested\n");
        av_free_packet(&packet);                      释放包
        break;
      }


47    av_free_packet(&packet);
48  }while(!decode_done);


49  av_write_trailer(oc);       写MPEG-TS流的结尾


50  av_bitstream_filter_close(bsfc);      释放所有的资源
    avcodec_close(video_st->codec);
    unsigned int k;
    for(k = 0; k < oc->nb_streams; k++)
    {
      av_freep(&oc->streams[k]->codec);
      av_freep(&oc->streams[k]);
    }


    av_free(ic);
    av_free(oc);
51  getchar();             等待用户输出任意字符结束
    return 0;
}


三、其它
1. 编译选项
# gcc tsmuxer.c -g -o tsmuxer 
-I/YOUR_SDK_INSTALL_PATH/include -L/YOUR_SDK_INSTALL_PATH/lib  
-lavformat -lavdevice -lavcodec  -lavutil -lavfilter -pthread -ldl -lswscale -lbz2 -lasound  
-lmp3lame -lfaac -lx264 -lrtmp -lz -lm


2. 完整代码下载
http://download.csdn.net/detail/fireroll/7292853