[FFmpeg-devel] [PATCH 27/57] avcodec/mpegpicture: Split ff_alloc_picture() into check and alloc part

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Tue Apr 30 00:14:08 EEST 2024


ff_alloc_picture() currently does two things: It checks the
consistency of the linesize (which should not be necessary, but is)
and it allocates certain buffers. (It does not actually allocate
the picture buffers, so its name is misleading.)
This commit splits it into two separate functions. The rationale
for this is that for the encoders, every picture needs its linesizes
checked, but not every picture needs these extra buffers.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>
---
 libavcodec/mpegpicture.c   | 70 ++++++++++++++------------------------
 libavcodec/mpegpicture.h   | 15 ++++++--
 libavcodec/mpegvideo_dec.c |  8 +++--
 libavcodec/mpegvideo_enc.c | 57 ++++++++++++++-----------------
 4 files changed, 69 insertions(+), 81 deletions(-)

diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c
index d0b529dc37..8a058c4a77 100644
--- a/libavcodec/mpegpicture.c
+++ b/libavcodec/mpegpicture.c
@@ -91,40 +91,27 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
     return 0;
 }
 
-/**
- * Check the pic's linesize and allocate linesize dependent scratch buffers
- */
-static int handle_pic_linesizes(AVCodecContext *avctx, Picture *pic,
-                                MotionEstContext *me, ScratchpadContext *sc,
-                                int linesize, int uvlinesize)
+int ff_mpv_pic_check_linesize(void *logctx, const AVFrame *f,
+                              ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep)
 {
-    int ret;
-
-    if ((linesize   &&   linesize != pic->f->linesize[0]) ||
-        (uvlinesize && uvlinesize != pic->f->linesize[1])) {
-        av_log(avctx, AV_LOG_ERROR, "Stride change unsupported: "
-               "linesize=%d/%d uvlinesize=%d/%d)\n",
-               linesize,   pic->f->linesize[0],
-               uvlinesize, pic->f->linesize[1]);
-        ff_mpeg_unref_picture(pic);
+    ptrdiff_t linesize = *linesizep, uvlinesize = *uvlinesizep;
+
+    if ((linesize   &&   linesize != f->linesize[0]) ||
+        (uvlinesize && uvlinesize != f->linesize[1])) {
+        av_log(logctx, AV_LOG_ERROR, "Stride change unsupported: "
+               "linesize=%"PTRDIFF_SPECIFIER"/%d uvlinesize=%"PTRDIFF_SPECIFIER"/%d)\n",
+               linesize,   f->linesize[0],
+               uvlinesize, f->linesize[1]);
         return AVERROR_PATCHWELCOME;
     }
 
-    if (av_pix_fmt_count_planes(pic->f->format) > 2 &&
-        pic->f->linesize[1] != pic->f->linesize[2]) {
-        av_log(avctx, AV_LOG_ERROR, "uv stride mismatch unsupported\n");
-        ff_mpeg_unref_picture(pic);
+    if (av_pix_fmt_count_planes(f->format) > 2 &&
+        f->linesize[1] != f->linesize[2]) {
+        av_log(logctx, AV_LOG_ERROR, "uv stride mismatch unsupported\n");
         return AVERROR_PATCHWELCOME;
     }
-
-    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);
-        return ret;
-    }
+    *linesizep   = f->linesize[0];
+    *uvlinesizep = f->linesize[1];
 
     return 0;
 }
@@ -155,28 +142,22 @@ static int alloc_picture_tables(BufferPoolContext *pools, Picture *pic,
     return 0;
 }
 
-/**
- * Allocate a Picture.
- * The pixels are allocated/set by calling get_buffer() if shared = 0
- */
-int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me,
-                     ScratchpadContext *sc, BufferPoolContext *pools,
-                     int mb_height, ptrdiff_t *linesize, ptrdiff_t *uvlinesize)
+int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, Picture *pic,
+                                 MotionEstContext *me, ScratchpadContext *sc,
+                                 BufferPoolContext *pools, int mb_height)
 {
     int ret;
 
-    if (handle_pic_linesizes(avctx, pic, me, sc,
-                             *linesize, *uvlinesize) < 0)
-        return -1;
-
-    *linesize   = pic->f->linesize[0];
-    *uvlinesize = pic->f->linesize[1];
-
     for (int i = 0; i < MPV_MAX_PLANES; i++) {
         pic->data[i]     = pic->f->data[i];
         pic->linesize[i] = pic->f->linesize[i];
     }
 
+    ret = ff_mpeg_framesize_alloc(avctx, me, sc,
+                                  pic->f->linesize[0]);
+    if (ret < 0)
+        goto fail;
+
     ret = alloc_picture_tables(pools, pic, mb_height);
     if (ret < 0)
         goto fail;
@@ -191,9 +172,8 @@ int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me,
 
     return 0;
 fail:
-    av_log(avctx, AV_LOG_ERROR, "Error allocating a picture.\n");
-    ff_mpeg_unref_picture(pic);
-    return AVERROR(ENOMEM);
+    av_log(avctx, AV_LOG_ERROR, "Error allocating picture accessories.\n");
+    return ret;
 }
 
 /**
diff --git a/libavcodec/mpegpicture.h b/libavcodec/mpegpicture.h
index 814f71213e..6589b38262 100644
--- a/libavcodec/mpegpicture.h
+++ b/libavcodec/mpegpicture.h
@@ -96,9 +96,18 @@ typedef struct Picture {
 /**
  * Allocate a Picture's accessories, but not the AVFrame's buffer itself.
  */
-int ff_alloc_picture(AVCodecContext *avctx, Picture *pic, MotionEstContext *me,
-                     ScratchpadContext *sc, BufferPoolContext *pools,
-                     int mb_height, ptrdiff_t *linesize, ptrdiff_t *uvlinesize);
+int ff_mpv_alloc_pic_accessories(AVCodecContext *avctx, Picture *pic,
+                                 MotionEstContext *me, ScratchpadContext *sc,
+                                 BufferPoolContext *pools, int mb_height);
+
+/**
+ * Check that the linesizes of an AVFrame are consistent with the requirements
+ * of mpegvideo.
+ * FIXME: There should be no need for this function. mpegvideo should be made
+ *        to work with changing linesizes.
+ */
+int ff_mpv_pic_check_linesize(void *logctx, const struct AVFrame *f,
+                              ptrdiff_t *linesizep, ptrdiff_t *uvlinesizep);
 
 int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me,
                             ScratchpadContext *sc, int linesize);
diff --git a/libavcodec/mpegvideo_dec.c b/libavcodec/mpegvideo_dec.c
index 570a422b6f..663d97e60f 100644
--- a/libavcodec/mpegvideo_dec.c
+++ b/libavcodec/mpegvideo_dec.c
@@ -259,6 +259,10 @@ static int alloc_picture(MpegEncContext *s, Picture **picp, int reference)
     if (ret < 0)
         goto fail;
 
+    ret = ff_mpv_pic_check_linesize(avctx, pic->f, &s->linesize, &s->uvlinesize);
+    if (ret < 0)
+        goto fail;
+
     ret = ff_hwaccel_frame_priv_alloc(avctx, &pic->hwaccel_picture_private);
     if (ret < 0)
         goto fail;
@@ -267,8 +271,8 @@ static int alloc_picture(MpegEncContext *s, Picture **picp, int reference)
     av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height ||
                FFALIGN(s->mb_height, 2) == s->buffer_pools.alloc_mb_height);
     av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride);
-    ret = ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, &s->buffer_pools,
-                           s->mb_height, &s->linesize, &s->uvlinesize);
+    ret = ff_mpv_alloc_pic_accessories(s->avctx, pic, &s->me, &s->sc,
+                                       &s->buffer_pools, s->mb_height);
     if (ret < 0)
         goto fail;
     *picp = pic;
diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c
index 15c6a90e9e..8e1ea36022 100644
--- a/libavcodec/mpegvideo_enc.c
+++ b/libavcodec/mpegvideo_enc.c
@@ -1103,6 +1103,10 @@ static int alloc_picture(MpegEncContext *s, Picture *pic)
     if (ret < 0)
         return ret;
 
+    ret = ff_mpv_pic_check_linesize(avctx, pic->f, &s->linesize, &s->uvlinesize);
+    if (ret < 0)
+        return ret;
+
     for (int i = 0; pic->f->data[i]; i++) {
         int offset = (EDGE_WIDTH >> (i ? s->chroma_y_shift : 0)) *
                      pic->f->linesize[i] +
@@ -1112,11 +1116,7 @@ static int alloc_picture(MpegEncContext *s, Picture *pic)
     pic->f->width  = avctx->width;
     pic->f->height = avctx->height;
 
-    av_assert1(s->mb_width  == s->buffer_pools.alloc_mb_width);
-    av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height);
-    av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride);
-    return ff_alloc_picture(s->avctx, pic, &s->me, &s->sc, &s->buffer_pools,
-                            s->mb_height, &s->linesize, &s->uvlinesize);
+    return 0;
 }
 
 static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
@@ -1188,7 +1188,7 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
         } else {
             ret = alloc_picture(s, pic);
             if (ret < 0)
-                return ret;
+                goto fail;
             ret = av_frame_copy_props(pic->f, pic_arg);
             if (ret < 0) {
                 ff_mpeg_unref_picture(pic);
@@ -1258,6 +1258,9 @@ static int load_input_picture(MpegEncContext *s, const AVFrame *pic_arg)
     s->input_picture[encoding_delay] = pic;
 
     return 0;
+fail:
+    ff_mpeg_unref_picture(pic);
+    return ret;
 }
 
 static int skip_check(MpegEncContext *s, const Picture *p, const Picture *ref)
@@ -1600,45 +1603,37 @@ no_output_pic:
            s->reordered_input_picture[0]->f->pict_type !=
                AV_PICTURE_TYPE_B ? 3 : 0;
 
-        if ((ret = av_frame_ref(s->new_pic,
-                                s->reordered_input_picture[0]->f)))
-            goto fail;
-
         if (s->reordered_input_picture[0]->shared || s->avctx->rc_buffer_size) {
             // input is a shared pix, so we can't modify it -> allocate a new
             // one & ensure that the shared one is reuseable
-
-            Picture *pic;
-            int i = ff_find_unused_picture(s->avctx, s->picture, 0);
-            if (i < 0)
-                return i;
-            pic = &s->picture[i];
-
-            pic->reference = s->reordered_input_picture[0]->reference;
-            ret = alloc_picture(s, pic);
+            av_frame_move_ref(s->new_pic, s->reordered_input_picture[0]->f);
+            ret = alloc_picture(s, s->reordered_input_picture[0]);
             if (ret < 0)
                 goto fail;
 
-            ret = av_frame_copy_props(pic->f, s->reordered_input_picture[0]->f);
-            if (ret < 0) {
-                ff_mpeg_unref_picture(pic);
+            ret = av_frame_copy_props(s->reordered_input_picture[0]->f, s->new_pic);
+            if (ret < 0)
                 goto fail;
-            }
-            pic->coded_picture_number = s->reordered_input_picture[0]->coded_picture_number;
-            pic->display_picture_number = s->reordered_input_picture[0]->display_picture_number;
-
-            /* mark us unused / free shared pic */
-            ff_mpeg_unref_picture(s->reordered_input_picture[0]);
-
-            s->cur_pic_ptr = pic;
         } else {
             // input is not a shared pix -> reuse buffer for current_pix
-            s->cur_pic_ptr = s->reordered_input_picture[0];
+            ret = av_frame_ref(s->new_pic, s->reordered_input_picture[0]->f);
+            if (ret < 0)
+                goto fail;
             for (int i = 0; i < MPV_MAX_PLANES; i++) {
                 if (s->new_pic->data[i])
                     s->new_pic->data[i] += INPLACE_OFFSET;
             }
         }
+        s->cur_pic_ptr = s->reordered_input_picture[0];
+        av_assert1(s->mb_width  == s->buffer_pools.alloc_mb_width);
+        av_assert1(s->mb_height == s->buffer_pools.alloc_mb_height);
+        av_assert1(s->mb_stride == s->buffer_pools.alloc_mb_stride);
+        ret = ff_mpv_alloc_pic_accessories(s->avctx, s->cur_pic_ptr, &s->me,
+                                           &s->sc, &s->buffer_pools, s->mb_height);
+        if (ret < 0) {
+            ff_mpeg_unref_picture(s->cur_pic_ptr);
+            return ret;
+        }
         s->picture_number = s->cur_pic_ptr->display_picture_number;
 
     }
-- 
2.40.1



More information about the ffmpeg-devel mailing list