• ffmpeg 之ffmpeg 整理流程分析


    这个篇文档主要对ffmpeg  命令分析:主要分析ffmpeg 程序主要流程:

     1. 分析命令行函数,解析出输入文件及输出文件

     ffmpeg_parse_option 

    1. int ffmpeg_parse_options(int argc, char **argv)
    2. {
    3. OptionParseContext octx;
    4. uint8_t error[128];
    5. int ret;
    6. memset(&octx, 0, sizeof(octx));
    7. /* split the commandline into an internal representation */
    8. ret = split_commandline(&octx, argc, argv, options, groups,
    9. FF_ARRAY_ELEMS(groups));
    10. if (ret < 0) {
    11. av_log(NULL, AV_LOG_FATAL, "Error splitting the argument list: ");
    12. goto fail;
    13. }
    14. /* apply global options */
    15. ret = parse_optgroup(NULL, &octx.global_opts);
    16. if (ret < 0) {
    17. av_log(NULL, AV_LOG_FATAL, "Error parsing global options: ");
    18. goto fail;
    19. }
    20. /* configure terminal and setup signal handlers */
    21. term_init();
    22. /* open input files */
    23. ret = open_files(&octx.groups[GROUP_INFILE], "input", open_input_file);
    24. if (ret < 0) {
    25. av_log(NULL, AV_LOG_FATAL, "Error opening input files: ");
    26. goto fail;
    27. }
    28. /* create the complex filtergraphs */
    29. ret = init_complex_filters();
    30. if (ret < 0) {
    31. av_log(NULL, AV_LOG_FATAL, "Error initializing complex filters.\n");
    32. goto fail;
    33. }
    34. /* open output files */
    35. ret = open_files(&octx.groups[GROUP_OUTFILE], "output", open_output_file);
    36. if (ret < 0) {
    37. av_log(NULL, AV_LOG_FATAL, "Error opening output files: ");
    38. goto fail;
    39. }
    40. check_filter_outputs();
    41. fail:
    42. uninit_parse_context(&octx);
    43. if (ret < 0) {
    44. av_strerror(ret, error, sizeof(error));
    45. av_log(NULL, AV_LOG_FATAL, "%s\n", error);
    46. }
    47. return ret;
    48. }

    2. transcode 转码处理

    1. static int transcode(void)
    2. {
    3. int ret, i;
    4. AVFormatContext *os;
    5. OutputStream *ost;
    6. InputStream *ist;
    7. int64_t timer_start;
    8. int64_t total_packets_written = 0;
    9. ret = transcode_init(); // 转码初始化
    10. if (ret < 0)
    11. goto fail;
    12. if (stdin_interaction) {
    13. av_log(NULL, AV_LOG_INFO, "Press [q] to stop, [?] for help\n");
    14. }
    15. timer_start = av_gettime_relative();
    16. #if HAVE_THREADS
    17. if ((ret = init_input_threads()) < 0)
    18. goto fail;
    19. #endif
    20. while (!received_sigterm) {
    21. int64_t cur_time= av_gettime_relative();
    22. /* if 'q' pressed, exits */
    23. if (stdin_interaction)
    24. if (check_keyboard_interaction(cur_time) < 0)
    25. break;
    26. /* check if there's any stream where output is still needed */
    27. if (!need_output()) {
    28. av_log(NULL, AV_LOG_VERBOSE, "No more output streams to write to, finishing.\n");
    29. break;
    30. }
    31. ret = transcode_step();
    32. if (ret < 0 && ret != AVERROR_EOF) {
    33. av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret));
    34. break;
    35. }
    36. /* dump report by using the output first video and audio streams */
    37. print_report(0, timer_start, cur_time);
    38. }
    39. #if HAVE_THREADS
    40. free_input_threads();
    41. #endif
    42. /* at the end of stream, we must flush the decoder buffers */
    43. for (i = 0; i < nb_input_streams; i++) {
    44. ist = input_streams[i];
    45. if (!input_files[ist->file_index]->eof_reached) {
    46. process_input_packet(ist, NULL, 0);
    47. }
    48. }
    49. flush_encoders();
    50. term_exit();
    51. /* write the trailer if needed and close file */
    52. for (i = 0; i < nb_output_files; i++) {
    53. os = output_files[i]->ctx;
    54. if (!output_files[i]->header_written) {
    55. av_log(NULL, AV_LOG_ERROR,
    56. "Nothing was written into output file %d (%s), because "
    57. "at least one of its streams received no packets.\n",
    58. i, os->url);
    59. continue;
    60. }
    61. if ((ret = av_write_trailer(os)) < 0) {
    62. av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", os->url, av_err2str(ret));
    63. if (exit_on_error)
    64. exit_program(1);
    65. }
    66. }
    67. /* dump report by using the first video and audio streams */
    68. print_report(1, timer_start, av_gettime_relative());
    69. /* close each encoder */
    70. for (i = 0; i < nb_output_streams; i++) {
    71. ost = output_streams[i];
    72. if (ost->encoding_needed) {
    73. av_freep(&ost->enc_ctx->stats_in);
    74. }
    75. total_packets_written += ost->packets_written;
    76. if (!ost->packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT_STREAM)) {
    77. av_log(NULL, AV_LOG_FATAL, "Empty output on stream %d.\n", i);
    78. exit_program(1);
    79. }
    80. }
    81. if (!total_packets_written && (abort_on_flags & ABORT_ON_FLAG_EMPTY_OUTPUT)) {
    82. av_log(NULL, AV_LOG_FATAL, "Empty output\n");
    83. exit_program(1);
    84. }
    85. /* close each decoder */
    86. for (i = 0; i < nb_input_streams; i++) {
    87. ist = input_streams[i];
    88. if (ist->decoding_needed) {
    89. avcodec_close(ist->dec_ctx);
    90. if (ist->hwaccel_uninit)
    91. ist->hwaccel_uninit(ist->dec_ctx);
    92. }
    93. }
    94. hw_device_free_all();
    95. /* finished ! */
    96. ret = 0;
    97. fail:
    98. #if HAVE_THREADS
    99. free_input_threads();
    100. #endif
    101. if (output_streams) {
    102. for (i = 0; i < nb_output_streams; i++) {
    103. ost = output_streams[i];
    104. if (ost) {
    105. if (ost->logfile) {
    106. if (fclose(ost->logfile))
    107. av_log(NULL, AV_LOG_ERROR,
    108. "Error closing logfile, loss of information possible: %s\n",
    109. av_err2str(AVERROR(errno)));
    110. ost->logfile = NULL;
    111. }
    112. av_freep(&ost->forced_kf_pts);
    113. av_freep(&ost->apad);
    114. av_freep(&ost->disposition);
    115. av_dict_free(&ost->encoder_opts);
    116. av_dict_free(&ost->sws_dict);
    117. av_dict_free(&ost->swr_opts);
    118. av_dict_free(&ost->resample_opts);
    119. }
    120. }
    121. }
    122. return ret;
    123. }

      2.1  transcode_step     // 转换流程。
                   process_input
                          process_input_packet

    1. /* pkt = NULL means EOF (needed to flush decoder buffers) */
    2. static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eof)
    3. {
    4. int ret = 0, i;
    5. int repeating = 0;
    6. int eof_reached = 0;
    7. AVPacket avpkt;
    8. if (!ist->saw_first_ts) {
    9. ist->dts = ist->st->avg_frame_rate.num ? - ist->dec_ctx->has_b_frames * AV_TIME_BASE / av_q2d(ist->st->avg_frame_rate) : 0;
    10. ist->pts = 0;
    11. if (pkt && pkt->pts != AV_NOPTS_VALUE && !ist->decoding_needed) {
    12. ist->dts += av_rescale_q(pkt->pts, ist->st->time_base, AV_TIME_BASE_Q);
    13. ist->pts = ist->dts; //unused but better to set it to a value thats not totally wrong
    14. }
    15. ist->saw_first_ts = 1;
    16. }
    17. if (ist->next_dts == AV_NOPTS_VALUE)
    18. ist->next_dts = ist->dts;
    19. if (ist->next_pts == AV_NOPTS_VALUE)
    20. ist->next_pts = ist->pts;
    21. if (!pkt) {
    22. /* EOF handling */
    23. av_init_packet(&avpkt);
    24. avpkt.data = NULL;
    25. avpkt.size = 0;
    26. } else {
    27. avpkt = *pkt;
    28. }
    29. if (pkt && pkt->dts != AV_NOPTS_VALUE) {
    30. ist->next_dts = ist->dts = av_rescale_q(pkt->dts, ist->st->time_base, AV_TIME_BASE_Q);
    31. if (ist->dec_ctx->codec_type != AVMEDIA_TYPE_VIDEO || !ist->decoding_needed)
    32. ist->next_pts = ist->pts = ist->dts;
    33. }
    34. // while we have more to decode or while the decoder did output something on EOF
    35. while (ist->decoding_needed) {
    36. int64_t duration_dts = 0;
    37. int64_t duration_pts = 0;
    38. int got_output = 0;
    39. int decode_failed = 0;
    40. ist->pts = ist->next_pts;
    41. ist->dts = ist->next_dts;
    42. switch (ist->dec_ctx->codec_type) {
    43. case AVMEDIA_TYPE_AUDIO:
    44. ret = decode_audio (ist, repeating ? NULL : &avpkt, &got_output,
    45. &decode_failed);
    46. break;
    47. case AVMEDIA_TYPE_VIDEO:
    48. ret = decode_video (ist, repeating ? NULL : &avpkt, &got_output, &duration_pts, !pkt,
    49. &decode_failed);
    50. if (!repeating || !pkt || got_output) {
    51. if (pkt && pkt->duration) {
    52. duration_dts = av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
    53. } else if(ist->dec_ctx->framerate.num != 0 && ist->dec_ctx->framerate.den != 0) {
    54. int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict+1 : ist->dec_ctx->ticks_per_frame;
    55. duration_dts = ((int64_t)AV_TIME_BASE *
    56. ist->dec_ctx->framerate.den * ticks) /
    57. ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
    58. }
    59. if(ist->dts != AV_NOPTS_VALUE && duration_dts) {
    60. ist->next_dts += duration_dts;
    61. }else
    62. ist->next_dts = AV_NOPTS_VALUE;
    63. }
    64. if (got_output) {
    65. if (duration_pts > 0) {
    66. ist->next_pts += av_rescale_q(duration_pts, ist->st->time_base, AV_TIME_BASE_Q);
    67. } else {
    68. ist->next_pts += duration_dts;
    69. }
    70. }
    71. break;
    72. case AVMEDIA_TYPE_SUBTITLE:
    73. if (repeating)
    74. break;
    75. ret = transcode_subtitles(ist, &avpkt, &got_output, &decode_failed);
    76. if (!pkt && ret >= 0)
    77. ret = AVERROR_EOF;
    78. break;
    79. default:
    80. return -1;
    81. }
    82. if (ret == AVERROR_EOF) {
    83. eof_reached = 1;
    84. break;
    85. }
    86. if (ret < 0) {
    87. if (decode_failed) {
    88. av_log(NULL, AV_LOG_ERROR, "Error while decoding stream #%d:%d: %s\n",
    89. ist->file_index, ist->st->index, av_err2str(ret));
    90. } else {
    91. av_log(NULL, AV_LOG_FATAL, "Error while processing the decoded "
    92. "data for stream #%d:%d\n", ist->file_index, ist->st->index);
    93. }
    94. if (!decode_failed || exit_on_error)
    95. exit_program(1);
    96. break;
    97. }
    98. if (got_output)
    99. ist->got_output = 1;
    100. if (!got_output)
    101. break;
    102. // During draining, we might get multiple output frames in this loop.
    103. // ffmpeg.c does not drain the filter chain on configuration changes,
    104. // which means if we send multiple frames at once to the filters, and
    105. // one of those frames changes configuration, the buffered frames will
    106. // be lost. This can upset certain FATE tests.
    107. // Decode only 1 frame per call on EOF to appease these FATE tests.
    108. // The ideal solution would be to rewrite decoding to use the new
    109. // decoding API in a better way.
    110. if (!pkt)
    111. break;
    112. repeating = 1;
    113. }
    114. /* after flushing, send an EOF on all the filter inputs attached to the stream */
    115. /* except when looping we need to flush but not to send an EOF */
    116. if (!pkt && ist->decoding_needed && eof_reached && !no_eof) {
    117. int ret = send_filter_eof(ist);
    118. if (ret < 0) {
    119. av_log(NULL, AV_LOG_FATAL, "Error marking filters as finished\n");
    120. exit_program(1);
    121. }
    122. }
    123. /* handle stream copy */
    124. if (!ist->decoding_needed && pkt) {
    125. ist->dts = ist->next_dts;
    126. switch (ist->dec_ctx->codec_type) {
    127. case AVMEDIA_TYPE_AUDIO:
    128. av_assert1(pkt->duration >= 0);
    129. if (ist->dec_ctx->sample_rate) {
    130. ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) /
    131. ist->dec_ctx->sample_rate;
    132. } else {
    133. ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
    134. }
    135. break;
    136. case AVMEDIA_TYPE_VIDEO:
    137. if (ist->framerate.num) {
    138. // TODO: Remove work-around for c99-to-c89 issue 7
    139. AVRational time_base_q = AV_TIME_BASE_Q;
    140. int64_t next_dts = av_rescale_q(ist->next_dts, time_base_q, av_inv_q(ist->framerate));
    141. ist->next_dts = av_rescale_q(next_dts + 1, av_inv_q(ist->framerate), time_base_q);
    142. } else if (pkt->duration) {
    143. ist->next_dts += av_rescale_q(pkt->duration, ist->st->time_base, AV_TIME_BASE_Q);
    144. } else if(ist->dec_ctx->framerate.num != 0) {
    145. int ticks= av_stream_get_parser(ist->st) ? av_stream_get_parser(ist->st)->repeat_pict + 1 : ist->dec_ctx->ticks_per_frame;
    146. ist->next_dts += ((int64_t)AV_TIME_BASE *
    147. ist->dec_ctx->framerate.den * ticks) /
    148. ist->dec_ctx->framerate.num / ist->dec_ctx->ticks_per_frame;
    149. }
    150. break;
    151. }
    152. ist->pts = ist->dts;
    153. ist->next_pts = ist->next_dts;
    154. }
    155. for (i = 0; i < nb_output_streams; i++) {
    156. OutputStream *ost = output_streams[i];
    157. if (!check_output_constraints(ist, ost) || ost->encoding_needed)
    158. continue;
    159. do_streamcopy(ist, ost, pkt); // packet 拷贝到输出文件
    160. }
    161. return !eof_reached;
    162. }

     3. do_streamcopy

    do_streamcopy
        output_packet
            write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
                av_interleaved_write_frame
                    write_packets_common
                        write_packet(AVFormatContext *s, AVPacket *pkt)
                            s->oformat->write_packet
                                 AVOutputFormat *oformat; mux  中函数:                

  • 相关阅读:
    学习笔记:SpringCloud 微服务技术栈_高级篇⑤_可靠消息服务
    mysql高阶sql语句
    仿京东放大镜效果(pink老师版)
    抖音聊天对话模板,制作一条一条冒出来的聊天对话短视频
    NVIDIA 7th SkyHackathon(七)Tao 目标检测模型可视化推理与导出
    ROS2-IRON Ubuntu-22.0 源码下载失败解决方法 vcs import --input
    Node 版本切换
    RHCE8 资料整理(七)
    高并发系统架构设计之实战篇:信息流设计之推模式
    系统移植 串口输入ECHO点灯
  • 原文地址:https://blog.csdn.net/u012794472/article/details/126748768