FFmpeg转码框架解析

FFmpeg情景分析 1. FFmpeg转码框架解析


本文的参考和借鉴: http://dranger.com/ffmpeg/tutorial01.html(文章在开篇就声明,它有些过时了)。所以本文分析的FFmpeg源码为Version0.8.2

我们在网络上看到的“视频”通常都是一种三层数据封装结构:

       编码图像和声音形成的裸视频流(如H.264, VP8, 等)和音频流(mp3, AAC等);

       用容器格式将这些裸流封装形成文件(FLV,rmvb, mkv等)或流(mpeg2-TS等);

       再利用传输协议(如RTSP, RTMP, HTTP, UDP等)将数据通过互联网,电视线路或无线网络等传输到用户端(电视机,PC,移动设备等)以收看。

FFmpeg的强大与复杂都体现在对这三层封装数据做了大量的支持和处理,从而使它能完成流或文件输入,解码显示,转码存储,封装推送等多项工作。

   闲言少絮,进入正题。

  对于C语言构建的面向过程编程的程序最基本的分析原则是:

          去掉无关,分层推进。

FFmpeg最精简的伪码描述可如下图所示:

简而言之就是,打开文件,读取一帧数据 ,处理一帧数据,如此循环直到文件结束。

这个描述是简单而正确的。我们以转码一个文件来对应实际的代码进行分析。

1.main函数(ffmpeg.c)

int main(int argc, char **argv)

{

   

      avcodec_register_all();
      av_register_all();                            // This registers all file formats andcodecs   

   

   

   init_opts();
    
   
   parse_options(argc, argv, options, opt_output_file);

            

   

    if(transcode(output_files,nb_output_files, input_files, nb_input_files,
                 stream_maps, nb_stream_maps)
< 0)
       ffmpeg_exit(1);

    returnffmpeg_exit(0);
}

转码结束后的收尾工作。

 

2.     transcode函数(ffmpeg.c)


static int transcode(AVFormatContext **output_files,intnb_output_files,
                    InputFile *input_files, int nb_input_files,
                    StreamMap *stream_maps, int nb_stream_maps)
{

   
    ost_table =av_mallocz(sizeof(OutputStream *) * nb_ostreams);
  //av_mallocz:是ffmpeg对“malloc”的简单封装,它确保了存储地址的对齐,但不保证存储器的内存泄漏,二次释放或其它的问题。

   
   for(k=0;k<nb_output_files;k++)
    ... }

   
   for(i=0;i<nb_ostreams;i++)
    {
           if (!ost->enc)
               ost->enc =avcodec_find_encoder(ost->st->codec->codec_id);
          
           switch(codec->codec_type)
           {
           case AVMEDIA_TYPE_AUDIO:
               
               ost->fifo= av_fifo_alloc(1024);
               
               ost->reformat_pair =MAKE_SFMT_PAIR(AV_SAMPLE_FMT_NONE,AV_SAMPLE_FMT_NONE);

               break;
           case AVMEDIA_TYPE_VIDEO:
               
               choose_pixel_fmt(ost->st,ost->enc);

               break;
           case AVMEDIA_TYPE_SUBTITLE:
               ost->encoding_needed = 1;
               ist->decoding_needed = 1;
               break;
           default:
               abort();
               break;
           }  
    }

   
   for(i=0;i<nb_ostreams;i++)
    {
       ost = ost_table[i];
       if (ost->encoding_needed)
       {
           AVCodec *codec = ost->enc;
           AVCodecContext *dec =input_streams[ost->source_index].st->codec;
                  
           
           if (avcodec_open2(ost->st->codec,codec, &ost->opts) <0)
           {
             ...
           }
           
       }
    }

   
    for (i = 0;i < nb_input_streams; i++)
    {
       ist = &input_streams[i];
       
       
       if (ist->decoding_needed)
       {  
          
           if (avcodec_open2(ist->st->codec,codec, &ist->opts) <0)
           {
              ...
           }
       }
    }


   
   for(i=0;i<nb_output_files;i++)
    {
     os = output_files[i];
     if (avformat_write_header(os, &output_opts[i])< 0)
     {
         ...
     }
    }



   
    for(;received_sigterm == 0;)
    {
       
       is = input_files[file_index].ctx;
       ret= av_read_frame(is, &pkt);
                            
       
       if (output_packet(ist, ist_index,ost_table, nb_ostreams,&pkt)< 0)
       {
         ...
       }

    }

   
    for (i = 0;i < nb_input_streams; i++)
    {
       ist = &input_streams[i];
       if (ist->decoding_needed)
       {
           output_packet(ist, i, ost_table, nb_ostreams, NULL);
       }
    }


   
   for(i=0;i<nb_output_files;i++)
    {
       os = output_files[i];
       av_write_trailer(os);
    }

   
   for(i=0;i<nb_ostreams;i++)
    {
       ost = ost_table[i];
       if (ost->encoding_needed)
       {
           av_freep(&ost->st->codec->stats_in);
           avcodec_close(ost->st->codec);
       }
    }

   
    for (i = 0;i < nb_input_streams; i++)
    {
       ist = &input_streams[i];
       if (ist->decoding_needed) {
           avcodec_close(ist->st->codec);
       }
    }

    returnret;
}


3.     output_packet函数(ffmpeg.c)

static int output_packet(InputStream *ist, int ist_index,
                        OutputStream **ost_table, int nb_ostreams,
                        const AVPacket *pkt)
{

    AVFramepicture;
    AVPacketavpkt;

    //先进行解码
    while(avpkt.size > 0 || (!pkt&& got_output))
   
       
       if (ist->decoding_needed) {
           switch(ist->st->codec->codec_type)
           {
           case AVMEDIA_TYPE_AUDIO:
               ret = avcodec_decode_audio3(ist->st->codec,samples, &decoded_data_size,&avpkt);
               break;
           caseAVMEDIA_TYPE_VIDEO:                  
               
               avcodec_get_frame_defaults(&picture);
               ret = avcodec_decode_video2(ist->st->codec,&picture, &got_output,&avpkt);
               break;
           case AVMEDIA_TYPE_SUBTITLE:
               ret =avcodec_decode_subtitle2(ist->st->codec,&subtitle,&got_output, &avpkt);
               break;
           default:
               return -1;
           }
       }

       
       
       if (start_time == 0 || ist->pts >=start_time)
           for(i=0;i<nb_ostreams;i++)
           {
               if (ost->source_index == ist_index)
               {
                   os = output_files[ost->file_index];

                   if (ost->encoding_needed)
                   {
                       av_assert0(ist->decoding_needed);
                       switch(ost->st->codec->codec_type)
                       {
                       case AVMEDIA_TYPE_AUDIO:
                           do_audio_out(os, ost, ist,decoded_data_buf, decoded_data_size);
                           break;
                       case AVMEDIA_TYPE_VIDEO:

                           do_video_out(os, ost, ist,&picture, &frame_size,same_quality? quality :ost->st->codec->global_quality);
                           if (vstats_filename &&frame_size)
                               do_video_stats(os, ost, frame_size);
                           break;
                       case AVMEDIA_TYPE_SUBTITLE:
                           do_subtitle_out(os, ost, ist, &subtitle,
                                           pkt->pts);
                           break;
                       default:
                           abort();
                      }
                   }
               }
           }

       av_free(buffer_to_free);
    }
    return0;
}

至此,框架分析结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值