diff mbox series

[FFmpeg-devel,2/2] fftools/ffmpeg.c: Add an option "multiple_output_final_stats"

Message ID 20200626212830.1734049-2-wangcao@google.com
State New
Headers show
Series [FFmpeg-devel,1/2] fftools/ffmpeg.c: Use the streams from the first output in print_final_stats.
Related show

Commit Message

Wang Cao June 26, 2020, 9:28 p.m. UTC
From: Wang Cao <doubleecao@gmail.com>

* "multiple_output_final_stats" is used to display stats for each output when ffmpeg completes processing.
* Also refactor to add a new function to print verbose stats for input/output so that the behavior is same as before by default.

Signed-off-by: Wang Cao <doubleecao@gmail.com>
---
 doc/ffmpeg.texi      |  6 +++++
 fftools/ffmpeg.c     | 53 +++++++++++++++++++++++++++++---------------
 fftools/ffmpeg.h     |  1 +
 fftools/ffmpeg_opt.c |  3 +++
 4 files changed, 45 insertions(+), 18 deletions(-)
diff mbox series

Patch

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 70b8965d7f..6c88c97c60 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -734,6 +734,12 @@  ffmpeg -dump_attachment:t "" -i INPUT
 Technical note -- attachments are implemented as codec extradata, so this
 option can actually be used to extract extradata from any stream, not just
 attachments.
+
+@item -multiple_output_final_stats (@emph{global})
+Print final stats for each output when processing completes.
+@example
+ffmpeg -i INPUT -multiple_output_final_stats out0.mkv out1.mkv
+@end example
 @end table
 
 @section Video Options
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index 07396204b6..1757899d7f 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -1514,8 +1514,9 @@  static int reap_filters(int flush)
     return 0;
 }
 
-static void print_final_stats(int64_t total_size)
+static void print_final_stats(int64_t total_size, int output_file_index)
 {
+    OutputFile *of;
     AVFormatContext *oc;
     uint64_t video_size = 0, audio_size = 0, extra_size = 0, other_size = 0;
     uint64_t subtitle_size = 0;
@@ -1524,10 +1525,11 @@  static void print_final_stats(int64_t total_size)
     int i, j;
     int pass1_used = 1;
 
-    oc = output_files[0]->ctx;
+    of = output_files[output_file_index];
+    oc = of->ctx;
 
     for (i = 0; i < oc->nb_streams; i++) {
-        OutputStream *ost = output_streams[i];
+        OutputStream *ost = output_streams[of->ost_index + i];
         switch (ost->enc_ctx->codec_type) {
             case AVMEDIA_TYPE_VIDEO: video_size += ost->data_size; break;
             case AVMEDIA_TYPE_AUDIO: audio_size += ost->data_size; break;
@@ -1555,6 +1557,18 @@  static void print_final_stats(int64_t total_size)
     else
         av_log(NULL, AV_LOG_INFO, "unknown");
     av_log(NULL, AV_LOG_INFO, "\n");
+    if (video_size + data_size + audio_size + subtitle_size + extra_size == 0){
+        av_log(NULL, AV_LOG_WARNING, "Output file is empty, nothing was encoded ");
+        if (pass1_used) {
+            av_log(NULL, AV_LOG_WARNING, "\n");
+        } else {
+            av_log(NULL, AV_LOG_WARNING, "(check -ss / -t / -frames parameters if used)\n");
+        }
+    }
+}
+
+static void print_verbose_input_output_stats() {
+    int i, j;
 
     /* print verbose per-stream stats */
     for (i = 0; i < nb_input_files; i++) {
@@ -1624,20 +1638,14 @@  static void print_final_stats(int64_t total_size)
         av_log(NULL, AV_LOG_VERBOSE, "  Total: %"PRIu64" packets (%"PRIu64" bytes) muxed\n",
                total_packets, total_size);
     }
-    if(video_size + data_size + audio_size + subtitle_size + extra_size == 0){
-        av_log(NULL, AV_LOG_WARNING, "Output file is empty, nothing was encoded ");
-        if (pass1_used) {
-            av_log(NULL, AV_LOG_WARNING, "\n");
-        } else {
-            av_log(NULL, AV_LOG_WARNING, "(check -ss / -t / -frames parameters if used)\n");
-        }
-    }
 }
 
-static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time)
+static void print_report(int is_last_report, int output_file_index,
+                         int64_t timer_start, int64_t cur_time)
 {
     AVBPrint buf, buf_script;
     OutputStream *ost;
+    OutputFile *of;
     AVFormatContext *oc;
     int64_t total_size;
     AVCodecContext *enc;
@@ -1668,7 +1676,8 @@  static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
     t = (cur_time-timer_start) / 1000000.0;
 
 
-    oc = output_files[0]->ctx;
+    of = output_files[output_file_index];
+    oc = of->ctx;
 
     total_size = avio_size(oc->pb);
     if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too
@@ -1679,7 +1688,7 @@  static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
     av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC);
     for (i = 0; i < oc->nb_streams; i++) {
         float q = -1;
-        ost = output_streams[i];
+        ost = output_streams[of->ost_index + i];
         enc = ost->enc_ctx;
         if (!ost->stream_copy)
             q = ost->quality / (float) FF_QP2LAMBDA;
@@ -1830,7 +1839,7 @@  static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
     }
 
     if (is_last_report)
-        print_final_stats(total_size);
+        print_final_stats(total_size, output_file_index);
 }
 
 static void ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par)
@@ -4672,7 +4681,7 @@  static int transcode(void)
         }
 
         /* dump report by using the output first video and audio streams */
-        print_report(0, timer_start, cur_time);
+        print_report(0, 0, timer_start, cur_time);
     }
 #if HAVE_THREADS
     free_input_threads();
@@ -4706,8 +4715,16 @@  static int transcode(void)
         }
     }
 
-    /* dump report by using the first video and audio streams */
-    print_report(1, timer_start, av_gettime_relative());
+    /* dump report for each output */
+    if (multiple_output_final_stats) {
+        for (i = 0; i < nb_output_files; i++) {
+            print_report(1, i, timer_start, av_gettime_relative());
+        }
+    } else {
+        /* dump report by using the first video and audio streams */
+        print_report(1, 0, timer_start, av_gettime_relative());
+    }
+    print_verbose_input_output_stats();
 
     /* close each encoder */
     for (i = 0; i < nb_output_streams; i++) {
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 6e3f2545c7..44414746e0 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -609,6 +609,7 @@  extern int frame_bits_per_raw_sample;
 extern AVIOContext *progress_avio;
 extern float max_error_rate;
 extern char *videotoolbox_pixfmt;
+extern int multiple_output_final_stats;
 
 extern int filter_nbthreads;
 extern int filter_complex_nbthreads;
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 9d1489ce01..2154a79aeb 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -172,6 +172,7 @@  float max_error_rate  = 2.0/3;
 int filter_nbthreads = 0;
 int filter_complex_nbthreads = 0;
 int vstats_version = 2;
+int multiple_output_final_stats = 0;
 
 
 static int intra_only         = 0;
@@ -3569,6 +3570,8 @@  const OptionDef options[] = {
         "set the maximum number of queued packets from the demuxer" },
     { "find_stream_info", OPT_BOOL | OPT_PERFILE | OPT_INPUT | OPT_EXPERT, { &find_stream_info },
         "read and decode the streams to fill missing information with heuristics" },
+    { "multiple_output_final_stats", OPT_BOOL | OPT_EXPERT, { &multiple_output_final_stats },
+        "display the encoding stats for first stream of each output." },
 
     /* video options */
     { "vframes",      OPT_VIDEO | HAS_ARG  | OPT_PERFILE | OPT_OUTPUT,           { .func_arg = opt_video_frames },