ffmpeg源码分析:transcode()函数

还是先看一下主函数吧:(省略了很多无关大雅的代码)

  1. intmain(intargc,char**argv)
  2. {
  3. OptionsContexto={0};
  4. int64_tti;
  5. //与命令行分析有关的结构的初始化,下面不再罗嗦
  6. reset_options(&o,0);
  7. //设置日志级别
  8. av_log_set_flags(AV_LOG_SKIP_REPEATED);
  9. parse_loglevel(argc,argv,options);
  10. if(argc>1&&!strcmp(argv[1],"-d")){
  11. run_as_daemon=1;
  12. av_log_set_callback(log_callback_null);
  13. argc--;
  14. argv++;
  15. }
  16. //注册组件们
  17. avcodec_register_all();
  18. #ifCONFIG_AVDEVICE
  19. avdevice_register_all();
  20. #endif
  21. #ifCONFIG_AVFILTER
  22. avfilter_register_all();
  23. #endif
  24. av_register_all();
  25. //初始化网络,windows下需要
  26. avformat_network_init();
  27. show_banner();
  28. term_init();
  29. //分析命令行输入的参数们
  30. parse_options(&o,argc,argv,options,opt_output_file);
  31. //文件的转换就在此函数中发生
  32. if(transcode(output_files,nb_output_files,input_files,nb_input_files)<0)
  33. exit_program(1);
  34. exit_program(0);
  35. return0;
  36. }

下面是transcode()函数,转换就发生在它里面.不废话,看注释吧,应很详细了

  1. staticinttranscode(
  2. OutputFile*output_files,//输出文件数组
  3. intnb_output_files,//输出文件的数量
  4. InputFile*input_files,//输入文件数组
  5. intnb_input_files)//输入文件的数量
  6. {
  7. intret,i;
  8. AVFormatContext*is,*os;
  9. OutputStream*ost;
  10. InputStream*ist;
  11. uint8_t*no_packet;
  12. intno_packet_count=0;
  13. int64_ttimer_start;
  14. intkey;
  15. if(!(no_packet=av_mallocz(nb_input_files)))
  16. exit_program(1);
  17. //设置编码参数,打开所有输出流的编码器,打开所有输入流的解码器,写入所有输出文件的文件头,于是准备好了
  18. ret=transcode_init(output_files,nb_output_files,input_files,nb_input_files);
  19. if(ret<0)
  20. gotofail;
  21. if(!using_stdin){
  22. av_log(NULL,AV_LOG_INFO,"Press[q]tostop,[?]forhelp\n");
  23. }
  24. timer_start=av_gettime();
  25. //循环,直到收到系统信号才退出
  26. for(;received_sigterm==0;)
  27. {
  28. intfile_index,ist_index;
  29. AVPacketpkt;
  30. int64_tipts_min;
  31. doubleopts_min;
  32. int64_tcur_time=av_gettime();
  33. ipts_min=INT64_MAX;
  34. opts_min=1e100;
  35. /*if'q'pressed,exits*/
  36. if(!using_stdin)
  37. {
  38. //先查看用户按下了什么键,跟据键做出相应的反应
  39. staticint64_tlast_time;
  40. if(received_nb_signals)
  41. break;
  42. /*read_key()returns0onEOF*/
  43. if(cur_time-last_time>=100000&&!run_as_daemon){
  44. key=read_key();
  45. last_time=cur_time;
  46. }else{
  47. <span></span>.................................
  48. }
  49. /*selectthestreamthatwemustreadnowbylookingatthe
  50. smallestoutputpts*/
  51. //下面这个循环的目的是找一个最小的输出pts(也就是离当前最近的)的输出流
  52. file_index=-1;
  53. for(i=0;i<nb_output_streams;i++){
  54. OutputFile*of;
  55. int64_tipts;
  56. doubleopts;
  57. ost=&output_streams[i];//循环每一个输出流
  58. of=&output_files[ost->file_index];//输出流对应的输出文件
  59. os=output_files[ost->file_index].ctx;//输出流对应的FormatContext
  60. ist=&input_streams[ost->source_index];//输出流对应的输入流
  61. if(ost->is_past_recording_time||//是否过了录制时间?(可能用户指定了一个录制时间段)
  62. no_packet[ist->file_index]||//对应的输入流这个时间内没有数据?
  63. (os->pb&&avio_tell(os->pb)>=of->limit_filesize))//是否超出了录制范围(也是用户指定的)
  64. continue;//是的,符合上面某一条,那么再看下一个输出流吧
  65. //判断当前输入流所在的文件是否可以使用(我也不很明白)
  66. opts=ost->st->pts.val*av_q2d(ost->st->time_base);
  67. ipts=ist->pts;
  68. if(!input_files[ist->file_index].eof_reached){
  69. if(ipts<ipts_min){
  70. //每找到一个pts更小的输入流就记录下来,这样循环完所有的输出流时就找到了
  71. //pts最小的输入流,及输入文件的序号
  72. ipts_min=ipts;
  73. if(input_sync)
  74. file_index=ist->file_index;
  75. }
  76. if(opts<opts_min){
  77. opts_min=opts;
  78. if(!input_sync)
  79. file_index=ist->file_index;
  80. }
  81. }
  82. //难道下面这句话的意思是:如果当前的输出流已接收的帧数,超出用户指定的输出最大帧数时,
  83. //则当前输出流所属的输出文件对应的所有输出流,都算超过了录像时间?
  84. if(ost->frame_number>=ost->max_frames){
  85. intj;
  86. for(j=0;j<of->ctx->nb_streams;j++)
  87. output_streams[of->ost_index+j].is_past_recording_time=1;
  88. continue;
  89. }
  90. }
  91. /*ifnone,ifisfinished*/
  92. if(file_index<0){
  93. //如果没有找到合适的输入文件
  94. if(no_packet_count){
  95. //如果是因为有的输入文件暂时得不到数据,则还不算是结束
  96. no_packet_count=0;
  97. memset(no_packet,0,nb_input_files);
  98. usleep(10000);
  99. continue;
  100. }
  101. //全部转换完成了,跳出大循环
  102. break;
  103. }
  104. //从找到的输入文件中读出一帧(可能是音频也可能是视频),并放到fifo队列中
  105. is=input_files[file_index].ctx;
  106. ret=av_read_frame(is,&pkt);
  107. if(ret==AVERROR(EAGAIN)){
  108. //此时发生了暂时没数据的情况
  109. no_packet[file_index]=1;
  110. no_packet_count++;
  111. continue;
  112. }
  113. //下文判断是否有输入文件到最后了
  114. if(ret<0){
  115. input_files[file_index].eof_reached=1;
  116. if(opt_shortest)
  117. break;
  118. else
  119. continue;
  120. }
  121. no_packet_count=0;
  122. memset(no_packet,0,nb_input_files);
  123. if(do_pkt_dump){
  124. av_pkt_dump_log2(NULL,AV_LOG_DEBUG,&pkt,do_hex_dump,
  125. is->streams[pkt.stream_index]);
  126. }
  127. /*thefollowingtestisneededincasenewstreamsappear
  128. dynamicallyinstream:weignorethem*/
  129. //如果在输入文件中遇到一个忽然冒出的流,那么我们不鸟它
  130. if(pkt.stream_index>=input_files[file_index].nb_streams)
  131. gotodiscard_packet;
  132. //取得当前获得的帧对应的输入流
  133. ist_index=input_files[file_index].ist_index+pkt.stream_index;
  134. ist=&input_streams[ist_index];
  135. if(ist->discard)
  136. gotodiscard_packet;
  137. //重新鼓捣一下帧的时间戳
  138. if(pkt.dts!=AV_NOPTS_VALUE)
  139. pkt.dts+=av_rescale_q(input_files[ist->file_index].ts_offset,
  140. AV_TIME_BASE_Q,ist->st->time_base);
  141. if(pkt.pts!=AV_NOPTS_VALUE)
  142. pkt.pts+=av_rescale_q(input_files[ist->file_index].ts_offset,
  143. AV_TIME_BASE_Q,ist->st->time_base);
  144. if(pkt.pts!=AV_NOPTS_VALUE)
  145. pkt.pts*=ist->ts_scale;
  146. if(pkt.dts!=AV_NOPTS_VALUE)
  147. pkt.dts*=ist->ts_scale;
  148. if(pkt.dts!=AV_NOPTS_VALUE&&ist->next_pts!=AV_NOPTS_VALUE
  149. &&(is->iformat->flags&AVFMT_TS_DISCONT))
  150. {
  151. int64_tpkt_dts=av_rescale_q(pkt.dts,ist->st->time_base,
  152. AV_TIME_BASE_Q);
  153. int64_tdelta=pkt_dts-ist->next_pts;
  154. if((delta<-1LL*dts_delta_threshold*AV_TIME_BASE
  155. ||(delta>1LL*dts_delta_threshold*AV_TIME_BASE
  156. &&ist->st->codec->codec_type
  157. !=AVMEDIA_TYPE_SUBTITLE)
  158. ||pkt_dts+1<ist->pts)&&!copy_ts)
  159. {
  160. input_files[ist->file_index].ts_offset-=delta;
  161. av_log(NULL,AV_LOG_DEBUG,
  162. "timestampdiscontinuity%"PRId64",newoffset=%"PRId64"\n",
  163. delta,input_files[ist->file_index].ts_offset);
  164. pkt.dts-=av_rescale_q(delta,AV_TIME_BASE_Q,ist->st->time_base);
  165. if(pkt.pts!=AV_NOPTS_VALUE)
  166. pkt.pts-=av_rescale_q(delta,AV_TIME_BASE_Q,ist->st->time_base);
  167. }
  168. }
  169. //把这一帧转换并写入到输出文件中
  170. if(output_packet(ist,output_streams,nb_output_streams,&pkt)<0){
  171. av_log(NULL,AV_LOG_ERROR,
  172. "Errorwhiledecodingstream#%d:%d\n",
  173. ist->file_index,ist->st->index);
  174. if(exit_on_error)
  175. exit_program(1);
  176. av_free_packet(&pkt);
  177. continue;
  178. }
  179. discard_packet:
  180. av_free_packet(&pkt);
  181. /*dumpreportbyusingtheoutputfirstvideoandaudiostreams*/
  182. print_report(output_files,output_streams,nb_output_streams,0,
  183. timer_start,cur_time);
  184. }
  185. //文件处理完了,把缓冲中剩余的数据写到输出文件中
  186. for(i=0;i<nb_input_streams;i++){
  187. ist=&input_streams[i];
  188. if(ist->decoding_needed){
  189. output_packet(ist,output_streams,nb_output_streams,NULL);
  190. }
  191. }
  192. flush_encoders(output_streams,nb_output_streams);
  193. term_exit();
  194. //为输出文件写文件尾(有的不需要).
  195. for(i=0;i<nb_output_files;i++){
  196. os=output_files[i].ctx;
  197. av_write_trailer(os);
  198. }
  199. /*dumpreportbyusingthefirstvideoandaudiostreams*/
  200. print_report(output_files,output_streams,nb_output_streams,1,
  201. timer_start,av_gettime());
  202. //关闭所有的编码器
  203. for(i=0;i<nb_output_streams;i++){
  204. ost=&output_streams[i];
  205. if(ost->encoding_needed){
  206. av_freep(&ost->st->codec->stats_in);
  207. avcodec_close(ost->st->codec);
  208. }
  209. #ifCONFIG_AVFILTER
  210. avfilter_graph_free(&ost->graph);
  211. #endif
  212. }
  213. //关闭所有的解码器
  214. for(i=0;i<nb_input_streams;i++){
  215. ist=&input_streams[i];
  216. if(ist->decoding_needed){
  217. avcodec_close(ist->st->codec);
  218. }
  219. }
  220. /*finished!*/
  221. ret=0;
  222. fail:av_freep(&bit_buffer);
  223. av_freep(&no_packet);
  224. if(output_streams){
  225. for(i=0;i<nb_output_streams;i++){
  226. ost=&output_streams[i];
  227. if(ost){
  228. if(ost->stream_copy)
  229. av_freep(&ost->st->codec->extradata);
  230. if(ost->logfile){
  231. fclose(ost->logfile);
  232. ost->logfile=NULL;
  233. }
  234. av_fifo_free(ost->fifo);/*workseveniffifoisnot
  235. initializedbutsettozero*/
  236. av_freep(&ost->st->codec->subtitle_header);
  237. av_free(ost->resample_frame.data[0]);
  238. av_free(ost->forced_kf_pts);
  239. if(ost->video_resample)
  240. sws_freeContext(ost->img_resample_ctx);
  241. swr_free(&ost->swr);
  242. av_dict_free(&ost->opts);
  243. }
  244. }
  245. }
  246. returnret;
  247. }

原文地址: http://blog.csdn.net/niu_gao/article/details/7175421
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值