PR #23009 opened by Mark Thompson (jkqxz) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23009 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23009.patch
The tile_dummy_bytes element was present in the cbs_apv header but not actually read - this was missed earlier because the reference encoder never generates it. (It looks like it would be a feature present to make CBR easier? Not sure exactly why it exists.) The CBS support allows it to be passed through unchanged since the dummy bytes, unlike filler, are allowed to take any value. After this change, ffmpeg can decode the tile_D conformance test stream. Also added is a delete_filler option to apv_metadata to remove all redundant bytes in the stream. Applied to the tile_D test stream it makes the file 1% smaller with no change in decoded output. >From 17d6cfeb0f6eef7d240b1f13841d80eba969960b Mon Sep 17 00:00:00 2001 From: Mark Thompson <[email protected]> Date: Mon, 4 May 2026 12:29:00 +0100 Subject: [PATCH 1/2] cbs_apv: Support tile_dummy_bytes --- libavcodec/cbs_apv_syntax_template.c | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/libavcodec/cbs_apv_syntax_template.c b/libavcodec/cbs_apv_syntax_template.c index cd26a4556c..62379ea80c 100644 --- a/libavcodec/cbs_apv_syntax_template.c +++ b/libavcodec/cbs_apv_syntax_template.c @@ -226,11 +226,13 @@ static int FUNC(tile)(CodedBitstreamContext *ctx, RWContext *rw, int tile_idx, uint32_t tile_size) { const CodedBitstreamAPVContext *priv = ctx->priv_data; + uint32_t data_size, padding_size; int err; CHECK(FUNC(tile_header)(ctx, rw, ¤t->tile_header, tile_idx, tile_size)); + data_size = 0; for (int c = 0; c < priv->num_comp; c++) { uint32_t comp_size = current->tile_header.tile_data_size[c]; #ifdef READ @@ -244,6 +246,24 @@ static int FUNC(tile)(CodedBitstreamContext *ctx, RWContext *rw, if (put_bytes_left(rw, 0) < comp_size) return AVERROR(ENOSPC); ff_copy_bits(rw, current->tile_data[c], comp_size * 8); +#endif + data_size += comp_size; + } + + av_assert0(tile_size >= + current->tile_header.tile_header_size + data_size); + padding_size = tile_size - + (current->tile_header.tile_header_size + data_size); + + if (padding_size > 0) { +#ifdef READ + current->tile_dummy_byte = (uint8_t*)align_get_bits(rw); + current->tile_dummy_byte_size = padding_size; + skip_bits_long(rw, 8 * padding_size); +#else + if (put_bytes_left(rw, 0) < padding_size) + return AVERROR(ENOSPC); + ff_copy_bits(rw, current->tile_dummy_byte, 8 * padding_size); #endif } @@ -263,10 +283,19 @@ static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(frame_header)(ctx, rw, ¤t->frame_header)); for (int t = 0; t < priv->num_tiles; t++) { + APVRawTile *tile = ¤t->tile[t]; +#ifdef WRITE + // Calculate tile size from header, components and padding + // before writing it. + uint32_t size = tile->tile_header.tile_header_size; + for (int c = 0; c < priv->num_comp; c++) + size += tile->tile_header.tile_data_size[c]; + size += tile->tile_dummy_byte_size; + current->tile_size[t] = size; +#endif us(32, tile_size[t], 10, MAX_INT_BITS(32), 1, t); - CHECK(FUNC(tile)(ctx, rw, ¤t->tile[t], - t, current->tile_size[t])); + CHECK(FUNC(tile)(ctx, rw, tile, t, current->tile_size[t])); } CHECK(FUNC(filler)(ctx, rw, ¤t->filler)); -- 2.52.0 >From 747aebb1d0fcba1ab88b5e79eb1d56d3eeb3f0cc Mon Sep 17 00:00:00 2001 From: Mark Thompson <[email protected]> Date: Mon, 4 May 2026 12:30:08 +0100 Subject: [PATCH 2/2] apv_metadata: Add delete_filler option Deletes all filler bytes in the stream: - Filler PBUs. - Filler at end of frame PBUs. - Dummy bytes trailing in tile data. - Filler at end of AU info PBUs. - Filler at end of metadata PBUs. - Filler metadata payloads. --- libavcodec/bsf/apv_metadata.c | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/libavcodec/bsf/apv_metadata.c b/libavcodec/bsf/apv_metadata.c index a1cdcf86c8..10cc42b655 100644 --- a/libavcodec/bsf/apv_metadata.c +++ b/libavcodec/bsf/apv_metadata.c @@ -32,6 +32,8 @@ typedef struct APVMetadataContext { int transfer_characteristics; int matrix_coefficients; int full_range_flag; + + int delete_filler; } APVMetadataContext; @@ -62,6 +64,8 @@ static int apv_metadata_update_frame_header(AVBSFContext *bsf, static int apv_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, CodedBitstreamFragment *frag) { + APVMetadataContext *ctx = bsf->priv_data; + const CodedBitstreamAPVContext *priv = ctx->common.input->priv_data; int err, i; for (i = 0; i < frag->nb_units; i++) { @@ -73,6 +77,64 @@ static int apv_metadata_update_fragment(AVBSFContext *bsf, AVPacket *pkt, } } + if (ctx->delete_filler) { + // Types of filler to delete: + // - Filler PBUs. + // - Filler at end of frame PBUs. + // - Dummy bytes trailing in tile data. + // - Filler at end of AU info PBUs. + // - Filler at end of metadata PBUs. + // - Filler metadata payloads. + + for (i = frag->nb_units - 1; i >= 0; i--) { + switch (frag->units[i].type) { + case APV_PBU_FILLER: + ff_cbs_delete_unit(frag, i); + break; + case APV_PBU_PRIMARY_FRAME: + case APV_PBU_NON_PRIMARY_FRAME: + case APV_PBU_PREVIEW_FRAME: + case APV_PBU_DEPTH_FRAME: + case APV_PBU_ALPHA_FRAME: + { + APVRawFrame *frame = frag->units[i].content; + frame->filler.filler_size = 0; + for (int t = 0; t < priv->num_tiles; t++) + frame->tile[t].tile_dummy_byte_size = 0; + // tile_size[t] may be wrong here, but are + // recalculated during CBS write. + } + break; + case APV_PBU_ACCESS_UNIT_INFORMATION: + { + APVRawAUInfo *au_info = frag->units[i].content; + au_info->filler.filler_size = 0; + } + break; + case APV_PBU_METADATA: + { + APVRawMetadata *md = frag->units[i].content; + int k = 0; + md->filler.filler_size = 0; + for (int j = 0; j < md->metadata_count; j++) { + APVRawMetadataPayload *pl = &md->payloads[j]; + if (pl->payload_type == APV_METADATA_FILLER) { + // Drop this payload. + } else { + if (k < j) + md->payloads[k] = md->payloads[j]; + ++k; + } + } + md->metadata_count = k; + // metadata_size may be wrong here, but is + // recalculated during CBS write. + } + break; + } + } + } + return 0; } @@ -109,6 +171,9 @@ static const AVOption apv_metadata_options[] = { { "pc", "PC (full) range", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .flags = FLAGS, .unit = "cr" }, + { "delete_filler", "Delete all filler in the stream", + OFFSET(delete_filler), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + { NULL } }; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
