The branch, master has been updated via 3ef2ea890bcd4ea98469b01a77dbb5d9b3848942 (commit) via 084b67f6e3f1495732579ca7f9008cf98c3f38fe (commit) via 4b39d776c39f3a049932c8be0d46f48a4a3a0a7c (commit) from 0469d68acb52081ca8385b844b9650398242be0f (commit)
- Log ----------------------------------------------------------------- commit 3ef2ea890bcd4ea98469b01a77dbb5d9b3848942 Author: James Almer <jamr...@gmail.com> AuthorDate: Mon Aug 11 19:43:33 2025 -0300 Commit: James Almer <jamr...@gmail.com> CommitDate: Tue Aug 12 19:59:21 2025 +0000 avcodec/apv_decode: set decoder as skip frame fill param capable No need to decode potentially huge frames just to get stream params. Signed-off-by: James Almer <jamr...@gmail.com> diff --git a/libavcodec/apv_decode.c b/libavcodec/apv_decode.c index f477cd37f3..27aaf7aac7 100644 --- a/libavcodec/apv_decode.c +++ b/libavcodec/apv_decode.c @@ -361,6 +361,9 @@ static int apv_decode(AVCodecContext *avctx, AVFrame *output, return err; } + if (avctx->skip_frame == AVDISCARD_ALL) + return 0; + desc = av_pix_fmt_desc_get(avctx->pix_fmt); av_assert0(desc); @@ -564,4 +567,5 @@ const FFCodec ff_apv_decoder = { .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, }; commit 084b67f6e3f1495732579ca7f9008cf98c3f38fe Author: James Almer <jamr...@gmail.com> AuthorDate: Mon Aug 11 19:01:03 2025 -0300 Commit: James Almer <jamr...@gmail.com> CommitDate: Tue Aug 12 19:59:21 2025 +0000 avcodec/apv: port to the receive_frame() API You can technically feed the decoder a single packet with more than one AU in it, even if a demuxer is unlikely to ever export such a thing. Given the parser does no packetization to ensure we get a single AU, in order to not discard any frame beyond the first, the decoupled input/output API should be used. Signed-off-by: James Almer <jamr...@gmail.com> diff --git a/libavcodec/apv_decode.c b/libavcodec/apv_decode.c index dd8a07e24f..f477cd37f3 100644 --- a/libavcodec/apv_decode.c +++ b/libavcodec/apv_decode.c @@ -52,9 +52,12 @@ typedef struct APVDecodeContext { CodedBitstreamFragment au; APVDerivedTileInfo tile_info; + AVPacket *pkt; AVFrame *output_frame; atomic_int tile_errors; + int nb_unit; + uint8_t warned_additional_frames; uint8_t warned_unknown_pbu_types; } APVDecodeContext; @@ -145,6 +148,7 @@ static av_cold int apv_decode_init(AVCodecContext *avctx) // Extradata could be set here, but is ignored by the decoder. + apv->pkt = avctx->internal->in_pkt; ff_apv_dsp_init(&apv->dsp); atomic_init(&apv->tile_errors, 0); @@ -152,6 +156,16 @@ static av_cold int apv_decode_init(AVCodecContext *avctx) return 0; } +static void apv_decode_flush(AVCodecContext *avctx) +{ + APVDecodeContext *apv = avctx->priv_data; + + apv->nb_unit = 0; + av_packet_unref(apv->pkt); + ff_cbs_fragment_reset(&apv->au); + ff_cbs_flush(apv->cbc); +} + static av_cold int apv_decode_close(AVCodecContext *avctx) { APVDecodeContext *apv = avctx->priv_data; @@ -446,29 +460,20 @@ static int apv_decode_metadata(AVCodecContext *avctx, AVFrame *frame, return 0; } -static int apv_decode_frame(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *packet) +static int apv_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) { APVDecodeContext *apv = avctx->priv_data; CodedBitstreamFragment *au = &apv->au; - int err; + int i, err; - err = ff_cbs_read_packet(apv->cbc, au, packet); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to read packet.\n"); - goto fail; - } - - for (int i = 0; i < au->nb_units; i++) { + for (i = apv->nb_unit; i < au->nb_units; i++) { CodedBitstreamUnit *pbu = &au->units[i]; switch (pbu->type) { case APV_PBU_PRIMARY_FRAME: err = apv_decode(avctx, frame, pbu->content); - if (err < 0) - goto fail; - *got_frame = 1; - break; + i++; + goto end; case APV_PBU_METADATA: apv_decode_metadata(avctx, frame, pbu->content); break; @@ -500,9 +505,49 @@ static int apv_decode_frame(AVCodecContext *avctx, AVFrame *frame, } } - err = packet->size; -fail: - ff_cbs_fragment_reset(au); + err = AVERROR(EAGAIN); +end: + av_assert0(i <= apv->au.nb_units); + apv->nb_unit = i; + + if ((err < 0 && err != AVERROR(EAGAIN)) || apv->au.nb_units == i) { + av_packet_unref(apv->pkt); + ff_cbs_fragment_reset(&apv->au); + apv->nb_unit = 0; + } + if (!err && !frame->buf[0]) + err = AVERROR(EAGAIN); + + return err; +} + +static int apv_receive_frame(AVCodecContext *avctx, AVFrame *frame) +{ + APVDecodeContext *apv = avctx->priv_data; + int err; + + do { + if (!apv->au.nb_units) { + err = ff_decode_get_packet(avctx, apv->pkt); + if (err < 0) + return err; + + err = ff_cbs_read_packet(apv->cbc, &apv->au, apv->pkt); + if (err < 0) { + ff_cbs_fragment_reset(&apv->au); + av_packet_unref(apv->pkt); + av_log(avctx, AV_LOG_ERROR, "Failed to read packet.\n"); + return err; + } + + apv->nb_unit = 0; + av_log(avctx, AV_LOG_DEBUG, "Total PBUs on this packet: %d.\n", + apv->au.nb_units); + } + + err = apv_receive_frame_internal(avctx, frame); + } while (err == AVERROR(EAGAIN)); + return err; } @@ -513,8 +558,9 @@ const FFCodec ff_apv_decoder = { .p.id = AV_CODEC_ID_APV, .priv_data_size = sizeof(APVDecodeContext), .init = apv_decode_init, + .flush = apv_decode_flush, .close = apv_decode_close, - FF_CODEC_DECODE_CB(apv_decode_frame), + FF_CODEC_RECEIVE_FRAME_CB(apv_receive_frame), .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, commit 4b39d776c39f3a049932c8be0d46f48a4a3a0a7c Author: James Almer <jamr...@gmail.com> AuthorDate: Sun Aug 10 13:44:31 2025 -0300 Commit: James Almer <jamr...@gmail.com> CommitDate: Tue Aug 12 19:59:21 2025 +0000 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 <jamr...@gmail.com> 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); diff --git a/libavcodec/cbs_apv.c b/libavcodec/cbs_apv.c index 5239cd1269..fdc9042939 100644 --- a/libavcodec/cbs_apv.c +++ b/libavcodec/cbs_apv.c @@ -37,33 +37,18 @@ static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh) } } -static void cbs_apv_derive_tile_info(APVDerivedTileInfo *ti, +static void cbs_apv_derive_tile_info(CodedBitstreamContext *ctx, const APVRawFrameHeader *fh) { + CodedBitstreamAPVContext *priv = ctx->priv_data; int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16; int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16; - int start_mb, i; + int tile_cols = (frame_width_in_mbs + fh->tile_info.tile_width_in_mbs - 1) / fh->tile_info.tile_width_in_mbs; + int tile_rows = (frame_height_in_mbs + fh->tile_info.tile_height_in_mbs - 1) / fh->tile_info.tile_height_in_mbs; - 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; - } - av_assert0(i <= APV_MAX_TILE_COLS); - 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++) { - av_assert0(i < APV_MAX_TILE_ROWS); - ti->row_starts[i] = start_mb * APV_MB_HEIGHT; - start_mb += fh->tile_info.tile_height_in_mbs; - } - av_assert0(i <= APV_MAX_TILE_ROWS); - ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT; - ti->tile_rows = i; + av_assert0(tile_cols <= APV_MAX_TILE_COLS && tile_rows <= APV_MAX_TILE_ROWS); - ti->num_tiles = ti->tile_cols * ti->tile_rows; + priv->num_tiles = tile_cols * tile_rows; } diff --git a/libavcodec/cbs_apv.h b/libavcodec/cbs_apv.h index cbaeb45acb..d91372e644 100644 --- a/libavcodec/cbs_apv.h +++ b/libavcodec/cbs_apv.h @@ -187,21 +187,11 @@ typedef struct APVRawMetadata { } APVRawMetadata; -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 CodedBitstreamAPVContext { int bit_depth; int num_comp; - APVDerivedTileInfo tile_info; + uint16_t num_tiles; } CodedBitstreamAPVContext; #endif /* AVCODEC_CBS_APV_H */ diff --git a/libavcodec/cbs_apv_syntax_template.c b/libavcodec/cbs_apv_syntax_template.c index b84565b107..621595ffbf 100644 --- a/libavcodec/cbs_apv_syntax_template.c +++ b/libavcodec/cbs_apv_syntax_template.c @@ -128,10 +128,10 @@ static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, ub(1, tile_size_present_in_fh_flag); - cbs_apv_derive_tile_info(&priv->tile_info, fh); + cbs_apv_derive_tile_info(ctx, fh); if (current->tile_size_present_in_fh_flag) { - for (int t = 0; t < priv->tile_info.num_tiles; t++) { + for (int t = 0; t < priv->num_tiles; t++) { us(32, tile_size_in_fh[t], 10, MAX_UINT_BITS(32), 1, t); } } @@ -262,7 +262,7 @@ static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header)); - for (int t = 0; t < priv->tile_info.num_tiles; t++) { + for (int t = 0; t < priv->num_tiles; t++) { us(32, tile_size[t], 10, MAX_UINT_BITS(32), 1, t); CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], ----------------------------------------------------------------------- Summary of changes: libavcodec/apv_decode.c | 135 +++++++++++++++++++++++++++++------ libavcodec/cbs_apv.c | 27 ++----- libavcodec/cbs_apv.h | 12 +--- libavcodec/cbs_apv_syntax_template.c | 6 +- 4 files changed, 123 insertions(+), 57 deletions(-) hooks/post-receive -- _______________________________________________ ffmpeg-cvslog mailing list ffmpeg-cvslog@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-cvslog To unsubscribe, visit link above, or email ffmpeg-cvslog-requ...@ffmpeg.org with subject "unsubscribe".