[FFmpeg-devel] [PATCH v3 07/11] avcodec: add cbs for h266/vvc

James Almer jamrial at gmail.com
Wed Jan 13 04:34:37 EET 2021


On 1/11/2021 1:33 PM, Nuo Mi wrote:
> ---
>   configure                             |    2 +
>   libavcodec/Makefile                   |    1 +
>   libavcodec/cbs.c                      |    6 +
>   libavcodec/cbs_h2645.c                |  374 ++++
>   libavcodec/cbs_h266.h                 |  758 +++++++
>   libavcodec/cbs_h266_syntax_template.c | 2774 +++++++++++++++++++++++++
>   libavcodec/cbs_internal.h             |    3 +-
>   7 files changed, 3917 insertions(+), 1 deletion(-)
>   create mode 100644 libavcodec/cbs_h266.h
>   create mode 100644 libavcodec/cbs_h266_syntax_template.c
> 

[...]

> +static int cbs_h266_replace_ph(CodedBitstreamContext *ctx,
> +                               CodedBitstreamUnit *unit)
> +{
> +    CodedBitstreamH266Context *priv = ctx->priv_data;
> +    int err;
> +    err = ff_cbs_make_unit_refcounted(ctx, unit);
> +    if (err < 0)
> +        return err;
> +    av_buffer_unref(&priv->ph_ref);
> +    av_assert0(unit->content_ref);
> +    priv->ph_ref = av_buffer_ref(unit->content_ref);
> +    if (!priv->ph_ref)
> +        return AVERROR(ENOMEM);
> +    priv->ph = (H266RawPH *)priv->ph_ref->data;

Make this function take a pointer to H266RawPH as argument, and set it here.
See below.

> +    return 0;
> +}
> +
> +static int cbs_h266_read_nal_unit(CodedBitstreamContext *ctx,
> +                                  CodedBitstreamUnit *unit)
> +{
> +    GetBitContext gbc;
> +    int err;
> +
> +    err = init_get_bits8(&gbc, unit->data, unit->data_size);
> +    if (err < 0)
> +        return err;
> +
> +    err = ff_cbs_alloc_unit_content2(ctx, unit);
> +    if (err < 0)
> +        return err;
> +
> +    switch (unit->type) {
> +    case VVC_SPS_NUT:
> +        {
> +            H266RawSPS *sps = unit->content;
> +
> +            err = cbs_h266_read_sps(ctx, &gbc, sps);
> +            if (err < 0)
> +                return err;
> +
> +            err = cbs_h266_replace_sps(ctx, unit);
> +            if (err < 0)
> +                return err;
> +        }
> +        break;
> +
> +    case VVC_PPS_NUT:
> +        {
> +            H266RawPPS *pps = unit->content;
> +
> +            err = cbs_h266_read_pps(ctx, &gbc, pps);
> +            if (err < 0)
> +                return err;
> +
> +            err = cbs_h266_replace_pps(ctx, unit);
> +            if (err < 0)
> +                return err;
> +        }
> +        break;
> +
> +    case VVC_PH_NUT:
> +        {
> +            H266RawPH *ph = unit->content;
> +            err = cbs_h266_read_ph(ctx, &gbc, ph);
> +            if (err < 0)
> +                return err;
> +
> +            err = cbs_h266_replace_ph(ctx, unit);

Pass ph as mentioned above.

> +            if (err < 0)
> +                return err;
> +        }
> +        break;
> +
> +    case VVC_TRAIL_NUT:
> +    case VVC_STSA_NUT:
> +    case VVC_RADL_NUT:
> +    case VVC_RASL_NUT:
> +    case VVC_IDR_W_RADL:
> +    case VVC_IDR_N_LP:
> +    case VVC_CRA_NUT:
> +    case VVC_GDR_NUT:
> +        {
> +            H266RawSlice *slice = unit->content;
> +            int pos, len;
> +
> +            err = cbs_h266_read_slice_header(ctx, &gbc, &slice->header);
> +            if (err < 0)
> +                return err;

Add a call to cbs_h266_replace_ph() here when 
slice->header.sh_picture_header_in_slice_header_flag is true, and pass a 
pointer to slice->header.sh_picture_header to it.

Do the same for the writing functions.

[...]

> +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw,
> +                              H266RawSliceHeader *current)
> +{
> +    CodedBitstreamH266Context *h266 = ctx->priv_data;
> +    const H266RawSPS *sps;
> +    const H266RawPPS *pps;
> +    const H266RawPH  *ph;
> +    const H266RefPicLists *ref_pic_lists;
> +    int      err, i;
> +    uint8_t  nal_unit_type, qp_bd_offset;
> +    uint16_t curr_subpic_idx;
> +    uint16_t num_slices_in_subpic;
> +
> +    HEADER("Slice Header");
> +
> +    CHECK(FUNC(nal_unit_header)(ctx, rw, &current->nal_unit_header, -1));
> +
> +    flag(sh_picture_header_in_slice_header_flag);
> +    if (current->sh_picture_header_in_slice_header_flag){
> +        CHECK(FUNC(picture_header)(ctx, rw, &current->sh_picture_header));
> +        if (!h266->ph_ref) {
> +            h266->ph_ref = av_buffer_allocz(sizeof(H266RawPH));
> +            if (!h266->ph_ref)
> +                return AVERROR(ENOMEM);
> +        }
> +        h266->ph = (H266RawPH*)h266->ph_ref->data;
> +        memcpy(h266->ph, &current->sh_picture_header, sizeof(H266RawPH));

With the above, you can remove all this and simply set ph to 
&current->sh_picture_header when 
current->sh_picture_header_in_slice_header_flag is true, or to h266->ph 
otherwise.

This saves an unnecessary buffer alloc per slice header that includes a 
picture header. The buffer reference most assuredly already exists, and 
you can reuse it.

> +    }
> +    sps = h266->active_sps;
> +    pps = h266->active_pps;
> +    ph  = h266->ph;
> +
> +    if (!ph) {
> +        av_log(ctx->log_ctx, AV_LOG_ERROR, "Picture header not available.\n");
> +        return AVERROR_INVALIDDATA;
> +    }


More information about the ffmpeg-devel mailing list