diff options
author | James Almer <jamrial@gmail.com> | 2025-08-10 13:44:31 -0300 |
---|---|---|
committer | James Almer <jamrial@gmail.com> | 2025-08-12 19:59:21 +0000 |
commit | 4b39d776c39f3a049932c8be0d46f48a4a3a0a7c (patch) | |
tree | dc4eb5ae84c6f89a51ceaca1e5edea31becf34e7 /libavcodec/apv_decode.c | |
parent | 0469d68acb52081ca8385b844b9650398242be0f (diff) | |
download | ffmpeg-4b39d776c39f3a049932c8be0d46f48a4a3a0a7c.tar.gz |
avcodec/cbs_apv: store derived tile information in a per frame basis
If a single fragment contains more than one frame unit, the tile information stored
in the private context will only correspond to one of them.
Fixes: crash (out of array access)
Fixes: 435489659/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_APV_fuzzer-6194885205229568
Found-by: continuous fuzzing process https://github.com/google/oss-fuzz/tree/master/projects/ffmpeg
Signed-off-by: James Almer <jamrial@gmail.com>
Diffstat (limited to 'libavcodec/apv_decode.c')
-rw-r--r-- | libavcodec/apv_decode.c | 49 |
1 files changed, 45 insertions, 4 deletions
diff --git a/libavcodec/apv_decode.c b/libavcodec/apv_decode.c index 330d4980c0..dd8a07e24f 100644 --- a/libavcodec/apv_decode.c +++ b/libavcodec/apv_decode.c @@ -35,6 +35,16 @@ #include "thread.h" +typedef struct APVDerivedTileInfo { + uint8_t tile_cols; + uint8_t tile_rows; + uint16_t num_tiles; + // The spec uses an extra element on the end of these arrays + // not corresponding to any tile. + uint16_t col_starts[APV_MAX_TILE_COLS + 1]; + uint16_t row_starts[APV_MAX_TILE_ROWS + 1]; +} APVDerivedTileInfo; + typedef struct APVDecodeContext { CodedBitstreamContext *cbc; APVDSPContext dsp; @@ -184,7 +194,7 @@ static int apv_decode_tile_component(AVCodecContext *avctx, void *data, APVRawFrame *input = data; APVDecodeContext *apv = avctx->priv_data; const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; - const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info; + const APVDerivedTileInfo *tile_info = &apv->tile_info; int tile_index = job / apv_cbc->num_comp; int comp_index = job % apv_cbc->num_comp; @@ -297,12 +307,38 @@ fail: return err; } +static void apv_derive_tile_info(APVDerivedTileInfo *ti, + const APVRawFrameHeader *fh) +{ + int frame_width_in_mbs = (fh->frame_info.frame_width + (APV_MB_WIDTH - 1)) >> 4; + int frame_height_in_mbs = (fh->frame_info.frame_height + (APV_MB_HEIGHT - 1)) >> 4; + int start_mb, i; + + start_mb = 0; + for (i = 0; start_mb < frame_width_in_mbs; i++) { + ti->col_starts[i] = start_mb * APV_MB_WIDTH; + start_mb += fh->tile_info.tile_width_in_mbs; + } + ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH; + ti->tile_cols = i; + + start_mb = 0; + for (i = 0; start_mb < frame_height_in_mbs; i++) { + ti->row_starts[i] = start_mb * APV_MB_HEIGHT; + start_mb += fh->tile_info.tile_height_in_mbs; + } + ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT; + ti->tile_rows = i; + + ti->num_tiles = ti->tile_cols * ti->tile_rows; +} + static int apv_decode(AVCodecContext *avctx, AVFrame *output, APVRawFrame *input) { APVDecodeContext *apv = avctx->priv_data; - const CodedBitstreamAPVContext *apv_cbc = apv->cbc->priv_data; - const APVDerivedTileInfo *tile_info = &apv_cbc->tile_info; + const AVPixFmtDescriptor *desc = NULL; + APVDerivedTileInfo *tile_info = &apv->tile_info; int err, job_count; err = apv_decode_check_format(avctx, &input->frame_header); @@ -311,6 +347,9 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output, return err; } + desc = av_pix_fmt_desc_get(avctx->pix_fmt); + av_assert0(desc); + err = ff_thread_get_buffer(avctx, output, 0); if (err < 0) return err; @@ -318,9 +357,11 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output, apv->output_frame = output; atomic_store_explicit(&apv->tile_errors, 0, memory_order_relaxed); + apv_derive_tile_info(tile_info, &input->frame_header); + // Each component within a tile is independent of every other, // so we can decode all in parallel. - job_count = tile_info->num_tiles * apv_cbc->num_comp; + job_count = tile_info->num_tiles * desc->nb_components; avctx->execute2(avctx, apv_decode_tile_component, input, NULL, job_count); |