From 82bc12ad189ca2e71732e387dd29598d70b16c83 Mon Sep 17 00:00:00 2001 From: Andreas Rheinhardt Date: Tue, 25 Feb 2025 00:48:08 +0100 Subject: [PATCH 25/30] avcodec/mpegvideo: Move bitstream_buffer to mpeg4videodec This is possible by moving the code using it to open a GetBitContext from h263dec.c to mpeg4videodec.c. Signed-off-by: Andreas Rheinhardt --- libavcodec/h263dec.c | 25 ++------- libavcodec/mpeg4video_parser.c | 4 +- libavcodec/mpeg4videodec.c | 95 ++++++++++++++++++++++++++-------- libavcodec/mpeg4videodec.h | 8 ++- libavcodec/mpegvideo.c | 5 -- libavcodec/mpegvideo.h | 3 -- libavcodec/mpegvideo_dec.c | 3 -- 7 files changed, 85 insertions(+), 58 deletions(-) diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index 2d8c200589..84895a93d4 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -446,26 +446,8 @@ int ff_h263_decode_frame(AVCodecContext *avctx, AVFrame *pict, } retry: - if (s->divx_packed && s->bitstream_buffer_size) { - int i; - for(i=0; i < buf_size-3; i++) { - if (buf[i]==0 && buf[i+1]==0 && buf[i+2]==1) { - if (buf[i+3]==0xB0) { - av_log(s->avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n"); - s->bitstream_buffer_size = 0; - } - break; - } - } - } - - if (s->bitstream_buffer_size && (s->divx_packed || buf_size <= MAX_NVOP_SIZE)) // divx 5.01+/xvid frame reorder - ret = init_get_bits8(&s->gb, s->bitstream_buffer, - s->bitstream_buffer_size); - else - ret = init_get_bits8(&s->gb, buf, buf_size); - - s->bitstream_buffer_size = 0; + // s->gb might be overridden in ff_mpeg4_decode_picture_header() below. + ret = init_get_bits8(&s->gb, buf, buf_size); if (ret < 0) return ret; @@ -480,7 +462,7 @@ retry: ret = ff_msmpeg4_decode_picture_header(s); #endif } else if (CONFIG_MPEG4_DECODER && avctx->codec_id == AV_CODEC_ID_MPEG4) { - ret = ff_mpeg4_decode_picture_header(avctx->priv_data, &s->gb, 0, 0); + ret = ff_mpeg4_decode_picture_header(s); s->skipped_last_frame = (ret == FRAME_SKIPPED); } else if (CONFIG_H263I_DECODER && s->codec_id == AV_CODEC_ID_H263I) { ret = ff_intel_h263_decode_picture_header(s); @@ -631,7 +613,6 @@ retry: ff_msmpeg4_decode_ext_header(s, buf_size) < 0) s->er.error_status_table[s->mb_num - 1] = ER_MB_ERROR; - av_assert1(s->bitstream_buffer_size == 0); frame_end: if (!s->studio_profile) ff_er_frame_end(&s->er, NULL); diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c index b00b523bde..ef9ea923f6 100644 --- a/libavcodec/mpeg4video_parser.c +++ b/libavcodec/mpeg4video_parser.c @@ -92,13 +92,13 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx, if (avctx->extradata_size && pc->first_picture) { init_get_bits(gb, avctx->extradata, avctx->extradata_size * 8); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 1, 1); + ret = ff_mpeg4_parse_picture_header(dec_ctx, gb, 1, 1); if (ret < 0) av_log(avctx, AV_LOG_WARNING, "Failed to parse extradata\n"); } init_get_bits(gb, buf, 8 * buf_size); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 0, 1); + ret = ff_mpeg4_parse_picture_header(dec_ctx, gb, 0, 1); if (s->width && (!avctx->width || !avctx->height || !avctx->coded_width || !avctx->coded_height)) { ret = ff_set_dimensions(avctx, s->width, s->height); diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index 14e4de9a45..e2ae09125a 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -25,6 +25,7 @@ #include "config_components.h" #include "libavutil/internal.h" +#include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/thread.h" #include "codec_internal.h" @@ -3463,8 +3464,8 @@ static int decode_studiovisualobject(Mpeg4DecContext *ctx, GetBitContext *gb) * FRAME_SKIPPED if a not coded VOP is found * 0 else */ -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, - int header, int parse_only) +int ff_mpeg4_parse_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, + int header, int parse_only) { MpegEncContext *s = &ctx->m; unsigned startcode, v; @@ -3621,16 +3622,50 @@ end: return decode_vop_header(ctx, gb, parse_only); } +int ff_mpeg4_decode_picture_header(MpegEncContext *s) +{ + Mpeg4DecContext *const ctx = (Mpeg4DecContext*)s; + + if (ctx->bitstream_buffer_size) { + int buf_size = get_bits_left(&s->gb) / 8U; + int bitstream_buffer_size = ctx->bitstream_buffer_size; + const uint8_t *buf = s->gb.buffer; + + if (s->divx_packed) { + for (int i = 0; i < buf_size - 3; i++) { + if (buf[i] == 0 && buf[i+1] == 0 && buf[i+2] == 1) { + if (buf[i+3] == 0xB0) { + av_log(s->avctx, AV_LOG_WARNING, "Discarding excessive bitstream in packed xvid\n"); + bitstream_buffer_size = 0; + } + break; + } + } + } + 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, + bitstream_buffer_size); + if (ret < 0) + return ret; + } + } + + 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) { Mpeg4DecContext *ctx = avctx->priv_data; MpegEncContext *s = &ctx->m; + av_assert1(ctx->bitstream_buffer_size == 0); + /* 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 == s->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3); + int current_pos = s->gb.buffer == ctx->bitstream_buffer ? 0 : (get_bits_count(&s->gb) >> 3); int startcode_found = 0; if (buf_size - current_pos > 7) { @@ -3654,16 +3689,16 @@ 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(&s->bitstream_buffer, - &s->allocated_bitstream_buffer_size, + av_fast_padded_malloc(&ctx->bitstream_buffer, + &ctx->allocated_bitstream_buffer_size, buf_size - current_pos); - if (!s->bitstream_buffer) { - s->bitstream_buffer_size = 0; + if (!ctx->bitstream_buffer) { + ctx->bitstream_buffer_size = 0; return AVERROR(ENOMEM); } - memcpy(s->bitstream_buffer, buf + current_pos, + memcpy(ctx->bitstream_buffer, buf + current_pos, buf_size - current_pos); - s->bitstream_buffer_size = buf_size - current_pos; + ctx->bitstream_buffer_size = buf_size - current_pos; } } @@ -3715,17 +3750,17 @@ 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->m.bitstream_buffer) { - av_fast_padded_malloc(&s->m.bitstream_buffer, - &s->m.allocated_bitstream_buffer_size, - s1->m.bitstream_buffer_size); - if (!s->m.bitstream_buffer) { - s->m.bitstream_buffer_size = 0; + 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->m.bitstream_buffer_size = s1->m.bitstream_buffer_size; - memcpy(s->m.bitstream_buffer, s1->m.bitstream_buffer, - s1->m.bitstream_buffer_size); + s->bitstream_buffer_size = s1->bitstream_buffer_size; + memcpy(s->bitstream_buffer, s1->bitstream_buffer, + s1->bitstream_buffer_size); } if (!init && s1->xvid_build >= 0) @@ -3825,12 +3860,30 @@ static av_cold int decode_init(AVCodecContext *avctx) GetBitContext gb; if (init_get_bits8(&gb, avctx->extradata, avctx->extradata_size) >= 0) - ff_mpeg4_decode_picture_header(ctx, &gb, 1, 0); + ff_mpeg4_parse_picture_header(ctx, &gb, 1, 0); } return 0; } +static av_cold void mpeg4_flush(AVCodecContext *avctx) +{ + Mpeg4DecContext *const ctx = avctx->priv_data; + + ctx->bitstream_buffer_size = 0; + ff_mpeg_flush(avctx); +} + +static av_cold int mpeg4_close(AVCodecContext *avctx) +{ + Mpeg4DecContext *const ctx = avctx->priv_data; + + ctx->bitstream_buffer_size = 0; + av_freep(&ctx->bitstream_buffer); + + return ff_mpv_decode_close(avctx); +} + #define OFFSET(x) offsetof(MpegEncContext, x) #define FLAGS AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY static const AVOption mpeg4_options[] = { @@ -3854,12 +3907,12 @@ const FFCodec ff_mpeg4_decoder = { .priv_data_size = sizeof(Mpeg4DecContext), .init = decode_init, FF_CODEC_DECODE_CB(ff_h263_decode_frame), - .close = ff_mpv_decode_close, + .close = mpeg4_close, .p.capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, - .flush = ff_mpeg_flush, + .flush = mpeg4_flush, .p.max_lowres = 3, .p.profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles), UPDATE_THREAD_CONTEXT(mpeg4_update_thread_context), diff --git a/libavcodec/mpeg4videodec.h b/libavcodec/mpeg4videodec.h index 734237b16f..c4f6897c73 100644 --- a/libavcodec/mpeg4videodec.h +++ b/libavcodec/mpeg4videodec.h @@ -70,6 +70,9 @@ 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; int vo_type; @@ -92,8 +95,9 @@ typedef struct Mpeg4DecContext { int16_t dpcm_macroblock[3][256]; } Mpeg4DecContext; -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, - int header, int parse_only); +int ff_mpeg4_decode_picture_header(MpegEncContext *s); +int ff_mpeg4_parse_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, + int header, int parse_only); void ff_mpeg4_decode_studio(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int block_size, int uvlinesize, int dct_linesize, int dct_offset); diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index 804c8095b2..73c513acbd 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -660,8 +660,6 @@ static void clear_context(MpegEncContext *s) memset(&s->sc, 0, sizeof(s->sc)); - s->bitstream_buffer = NULL; - s->allocated_bitstream_buffer_size = 0; s->p_field_mv_table_base = NULL; for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) @@ -777,9 +775,6 @@ void ff_mpv_common_end(MpegEncContext *s) if (s->slice_context_count > 1) s->slice_context_count = 1; - av_freep(&s->bitstream_buffer); - s->allocated_bitstream_buffer_size = 0; - ff_mpv_unref_picture(&s->last_pic); ff_mpv_unref_picture(&s->cur_pic); ff_mpv_unref_picture(&s->next_pic); diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index eb71198190..48fc1d418e 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -395,9 +395,6 @@ typedef struct MpegEncContext { /* divx specific, used to workaround (many) bugs in divx5 */ int divx_packed; - 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; /* RV10 specific */ int rv10_version; ///< RV10 version: 0 or 3 diff --git a/libavcodec/mpegvideo_dec.c b/libavcodec/mpegvideo_dec.c index 8d4ba341d5..532d8cf5c1 100644 --- a/libavcodec/mpegvideo_dec.c +++ b/libavcodec/mpegvideo_dec.c @@ -97,8 +97,6 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, s->context_reinit = 0; s->avctx = dst; s->private_ctx = private_ctx; - s->bitstream_buffer = NULL; - s->bitstream_buffer_size = s->allocated_bitstream_buffer_size = 0; if (s1->context_initialized) { if ((err = ff_mpv_common_init(s)) < 0) @@ -439,7 +437,6 @@ void ff_mpeg_flush(AVCodecContext *avctx) s->mb_x = s->mb_y = 0; - s->bitstream_buffer_size = 0; s->pp_time = 0; } -- 2.45.2