[FFmpeg-cvslog] avcodec/mpeg4videodec: Avoid copying packed bitstream data

Andreas Rheinhardt git at videolan.org
Tue Mar 4 14:35:41 EET 2025


ffmpeg | branch: master | Andreas Rheinhardt <andreas.rheinhardt at outlook.com> | Tue Feb 25 16:21:07 2025 +0100| [4f2becc2dc4668f837b5ba96c11c3426bc120ac0] | committer: Andreas Rheinhardt

avcodec/mpeg4videodec: Avoid copying packed bitstream data

This is possible because the packet is reference-counted
and because we never combine the data from several packets.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at outlook.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=4f2becc2dc4668f837b5ba96c11c3426bc120ac0
---

 libavcodec/h263dec.c       |  2 +-
 libavcodec/mpeg4videodec.c | 57 +++++++++++++++++-----------------------------
 libavcodec/mpeg4videodec.h |  7 +++---
 3 files changed, 25 insertions(+), 41 deletions(-)

diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c
index 84895a93d4..9ccdd914ce 100644
--- a/libavcodec/h263dec.c
+++ b/libavcodec/h263dec.c
@@ -626,7 +626,7 @@ frame_end:
     ff_mpv_frame_end(s);
 
     if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4)
-        ff_mpeg4_frame_end(avctx, buf, buf_size);
+        ff_mpeg4_frame_end(avctx, avpkt);
 
     av_assert1(s->pict_type == s->cur_pic.ptr->f->pict_type);
     if (s->pict_type == AV_PICTURE_TYPE_B || s->low_delay) {
diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c
index e2ae09125a..eace43b4cb 100644
--- a/libavcodec/mpeg4videodec.c
+++ b/libavcodec/mpeg4videodec.c
@@ -25,7 +25,6 @@
 #include "config_components.h"
 
 #include "libavutil/internal.h"
-#include "libavutil/mem.h"
 #include "libavutil/opt.h"
 #include "libavutil/thread.h"
 #include "codec_internal.h"
@@ -3626,9 +3625,9 @@ int ff_mpeg4_decode_picture_header(MpegEncContext *s)
 {
     Mpeg4DecContext *const ctx = (Mpeg4DecContext*)s;
 
-    if (ctx->bitstream_buffer_size) {
+    if (ctx->bitstream_buffer) {
         int buf_size = get_bits_left(&s->gb) / 8U;
-        int bitstream_buffer_size = ctx->bitstream_buffer_size;
+        int bitstream_buffer_size = ctx->bitstream_buffer->size;
         const uint8_t *buf = s->gb.buffer;
 
         if (s->divx_packed) {
@@ -3642,31 +3641,33 @@ int ff_mpeg4_decode_picture_header(MpegEncContext *s)
                 }
             }
         }
-        ctx->bitstream_buffer_size = 0;
+        ctx->bitstream_buffer->size = 0;
         if (bitstream_buffer_size && (s->divx_packed || buf_size <= MAX_NVOP_SIZE)) {// divx 5.01+/xvid frame reorder
-            int ret = init_get_bits8(&s->gb, ctx->bitstream_buffer,
+            int ret = init_get_bits8(&s->gb, ctx->bitstream_buffer->data,
                                      bitstream_buffer_size);
             if (ret < 0)
                 return ret;
-        }
+        } else
+            av_buffer_unref(&ctx->bitstream_buffer);
     }
 
     return ff_mpeg4_parse_picture_header(ctx, &s->gb, 0, 0);
 }
 
-int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
+int ff_mpeg4_frame_end(AVCodecContext *avctx, const AVPacket *pkt)
 {
     Mpeg4DecContext *ctx = avctx->priv_data;
     MpegEncContext    *s = &ctx->m;
+    int ret;
 
-    av_assert1(ctx->bitstream_buffer_size == 0);
+    av_assert1(!ctx->bitstream_buffer || !ctx->bitstream_buffer->size);
 
     /* divx 5.01+ bitstream reorder stuff */
-    /* Since this clobbers the input buffer and hwaccel codecs still need the
-     * data during hwaccel->end_frame we should not do this any earlier */
     if (s->divx_packed) {
-        int current_pos     = s->gb.buffer == ctx->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3);
+        int current_pos     = ctx->bitstream_buffer && s->gb.buffer == ctx->bitstream_buffer->data ? 0 : (get_bits_count(&s->gb) >> 3);
         int startcode_found = 0;
+        uint8_t *buf = pkt->data;
+        int buf_size = pkt->size;
 
         if (buf_size - current_pos > 7) {
 
@@ -3689,16 +3690,12 @@ int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size)
                        "Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it.\n");
                 ctx->showed_packed_warning = 1;
             }
-            av_fast_padded_malloc(&ctx->bitstream_buffer,
-                           &ctx->allocated_bitstream_buffer_size,
-                           buf_size - current_pos);
-            if (!ctx->bitstream_buffer) {
-                ctx->bitstream_buffer_size = 0;
-                return AVERROR(ENOMEM);
-            }
-            memcpy(ctx->bitstream_buffer, buf + current_pos,
-                   buf_size - current_pos);
-            ctx->bitstream_buffer_size = buf_size - current_pos;
+            ret = av_buffer_replace(&ctx->bitstream_buffer, pkt->buf);
+            if (ret < 0)
+                return ret;
+
+            ctx->bitstream_buffer->data = buf + current_pos;
+            ctx->bitstream_buffer->size = buf_size - current_pos;
         }
     }
 
@@ -3750,18 +3747,7 @@ static int mpeg4_update_thread_context(AVCodecContext *dst,
     memcpy(s->sprite_shift, s1->sprite_shift, sizeof(s1->sprite_shift));
     memcpy(s->sprite_traj,  s1->sprite_traj,  sizeof(s1->sprite_traj));
 
-    if (s1->bitstream_buffer) {
-        av_fast_padded_malloc(&s->bitstream_buffer,
-                              &s->allocated_bitstream_buffer_size,
-                              s1->bitstream_buffer_size);
-        if (!s->bitstream_buffer) {
-            s->bitstream_buffer_size = 0;
-            return AVERROR(ENOMEM);
-        }
-        s->bitstream_buffer_size = s1->bitstream_buffer_size;
-        memcpy(s->bitstream_buffer, s1->bitstream_buffer,
-               s1->bitstream_buffer_size);
-    }
+    ret = av_buffer_replace(&s->bitstream_buffer, s1->bitstream_buffer);
 
     if (!init && s1->xvid_build >= 0)
         ff_xvid_idct_init(&s->m.idsp, dst);
@@ -3870,7 +3856,7 @@ static av_cold void mpeg4_flush(AVCodecContext *avctx)
 {
     Mpeg4DecContext *const ctx = avctx->priv_data;
 
-    ctx->bitstream_buffer_size = 0;
+    av_buffer_unref(&ctx->bitstream_buffer);
     ff_mpeg_flush(avctx);
 }
 
@@ -3878,8 +3864,7 @@ static av_cold int mpeg4_close(AVCodecContext *avctx)
 {
     Mpeg4DecContext *const ctx = avctx->priv_data;
 
-    ctx->bitstream_buffer_size = 0;
-    av_freep(&ctx->bitstream_buffer);
+    av_buffer_unref(&ctx->bitstream_buffer);
 
     return ff_mpv_decode_close(avctx);
 }
diff --git a/libavcodec/mpeg4videodec.h b/libavcodec/mpeg4videodec.h
index c4f6897c73..bb14d24c88 100644
--- a/libavcodec/mpeg4videodec.h
+++ b/libavcodec/mpeg4videodec.h
@@ -70,9 +70,8 @@ typedef struct Mpeg4DecContext {
     int divx_build;
     int xvid_build;
     int lavc_build;
-    uint8_t *bitstream_buffer; //Divx 5.01 puts several frames in a single one, this is used to reorder them
-    int bitstream_buffer_size;
-    unsigned int allocated_bitstream_buffer_size;
+    /// Divx 5.01 puts several frames in a single one, this is used to reorder them
+    AVBufferRef *bitstream_buffer;
 
     int vo_type;
 
@@ -110,7 +109,7 @@ int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx);
 int ff_mpeg4_workaround_bugs(AVCodecContext *avctx);
 void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n,
                       int dir);
-int ff_mpeg4_frame_end(AVCodecContext *avctx, const uint8_t *buf, int buf_size);
+int ff_mpeg4_frame_end(AVCodecContext *avctx, const AVPacket *pkt);
 
 
 #endif



More information about the ffmpeg-cvslog mailing list