This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit 5e56937b742b9110d38ce6fa4c7bdf2d5c355df4
Author:     Niklas Haas <[email protected]>
AuthorDate: Fri Dec 5 19:41:36 2025 +0100
Commit:     Niklas Haas <[email protected]>
CommitDate: Fri Dec 5 19:42:41 2025 +0100

    avcodec: allow bypassing frame threading with an optional flag
    
    Normally, this function tries to make sure all threads are saturated with
    work to do before returning any frames; and will continue requesting packets
    until that is the case.
    
    However, this significantly slows down initial decoding latency when only
    requesting a single frame (to e.g. configure the filter graph), and also
    wastes a lot of unnecessary memory in the event that the user does not 
intend
    to decode more frames until later.
    
    By introducing a new `flags` paramater and a new flag
    `AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS` to go along with it, we can allow
    users to temporarily bypass this logic.
---
 doc/APIchanges                |  4 ++++
 libavcodec/avcodec.c          | 10 ++++++++--
 libavcodec/avcodec.h          | 14 ++++++++++++++
 libavcodec/avcodec_internal.h |  8 +++++---
 libavcodec/decode.c           | 11 ++++++-----
 libavcodec/pthread_frame.c    |  7 ++++++-
 libavcodec/version.h          |  2 +-
 7 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 239137f1f2..f308fd40a2 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,6 +2,10 @@ The last version increases of all libraries were on 2025-03-28
 
 API changes, most recent first:
 
+2025-12-xx - xxxxxxxxxx - lavc 62.22.100 - avcodec.h
+  Add avcodec_receive_frame2().
+  Add AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS.
+
 2025-09-xx - xxxxxxxxxx - lavfi 11.10.100 - buffersrc.h
   Add av_buffersrc_get_status().
 
diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index dacdfba8da..8b4b305fcd 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -705,7 +705,8 @@ int avcodec_is_open(AVCodecContext *s)
     return !!s->internal;
 }
 
-int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame 
*frame)
+int attribute_align_arg avcodec_receive_frame2(AVCodecContext *avctx,
+                                               AVFrame *frame, unsigned flags)
 {
     av_frame_unref(frame);
 
@@ -713,10 +714,15 @@ int attribute_align_arg 
avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr
         return AVERROR(EINVAL);
 
     if (ff_codec_is_decoder(avctx->codec))
-        return ff_decode_receive_frame(avctx, frame);
+        return ff_decode_receive_frame(avctx, frame, flags);
     return ff_encode_receive_frame(avctx, frame);
 }
 
+int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+{
+    return avcodec_receive_frame2(avctx, frame, 0);
+}
+
 #define WRAP_CONFIG(allowed_type, field, var, field_type, sentinel_check)   \
     do {                                                                    \
         if (codec->type != (allowed_type))                                  \
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 91bd7cb7ef..92c0207cf6 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -415,6 +415,14 @@ typedef struct RcOverride{
  */
 #define AV_GET_ENCODE_BUFFER_FLAG_REF (1 << 0)
 
+/**
+ * The decoder will bypass frame threading and return the next frame as soon as
+ * possible. Note that this may deliver frames earlier than the advertised
+ * `AVCodecContext.delay`. No effect when frame threading is disabled, or on
+ * encoding.
+ */
+#define AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS (1 << 0)
+
 /**
  * main external API structure.
  * New fields can be added to the end with minor version bumps.
@@ -2360,6 +2368,7 @@ int avcodec_send_packet(AVCodecContext *avctx, const 
AVPacket *avpkt);
  *              frame (depending on the decoder type) allocated by the
  *              codec. Note that the function will always call
  *              av_frame_unref(frame) before doing anything else.
+ * @param flags Combination of AV_CODEC_RECEIVE_FRAME_FLAG_* flags.
  *
  * @retval 0                success, a frame was returned
  * @retval AVERROR(EAGAIN)  output is not available in this state - user must
@@ -2370,6 +2379,11 @@ int avcodec_send_packet(AVCodecContext *avctx, const 
AVPacket *avpkt);
  *                          @ref AV_CODEC_FLAG_RECON_FRAME flag enabled
  * @retval "other negative error code" legitimate decoding errors
  */
+int avcodec_receive_frame2(AVCodecContext *avctx, AVFrame *frame, unsigned 
flags);
+
+/**
+ * Alias for `avcodec_receive_frame2(avctx, frame, 0)`.
+ */
 int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
 
 /**
diff --git a/libavcodec/avcodec_internal.h b/libavcodec/avcodec_internal.h
index 184d7b526c..06645e91a0 100644
--- a/libavcodec/avcodec_internal.h
+++ b/libavcodec/avcodec_internal.h
@@ -45,7 +45,8 @@ extern const SideDataMap ff_sd_global_map[];
 /**
  * avcodec_receive_frame() implementation for decoders.
  */
-int ff_decode_receive_frame(struct AVCodecContext *avctx, struct AVFrame 
*frame);
+int ff_decode_receive_frame(struct AVCodecContext *avctx, struct AVFrame 
*frame,
+                            unsigned flags);
 
 /**
  * avcodec_receive_frame() implementation for encoders.
@@ -91,9 +92,10 @@ void ff_thread_flush(struct AVCodecContext *avctx);
  * Submit available packets for decoding to worker threads, return a
  * decoded frame if available. Returns AVERROR(EAGAIN) if none is available.
  *
- * Parameters are the same as FFCodec.receive_frame.
+ * Parameters are the same as FFCodec.receive_frame, plus flags.
  */
-int ff_thread_receive_frame(struct AVCodecContext *avctx, AVFrame *frame);
+int ff_thread_receive_frame(struct AVCodecContext *avctx, AVFrame *frame,
+                            unsigned flags);
 
 /**
  * Do the actual decoding and obtain a decoded frame from the decoder, if
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index f0646901c8..89a55c1cd8 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -645,14 +645,15 @@ int ff_decode_receive_frame_internal(AVCodecContext 
*avctx, AVFrame *frame)
     return ret;
 }
 
-static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
+static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame,
+                                         unsigned flags)
 {
     AVCodecInternal *avci = avctx->internal;
     DecodeContext     *dc = decode_ctx(avci);
     int ret, ok;
 
     if (avctx->active_thread_type & FF_THREAD_FRAME)
-        ret = ff_thread_receive_frame(avctx, frame);
+        ret = ff_thread_receive_frame(avctx, frame, flags);
     else
         ret = ff_decode_receive_frame_internal(avctx, frame);
 
@@ -730,7 +731,7 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext 
*avctx, const AVPacke
         dc->draining_started = 1;
 
     if (!avci->buffer_frame->buf[0] && !dc->draining_started) {
-        ret = decode_receive_frame_internal(avctx, avci->buffer_frame);
+        ret = decode_receive_frame_internal(avctx, avci->buffer_frame, 0);
         if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF)
             return ret;
     }
@@ -792,7 +793,7 @@ fail:
     return AVERROR_BUG;
 }
 
-int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame *frame, unsigned 
flags)
 {
     AVCodecInternal *avci = avctx->internal;
     int ret;
@@ -800,7 +801,7 @@ int ff_decode_receive_frame(AVCodecContext *avctx, AVFrame 
*frame)
     if (avci->buffer_frame->buf[0]) {
         av_frame_move_ref(frame, avci->buffer_frame);
     } else {
-        ret = decode_receive_frame_internal(avctx, frame);
+        ret = decode_receive_frame_internal(avctx, frame, flags);
         if (ret < 0)
             return ret;
     }
diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c
index ff015c00b3..2115d4204d 100644
--- a/libavcodec/pthread_frame.c
+++ b/libavcodec/pthread_frame.c
@@ -559,7 +559,7 @@ static int submit_packet(PerThreadContext *p, 
AVCodecContext *user_avctx,
     return 0;
 }
 
-int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame)
+int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame *frame, unsigned 
flags)
 {
     FrameThreadContext *fctx = avctx->internal->thread_ctx;
     int ret = 0;
@@ -572,6 +572,10 @@ int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame 
*frame)
     while (!fctx->df.nb_f && !fctx->result) {
         PerThreadContext *p;
 
+        if (fctx->next_decoding != fctx->next_finished &&
+            (flags & AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS))
+            goto wait_for_result;
+
         /* get a packet to be submitted to the next thread */
         av_packet_unref(fctx->next_pkt);
         ret = ff_decode_get_packet(avctx, fctx->next_pkt);
@@ -588,6 +592,7 @@ int ff_thread_receive_frame(AVCodecContext *avctx, AVFrame 
*frame)
             !avctx->internal->draining)
             continue;
 
+    wait_for_result:
         p                   = &fctx->threads[fctx->next_finished];
         fctx->next_finished = (fctx->next_finished + 1) % avctx->thread_count;
 
diff --git a/libavcodec/version.h b/libavcodec/version.h
index da6f3a84ac..9411511e04 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR  21
+#define LIBAVCODEC_VERSION_MINOR  22
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \

_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to