diff mbox series

[FFmpeg-devel,v4,1/5] ffmpeg: add a data size threshold for muxing queue size

Message ID 20201027183056.17993-2-jeebjp@gmail.com
State Accepted
Headers show
Series ffmpeg: late A/V encoder init, AVFrame metadata usage
Related show

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished

Commit Message

Jan Ekström Oct. 27, 2020, 6:30 p.m. UTC
This way the old max queue size limit based behavior for streams
where each individual packet is large is kept, while for smaller
streams more packets can be buffered (current default is at 50
megabytes per stream).

For some explanation, by default ffmpeg copies packets from before
the appointed seek point/start time and puts them into the local
muxing queue. Before, it getting utilized was much less likely
since as soon as the filter chain was initialized, the encoder
(and thus output stream) was also initialized.

Now, since we will be pushing the encoder initialization to when the
first AVFrame is decoded and filtered - which only happens after
the exact seek point is hit as packets are ignored until then -
this queue will be seeing much more usage.

In more layman's terms, this attempts to fix cases such as where:
- seek point ends up being 5 seconds before requested time.
- audio is set to copy, and thus immediately begins filling the
  muxing queue.
- video is being encoded, and thus all received packets are skipped
  until the requested time is hit.
---
 doc/ffmpeg.texi      |  5 +++++
 fftools/ffmpeg.c     | 11 +++++++++--
 fftools/ffmpeg.h     | 11 +++++++++++
 fftools/ffmpeg_opt.c |  8 ++++++++
 4 files changed, 33 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi
index 96b3257e79..95d6463685 100644
--- a/doc/ffmpeg.texi
+++ b/doc/ffmpeg.texi
@@ -1746,6 +1746,11 @@  this buffer, in packets, for the matching output stream.
 The default value of this option should be high enough for most uses, so only
 touch this option if you are sure that you need it.
 
+@item -muxing_queue_data_threshold @var{bytes} (@emph{output,per-stream})
+This is a minimum threshold until which the muxing queue size is not taken into
+account. Defaults to 50 megabytes per stream, and is based on the overall size
+of packets passed to the muxer.
+
 @item -auto_conversion_filters (@emph{global})
 Enable automatically inserting format conversion filters in all filter
 graphs, including those defined by @option{-vf}, @option{-af},
diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
index cb7644de6a..3af189e7f2 100644
--- a/fftools/ffmpeg.c
+++ b/fftools/ffmpeg.c
@@ -725,8 +725,13 @@  static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int u
         AVPacket tmp_pkt = {0};
         /* the muxer is not initialized yet, buffer the packet */
         if (!av_fifo_space(ost->muxing_queue)) {
-            int new_size = FFMIN(2 * av_fifo_size(ost->muxing_queue),
-                                 ost->max_muxing_queue_size);
+            unsigned int are_we_over_size =
+                (ost->muxing_queue_data_size + pkt->size) > ost->muxing_queue_data_threshold;
+            int new_size = are_we_over_size ?
+                           FFMIN(2 * av_fifo_size(ost->muxing_queue),
+                                 ost->max_muxing_queue_size) :
+                           2 * av_fifo_size(ost->muxing_queue);
+
             if (new_size <= av_fifo_size(ost->muxing_queue)) {
                 av_log(NULL, AV_LOG_ERROR,
                        "Too many packets buffered for output stream %d:%d.\n",
@@ -741,6 +746,7 @@  static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int u
         if (ret < 0)
             exit_program(1);
         av_packet_move_ref(&tmp_pkt, pkt);
+        ost->muxing_queue_data_size += tmp_pkt.size;
         av_fifo_generic_write(ost->muxing_queue, &tmp_pkt, sizeof(tmp_pkt), NULL);
         return;
     }
@@ -2991,6 +2997,7 @@  static int check_init_output_file(OutputFile *of, int file_index)
         while (av_fifo_size(ost->muxing_queue)) {
             AVPacket pkt;
             av_fifo_generic_read(ost->muxing_queue, &pkt, sizeof(pkt), NULL);
+            ost->muxing_queue_data_size -= pkt.size;
             write_packet(of, &pkt, ost, 1);
         }
     }
diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
index 8665218dcf..3b54dab7fc 100644
--- a/fftools/ffmpeg.h
+++ b/fftools/ffmpeg.h
@@ -215,6 +215,8 @@  typedef struct OptionsContext {
     int        nb_passlogfiles;
     SpecifierOpt *max_muxing_queue_size;
     int        nb_max_muxing_queue_size;
+    SpecifierOpt *muxing_queue_data_threshold;
+    int        nb_muxing_queue_data_threshold;
     SpecifierOpt *guess_layout_max;
     int        nb_guess_layout_max;
     SpecifierOpt *apad;
@@ -547,6 +549,15 @@  typedef struct OutputStream {
     /* the packets are buffered here until the muxer is ready to be initialized */
     AVFifoBuffer *muxing_queue;
 
+    /*
+     * The size of the AVPackets' buffers in queue.
+     * Updated when a packet is either pushed or pulled from the queue.
+     */
+    size_t muxing_queue_data_size;
+
+    /* Threshold after which max_muxing_queue_size will be in effect */
+    size_t muxing_queue_data_threshold;
+
     /* packet picture type */
     int pict_type;
 
diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
index 19f719e3ff..39e0a31ea2 100644
--- a/fftools/ffmpeg_opt.c
+++ b/fftools/ffmpeg_opt.c
@@ -87,6 +87,7 @@  static const char *opt_name_canvas_sizes[]              = {"canvas_size", NULL};
 static const char *opt_name_pass[]                      = {"pass", NULL};
 static const char *opt_name_passlogfiles[]              = {"passlogfile", NULL};
 static const char *opt_name_max_muxing_queue_size[]     = {"max_muxing_queue_size", NULL};
+static const char *opt_name_muxing_queue_data_threshold[] = {"muxing_queue_data_threshold", NULL};
 static const char *opt_name_guess_layout_max[]          = {"guess_layout_max", NULL};
 static const char *opt_name_apad[]                      = {"apad", NULL};
 static const char *opt_name_discard[]                   = {"discard", NULL};
@@ -1564,6 +1565,11 @@  static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e
     MATCH_PER_STREAM_OPT(max_muxing_queue_size, i, ost->max_muxing_queue_size, oc, st);
     ost->max_muxing_queue_size *= sizeof(AVPacket);
 
+    ost->muxing_queue_data_size = 0;
+
+    ost->muxing_queue_data_threshold = 50*1024*1024;
+    MATCH_PER_STREAM_OPT(muxing_queue_data_threshold, i, ost->muxing_queue_data_threshold, oc, st);
+
     if (oc->oformat->flags & AVFMT_GLOBALHEADER)
         ost->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
 
@@ -3760,6 +3766,8 @@  const OptionDef options[] = {
 
     { "max_muxing_queue_size", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(max_muxing_queue_size) },
         "maximum number of packets that can be buffered while waiting for all streams to initialize", "packets" },
+    { "muxing_queue_data_threshold", HAS_ARG | OPT_INT | OPT_SPEC | OPT_EXPERT | OPT_OUTPUT, { .off = OFFSET(muxing_queue_data_threshold) },
+        "set the threshold after which max_muxing_queue_size is taken into account", "bytes" },
 
     /* data codec support */
     { "dcodec", HAS_ARG | OPT_DATA | OPT_PERFILE | OPT_EXPERT | OPT_INPUT | OPT_OUTPUT, { .func_arg = opt_data_codec },