diff mbox series

[FFmpeg-devel,v5,2/8] cbs: Make tracing more general

Message ID 20230911075232.797886-2-fei.w.wang@intel.com
State New
Headers show
Series [FFmpeg-devel,v5,1/8] avcodec/cbs_av1: Add tx mode enum values | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Wang, Fei W Sept. 11, 2023, 7:52 a.m. UTC
From: Mark Thompson <sw@jkqxz.net>

Turn tracing into callbacks for each syntax element, with default
callbacks to match current trace_headers behaviour for debug.  Move
the construction of bit strings into the trace callback, which
simplifies all of the read and write functions.

Signed-off-by: Fei Wang <fei.w.wang@intel.com>
---
 libavcodec/cbs.c               | 121 +++++++++----------
 libavcodec/cbs.h               |  88 +++++++++++++-
 libavcodec/cbs_av1.c           | 206 +++++++++------------------------
 libavcodec/cbs_bsf.c           |   5 +
 libavcodec/cbs_h2645.c         | 134 +++++++++------------
 libavcodec/cbs_internal.h      |  85 +++++++++++++-
 libavcodec/cbs_vp9.c           | 108 +++++------------
 libavcodec/trace_headers_bsf.c |   2 +
 8 files changed, 373 insertions(+), 376 deletions(-)

Comments

Neal Gompa Sept. 20, 2023, 12:41 a.m. UTC | #1
On Mon, Sep 11, 2023 at 3:53 AM <fei.w.wang-at-intel.com@ffmpeg.org> wrote:
>
> From: Mark Thompson <sw@jkqxz.net>
>
> Turn tracing into callbacks for each syntax element, with default
> callbacks to match current trace_headers behaviour for debug.  Move
> the construction of bit strings into the trace callback, which
> simplifies all of the read and write functions.
>
> Signed-off-by: Fei Wang <fei.w.wang@intel.com>
> ---
>  libavcodec/cbs.c               | 121 +++++++++----------
>  libavcodec/cbs.h               |  88 +++++++++++++-
>  libavcodec/cbs_av1.c           | 206 +++++++++------------------------
>  libavcodec/cbs_bsf.c           |   5 +
>  libavcodec/cbs_h2645.c         | 134 +++++++++------------
>  libavcodec/cbs_internal.h      |  85 +++++++++++++-
>  libavcodec/cbs_vp9.c           | 108 +++++------------
>  libavcodec/trace_headers_bsf.c |   2 +
>  8 files changed, 373 insertions(+), 376 deletions(-)
>
> diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
> index 3ec8285e21..daf7f66427 100644
> --- a/libavcodec/cbs.c
> +++ b/libavcodec/cbs.c
> @@ -117,8 +117,9 @@ av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr,
>
>      ctx->decompose_unit_types = NULL;
>
> -    ctx->trace_enable = 0;
> -    ctx->trace_level  = AV_LOG_TRACE;
> +    ctx->trace_enable  = 0;
> +    ctx->trace_level   = AV_LOG_TRACE;
> +    ctx->trace_context = ctx;
>
>      *ctx_ptr = ctx;
>      return 0;
> @@ -496,19 +497,27 @@ void ff_cbs_trace_header(CodedBitstreamContext *ctx,
>      av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
>  }
>
> -void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
> -                                 const char *str, const int *subscripts,
> -                                 const char *bits, int64_t value)
> +void ff_cbs_trace_read_log(void *trace_context,
> +                           GetBitContext *gbc, int length,
> +                           const char *str, const int *subscripts,
> +                           int64_t value)
>  {
> +    CodedBitstreamContext *ctx = trace_context;
>      char name[256];
> +    char bits[256];
>      size_t name_len, bits_len;
>      int pad, subs, i, j, k, n;
> -
> -    if (!ctx->trace_enable)
> -        return;
> +    int position;
>
>      av_assert0(value >= INT_MIN && value <= UINT32_MAX);
>
> +    position = get_bits_count(gbc);
> +
> +    av_assert0(length < 256);
> +    for (i = 0; i < length; i++)
> +        bits[i] = get_bits1(gbc) ? '1' : '0';
> +    bits[length] = 0;
> +
>      subs = subscripts ? subscripts[0] : 0;
>      n = 0;
>      for (i = j = 0; str[i];) {
> @@ -535,7 +544,7 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
>      av_assert0(n == subs);
>
>      name_len = strlen(name);
> -    bits_len = strlen(bits);
> +    bits_len = length;
>
>      if (name_len + bits_len > 60)
>          pad = bits_len + 2;
> @@ -546,6 +555,36 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
>             position, name, pad, bits, value);
>  }
>
> +void ff_cbs_trace_write_log(void *trace_context,
> +                            PutBitContext *pbc, int length,
> +                            const char *str, const int *subscripts,
> +                            int64_t value)
> +{
> +    CodedBitstreamContext *ctx = trace_context;
> +
> +    // Ensure that the syntax element is written to the output buffer,
> +    // make a GetBitContext pointed at the start position, then call the
> +    // read log function which can read the bits back to log them.
> +
> +    GetBitContext gbc;
> +    int position;
> +
> +    if (length > 0) {
> +        PutBitContext flush;
> +        flush = *pbc;
> +        flush_put_bits(&flush);
> +    }
> +
> +    position = put_bits_count(pbc);
> +    av_assert0(position >= length);
> +
> +    init_get_bits(&gbc, pbc->buf, position);
> +
> +    skip_bits_long(&gbc, position - length);
> +
> +    ff_cbs_trace_read_log(ctx, &gbc, length, str, subscripts, value);
> +}
> +
>  static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
>                                                GetBitContext *gbc,
>                                                int width, const char *name,
> @@ -555,7 +594,8 @@ static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
>                                                uint32_t range_max)
>  {
>      uint32_t value;
> -    int position;
> +
> +    CBS_TRACE_READ_START();
>
>      av_assert0(width > 0 && width <= 32);
>
> @@ -565,21 +605,9 @@ static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
>          return AVERROR_INVALIDDATA;
>      }
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> -
>      value = get_bits_long(gbc, width);
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < width; i++)
> -            bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
> -        bits[i] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
> -                                    bits, value);
> -    }
> +    CBS_TRACE_READ_END();
>
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -613,6 +641,8 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
>                            const int *subscripts, uint32_t value,
>                            uint32_t range_min, uint32_t range_max)
>  {
> +    CBS_TRACE_WRITE_START();
> +
>      av_assert0(width > 0 && width <= 32);
>
>      if (value < range_min || value > range_max) {
> @@ -625,22 +655,13 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
>      if (put_bits_left(pbc) < width)
>          return AVERROR(ENOSPC);
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < width; i++)
> -            bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
> -        bits[i] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, subscripts, bits, value);
> -    }
> -
>      if (width < 32)
>          put_bits(pbc, width, value);
>      else
>          put_bits32(pbc, value);
>
> +    CBS_TRACE_WRITE_END();
> +
>      return 0;
>  }
>
> @@ -657,7 +678,8 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                         int32_t range_min, int32_t range_max)
>  {
>      int32_t value;
> -    int position;
> +
> +    CBS_TRACE_READ_START();
>
>      av_assert0(width > 0 && width <= 32);
>
> @@ -667,21 +689,9 @@ int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
>          return AVERROR_INVALIDDATA;
>      }
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> -
>      value = get_sbits_long(gbc, width);
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < width; i++)
> -            bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
> -        bits[i] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
> -                                    bits, value);
> -    }
> +    CBS_TRACE_READ_END();
>
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -699,6 +709,8 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
>                          const int *subscripts, int32_t value,
>                          int32_t range_min, int32_t range_max)
>  {
> +    CBS_TRACE_WRITE_START();
> +
>      av_assert0(width > 0 && width <= 32);
>
>      if (value < range_min || value > range_max) {
> @@ -711,22 +723,13 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
>      if (put_bits_left(pbc) < width)
>          return AVERROR(ENOSPC);
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < width; i++)
> -            bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
> -        bits[i] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, subscripts, bits, value);
> -    }
> -
>      if (width < 32)
>          put_sbits(pbc, width, value);
>      else
>          put_bits32(pbc, value);
>
> +    CBS_TRACE_WRITE_END();
> +
>      return 0;
>  }
>
> diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h
> index b4131db5fe..ffb2797761 100644
> --- a/libavcodec/cbs.h
> +++ b/libavcodec/cbs.h
> @@ -168,6 +168,51 @@ typedef struct CodedBitstreamFragment {
>      CodedBitstreamUnit *units;
>  } CodedBitstreamFragment;
>
> +
> +struct CodedBitstreamContext;
> +struct GetBitContext;
> +struct PutBitContext;
> +
> +/**
> + * Callback type for read tracing.
> + *
> + * @param ctx         User-set trace context.
> + * @param gbc         A GetBitContext set at the start of the syntax
> + *                    element.  This is a copy, the callee does not
> + *                    need to preserve it.
> + * @param length      Length in bits of the syntax element.
> + * @param name        String name of the syntax elements.
> + * @param subscripts  If the syntax element is an array, a pointer to
> + *                    an array of subscripts into the array.
> + * @param value       Parsed value of the syntax element.
> + */
> +typedef void (*CBSTraceReadCallback)(void *trace_context,
> +                                     struct GetBitContext *gbc,
> +                                     int start_position,
> +                                     const char *name,
> +                                     const int *subscripts,
> +                                     int64_t value);
> +
> +/**
> + * Callback type for write tracing.
> + *
> + * @param ctx         User-set trace context.
> + * @param pbc         A PutBitContext set at the end of the syntax
> + *                    element.  The user must not modify this, but may
> + *                    inspect it to determine state.
> + * @param length      Length in bits of the syntax element.
> + * @param name        String name of the syntax elements.
> + * @param subscripts  If the syntax element is an array, a pointer to
> + *                    an array of subscripts into the array.
> + * @param value       Written value of the syntax element.
> + */
> +typedef void (*CBSTraceWriteCallback)(void *trace_context,
> +                                      struct PutBitContext *pbc,
> +                                      int start_position,
> +                                      const char *name,
> +                                      const int *subscripts,
> +                                      int64_t value);
> +
>  /**
>   * Context structure for coded bitstream operations.
>   */
> @@ -211,11 +256,29 @@ typedef struct CodedBitstreamContext {
>       */
>      int trace_enable;
>      /**
> -     * Log level to use for trace output.
> +     * Log level to use for default trace output.
>       *
>       * From AV_LOG_*; defaults to AV_LOG_TRACE.
>       */
>      int trace_level;
> +    /**
> +     * User context pointer to pass to trace callbacks.
> +     */
> +    void *trace_context;
> +    /**
> +     * Callback for read tracing.
> +     *
> +     * If tracing is enabled then this is called once for each syntax
> +     * element parsed.
> +     */
> +    CBSTraceReadCallback  trace_read_callback;
> +    /**
> +     * Callback for write tracing.
> +     *
> +     * If tracing is enabled then this is called once for each syntax
> +     * element written.
> +     */
> +    CBSTraceWriteCallback trace_write_callback;
>
>      /**
>       * Write buffer. Used as intermediate buffer when writing units.
> @@ -450,4 +513,27 @@ void ff_cbs_discard_units(CodedBitstreamContext *ctx,
>                            enum AVDiscard skip,
>                            int flags);
>
> +
> +/**
> + * Helper function for read tracing which formats the syntax element
> + * and logs the result.
> + *
> + * Trace context should be set to the CodedBitstreamContext.
> + */
> +void ff_cbs_trace_read_log(void *trace_context,
> +                           struct GetBitContext *gbc, int length,
> +                           const char *str, const int *subscripts,
> +                           int64_t value);
> +
> +/**
> + * Helper function for write tracing which formats the syntax element
> + * and logs the result.
> + *
> + * Trace context should be set to the CodedBitstreamContext.
> + */
> +void ff_cbs_trace_write_log(void *trace_context,
> +                            struct PutBitContext *pbc, int length,
> +                            const char *str, const int *subscripts,
> +                            int64_t value);
> +
>  #endif /* AVCODEC_CBS_H */
> diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
> index 7fb5bd8b42..6c478603f1 100644
> --- a/libavcodec/cbs_av1.c
> +++ b/libavcodec/cbs_av1.c
> @@ -31,10 +31,8 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                               uint32_t range_min, uint32_t range_max)
>  {
>      uint32_t zeroes, bits_value, value;
> -    int position;
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
>      zeroes = 0;
>      while (1) {
> @@ -50,6 +48,9 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
>      }
>
>      if (zeroes >= 32) {
> +        // Note that the spec allows an arbitrarily large number of
> +        // zero bits followed by a one bit in this case, but the
> +        // libaom implementation does not support it.
>          value = MAX_UINT_BITS(32);
>      } else {
>          if (get_bits_left(gbc) < zeroes) {
> @@ -62,36 +63,7 @@ static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
>          value = bits_value + (UINT32_C(1) << zeroes) - 1;
>      }
>
> -    if (ctx->trace_enable) {
> -        char bits[65];
> -        int i, j, k;
> -
> -        if (zeroes >= 32) {
> -            while (zeroes > 32) {
> -                k = FFMIN(zeroes - 32, 32);
> -                for (i = 0; i < k; i++)
> -                    bits[i] = '0';
> -                bits[i] = 0;
> -                ff_cbs_trace_syntax_element(ctx, position, name,
> -                                            NULL, bits, 0);
> -                zeroes -= k;
> -                position += k;
> -            }
> -        }
> -
> -        for (i = 0; i < zeroes; i++)
> -            bits[i] = '0';
> -        bits[i++] = '1';
> -
> -        if (zeroes < 32) {
> -            for (j = 0; j < zeroes; j++)
> -                bits[i++] = (bits_value >> (zeroes - j - 1) & 1) ? '1' : '0';
> -        }
> -
> -        bits[i] = 0;
> -        ff_cbs_trace_syntax_element(ctx, position, name,
> -                                    NULL, bits, value);
> -    }
> +    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
>
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -109,7 +81,9 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
>                                uint32_t range_min, uint32_t range_max)
>  {
>      uint32_t v;
> -    int position, zeroes;
> +    int zeroes;
> +
> +    CBS_TRACE_WRITE_START();
>
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -118,28 +92,17 @@ static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
>          return AVERROR_INVALIDDATA;
>      }
>
> -    if (ctx->trace_enable)
> -        position = put_bits_count(pbc);
> -
>      zeroes = av_log2(value + 1);
>      v = value - (1U << zeroes) + 1;
> +
> +    if (put_bits_left(pbc) < 2 * zeroes + 1)
> +        return AVERROR(ENOSPC);
> +
>      put_bits(pbc, zeroes, 0);
>      put_bits(pbc, 1, 1);
>      put_bits(pbc, zeroes, v);
>
> -    if (ctx->trace_enable) {
> -        char bits[65];
> -        int i, j;
> -        i = 0;
> -        for (j = 0; j < zeroes; j++)
> -            bits[i++] = '0';
> -        bits[i++] = '1';
> -        for (j = 0; j < zeroes; j++)
> -            bits[i++] = (v >> (zeroes - j - 1) & 1) ? '1' : '0';
> -        bits[i++] = 0;
> -        ff_cbs_trace_syntax_element(ctx, position, name, NULL,
> -                                    bits, value);
> -    }
> +    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
>
>      return 0;
>  }
> @@ -148,20 +111,19 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                                 const char *name, uint64_t *write_to)
>  {
>      uint64_t value;
> -    int position, err, i;
> +    uint32_t byte;
> +    int i;
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
>      value = 0;
>      for (i = 0; i < 8; i++) {
> -        int subscript[2] = { 1, i };
> -        uint32_t byte;
> -        err = ff_cbs_read_unsigned(ctx, gbc, 8, "leb128_byte[i]", subscript,
> -                                   &byte, 0x00, 0xff);
> -        if (err < 0)
> -            return err;
> -
> +        if (get_bits_left(gbc) < 8) {
> +            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid leb128 at "
> +                   "%s: bitstream ended.\n", name);
> +            return AVERROR_INVALIDDATA;
> +        }
> +        byte = get_bits(gbc, 8);
>          value |= (uint64_t)(byte & 0x7f) << (i * 7);
>          if (!(byte & 0x80))
>              break;
> @@ -170,8 +132,7 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
>      if (value > UINT32_MAX)
>          return AVERROR_INVALIDDATA;
>
> -    if (ctx->trace_enable)
> -        ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value);
> +    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
>
>      *write_to = value;
>      return 0;
> @@ -180,29 +141,25 @@ static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
>  static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc,
>                                  const char *name, uint64_t value)
>  {
> -    int position, err, len, i;
> +    int len, i;
>      uint8_t byte;
>
> -    len = (av_log2(value) + 7) / 7;
> +    CBS_TRACE_WRITE_START();
>
> -    if (ctx->trace_enable)
> -        position = put_bits_count(pbc);
> +    len = (av_log2(value) + 7) / 7;
>
>      for (i = 0; i < len; i++) {
> -        int subscript[2] = { 1, i };
> +        if (put_bits_left(pbc) < 8)
> +            return AVERROR(ENOSPC);
>
>          byte = value >> (7 * i) & 0x7f;
>          if (i < len - 1)
>              byte |= 0x80;
>
> -        err = ff_cbs_write_unsigned(ctx, pbc, 8, "leb128_byte[i]", subscript,
> -                                    byte, 0x00, 0xff);
> -        if (err < 0)
> -            return err;
> +        put_bits(pbc, 8, byte);
>      }
>
> -    if (ctx->trace_enable)
> -        ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value);
> +    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
>
>      return 0;
>  }
> @@ -212,12 +169,11 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                             const int *subscripts, uint32_t *write_to)
>  {
>      uint32_t m, v, extra_bit, value;
> -    int position, w;
> +    int w;
>
> -    av_assert0(n > 0);
> +    CBS_TRACE_READ_START();
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    av_assert0(n > 0);
>
>      w = av_log2(n) + 1;
>      m = (1 << w) - n;
> @@ -240,18 +196,7 @@ static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
>          value = (v << 1) - m + extra_bit;
>      }
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < w - 1; i++)
> -            bits[i] = (v >> i & 1) ? '1' : '0';
> -        if (v >= m)
> -            bits[i++] = extra_bit ? '1' : '0';
> -        bits[i] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, position,
> -                                    name, subscripts, bits, value);
> -    }
> +    CBS_TRACE_READ_END();
>
>      *write_to = value;
>      return 0;
> @@ -262,7 +207,8 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
>                              const int *subscripts, uint32_t value)
>  {
>      uint32_t w, m, v, extra_bit;
> -    int position;
> +
> +    CBS_TRACE_WRITE_START();
>
>      if (value > n) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -271,9 +217,6 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
>          return AVERROR_INVALIDDATA;
>      }
>
> -    if (ctx->trace_enable)
> -        position = put_bits_count(pbc);
> -
>      w = av_log2(n) + 1;
>      m = (1 << w) - n;
>
> @@ -290,18 +233,7 @@ static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
>          put_bits(pbc, 1, extra_bit);
>      }
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < w - 1; i++)
> -            bits[i] = (v >> i & 1) ? '1' : '0';
> -        if (value >= m)
> -            bits[i++] = extra_bit ? '1' : '0';
> -        bits[i] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, position,
> -                                    name, subscripts, bits, value);
> -    }
> +    CBS_TRACE_WRITE_END();
>
>      return 0;
>  }
> @@ -311,33 +243,24 @@ static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
>                                    const char *name, uint32_t *write_to)
>  {
>      uint32_t value;
> -    int position, i;
> -    char bits[33];
>
> -    av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1);
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
> -    for (i = 0, value = range_min; value < range_max;) {
> +    av_assert0(range_min <= range_max && range_max - range_min < 32);
> +
> +    for (value = range_min; value < range_max;) {
>          if (get_bits_left(gbc) < 1) {
>              av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at "
>                     "%s: bitstream ended.\n", name);
>              return AVERROR_INVALIDDATA;
>          }
> -        if (get_bits1(gbc)) {
> -            bits[i++] = '1';
> +        if (get_bits1(gbc))
>              ++value;
> -        } else {
> -            bits[i++] = '0';
> +        else
>              break;
> -        }
>      }
>
> -    if (ctx->trace_enable) {
> -        bits[i] = 0;
> -        ff_cbs_trace_syntax_element(ctx, position,
> -                                    name, NULL, bits, value);
> -    }
> +    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
>
>      *write_to = value;
>      return 0;
> @@ -349,6 +272,8 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
>  {
>      int len;
>
> +    CBS_TRACE_WRITE_START();
> +
>      av_assert0(range_min <= range_max && range_max - range_min < 32);
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -364,23 +289,11 @@ static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
>      if (put_bits_left(pbc) < len)
>          return AVERROR(ENOSPC);
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < len; i++) {
> -            if (range_min + i == value)
> -                bits[i] = '0';
> -            else
> -                bits[i] = '1';
> -        }
> -        bits[i] = 0;
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, NULL, bits, value);
> -    }
> -
>      if (len > 0)
>          put_bits(pbc, len, (1 << len) - 1 - (value != range_max));
>
> +    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
> +
>      return 0;
>  }
>
> @@ -388,12 +301,10 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                                 uint32_t range_max, const char *name,
>                                 const int *subscripts, uint32_t *write_to)
>  {
> -    uint32_t value;
> -    int position, err;
> -    uint32_t max_len, len, range_offset, range_bits;
> +    uint32_t value, max_len, len, range_offset, range_bits;
> +    int err;
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
>      av_assert0(range_max > 0);
>      max_len = av_log2(range_max - 1) - 3;
> @@ -425,9 +336,7 @@ static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
>      }
>      value += range_offset;
>
> -    if (ctx->trace_enable)
> -        ff_cbs_trace_syntax_element(ctx, position,
> -                                    name, subscripts, "", value);
> +    CBS_TRACE_READ_END_VALUE_ONLY();
>
>      *write_to = value;
>      return err;
> @@ -437,9 +346,11 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
>                                  uint32_t range_max, const char *name,
>                                  const int *subscripts, uint32_t value)
>  {
> -    int position, err;
> +    int err;
>      uint32_t max_len, len, range_offset, range_bits;
>
> +    CBS_TRACE_WRITE_START();
> +
>      if (value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
>                 "%"PRIu32", but must be in [0,%"PRIu32"].\n",
> @@ -447,9 +358,6 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
>          return AVERROR_INVALIDDATA;
>      }
>
> -    if (ctx->trace_enable)
> -        position = put_bits_count(pbc);
> -
>      av_assert0(range_max > 0);
>      max_len = av_log2(range_max - 1) - 3;
>
> @@ -489,9 +397,7 @@ static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
>              return err;
>      }
>
> -    if (ctx->trace_enable)
> -        ff_cbs_trace_syntax_element(ctx, position,
> -                                    name, subscripts, "", value);
> +    CBS_TRACE_WRITE_END_VALUE_ONLY();
>
>      return err;
>  }
> diff --git a/libavcodec/cbs_bsf.c b/libavcodec/cbs_bsf.c
> index 069f6e9918..b25285483b 100644
> --- a/libavcodec/cbs_bsf.c
> +++ b/libavcodec/cbs_bsf.c
> @@ -123,6 +123,11 @@ int ff_cbs_bsf_generic_init(AVBSFContext *bsf, const CBSBSFType *type)
>      if (err < 0)
>          return err;
>
> +    ctx->output->trace_enable = 1;
> +    ctx->output->trace_level  = AV_LOG_TRACE;
> +    ctx->output->trace_context = ctx->output;
> +    ctx->output->trace_write_callback = ff_cbs_trace_write_log;
> +
>      if (bsf->par_in->extradata) {
>          err = ff_cbs_read_extradata(ctx->input, frag, bsf->par_in);
>          if (err < 0) {
> diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
> index 318c997d94..0a1c8ea426 100644
> --- a/libavcodec/cbs_h2645.c
> +++ b/libavcodec/cbs_h2645.c
> @@ -36,41 +36,38 @@ static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                                uint32_t *write_to,
>                                uint32_t range_min, uint32_t range_max)
>  {
> -    uint32_t value;
> -    int position, i, j;
> -    unsigned int k;
> -    char bits[65];
> +    uint32_t leading_bits, value;
> +    int max_length, leading_zeroes;
>
> -    position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
> -    for (i = 0; i < 32; i++) {
> -        if (get_bits_left(gbc) < i + 1) {
> +    max_length = FFMIN(get_bits_left(gbc), 32);
> +
> +    leading_bits = show_bits_long(gbc, max_length);
> +    if (leading_bits == 0) {
> +        if (max_length >= 32) {
> +            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
> +                   "%s: more than 31 zeroes.\n", name);
> +            return AVERROR_INVALIDDATA;
> +        } else {
>              av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
>                     "%s: bitstream ended.\n", name);
>              return AVERROR_INVALIDDATA;
>          }
> -        k = get_bits1(gbc);
> -        bits[i] = k ? '1' : '0';
> -        if (k)
> -            break;
>      }
> -    if (i >= 32) {
> +
> +    leading_zeroes = max_length - 1 - av_log2(leading_bits);
> +    skip_bits_long(gbc, leading_zeroes);
> +
> +    if (get_bits_left(gbc) < leading_zeroes + 1) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
> -               "%s: more than 31 zeroes.\n", name);
> +               "%s: bitstream ended.\n", name);
>          return AVERROR_INVALIDDATA;
>      }
> -    value = 1;
> -    for (j = 0; j < i; j++) {
> -        k = get_bits1(gbc);
> -        bits[i + j + 1] = k ? '1' : '0';
> -        value = value << 1 | k;
> -    }
> -    bits[i + j + 1] = 0;
> -    --value;
>
> -    if (ctx->trace_enable)
> -        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
> -                                    bits, value);
> +    value = get_bits_long(gbc, leading_zeroes + 1) - 1;
> +
> +    CBS_TRACE_READ_END();
>
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -88,45 +85,44 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                                int32_t *write_to,
>                                int32_t range_min, int32_t range_max)
>  {
> +    uint32_t leading_bits, unsigned_value;
> +    int max_length, leading_zeroes;
>      int32_t value;
> -    int position, i, j;
> -    unsigned int k;
> -    uint32_t v;
> -    char bits[65];
>
> -    position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
> -    for (i = 0; i < 32; i++) {
> -        if (get_bits_left(gbc) < i + 1) {
> +    max_length = FFMIN(get_bits_left(gbc), 32);
> +
> +    leading_bits = show_bits_long(gbc, max_length);
> +    if (leading_bits == 0) {
> +        if (max_length >= 32) {
> +            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
> +                   "%s: more than 31 zeroes.\n", name);
> +            return AVERROR_INVALIDDATA;
> +        } else {
>              av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
>                     "%s: bitstream ended.\n", name);
>              return AVERROR_INVALIDDATA;
>          }
> -        k = get_bits1(gbc);
> -        bits[i] = k ? '1' : '0';
> -        if (k)
> -            break;
>      }
> -    if (i >= 32) {
> +
> +    leading_zeroes = max_length - 1 - av_log2(leading_bits);
> +    skip_bits_long(gbc, leading_zeroes);
> +
> +    if (get_bits_left(gbc) < leading_zeroes + 1) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
> -               "%s: more than 31 zeroes.\n", name);
> +               "%s: bitstream ended.\n", name);
>          return AVERROR_INVALIDDATA;
>      }
> -    v = 1;
> -    for (j = 0; j < i; j++) {
> -        k = get_bits1(gbc);
> -        bits[i + j + 1] = k ? '1' : '0';
> -        v = v << 1 | k;
> -    }
> -    bits[i + j + 1] = 0;
> -    if (v & 1)
> -        value = -(int32_t)(v / 2);
> +
> +    unsigned_value = get_bits_long(gbc, leading_zeroes + 1);
> +
> +    if (unsigned_value & 1)
> +        value = -(int32_t)(unsigned_value / 2);
>      else
> -        value = v / 2;
> +        value = unsigned_value / 2;
>
> -    if (ctx->trace_enable)
> -        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
> -                                    bits, value);
> +    CBS_TRACE_READ_END();
>
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -146,6 +142,8 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
>  {
>      int len;
>
> +    CBS_TRACE_WRITE_START();
> +
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
>                 "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n",
> @@ -158,27 +156,14 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
>      if (put_bits_left(pbc) < 2 * len + 1)
>          return AVERROR(ENOSPC);
>
> -    if (ctx->trace_enable) {
> -        char bits[65];
> -        int i;
> -
> -        for (i = 0; i < len; i++)
> -            bits[i] = '0';
> -        bits[len] = '1';
> -        for (i = 0; i < len; i++)
> -            bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0';
> -        bits[len + len + 1] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, subscripts, bits, value);
> -    }
> -
>      put_bits(pbc, len, 0);
>      if (len + 1 < 32)
>          put_bits(pbc, len + 1, value + 1);
>      else
>          put_bits32(pbc, value + 1);
>
> +    CBS_TRACE_WRITE_END();
> +
>      return 0;
>  }
>
> @@ -190,6 +175,8 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
>      int len;
>      uint32_t uvalue;
>
> +    CBS_TRACE_WRITE_START();
> +
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
>                 "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
> @@ -209,27 +196,14 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
>      if (put_bits_left(pbc) < 2 * len + 1)
>          return AVERROR(ENOSPC);
>
> -    if (ctx->trace_enable) {
> -        char bits[65];
> -        int i;
> -
> -        for (i = 0; i < len; i++)
> -            bits[i] = '0';
> -        bits[len] = '1';
> -        for (i = 0; i < len; i++)
> -            bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0';
> -        bits[len + len + 1] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, subscripts, bits, value);
> -    }
> -
>      put_bits(pbc, len, 0);
>      if (len + 1 < 32)
>          put_bits(pbc, len + 1, uvalue + 1);
>      else
>          put_bits32(pbc, uvalue + 1);
>
> +    CBS_TRACE_WRITE_END();
> +
>      return 0;
>  }
>
> diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
> index da84697a29..285deb40d5 100644
> --- a/libavcodec/cbs_internal.h
> +++ b/libavcodec/cbs_internal.h
> @@ -157,10 +157,6 @@ typedef struct CodedBitstreamType {
>  void ff_cbs_trace_header(CodedBitstreamContext *ctx,
>                           const char *name);
>
> -void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
> -                                 const char *name, const int *subscripts,
> -                                 const char *bitstring, int64_t value);
> -
>
>  // Helper functions for read/write of common bitstream elements, including
>  // generation of trace output. The simple functions are equivalent to
> @@ -206,6 +202,87 @@ int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
>  // range_min in the above functions.
>  #define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1)))
>
> +
> +// Start of a syntax element during read tracing.
> +#define CBS_TRACE_READ_START() \
> +    GetBitContext trace_start; \
> +    do { \
> +        if (ctx->trace_enable) \
> +            trace_start = *gbc; \
> +    } while (0)
> +
> +// End of a syntax element for tracing, make callback.
> +#define CBS_TRACE_READ_END() \
> +    do { \
> +        if (ctx->trace_enable) { \
> +            int start_position = get_bits_count(&trace_start); \
> +            int end_position   = get_bits_count(gbc); \
> +            av_assert0(start_position <= end_position); \
> +            ctx->trace_read_callback(ctx->trace_context, &trace_start, \
> +                                     end_position - start_position, \
> +                                     name, subscripts, value); \
> +        } \
> +    } while (0)
> +
> +// End of a syntax element with no subscript entries.
> +#define CBS_TRACE_READ_END_NO_SUBSCRIPTS() \
> +    do { \
> +        const int *subscripts = NULL; \
> +        CBS_TRACE_READ_END(); \
> +    } while (0)
> +
> +// End of a syntax element which is made up of subelements which
> +// are aleady traced, so we are only showing the value.
> +#define CBS_TRACE_READ_END_VALUE_ONLY() \
> +    do { \
> +        if (ctx->trace_enable) { \
> +            ctx->trace_read_callback(ctx->trace_context, &trace_start, 0, \
> +                                     name, subscripts, value); \
> +        } \
> +    } while (0)
> +
> +// Start of a syntax element during write tracing.
> +#define CBS_TRACE_WRITE_START() \
> +    int start_position; \
> +    do { \
> +        if (ctx->trace_enable) \
> +            start_position = put_bits_count(pbc);; \
> +    } while (0)
> +
> +// End of a syntax element for tracing, make callback.
> +#define CBS_TRACE_WRITE_END() \
> +    do { \
> +        if (ctx->trace_enable) { \
> +            int end_position   = put_bits_count(pbc); \
> +            av_assert0(start_position <= end_position); \
> +            ctx->trace_write_callback(ctx->trace_context, pbc, \
> +                                      end_position - start_position, \
> +                                      name, subscripts, value); \
> +        } \
> +    } while (0)
> +
> +// End of a syntax element with no subscript entries.
> +#define CBS_TRACE_WRITE_END_NO_SUBSCRIPTS() \
> +    do { \
> +        const int *subscripts = NULL; \
> +        CBS_TRACE_WRITE_END(); \
> +    } while (0)
> +
> +// End of a syntax element which is made up of subelements which are
> +// aleady traced, so we are only showing the value.  This forges a
> +// PutBitContext to point to the position of the start of the syntax
> +// element, but the other state doesn't matter because length is zero.
> +#define CBS_TRACE_WRITE_END_VALUE_ONLY() \
> +    do { \
> +        if (ctx->trace_enable) { \
> +            PutBitContext tmp; \
> +            init_put_bits(&tmp, pbc->buf, start_position); \
> +            skip_put_bits(&tmp, start_position); \
> +            ctx->trace_write_callback(ctx->trace_context, &tmp, 0, \
> +                                      name, subscripts, value); \
> +        } \
> +    } while (0)
> +
>  #define TYPE_LIST(...) { __VA_ARGS__ }
>  #define CBS_UNIT_TYPE_POD(type_, structure) { \
>          .nb_unit_types  = 1, \
> diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c
> index b0d5bd8763..816d06da04 100644
> --- a/libavcodec/cbs_vp9.c
> +++ b/libavcodec/cbs_vp9.c
> @@ -28,11 +28,10 @@ static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                            const int *subscripts, int32_t *write_to)
>  {
>      uint32_t magnitude;
> -    int position, sign;
> +    int sign;
>      int32_t value;
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
>      if (get_bits_left(gbc) < width + 1) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid signed value at "
> @@ -44,17 +43,7 @@ static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc,
>      sign      = get_bits1(gbc);
>      value     = sign ? -(int32_t)magnitude : magnitude;
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < width; i++)
> -            bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0';
> -        bits[i] = sign ? '1' : '0';
> -        bits[i + 1] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
> -                                    bits, value);
> -    }
> +    CBS_TRACE_READ_END();
>
>      *write_to = value;
>      return 0;
> @@ -67,27 +56,19 @@ static int cbs_vp9_write_s(CodedBitstreamContext *ctx, PutBitContext *pbc,
>      uint32_t magnitude;
>      int sign;
>
> +    CBS_TRACE_WRITE_START();
> +
>      if (put_bits_left(pbc) < width + 1)
>          return AVERROR(ENOSPC);
>
>      sign      = value < 0;
>      magnitude = sign ? -value : value;
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (i = 0; i < width; i++)
> -            bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0';
> -        bits[i] = sign ? '1' : '0';
> -        bits[i + 1] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, subscripts, bits, value);
> -    }
> -
>      put_bits(pbc, width, magnitude);
>      put_bits(pbc, 1, sign);
>
> +    CBS_TRACE_WRITE_END();
> +
>      return 0;
>  }
>
> @@ -96,32 +77,24 @@ static int cbs_vp9_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
>                                    const char *name, uint32_t *write_to)
>  {
>      uint32_t value;
> -    int position, i;
> -    char bits[8];
>
> -    av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1);
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    CBS_TRACE_READ_START();
>
> -    for (i = 0, value = range_min; value < range_max;) {
> +    av_assert0(range_min <= range_max && range_max - range_min < 32);
> +
> +    for (value = range_min; value < range_max;) {
>          if (get_bits_left(gbc) < 1) {
>              av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at "
>                     "%s: bitstream ended.\n", name);
>              return AVERROR_INVALIDDATA;
>          }
> -        if (get_bits1(gbc)) {
> -            bits[i++] = '1';
> +        if (get_bits1(gbc))
>              ++value;
> -        } else {
> -            bits[i++] = '0';
> +        else
>              break;
> -        }
>      }
>
> -    if (ctx->trace_enable) {
> -        bits[i] = 0;
> -        ff_cbs_trace_syntax_element(ctx, position, name, NULL, bits, value);
> -    }
> +    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
>
>      *write_to = value;
>      return 0;
> @@ -133,6 +106,8 @@ static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
>  {
>      int len;
>
> +    CBS_TRACE_WRITE_START();
> +
>      av_assert0(range_min <= range_max && range_max - range_min < 8);
>      if (value < range_min || value > range_max) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
> @@ -148,23 +123,11 @@ static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
>      if (put_bits_left(pbc) < len)
>          return AVERROR(ENOSPC);
>
> -    if (ctx->trace_enable) {
> -        char bits[8];
> -        int i;
> -        for (i = 0; i < len; i++) {
> -            if (range_min + i == value)
> -                bits[i] = '0';
> -            else
> -                bits[i] = '1';
> -        }
> -        bits[i] = 0;
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, NULL, bits, value);
> -    }
> -
>      if (len > 0)
>          put_bits(pbc, len, (1 << len) - 1 - (value != range_max));
>
> +    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
> +
>      return 0;
>  }
>
> @@ -173,12 +136,11 @@ static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc,
>                             const int *subscripts, uint32_t *write_to)
>  {
>      uint32_t value;
> -    int position, b;
> +    int b;
>
> -    av_assert0(width % 8 == 0);
> +    CBS_TRACE_READ_START();
>
> -    if (ctx->trace_enable)
> -        position = get_bits_count(gbc);
> +    av_assert0(width % 8 == 0);
>
>      if (get_bits_left(gbc) < width) {
>          av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid le value at "
> @@ -190,17 +152,7 @@ static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc,
>      for (b = 0; b < width; b += 8)
>          value |= get_bits(gbc, 8) << b;
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (b = 0; b < width; b += 8)
> -            for (i = 0; i < 8; i++)
> -                bits[b + i] = value >> (b + i) & 1 ? '1' : '0';
> -        bits[b] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
> -                                    bits, value);
> -    }
> +    CBS_TRACE_READ_END();
>
>      *write_to = value;
>      return 0;
> @@ -212,26 +164,18 @@ static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
>  {
>      int b;
>
> +    CBS_TRACE_WRITE_START();
> +
>      av_assert0(width % 8 == 0);
>
>      if (put_bits_left(pbc) < width)
>          return AVERROR(ENOSPC);
>
> -    if (ctx->trace_enable) {
> -        char bits[33];
> -        int i;
> -        for (b = 0; b < width; b += 8)
> -            for (i = 0; i < 8; i++)
> -                bits[b + i] = value >> (b + i) & 1 ? '1' : '0';
> -        bits[b] = 0;
> -
> -        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
> -                                    name, subscripts, bits, value);
> -    }
> -
>      for (b = 0; b < width; b += 8)
>          put_bits(pbc, 8, value >> b & 0xff);
>
> +    CBS_TRACE_WRITE_END();
> +
>      return 0;
>  }
>
> diff --git a/libavcodec/trace_headers_bsf.c b/libavcodec/trace_headers_bsf.c
> index 028b0a1e59..8781f5f100 100644
> --- a/libavcodec/trace_headers_bsf.c
> +++ b/libavcodec/trace_headers_bsf.c
> @@ -44,6 +44,8 @@ static int trace_headers_init(AVBSFContext *bsf)
>
>      ctx->cbc->trace_enable = 1;
>      ctx->cbc->trace_level  = AV_LOG_INFO;
> +    ctx->cbc->trace_context = ctx->cbc;
> +    ctx->cbc->trace_read_callback = ff_cbs_trace_read_log;
>
>      if (bsf->par_in->extradata) {
>          CodedBitstreamFragment *frag = &ctx->fragment;
> --
> 2.25.1
>

Code looks good to me, the parts I can exercise works with my hardware.

Reviewed-by: Neal Gompa <ngompa13@gmail.com>




--
真実はいつも一つ!/ Always, there's only one truth!
diff mbox series

Patch

diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c
index 3ec8285e21..daf7f66427 100644
--- a/libavcodec/cbs.c
+++ b/libavcodec/cbs.c
@@ -117,8 +117,9 @@  av_cold int ff_cbs_init(CodedBitstreamContext **ctx_ptr,
 
     ctx->decompose_unit_types = NULL;
 
-    ctx->trace_enable = 0;
-    ctx->trace_level  = AV_LOG_TRACE;
+    ctx->trace_enable  = 0;
+    ctx->trace_level   = AV_LOG_TRACE;
+    ctx->trace_context = ctx;
 
     *ctx_ptr = ctx;
     return 0;
@@ -496,19 +497,27 @@  void ff_cbs_trace_header(CodedBitstreamContext *ctx,
     av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name);
 }
 
-void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
-                                 const char *str, const int *subscripts,
-                                 const char *bits, int64_t value)
+void ff_cbs_trace_read_log(void *trace_context,
+                           GetBitContext *gbc, int length,
+                           const char *str, const int *subscripts,
+                           int64_t value)
 {
+    CodedBitstreamContext *ctx = trace_context;
     char name[256];
+    char bits[256];
     size_t name_len, bits_len;
     int pad, subs, i, j, k, n;
-
-    if (!ctx->trace_enable)
-        return;
+    int position;
 
     av_assert0(value >= INT_MIN && value <= UINT32_MAX);
 
+    position = get_bits_count(gbc);
+
+    av_assert0(length < 256);
+    for (i = 0; i < length; i++)
+        bits[i] = get_bits1(gbc) ? '1' : '0';
+    bits[length] = 0;
+
     subs = subscripts ? subscripts[0] : 0;
     n = 0;
     for (i = j = 0; str[i];) {
@@ -535,7 +544,7 @@  void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
     av_assert0(n == subs);
 
     name_len = strlen(name);
-    bits_len = strlen(bits);
+    bits_len = length;
 
     if (name_len + bits_len > 60)
         pad = bits_len + 2;
@@ -546,6 +555,36 @@  void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
            position, name, pad, bits, value);
 }
 
+void ff_cbs_trace_write_log(void *trace_context,
+                            PutBitContext *pbc, int length,
+                            const char *str, const int *subscripts,
+                            int64_t value)
+{
+    CodedBitstreamContext *ctx = trace_context;
+
+    // Ensure that the syntax element is written to the output buffer,
+    // make a GetBitContext pointed at the start position, then call the
+    // read log function which can read the bits back to log them.
+
+    GetBitContext gbc;
+    int position;
+
+    if (length > 0) {
+        PutBitContext flush;
+        flush = *pbc;
+        flush_put_bits(&flush);
+    }
+
+    position = put_bits_count(pbc);
+    av_assert0(position >= length);
+
+    init_get_bits(&gbc, pbc->buf, position);
+
+    skip_bits_long(&gbc, position - length);
+
+    ff_cbs_trace_read_log(ctx, &gbc, length, str, subscripts, value);
+}
+
 static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
                                               GetBitContext *gbc,
                                               int width, const char *name,
@@ -555,7 +594,8 @@  static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
                                               uint32_t range_max)
 {
     uint32_t value;
-    int position;
+
+    CBS_TRACE_READ_START();
 
     av_assert0(width > 0 && width <= 32);
 
@@ -565,21 +605,9 @@  static av_always_inline int cbs_read_unsigned(CodedBitstreamContext *ctx,
         return AVERROR_INVALIDDATA;
     }
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
-
     value = get_bits_long(gbc, width);
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < width; i++)
-            bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
-        bits[i] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
-                                    bits, value);
-    }
+    CBS_TRACE_READ_END();
 
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -613,6 +641,8 @@  int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
                           const int *subscripts, uint32_t value,
                           uint32_t range_min, uint32_t range_max)
 {
+    CBS_TRACE_WRITE_START();
+
     av_assert0(width > 0 && width <= 32);
 
     if (value < range_min || value > range_max) {
@@ -625,22 +655,13 @@  int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc,
     if (put_bits_left(pbc) < width)
         return AVERROR(ENOSPC);
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < width; i++)
-            bits[i] = value >> (width - i - 1) & 1 ? '1' : '0';
-        bits[i] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, subscripts, bits, value);
-    }
-
     if (width < 32)
         put_bits(pbc, width, value);
     else
         put_bits32(pbc, value);
 
+    CBS_TRACE_WRITE_END();
+
     return 0;
 }
 
@@ -657,7 +678,8 @@  int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
                        int32_t range_min, int32_t range_max)
 {
     int32_t value;
-    int position;
+
+    CBS_TRACE_READ_START();
 
     av_assert0(width > 0 && width <= 32);
 
@@ -667,21 +689,9 @@  int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc,
         return AVERROR_INVALIDDATA;
     }
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
-
     value = get_sbits_long(gbc, width);
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < width; i++)
-            bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
-        bits[i] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
-                                    bits, value);
-    }
+    CBS_TRACE_READ_END();
 
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -699,6 +709,8 @@  int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
                         const int *subscripts, int32_t value,
                         int32_t range_min, int32_t range_max)
 {
+    CBS_TRACE_WRITE_START();
+
     av_assert0(width > 0 && width <= 32);
 
     if (value < range_min || value > range_max) {
@@ -711,22 +723,13 @@  int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
     if (put_bits_left(pbc) < width)
         return AVERROR(ENOSPC);
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < width; i++)
-            bits[i] = value & (1U << (width - i - 1)) ? '1' : '0';
-        bits[i] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, subscripts, bits, value);
-    }
-
     if (width < 32)
         put_sbits(pbc, width, value);
     else
         put_bits32(pbc, value);
 
+    CBS_TRACE_WRITE_END();
+
     return 0;
 }
 
diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h
index b4131db5fe..ffb2797761 100644
--- a/libavcodec/cbs.h
+++ b/libavcodec/cbs.h
@@ -168,6 +168,51 @@  typedef struct CodedBitstreamFragment {
     CodedBitstreamUnit *units;
 } CodedBitstreamFragment;
 
+
+struct CodedBitstreamContext;
+struct GetBitContext;
+struct PutBitContext;
+
+/**
+ * Callback type for read tracing.
+ *
+ * @param ctx         User-set trace context.
+ * @param gbc         A GetBitContext set at the start of the syntax
+ *                    element.  This is a copy, the callee does not
+ *                    need to preserve it.
+ * @param length      Length in bits of the syntax element.
+ * @param name        String name of the syntax elements.
+ * @param subscripts  If the syntax element is an array, a pointer to
+ *                    an array of subscripts into the array.
+ * @param value       Parsed value of the syntax element.
+ */
+typedef void (*CBSTraceReadCallback)(void *trace_context,
+                                     struct GetBitContext *gbc,
+                                     int start_position,
+                                     const char *name,
+                                     const int *subscripts,
+                                     int64_t value);
+
+/**
+ * Callback type for write tracing.
+ *
+ * @param ctx         User-set trace context.
+ * @param pbc         A PutBitContext set at the end of the syntax
+ *                    element.  The user must not modify this, but may
+ *                    inspect it to determine state.
+ * @param length      Length in bits of the syntax element.
+ * @param name        String name of the syntax elements.
+ * @param subscripts  If the syntax element is an array, a pointer to
+ *                    an array of subscripts into the array.
+ * @param value       Written value of the syntax element.
+ */
+typedef void (*CBSTraceWriteCallback)(void *trace_context,
+                                      struct PutBitContext *pbc,
+                                      int start_position,
+                                      const char *name,
+                                      const int *subscripts,
+                                      int64_t value);
+
 /**
  * Context structure for coded bitstream operations.
  */
@@ -211,11 +256,29 @@  typedef struct CodedBitstreamContext {
      */
     int trace_enable;
     /**
-     * Log level to use for trace output.
+     * Log level to use for default trace output.
      *
      * From AV_LOG_*; defaults to AV_LOG_TRACE.
      */
     int trace_level;
+    /**
+     * User context pointer to pass to trace callbacks.
+     */
+    void *trace_context;
+    /**
+     * Callback for read tracing.
+     *
+     * If tracing is enabled then this is called once for each syntax
+     * element parsed.
+     */
+    CBSTraceReadCallback  trace_read_callback;
+    /**
+     * Callback for write tracing.
+     *
+     * If tracing is enabled then this is called once for each syntax
+     * element written.
+     */
+    CBSTraceWriteCallback trace_write_callback;
 
     /**
      * Write buffer. Used as intermediate buffer when writing units.
@@ -450,4 +513,27 @@  void ff_cbs_discard_units(CodedBitstreamContext *ctx,
                           enum AVDiscard skip,
                           int flags);
 
+
+/**
+ * Helper function for read tracing which formats the syntax element
+ * and logs the result.
+ *
+ * Trace context should be set to the CodedBitstreamContext.
+ */
+void ff_cbs_trace_read_log(void *trace_context,
+                           struct GetBitContext *gbc, int length,
+                           const char *str, const int *subscripts,
+                           int64_t value);
+
+/**
+ * Helper function for write tracing which formats the syntax element
+ * and logs the result.
+ *
+ * Trace context should be set to the CodedBitstreamContext.
+ */
+void ff_cbs_trace_write_log(void *trace_context,
+                            struct PutBitContext *pbc, int length,
+                            const char *str, const int *subscripts,
+                            int64_t value);
+
 #endif /* AVCODEC_CBS_H */
diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c
index 7fb5bd8b42..6c478603f1 100644
--- a/libavcodec/cbs_av1.c
+++ b/libavcodec/cbs_av1.c
@@ -31,10 +31,8 @@  static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
                              uint32_t range_min, uint32_t range_max)
 {
     uint32_t zeroes, bits_value, value;
-    int position;
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
     zeroes = 0;
     while (1) {
@@ -50,6 +48,9 @@  static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
     }
 
     if (zeroes >= 32) {
+        // Note that the spec allows an arbitrarily large number of
+        // zero bits followed by a one bit in this case, but the
+        // libaom implementation does not support it.
         value = MAX_UINT_BITS(32);
     } else {
         if (get_bits_left(gbc) < zeroes) {
@@ -62,36 +63,7 @@  static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc,
         value = bits_value + (UINT32_C(1) << zeroes) - 1;
     }
 
-    if (ctx->trace_enable) {
-        char bits[65];
-        int i, j, k;
-
-        if (zeroes >= 32) {
-            while (zeroes > 32) {
-                k = FFMIN(zeroes - 32, 32);
-                for (i = 0; i < k; i++)
-                    bits[i] = '0';
-                bits[i] = 0;
-                ff_cbs_trace_syntax_element(ctx, position, name,
-                                            NULL, bits, 0);
-                zeroes -= k;
-                position += k;
-            }
-        }
-
-        for (i = 0; i < zeroes; i++)
-            bits[i] = '0';
-        bits[i++] = '1';
-
-        if (zeroes < 32) {
-            for (j = 0; j < zeroes; j++)
-                bits[i++] = (bits_value >> (zeroes - j - 1) & 1) ? '1' : '0';
-        }
-
-        bits[i] = 0;
-        ff_cbs_trace_syntax_element(ctx, position, name,
-                                    NULL, bits, value);
-    }
+    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
 
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -109,7 +81,9 @@  static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
                               uint32_t range_min, uint32_t range_max)
 {
     uint32_t v;
-    int position, zeroes;
+    int zeroes;
+
+    CBS_TRACE_WRITE_START();
 
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -118,28 +92,17 @@  static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc,
         return AVERROR_INVALIDDATA;
     }
 
-    if (ctx->trace_enable)
-        position = put_bits_count(pbc);
-
     zeroes = av_log2(value + 1);
     v = value - (1U << zeroes) + 1;
+
+    if (put_bits_left(pbc) < 2 * zeroes + 1)
+        return AVERROR(ENOSPC);
+
     put_bits(pbc, zeroes, 0);
     put_bits(pbc, 1, 1);
     put_bits(pbc, zeroes, v);
 
-    if (ctx->trace_enable) {
-        char bits[65];
-        int i, j;
-        i = 0;
-        for (j = 0; j < zeroes; j++)
-            bits[i++] = '0';
-        bits[i++] = '1';
-        for (j = 0; j < zeroes; j++)
-            bits[i++] = (v >> (zeroes - j - 1) & 1) ? '1' : '0';
-        bits[i++] = 0;
-        ff_cbs_trace_syntax_element(ctx, position, name, NULL,
-                                    bits, value);
-    }
+    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
 
     return 0;
 }
@@ -148,20 +111,19 @@  static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
                                const char *name, uint64_t *write_to)
 {
     uint64_t value;
-    int position, err, i;
+    uint32_t byte;
+    int i;
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
     value = 0;
     for (i = 0; i < 8; i++) {
-        int subscript[2] = { 1, i };
-        uint32_t byte;
-        err = ff_cbs_read_unsigned(ctx, gbc, 8, "leb128_byte[i]", subscript,
-                                   &byte, 0x00, 0xff);
-        if (err < 0)
-            return err;
-
+        if (get_bits_left(gbc) < 8) {
+            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid leb128 at "
+                   "%s: bitstream ended.\n", name);
+            return AVERROR_INVALIDDATA;
+        }
+        byte = get_bits(gbc, 8);
         value |= (uint64_t)(byte & 0x7f) << (i * 7);
         if (!(byte & 0x80))
             break;
@@ -170,8 +132,7 @@  static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
     if (value > UINT32_MAX)
         return AVERROR_INVALIDDATA;
 
-    if (ctx->trace_enable)
-        ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value);
+    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
 
     *write_to = value;
     return 0;
@@ -180,29 +141,25 @@  static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc,
 static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc,
                                 const char *name, uint64_t value)
 {
-    int position, err, len, i;
+    int len, i;
     uint8_t byte;
 
-    len = (av_log2(value) + 7) / 7;
+    CBS_TRACE_WRITE_START();
 
-    if (ctx->trace_enable)
-        position = put_bits_count(pbc);
+    len = (av_log2(value) + 7) / 7;
 
     for (i = 0; i < len; i++) {
-        int subscript[2] = { 1, i };
+        if (put_bits_left(pbc) < 8)
+            return AVERROR(ENOSPC);
 
         byte = value >> (7 * i) & 0x7f;
         if (i < len - 1)
             byte |= 0x80;
 
-        err = ff_cbs_write_unsigned(ctx, pbc, 8, "leb128_byte[i]", subscript,
-                                    byte, 0x00, 0xff);
-        if (err < 0)
-            return err;
+        put_bits(pbc, 8, byte);
     }
 
-    if (ctx->trace_enable)
-        ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value);
+    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
 
     return 0;
 }
@@ -212,12 +169,11 @@  static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
                            const int *subscripts, uint32_t *write_to)
 {
     uint32_t m, v, extra_bit, value;
-    int position, w;
+    int w;
 
-    av_assert0(n > 0);
+    CBS_TRACE_READ_START();
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    av_assert0(n > 0);
 
     w = av_log2(n) + 1;
     m = (1 << w) - n;
@@ -240,18 +196,7 @@  static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc,
         value = (v << 1) - m + extra_bit;
     }
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < w - 1; i++)
-            bits[i] = (v >> i & 1) ? '1' : '0';
-        if (v >= m)
-            bits[i++] = extra_bit ? '1' : '0';
-        bits[i] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, position,
-                                    name, subscripts, bits, value);
-    }
+    CBS_TRACE_READ_END();
 
     *write_to = value;
     return 0;
@@ -262,7 +207,8 @@  static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
                             const int *subscripts, uint32_t value)
 {
     uint32_t w, m, v, extra_bit;
-    int position;
+
+    CBS_TRACE_WRITE_START();
 
     if (value > n) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -271,9 +217,6 @@  static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
         return AVERROR_INVALIDDATA;
     }
 
-    if (ctx->trace_enable)
-        position = put_bits_count(pbc);
-
     w = av_log2(n) + 1;
     m = (1 << w) - n;
 
@@ -290,18 +233,7 @@  static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc,
         put_bits(pbc, 1, extra_bit);
     }
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < w - 1; i++)
-            bits[i] = (v >> i & 1) ? '1' : '0';
-        if (value >= m)
-            bits[i++] = extra_bit ? '1' : '0';
-        bits[i] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, position,
-                                    name, subscripts, bits, value);
-    }
+    CBS_TRACE_WRITE_END();
 
     return 0;
 }
@@ -311,33 +243,24 @@  static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
                                   const char *name, uint32_t *write_to)
 {
     uint32_t value;
-    int position, i;
-    char bits[33];
 
-    av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1);
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
-    for (i = 0, value = range_min; value < range_max;) {
+    av_assert0(range_min <= range_max && range_max - range_min < 32);
+
+    for (value = range_min; value < range_max;) {
         if (get_bits_left(gbc) < 1) {
             av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at "
                    "%s: bitstream ended.\n", name);
             return AVERROR_INVALIDDATA;
         }
-        if (get_bits1(gbc)) {
-            bits[i++] = '1';
+        if (get_bits1(gbc))
             ++value;
-        } else {
-            bits[i++] = '0';
+        else
             break;
-        }
     }
 
-    if (ctx->trace_enable) {
-        bits[i] = 0;
-        ff_cbs_trace_syntax_element(ctx, position,
-                                    name, NULL, bits, value);
-    }
+    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
 
     *write_to = value;
     return 0;
@@ -349,6 +272,8 @@  static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
 {
     int len;
 
+    CBS_TRACE_WRITE_START();
+
     av_assert0(range_min <= range_max && range_max - range_min < 32);
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -364,23 +289,11 @@  static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
     if (put_bits_left(pbc) < len)
         return AVERROR(ENOSPC);
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < len; i++) {
-            if (range_min + i == value)
-                bits[i] = '0';
-            else
-                bits[i] = '1';
-        }
-        bits[i] = 0;
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, NULL, bits, value);
-    }
-
     if (len > 0)
         put_bits(pbc, len, (1 << len) - 1 - (value != range_max));
 
+    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
+
     return 0;
 }
 
@@ -388,12 +301,10 @@  static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
                                uint32_t range_max, const char *name,
                                const int *subscripts, uint32_t *write_to)
 {
-    uint32_t value;
-    int position, err;
-    uint32_t max_len, len, range_offset, range_bits;
+    uint32_t value, max_len, len, range_offset, range_bits;
+    int err;
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
     av_assert0(range_max > 0);
     max_len = av_log2(range_max - 1) - 3;
@@ -425,9 +336,7 @@  static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc,
     }
     value += range_offset;
 
-    if (ctx->trace_enable)
-        ff_cbs_trace_syntax_element(ctx, position,
-                                    name, subscripts, "", value);
+    CBS_TRACE_READ_END_VALUE_ONLY();
 
     *write_to = value;
     return err;
@@ -437,9 +346,11 @@  static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
                                 uint32_t range_max, const char *name,
                                 const int *subscripts, uint32_t value)
 {
-    int position, err;
+    int err;
     uint32_t max_len, len, range_offset, range_bits;
 
+    CBS_TRACE_WRITE_START();
+
     if (value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
                "%"PRIu32", but must be in [0,%"PRIu32"].\n",
@@ -447,9 +358,6 @@  static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
         return AVERROR_INVALIDDATA;
     }
 
-    if (ctx->trace_enable)
-        position = put_bits_count(pbc);
-
     av_assert0(range_max > 0);
     max_len = av_log2(range_max - 1) - 3;
 
@@ -489,9 +397,7 @@  static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc,
             return err;
     }
 
-    if (ctx->trace_enable)
-        ff_cbs_trace_syntax_element(ctx, position,
-                                    name, subscripts, "", value);
+    CBS_TRACE_WRITE_END_VALUE_ONLY();
 
     return err;
 }
diff --git a/libavcodec/cbs_bsf.c b/libavcodec/cbs_bsf.c
index 069f6e9918..b25285483b 100644
--- a/libavcodec/cbs_bsf.c
+++ b/libavcodec/cbs_bsf.c
@@ -123,6 +123,11 @@  int ff_cbs_bsf_generic_init(AVBSFContext *bsf, const CBSBSFType *type)
     if (err < 0)
         return err;
 
+    ctx->output->trace_enable = 1;
+    ctx->output->trace_level  = AV_LOG_TRACE;
+    ctx->output->trace_context = ctx->output;
+    ctx->output->trace_write_callback = ff_cbs_trace_write_log;
+
     if (bsf->par_in->extradata) {
         err = ff_cbs_read_extradata(ctx->input, frag, bsf->par_in);
         if (err < 0) {
diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c
index 318c997d94..0a1c8ea426 100644
--- a/libavcodec/cbs_h2645.c
+++ b/libavcodec/cbs_h2645.c
@@ -36,41 +36,38 @@  static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
                               uint32_t *write_to,
                               uint32_t range_min, uint32_t range_max)
 {
-    uint32_t value;
-    int position, i, j;
-    unsigned int k;
-    char bits[65];
+    uint32_t leading_bits, value;
+    int max_length, leading_zeroes;
 
-    position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
-    for (i = 0; i < 32; i++) {
-        if (get_bits_left(gbc) < i + 1) {
+    max_length = FFMIN(get_bits_left(gbc), 32);
+
+    leading_bits = show_bits_long(gbc, max_length);
+    if (leading_bits == 0) {
+        if (max_length >= 32) {
+            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
+                   "%s: more than 31 zeroes.\n", name);
+            return AVERROR_INVALIDDATA;
+        } else {
             av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
                    "%s: bitstream ended.\n", name);
             return AVERROR_INVALIDDATA;
         }
-        k = get_bits1(gbc);
-        bits[i] = k ? '1' : '0';
-        if (k)
-            break;
     }
-    if (i >= 32) {
+
+    leading_zeroes = max_length - 1 - av_log2(leading_bits);
+    skip_bits_long(gbc, leading_zeroes);
+
+    if (get_bits_left(gbc) < leading_zeroes + 1) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at "
-               "%s: more than 31 zeroes.\n", name);
+               "%s: bitstream ended.\n", name);
         return AVERROR_INVALIDDATA;
     }
-    value = 1;
-    for (j = 0; j < i; j++) {
-        k = get_bits1(gbc);
-        bits[i + j + 1] = k ? '1' : '0';
-        value = value << 1 | k;
-    }
-    bits[i + j + 1] = 0;
-    --value;
 
-    if (ctx->trace_enable)
-        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
-                                    bits, value);
+    value = get_bits_long(gbc, leading_zeroes + 1) - 1;
+
+    CBS_TRACE_READ_END();
 
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -88,45 +85,44 @@  static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc,
                               int32_t *write_to,
                               int32_t range_min, int32_t range_max)
 {
+    uint32_t leading_bits, unsigned_value;
+    int max_length, leading_zeroes;
     int32_t value;
-    int position, i, j;
-    unsigned int k;
-    uint32_t v;
-    char bits[65];
 
-    position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
-    for (i = 0; i < 32; i++) {
-        if (get_bits_left(gbc) < i + 1) {
+    max_length = FFMIN(get_bits_left(gbc), 32);
+
+    leading_bits = show_bits_long(gbc, max_length);
+    if (leading_bits == 0) {
+        if (max_length >= 32) {
+            av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
+                   "%s: more than 31 zeroes.\n", name);
+            return AVERROR_INVALIDDATA;
+        } else {
             av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
                    "%s: bitstream ended.\n", name);
             return AVERROR_INVALIDDATA;
         }
-        k = get_bits1(gbc);
-        bits[i] = k ? '1' : '0';
-        if (k)
-            break;
     }
-    if (i >= 32) {
+
+    leading_zeroes = max_length - 1 - av_log2(leading_bits);
+    skip_bits_long(gbc, leading_zeroes);
+
+    if (get_bits_left(gbc) < leading_zeroes + 1) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at "
-               "%s: more than 31 zeroes.\n", name);
+               "%s: bitstream ended.\n", name);
         return AVERROR_INVALIDDATA;
     }
-    v = 1;
-    for (j = 0; j < i; j++) {
-        k = get_bits1(gbc);
-        bits[i + j + 1] = k ? '1' : '0';
-        v = v << 1 | k;
-    }
-    bits[i + j + 1] = 0;
-    if (v & 1)
-        value = -(int32_t)(v / 2);
+
+    unsigned_value = get_bits_long(gbc, leading_zeroes + 1);
+
+    if (unsigned_value & 1)
+        value = -(int32_t)(unsigned_value / 2);
     else
-        value = v / 2;
+        value = unsigned_value / 2;
 
-    if (ctx->trace_enable)
-        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
-                                    bits, value);
+    CBS_TRACE_READ_END();
 
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -146,6 +142,8 @@  static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
 {
     int len;
 
+    CBS_TRACE_WRITE_START();
+
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
                "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n",
@@ -158,27 +156,14 @@  static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
     if (put_bits_left(pbc) < 2 * len + 1)
         return AVERROR(ENOSPC);
 
-    if (ctx->trace_enable) {
-        char bits[65];
-        int i;
-
-        for (i = 0; i < len; i++)
-            bits[i] = '0';
-        bits[len] = '1';
-        for (i = 0; i < len; i++)
-            bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0';
-        bits[len + len + 1] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, subscripts, bits, value);
-    }
-
     put_bits(pbc, len, 0);
     if (len + 1 < 32)
         put_bits(pbc, len + 1, value + 1);
     else
         put_bits32(pbc, value + 1);
 
+    CBS_TRACE_WRITE_END();
+
     return 0;
 }
 
@@ -190,6 +175,8 @@  static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
     int len;
     uint32_t uvalue;
 
+    CBS_TRACE_WRITE_START();
+
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
                "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n",
@@ -209,27 +196,14 @@  static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc,
     if (put_bits_left(pbc) < 2 * len + 1)
         return AVERROR(ENOSPC);
 
-    if (ctx->trace_enable) {
-        char bits[65];
-        int i;
-
-        for (i = 0; i < len; i++)
-            bits[i] = '0';
-        bits[len] = '1';
-        for (i = 0; i < len; i++)
-            bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0';
-        bits[len + len + 1] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, subscripts, bits, value);
-    }
-
     put_bits(pbc, len, 0);
     if (len + 1 < 32)
         put_bits(pbc, len + 1, uvalue + 1);
     else
         put_bits32(pbc, uvalue + 1);
 
+    CBS_TRACE_WRITE_END();
+
     return 0;
 }
 
diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h
index da84697a29..285deb40d5 100644
--- a/libavcodec/cbs_internal.h
+++ b/libavcodec/cbs_internal.h
@@ -157,10 +157,6 @@  typedef struct CodedBitstreamType {
 void ff_cbs_trace_header(CodedBitstreamContext *ctx,
                          const char *name);
 
-void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position,
-                                 const char *name, const int *subscripts,
-                                 const char *bitstring, int64_t value);
-
 
 // Helper functions for read/write of common bitstream elements, including
 // generation of trace output. The simple functions are equivalent to
@@ -206,6 +202,87 @@  int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc,
 // range_min in the above functions.
 #define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1)))
 
+
+// Start of a syntax element during read tracing.
+#define CBS_TRACE_READ_START() \
+    GetBitContext trace_start; \
+    do { \
+        if (ctx->trace_enable) \
+            trace_start = *gbc; \
+    } while (0)
+
+// End of a syntax element for tracing, make callback.
+#define CBS_TRACE_READ_END() \
+    do { \
+        if (ctx->trace_enable) { \
+            int start_position = get_bits_count(&trace_start); \
+            int end_position   = get_bits_count(gbc); \
+            av_assert0(start_position <= end_position); \
+            ctx->trace_read_callback(ctx->trace_context, &trace_start, \
+                                     end_position - start_position, \
+                                     name, subscripts, value); \
+        } \
+    } while (0)
+
+// End of a syntax element with no subscript entries.
+#define CBS_TRACE_READ_END_NO_SUBSCRIPTS() \
+    do { \
+        const int *subscripts = NULL; \
+        CBS_TRACE_READ_END(); \
+    } while (0)
+
+// End of a syntax element which is made up of subelements which
+// are aleady traced, so we are only showing the value.
+#define CBS_TRACE_READ_END_VALUE_ONLY() \
+    do { \
+        if (ctx->trace_enable) { \
+            ctx->trace_read_callback(ctx->trace_context, &trace_start, 0, \
+                                     name, subscripts, value); \
+        } \
+    } while (0)
+
+// Start of a syntax element during write tracing.
+#define CBS_TRACE_WRITE_START() \
+    int start_position; \
+    do { \
+        if (ctx->trace_enable) \
+            start_position = put_bits_count(pbc);; \
+    } while (0)
+
+// End of a syntax element for tracing, make callback.
+#define CBS_TRACE_WRITE_END() \
+    do { \
+        if (ctx->trace_enable) { \
+            int end_position   = put_bits_count(pbc); \
+            av_assert0(start_position <= end_position); \
+            ctx->trace_write_callback(ctx->trace_context, pbc, \
+                                      end_position - start_position, \
+                                      name, subscripts, value); \
+        } \
+    } while (0)
+
+// End of a syntax element with no subscript entries.
+#define CBS_TRACE_WRITE_END_NO_SUBSCRIPTS() \
+    do { \
+        const int *subscripts = NULL; \
+        CBS_TRACE_WRITE_END(); \
+    } while (0)
+
+// End of a syntax element which is made up of subelements which are
+// aleady traced, so we are only showing the value.  This forges a
+// PutBitContext to point to the position of the start of the syntax
+// element, but the other state doesn't matter because length is zero.
+#define CBS_TRACE_WRITE_END_VALUE_ONLY() \
+    do { \
+        if (ctx->trace_enable) { \
+            PutBitContext tmp; \
+            init_put_bits(&tmp, pbc->buf, start_position); \
+            skip_put_bits(&tmp, start_position); \
+            ctx->trace_write_callback(ctx->trace_context, &tmp, 0, \
+                                      name, subscripts, value); \
+        } \
+    } while (0)
+
 #define TYPE_LIST(...) { __VA_ARGS__ }
 #define CBS_UNIT_TYPE_POD(type_, structure) { \
         .nb_unit_types  = 1, \
diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c
index b0d5bd8763..816d06da04 100644
--- a/libavcodec/cbs_vp9.c
+++ b/libavcodec/cbs_vp9.c
@@ -28,11 +28,10 @@  static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc,
                           const int *subscripts, int32_t *write_to)
 {
     uint32_t magnitude;
-    int position, sign;
+    int sign;
     int32_t value;
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
     if (get_bits_left(gbc) < width + 1) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid signed value at "
@@ -44,17 +43,7 @@  static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc,
     sign      = get_bits1(gbc);
     value     = sign ? -(int32_t)magnitude : magnitude;
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < width; i++)
-            bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0';
-        bits[i] = sign ? '1' : '0';
-        bits[i + 1] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
-                                    bits, value);
-    }
+    CBS_TRACE_READ_END();
 
     *write_to = value;
     return 0;
@@ -67,27 +56,19 @@  static int cbs_vp9_write_s(CodedBitstreamContext *ctx, PutBitContext *pbc,
     uint32_t magnitude;
     int sign;
 
+    CBS_TRACE_WRITE_START();
+
     if (put_bits_left(pbc) < width + 1)
         return AVERROR(ENOSPC);
 
     sign      = value < 0;
     magnitude = sign ? -value : value;
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (i = 0; i < width; i++)
-            bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0';
-        bits[i] = sign ? '1' : '0';
-        bits[i + 1] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, subscripts, bits, value);
-    }
-
     put_bits(pbc, width, magnitude);
     put_bits(pbc, 1, sign);
 
+    CBS_TRACE_WRITE_END();
+
     return 0;
 }
 
@@ -96,32 +77,24 @@  static int cbs_vp9_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc
                                   const char *name, uint32_t *write_to)
 {
     uint32_t value;
-    int position, i;
-    char bits[8];
 
-    av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1);
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    CBS_TRACE_READ_START();
 
-    for (i = 0, value = range_min; value < range_max;) {
+    av_assert0(range_min <= range_max && range_max - range_min < 32);
+
+    for (value = range_min; value < range_max;) {
         if (get_bits_left(gbc) < 1) {
             av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at "
                    "%s: bitstream ended.\n", name);
             return AVERROR_INVALIDDATA;
         }
-        if (get_bits1(gbc)) {
-            bits[i++] = '1';
+        if (get_bits1(gbc))
             ++value;
-        } else {
-            bits[i++] = '0';
+        else
             break;
-        }
     }
 
-    if (ctx->trace_enable) {
-        bits[i] = 0;
-        ff_cbs_trace_syntax_element(ctx, position, name, NULL, bits, value);
-    }
+    CBS_TRACE_READ_END_NO_SUBSCRIPTS();
 
     *write_to = value;
     return 0;
@@ -133,6 +106,8 @@  static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
 {
     int len;
 
+    CBS_TRACE_WRITE_START();
+
     av_assert0(range_min <= range_max && range_max - range_min < 8);
     if (value < range_min || value > range_max) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: "
@@ -148,23 +123,11 @@  static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pb
     if (put_bits_left(pbc) < len)
         return AVERROR(ENOSPC);
 
-    if (ctx->trace_enable) {
-        char bits[8];
-        int i;
-        for (i = 0; i < len; i++) {
-            if (range_min + i == value)
-                bits[i] = '0';
-            else
-                bits[i] = '1';
-        }
-        bits[i] = 0;
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, NULL, bits, value);
-    }
-
     if (len > 0)
         put_bits(pbc, len, (1 << len) - 1 - (value != range_max));
 
+    CBS_TRACE_WRITE_END_NO_SUBSCRIPTS();
+
     return 0;
 }
 
@@ -173,12 +136,11 @@  static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc,
                            const int *subscripts, uint32_t *write_to)
 {
     uint32_t value;
-    int position, b;
+    int b;
 
-    av_assert0(width % 8 == 0);
+    CBS_TRACE_READ_START();
 
-    if (ctx->trace_enable)
-        position = get_bits_count(gbc);
+    av_assert0(width % 8 == 0);
 
     if (get_bits_left(gbc) < width) {
         av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid le value at "
@@ -190,17 +152,7 @@  static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc,
     for (b = 0; b < width; b += 8)
         value |= get_bits(gbc, 8) << b;
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (b = 0; b < width; b += 8)
-            for (i = 0; i < 8; i++)
-                bits[b + i] = value >> (b + i) & 1 ? '1' : '0';
-        bits[b] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, position, name, subscripts,
-                                    bits, value);
-    }
+    CBS_TRACE_READ_END();
 
     *write_to = value;
     return 0;
@@ -212,26 +164,18 @@  static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc,
 {
     int b;
 
+    CBS_TRACE_WRITE_START();
+
     av_assert0(width % 8 == 0);
 
     if (put_bits_left(pbc) < width)
         return AVERROR(ENOSPC);
 
-    if (ctx->trace_enable) {
-        char bits[33];
-        int i;
-        for (b = 0; b < width; b += 8)
-            for (i = 0; i < 8; i++)
-                bits[b + i] = value >> (b + i) & 1 ? '1' : '0';
-        bits[b] = 0;
-
-        ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc),
-                                    name, subscripts, bits, value);
-    }
-
     for (b = 0; b < width; b += 8)
         put_bits(pbc, 8, value >> b & 0xff);
 
+    CBS_TRACE_WRITE_END();
+
     return 0;
 }
 
diff --git a/libavcodec/trace_headers_bsf.c b/libavcodec/trace_headers_bsf.c
index 028b0a1e59..8781f5f100 100644
--- a/libavcodec/trace_headers_bsf.c
+++ b/libavcodec/trace_headers_bsf.c
@@ -44,6 +44,8 @@  static int trace_headers_init(AVBSFContext *bsf)
 
     ctx->cbc->trace_enable = 1;
     ctx->cbc->trace_level  = AV_LOG_INFO;
+    ctx->cbc->trace_context = ctx->cbc;
+    ctx->cbc->trace_read_callback = ff_cbs_trace_read_log;
 
     if (bsf->par_in->extradata) {
         CodedBitstreamFragment *frag = &ctx->fragment;