1. 程式人生 > >最新版ffmpeg原始碼分析二:transcode()函式

最新版ffmpeg原始碼分析二:transcode()函式

還是先看一下主函式吧:(省略了很多無關大雅的程式碼)

  1. int main(int argc, char **argv)

  2. {

  3. OptionsContext o = { 0 };

  4. int64_t ti;

  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. #if CONFIG_AVDEVICE

  19. avdevice_register_all();

  20. #endif

  21. #if CONFIG_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. return 0;

  36. }

下面是transcode()函式,轉換就發生在它裡面.不廢話,看註釋吧,應很詳細了

  1. static int transcode(

  2. OutputFile *output_files,//輸出檔案陣列

  3. int nb_output_files,//輸出檔案的數量

  4. InputFile *input_files,//輸入檔案陣列

  5. int nb_input_files)//輸入檔案的數量

  6. {

  7. int ret, i;

  8. AVFormatContext *is, *os;

  9. OutputStream *ost;

  10. InputStream *ist;

  11. uint8_t *no_packet;

  12. int no_packet_count = 0;

  13. int64_t timer_start;

  14. int key;

  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. goto fail;

  21. if (!using_stdin){

  22. av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");

  23. }

  24. timer_start = av_gettime();

  25. //迴圈,直到收到系統訊號才退出

  26. for (; received_sigterm == 0;)

  27. {

  28. int file_index, ist_index;

  29. AVPacket pkt;

  30. int64_t ipts_min;

  31. double opts_min;

  32. int64_t cur_time = av_gettime();

  33. ipts_min = INT64_MAX;

  34. opts_min = 1e100;

  35. /* if 'q' pressed, exits */

  36. if (!using_stdin)

  37. {

  38. //先檢視使用者按下了什麼鍵,跟據鍵做出相應的反應

  39. static int64_t last_time;

  40. if (received_nb_signals)

  41. break;

  42. /* read_key() returns 0 on EOF */

  43. if (cur_time - last_time >= 100000 && !run_as_daemon){

  44. key = read_key();

  45. last_time = cur_time;

  46. }else{

  47. .................................

  48. }

  49. /* select the stream that we must read now by looking at the

  50. smallest output pts */

  51. //下面這個迴圈的目的是找一個最小的輸出pts(也就是離當前最近的)的輸出流

  52. file_index = -1;

  53. for (i = 0; i < nb_output_streams; i++){

  54. OutputFile *of;

  55. int64_t ipts;

  56. double opts;

  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. int j;

  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. /* if none, if is finished */

  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. /* the following test is needed in case new streams appear

  128. dynamically in stream : we ignore them */

  129. //如果在輸入檔案中遇到一個忽然冒出的流,那麼我們不鳥它

  130. if (pkt.stream_index >= input_files[file_index].nb_streams)

  131. goto discard_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. goto discard_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_t pkt_dts = av_rescale_q(pkt.dts, ist->st->time_base,

  152. AV_TIME_BASE_Q);

  153. int64_t delta = 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. "timestamp discontinuity %"PRId64", new offset= %"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. "Error while decoding stream #%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. /* dump report by using the output first video and audio streams */

  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. /* dump report by using the first video and audio streams */

  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. #if CONFIG_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); /* works even if fifo is not

  235. initialized but set to zero */

  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. return ret;