[FFmpeg-devel] [PATCH v2 2/14] avcodec/mpegpicture: Store linesize in ScratchpadContext

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Mon Apr 29 18:09:56 EEST 2024


The mpegvideo-based codecs currently require the linesize to be
constant (except when the frame dimensions change); one reason
for this is that certain scratch buffers whose size depend on
linesize are only allocated once and are presumed to be correctly
sized if the pointers are != NULL.

This commit changes this by storing the actual linesize these
buffers belong to and reallocating the buffers if it does not
suffice. This is not enough to actually support changing linesizes,
but it is a start. And it is a prerequisite for the next patch.

Also don't emit an error message in case the source ctx's
edge_emu_buffer is unset in ff_mpeg_update_thread_context().
It need not be an error at all; e.g. it is a perfectly normal
state in case a hardware acceleration is used as the scratch
buffers are not allocated in this case (it is easy to run into
this issue with MPEG-4) or if the src context was not initialized
at all (e.g. because the first packet contained garbage).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>
---
Updated the commit message to include that this also removes
error spam for MPEG-4 frame-threading with hwaccel.

 libavcodec/mpegpicture.c   | 19 ++++++++++++++-----
 libavcodec/mpegpicture.h   |  1 +
 libavcodec/mpegvideo.c     | 19 +++++++------------
 libavcodec/mpegvideo_dec.c | 19 +++++++------------
 4 files changed, 29 insertions(+), 29 deletions(-)

diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c
index 06b6daa01a..aa882cf747 100644
--- a/libavcodec/mpegpicture.c
+++ b/libavcodec/mpegpicture.c
@@ -89,12 +89,16 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
                             ScratchpadContext *sc, int linesize)
 {
 #   define EMU_EDGE_HEIGHT (4 * 70)
-    int alloc_size = FFALIGN(FFABS(linesize) + 64, 32);
+    int linesizeabs = FFABS(linesize);
+    int alloc_size = FFALIGN(linesizeabs + 64, 32);
+
+    if (linesizeabs <= sc->linesize)
+        return 0;
 
     if (avctx->hwaccel)
         return 0;
 
-    if (linesize < 24) {
+    if (linesizeabs < 24) {
         av_log(avctx, AV_LOG_ERROR, "Image too small, temporary buffers cannot function\n");
         return AVERROR_PATCHWELCOME;
     }
@@ -102,6 +106,9 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
     if (av_image_check_size2(alloc_size, EMU_EDGE_HEIGHT, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx) < 0)
         return AVERROR(ENOMEM);
 
+    av_freep(&sc->edge_emu_buffer);
+    av_freep(&me->scratchpad);
+
     // edge emu needs blocksize + filter length - 1
     // (= 17x17 for  halfpel / 21x21 for H.264)
     // VC-1 computes luma and chroma simultaneously and needs 19X19 + 9x9
@@ -110,9 +117,11 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
     // we also use this buffer for encoding in encode_mb_internal() needig an additional 32 lines
     if (!FF_ALLOCZ_TYPED_ARRAY(sc->edge_emu_buffer, alloc_size * EMU_EDGE_HEIGHT) ||
         !FF_ALLOCZ_TYPED_ARRAY(me->scratchpad,      alloc_size * 4 * 16 * 2)) {
+        sc->linesize = 0;
         av_freep(&sc->edge_emu_buffer);
         return AVERROR(ENOMEM);
     }
+    sc->linesize = linesizeabs;
 
     me->temp            = me->scratchpad;
     sc->rd_scratchpad   = me->scratchpad;
@@ -149,9 +158,9 @@ static int handle_pic_linesizes(AVCodecContext *avctx, Picture *pic,
         return -1;
     }
 
-    if (!sc->edge_emu_buffer &&
-        (ret = ff_mpeg_framesize_alloc(avctx, me, sc,
-                                       pic->f->linesize[0])) < 0) {
+    ret = ff_mpeg_framesize_alloc(avctx, me, sc,
+                                  pic->f->linesize[0]);
+    if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR,
                "get_buffer() failed to allocate context scratch buffers.\n");
         ff_mpeg_unref_picture(pic);
diff --git a/libavcodec/mpegpicture.h b/libavcodec/mpegpicture.h
index a457586be5..215e7388ef 100644
--- a/libavcodec/mpegpicture.h
+++ b/libavcodec/mpegpicture.h
@@ -38,6 +38,7 @@ typedef struct ScratchpadContext {
     uint8_t *rd_scratchpad;       ///< scratchpad for rate distortion mb decision
     uint8_t *obmc_scratchpad;
     uint8_t *b_scratchpad;        ///< scratchpad used for writing into write only buffers
+    int      linesize;            ///< linesize that the buffers in this context have been allocated for
 } ScratchpadContext;
 
 /**
diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c
index 7af823b8bd..130ccb4c97 100644
--- a/libavcodec/mpegvideo.c
+++ b/libavcodec/mpegvideo.c
@@ -443,6 +443,7 @@ static void free_duplicate_context(MpegEncContext *s)
     s->sc.rd_scratchpad =
     s->sc.b_scratchpad =
     s->sc.obmc_scratchpad = NULL;
+    s->sc.linesize = 0;
 
     av_freep(&s->dct_error_sum);
     av_freep(&s->me.map);
@@ -464,12 +465,9 @@ static void free_duplicate_contexts(MpegEncContext *s)
 static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src)
 {
 #define COPY(a) bak->a = src->a
-    COPY(sc.edge_emu_buffer);
+    COPY(sc);
     COPY(me.scratchpad);
     COPY(me.temp);
-    COPY(sc.rd_scratchpad);
-    COPY(sc.b_scratchpad);
-    COPY(sc.obmc_scratchpad);
     COPY(me.map);
     COPY(me.score_map);
     COPY(blocks);
@@ -503,9 +501,9 @@ int ff_update_duplicate_context(MpegEncContext *dst, const MpegEncContext *src)
         // exchange uv
         FFSWAP(void *, dst->pblocks[4], dst->pblocks[5]);
     }
-    if (!dst->sc.edge_emu_buffer &&
-        (ret = ff_mpeg_framesize_alloc(dst->avctx, &dst->me,
-                                       &dst->sc, dst->linesize)) < 0) {
+    ret = ff_mpeg_framesize_alloc(dst->avctx, &dst->me,
+                                  &dst->sc, dst->linesize);
+    if (ret < 0) {
         av_log(dst->avctx, AV_LOG_ERROR, "failed to allocate context "
                "scratch buffers.\n");
         return ret;
@@ -646,12 +644,9 @@ static void clear_context(MpegEncContext *s)
     s->ac_val[0] =
     s->ac_val[1] =
     s->ac_val[2] =NULL;
-    s->sc.edge_emu_buffer = NULL;
     s->me.scratchpad = NULL;
-    s->me.temp =
-    s->sc.rd_scratchpad =
-    s->sc.b_scratchpad =
-    s->sc.obmc_scratchpad = NULL;
+    s->me.temp = NULL;
+    memset(&s->sc, 0, sizeof(s->sc));
 
 
     s->bitstream_buffer = NULL;
diff --git a/libavcodec/mpegvideo_dec.c b/libavcodec/mpegvideo_dec.c
index 4353f1fd68..31403d9acc 100644
--- a/libavcodec/mpegvideo_dec.c
+++ b/libavcodec/mpegvideo_dec.c
@@ -167,18 +167,13 @@ do {\
     }
 
     // linesize-dependent scratch buffer allocation
-    if (!s->sc.edge_emu_buffer)
-        if (s1->linesize) {
-            if (ff_mpeg_framesize_alloc(s->avctx, &s->me,
-                                        &s->sc, s1->linesize) < 0) {
-                av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate context "
-                       "scratch buffers.\n");
-                return AVERROR(ENOMEM);
-            }
-        } else {
-            av_log(s->avctx, AV_LOG_ERROR, "Context scratch buffers could not "
-                   "be allocated due to unknown size.\n");
-        }
+    ret = ff_mpeg_framesize_alloc(s->avctx, &s->me,
+                                  &s->sc, s1->linesize);
+    if (ret < 0) {
+        av_log(s->avctx, AV_LOG_ERROR, "Failed to allocate context "
+               "scratch buffers.\n");
+        return ret;
+    }
 
     // MPEG-2/interlacing info
     memcpy(&s->progressive_sequence, &s1->progressive_sequence,
-- 
2.40.1



More information about the ffmpeg-devel mailing list