[FFmpeg-devel] [PATCH 2/4] avcodec/decode: allow the decoder to signal an unrecoverable error was found

James Almer jamrial at gmail.com
Tue Nov 22 15:07:30 EET 2022


Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavcodec/avcodec.c  |  1 +
 libavcodec/decode.c   | 17 ++++++++++++++++-
 libavcodec/internal.h |  5 +++++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/libavcodec/avcodec.c b/libavcodec/avcodec.c
index a85d3c2309..7818b6e33b 100644
--- a/libavcodec/avcodec.c
+++ b/libavcodec/avcodec.c
@@ -397,6 +397,7 @@ void avcodec_flush_buffers(AVCodecContext *avctx)
         av_bsf_flush(avci->bsf);
     }
 
+    avci->fatal         = 0;
     avci->draining      = 0;
     avci->draining_done = 0;
     avci->nb_draining_errors = 0;
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 6be2d3d6ed..04c9d374ce 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -576,7 +576,9 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
 
     av_assert0(!frame->buf[0]);
 
-    if (codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME) {
+    if (avci->fatal) {
+        ret = avci->draining ? AVERROR_EOF : AVERROR_UNRECOVERABLE;
+    } else if (codec->cb_type == FF_CODEC_CB_TYPE_RECEIVE_FRAME) {
         ret = codec->cb.receive_frame(avctx, frame);
         if (ret != AVERROR(EAGAIN))
             av_packet_unref(avci->last_pkt_props);
@@ -586,6 +588,9 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame)
     if (ret == AVERROR_EOF)
         avci->draining_done = 1;
 
+    if (ret == AVERROR_UNRECOVERABLE)
+        avci->fatal = 1;
+
     /* preserve ret */
     ok = detect_colorspace(avctx, frame);
     if (ok < 0) {
@@ -648,6 +653,16 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke
     if (avpkt && !avpkt->size && avpkt->data)
         return AVERROR(EINVAL);
 
+    if (avctx->internal->fatal) {
+        /* The API expects EOF signaling to always be handled even with
+         * decoding errors */
+        if (!avpkt || (!avpkt->data && !avpkt->side_data_elems)) {
+            avctx->internal->draining = 1;
+            return 0;
+        }
+        return AVERROR_UNRECOVERABLE;
+    }
+
     av_packet_unref(avci->buffer_pkt);
     if (avpkt && (avpkt->data || avpkt->side_data_elems)) {
         ret = av_packet_ref(avci->buffer_pkt, avpkt);
diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index 76a6ea6bc6..622f5728e2 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -142,6 +142,11 @@ typedef struct AVCodecInternal {
      */
     int draining;
 
+    /**
+     * An unrecoverable error was found, decoding can't proceed normally
+     */
+    int fatal;
+
     /**
      * Temporary buffers for newly received or not yet output packets/frames.
      */
-- 
2.38.1



More information about the ffmpeg-devel mailing list