Message ID | d356d5cb-d93d-ed90-5e70-55e272ebd1f5@jkqxz.net |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel] cbs_av1: Make fake OBU size length field a write option | expand |
Context | Check | Description |
---|---|---|
andriy/configure_x86 | warning | Failed to apply patch |
On Mon, 2023-09-25 at 14:53 +0100, Mark Thompson wrote: > This is an option to modify the behaviour of the writer, not a syntax > field. > --- > Tested by hacking av1_metadata. For example, adding: > > av_opt_set_int(ctx->common.output->priv_data, > "fixed_obu_size_length", 7, 0); > > gets you OBU headers that look like: > > [trace_headers @ 0x55706fcb2880] OBU header > [trace_headers @ 0x55706fcb2880] > 0 obu_forbidden_bit > 0 = 0 > [trace_headers @ 0x55706fcb2880] > 1 obu_type > 0100 = 4 > [trace_headers @ 0x55706fcb2880] > 5 obu_extension_flag > 0 = 0 > [trace_headers @ 0x55706fcb2880] > 6 obu_has_size_field > 1 = 1 > [trace_headers @ 0x55706fcb2880] > 7 obu_reserved_1bit > 0 = 0 > [trace_headers @ 0x55706fcb2880] > 8 obu_size 10101110100010101000000010000000100000001000000 > 000000000 = 1326 > > It's not obvious that there is any value in exposing this option more > generally, though? It could made a visible option of av1_metadata or > others if there is any use-case for it. > > Thanks, > > - Mark > > > libavcodec/cbs_av1.c | 31 +++++++++++++++++++++---------- > libavcodec/cbs_av1.h | 5 ++++- > libavcodec/vaapi_encode_av1.c | 4 +++- > 3 files changed, 28 insertions(+), 12 deletions(-) > > diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c > index 4e687ace79..ed9a7b80d4 100644 > --- a/libavcodec/cbs_av1.c > +++ b/libavcodec/cbs_av1.c > @@ -138,19 +138,25 @@ static int > cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, > return 0; > } > > -/** Minimum byte length will be used to indicate the len128 of value > if byte_len is 0. */ > static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, > PutBitContext *pbc, > - const char *name, uint64_t value, > uint8_t byte_len) > + const char *name, uint64_t value, > int fixed_length) > { > int len, i; > uint8_t byte; > > CBS_TRACE_WRITE_START(); > > - if (byte_len) > - av_assert0(byte_len >= (av_log2(value) + 7) / 7); > + len = (av_log2(value) + 7) / 7; > > - len = byte_len ? byte_len : (av_log2(value) + 7) / 7; > + if (fixed_length) { > + if (fixed_length < len) { > + av_log(ctx->log_ctx, AV_LOG_ERROR, "OBU is too large for > " > + "fixed length size field (%d > %d).\n", > + len, fixed_length); > + return AVERROR(EINVAL); > + } > + len = fixed_length; > + } > > for (i = 0; i < len; i++) { > if (put_bits_left(pbc) < 8) > @@ -1006,8 +1012,8 @@ static int > cbs_av1_write_obu(CodedBitstreamContext *ctx, > > if (obu->header.obu_has_size_field) { > pbc_tmp = *pbc; > - if (obu->obu_size_byte_len) { > - for (int i = 0; i < obu->obu_size_byte_len; i++) > + if (priv->fixed_obu_size_length) { > + for (int i = 0; i < priv->fixed_obu_size_length; i++) > put_bits(pbc, 8, 0); > } else { > // Add space for the size field to fill later. > @@ -1133,7 +1139,8 @@ static int > cbs_av1_write_obu(CodedBitstreamContext *ctx, > end_pos /= 8; > > *pbc = pbc_tmp; > - err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size, > obu->obu_size_byte_len); > + err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size, > + priv->fixed_obu_size_length); > if (err < 0) > goto error; > > @@ -1150,10 +1157,12 @@ static int > cbs_av1_write_obu(CodedBitstreamContext *ctx, > } > > if (obu->obu_size > 0) { > - if (!obu->obu_size_byte_len) { > - obu->obu_size_byte_len = start_pos - data_pos; > + if (!priv->fixed_obu_size_length) { > memmove(pbc->buf + data_pos, > pbc->buf + start_pos, header_size); > + } else { > + // The size was fixed so the following data was > + // already written in the correct place. > } > skip_put_bytes(pbc, header_size); > > @@ -1273,6 +1282,8 @@ static const CodedBitstreamUnitTypeDescriptor > cbs_av1_unit_types[] = { > static const AVOption cbs_av1_options[] = { > { "operating_point", "Set operating point to select layers to > parse from a scalable bitstream", > OFFSET(operating_point), AV_OPT_TYPE_INT, > { .i64 = -1 }, -1, AV1_MAX_OPERATING_POINTS - 1, 0 }, > + { "fixed_obu_size_length", "Set fixed length of the obu_size > field", > + OFFSET(fixed_obu_size_length), AV_OPT_TYPE_INT, { .i64 = 0 }, > 0, 8, 0 }, > { NULL } > }; > > diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h > index a9e2d2284f..7924257164 100644 > --- a/libavcodec/cbs_av1.h > +++ b/libavcodec/cbs_av1.h > @@ -401,7 +401,6 @@ typedef struct AV1RawOBU { > AV1RawOBUHeader header; > > size_t obu_size; > - uint8_t obu_size_byte_len; > > union { > AV1RawSequenceHeader sequence_header; > @@ -468,6 +467,10 @@ typedef struct CodedBitstreamAV1Context { > > // AVOptions > int operating_point; > + // When writing, fix the length in bytes of the obu_size field. > + // Writing will fail with an error if an OBU larger than can be > + // represented by the fixed size is encountered. > + int fixed_obu_size_length; > } CodedBitstreamAV1Context; > > > diff --git a/libavcodec/vaapi_encode_av1.c > b/libavcodec/vaapi_encode_av1.c > index 3ff1c47b53..861bf4a13b 100644 > --- a/libavcodec/vaapi_encode_av1.c > +++ b/libavcodec/vaapi_encode_av1.c > @@ -133,6 +133,9 @@ static av_cold int > vaapi_encode_av1_configure(AVCodecContext *avctx) > priv->cbc->trace_context = ctx; > priv->cbc->trace_write_callback = > vaapi_encode_av1_trace_write_log; > > + av_opt_set_int(priv->cbc->priv_data, "fixed_obu_size_length", > + priv->attr_ext2.bits.obu_size_bytes_minus1 + 1, > 0); > + This should be put after querying priv.attr_ext2 in vaapi_encode_av1_init(). Thanks Fei > if (ctx->rc_mode->quality) { > priv->q_idx_p = av_clip(ctx->rc_quality, 0, AV1_MAX_QUANT); > if (fabs(avctx->i_quant_factor) > 0.0) > @@ -634,7 +637,6 @@ static int > vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, > } > } > > - fh_obu->obu_size_byte_len = priv- > >attr_ext2.bits.obu_size_bytes_minus1 + 1; > ret = vaapi_encode_av1_add_obu(avctx, obu, > AV1_OBU_FRAME_HEADER, &priv->fh); > if (ret < 0) > goto end;
Mark Thompson: > This is an option to modify the behaviour of the writer, not a syntax > field. > --- > Tested by hacking av1_metadata. For example, adding: > > av_opt_set_int(ctx->common.output->priv_data, "fixed_obu_size_length", > 7, 0); > > gets you OBU headers that look like: > > [trace_headers @ 0x55706fcb2880] OBU header > [trace_headers @ 0x55706fcb2880] 0 > obu_forbidden_bit 0 = 0 > [trace_headers @ 0x55706fcb2880] 1 > obu_type 0100 = 4 > [trace_headers @ 0x55706fcb2880] 5 > obu_extension_flag 0 = 0 > [trace_headers @ 0x55706fcb2880] 6 > obu_has_size_field 1 = 1 > [trace_headers @ 0x55706fcb2880] 7 > obu_reserved_1bit 0 = 0 > [trace_headers @ 0x55706fcb2880] 8 obu_size > 10101110100010101000000010000000100000001000000000000000 = 1326 > > It's not obvious that there is any value in exposing this option more > generally, though? It could made a visible option of av1_metadata or > others if there is any use-case for it. > > Thanks, > > - Mark > > > libavcodec/cbs_av1.c | 31 +++++++++++++++++++++---------- > libavcodec/cbs_av1.h | 5 ++++- > libavcodec/vaapi_encode_av1.c | 4 +++- > 3 files changed, 28 insertions(+), 12 deletions(-) What is the advantage of this? Why would people want to waste space? - Andreas
On 26/09/2023 10:19, Andreas Rheinhardt wrote: > Mark Thompson: >> This is an option to modify the behaviour of the writer, not a syntax >> field. >> --- >> Tested by hacking av1_metadata. For example, adding: >> >> av_opt_set_int(ctx->common.output->priv_data, "fixed_obu_size_length", >> 7, 0); >> >> gets you OBU headers that look like: >> >> [trace_headers @ 0x55706fcb2880] OBU header >> [trace_headers @ 0x55706fcb2880] 0 >> obu_forbidden_bit 0 = 0 >> [trace_headers @ 0x55706fcb2880] 1 >> obu_type 0100 = 4 >> [trace_headers @ 0x55706fcb2880] 5 >> obu_extension_flag 0 = 0 >> [trace_headers @ 0x55706fcb2880] 6 >> obu_has_size_field 1 = 1 >> [trace_headers @ 0x55706fcb2880] 7 >> obu_reserved_1bit 0 = 0 >> [trace_headers @ 0x55706fcb2880] 8 obu_size >> 10101110100010101000000010000000100000001000000000000000 = 1326 >> >> It's not obvious that there is any value in exposing this option more >> generally, though? It could made a visible option of av1_metadata or >> others if there is any use-case for it. >> >> Thanks, >> >> - Mark >> >> >> libavcodec/cbs_av1.c | 31 +++++++++++++++++++++---------- >> libavcodec/cbs_av1.h | 5 ++++- >> libavcodec/vaapi_encode_av1.c | 4 +++- >> 3 files changed, 28 insertions(+), 12 deletions(-) > > What is the advantage of this? Why would people want to waste space? Because they want to be able to write a different size into the field later without realigning all the following bytes. VAAPI seems to require this, hence the previous code which added a fake syntax element field to the OBU structure containing the size to be written with, which this patch is replacing with an external option. Thanks, - Mark
diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c index 4e687ace79..ed9a7b80d4 100644 --- a/libavcodec/cbs_av1.c +++ b/libavcodec/cbs_av1.c @@ -138,19 +138,25 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, return 0; } -/** Minimum byte length will be used to indicate the len128 of value if byte_len is 0. */ static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc, - const char *name, uint64_t value, uint8_t byte_len) + const char *name, uint64_t value, int fixed_length) { int len, i; uint8_t byte; CBS_TRACE_WRITE_START(); - if (byte_len) - av_assert0(byte_len >= (av_log2(value) + 7) / 7); + len = (av_log2(value) + 7) / 7; - len = byte_len ? byte_len : (av_log2(value) + 7) / 7; + if (fixed_length) { + if (fixed_length < len) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "OBU is too large for " + "fixed length size field (%d > %d).\n", + len, fixed_length); + return AVERROR(EINVAL); + } + len = fixed_length; + } for (i = 0; i < len; i++) { if (put_bits_left(pbc) < 8) @@ -1006,8 +1012,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, if (obu->header.obu_has_size_field) { pbc_tmp = *pbc; - if (obu->obu_size_byte_len) { - for (int i = 0; i < obu->obu_size_byte_len; i++) + if (priv->fixed_obu_size_length) { + for (int i = 0; i < priv->fixed_obu_size_length; i++) put_bits(pbc, 8, 0); } else { // Add space for the size field to fill later. @@ -1133,7 +1139,8 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, end_pos /= 8; *pbc = pbc_tmp; - err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size, obu->obu_size_byte_len); + err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size, + priv->fixed_obu_size_length); if (err < 0) goto error; @@ -1150,10 +1157,12 @@ static int cbs_av1_write_obu(CodedBitstreamContext *ctx, } if (obu->obu_size > 0) { - if (!obu->obu_size_byte_len) { - obu->obu_size_byte_len = start_pos - data_pos; + if (!priv->fixed_obu_size_length) { memmove(pbc->buf + data_pos, pbc->buf + start_pos, header_size); + } else { + // The size was fixed so the following data was + // already written in the correct place. } skip_put_bytes(pbc, header_size); @@ -1273,6 +1282,8 @@ static const CodedBitstreamUnitTypeDescriptor cbs_av1_unit_types[] = { static const AVOption cbs_av1_options[] = { { "operating_point", "Set operating point to select layers to parse from a scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, AV1_MAX_OPERATING_POINTS - 1, 0 }, + { "fixed_obu_size_length", "Set fixed length of the obu_size field", + OFFSET(fixed_obu_size_length), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8, 0 }, { NULL } }; diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h index a9e2d2284f..7924257164 100644 --- a/libavcodec/cbs_av1.h +++ b/libavcodec/cbs_av1.h @@ -401,7 +401,6 @@ typedef struct AV1RawOBU { AV1RawOBUHeader header; size_t obu_size; - uint8_t obu_size_byte_len; union { AV1RawSequenceHeader sequence_header; @@ -468,6 +467,10 @@ typedef struct CodedBitstreamAV1Context { // AVOptions int operating_point; + // When writing, fix the length in bytes of the obu_size field. + // Writing will fail with an error if an OBU larger than can be + // represented by the fixed size is encountered. + int fixed_obu_size_length; } CodedBitstreamAV1Context; diff --git a/libavcodec/vaapi_encode_av1.c b/libavcodec/vaapi_encode_av1.c index 3ff1c47b53..861bf4a13b 100644 --- a/libavcodec/vaapi_encode_av1.c +++ b/libavcodec/vaapi_encode_av1.c @@ -133,6 +133,9 @@ static av_cold int vaapi_encode_av1_configure(AVCodecContext *avctx) priv->cbc->trace_context = ctx; priv->cbc->trace_write_callback = vaapi_encode_av1_trace_write_log; + av_opt_set_int(priv->cbc->priv_data, "fixed_obu_size_length", + priv->attr_ext2.bits.obu_size_bytes_minus1 + 1, 0); + if (ctx->rc_mode->quality) { priv->q_idx_p = av_clip(ctx->rc_quality, 0, AV1_MAX_QUANT); if (fabs(avctx->i_quant_factor) > 0.0) @@ -634,7 +637,6 @@ static int vaapi_encode_av1_init_picture_params(AVCodecContext *avctx, } } - fh_obu->obu_size_byte_len = priv->attr_ext2.bits.obu_size_bytes_minus1 + 1; ret = vaapi_encode_av1_add_obu(avctx, obu, AV1_OBU_FRAME_HEADER, &priv->fh); if (ret < 0) goto end;