[FFmpeg-devel] [PATCH 4/6] avcodec: add cbs for h266

Nuo Mi nuomi2021 at gmail.com
Sat Jan 9 09:37:52 EET 2021


On Tue, Dec 22, 2020 at 6:53 AM Mark Thompson <sw at jkqxz.net> wrote:

> On 21/12/2020 06:07, Nuo Mi wrote:
> > ---
> >   libavcodec/Makefile                   |    1 +
> >   libavcodec/cbs.c                      |    6 +
> >   libavcodec/cbs_h2645.c                |  337 ++++++
> >   libavcodec/cbs_h266.h                 |  711 ++++++++++++
> >   libavcodec/cbs_h266_syntax_template.c | 1493 +++++++++++++++++++++++++
> >   libavcodec/cbs_internal.h             |    1 +
> >   6 files changed, 2549 insertions(+)
> >   create mode 100644 libavcodec/cbs_h266.h
> >   create mode 100644 libavcodec/cbs_h266_syntax_template.c
> >
> > diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> > index 450781886d..4045c002b7 100644
> > --- a/libavcodec/Makefile
> > +++ b/libavcodec/Makefile
> >
> >
> > +#define FUNC(name) FUNC_H266(READWRITE, name)
> > +#include "cbs_h266_syntax_template.c"
> > +#undef FUNC
> > +
> >   #undef READ
> >   #undef READWRITE
> >   #undef RWContext
>
> Please include the second time for write support as well.  (With only read
> this is incredibly hard to test.)
>
Done

>
> >
> > +static int cbs_h266_read_nal_unit(CodedBitstreamContext *ctx,
> > +                                  CodedBitstreamUnit *unit)
> > +{
> > +    GetBitContext gbc;
> > +    int err;
> > +
> > +    err = init_get_bits(&gbc, unit->data, 8 * unit->data_size);
>
> init_get_bits8()
>
Done

>
> > +    if (err < 0)
> > +        return err;
> > +
> > +    err = ff_cbs_alloc_unit_content2(ctx, unit);
> > +    if (err < 0)
> > +        return err;
> > +
> > +    switch (unit->type) {
> > +    case H266_NAL_VPS:
> > +        {
> > +            H266RawVPS *vps = unit->content;
> > +
> > +            err = cbs_h266_read_vps(ctx, &gbc, vps);
>
> This isn't implemented, so don't include it here so it returns ENOSYS.
>
Done

>
>
> > +
> > +    case H266_NAL_PPS:
> > +        {
> > +            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 H266_NAL_TRAIL:
> > +    case H266_NAL_STSA:
> > +    case H266_NAL_RADL:
>
> Missing case H266_NUT_RASL.
>
Fixed

>
> > +
> > +    case H266_NAL_PREFIX_SEI:
> > +    case H266_NAL_SUFFIX_SEI:
> > +        {
> > +            err = cbs_h266_read_sei(ctx, &gbc, unit->content,
> > +                                    unit->type == H266_NAL_PREFIX_SEI);
> > +
> > +            if (err < 0)
> > +                return err;
> > +        }
> > +        break;
>
> Don't include SEI at all given that you haven't implemented it; just let
> it return ENOSYS.

Implemented.

> > +
> > +    default:
> > +        return AVERROR(ENOSYS);
> > +    }
> > +    return 0;
> > +}
> > +
> >   static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx,
> >                                         PutBitContext *pbc, const
> uint8_t *data,
> >                                         size_t data_size, int
> data_bit_start)
> > @@ -1207,6 +1328,120 @@ static int
> cbs_h265_write_nal_unit(CodedBitstreamContext *ctx,
> >       return 0;
> >   }
> >
> > +static int cbs_h266_write_nal_unit(CodedBitstreamContext *ctx,
> > +                                   CodedBitstreamUnit *unit,
> > +                                   PutBitContext *pbc)
> > +{
> > +    printf("TODO: cbs_h266_write_nal_unit");
>
> Yes.
>
Implemented.

>
> >
> > +static void cbs_h266_close(CodedBitstreamContext *ctx)
> > +{
> > +    CodedBitstreamH266Context *h266 = ctx->priv_data;
> > +    int i;
> > +
> > +    ff_h2645_packet_uninit(&h266->common.read_packet);
> > +
> > +    for (i = 0; i < FF_ARRAY_ELEMS(h266->vps); i++)
> > +        av_buffer_unref(&h266->vps_ref[i]);
> > +    for (i = 0; i < FF_ARRAY_ELEMS(h266->sps); i++)
> > +        av_buffer_unref(&h266->sps_ref[i]);
> > +    for (i = 0; i < FF_ARRAY_ELEMS(h266->pps); i++)
> > +        av_buffer_unref(&h266->pps_ref[i]);
>
> These loops look like exactly what flush does.
>
Fixed, will call flush, I will send a separate patch for h264/h265

>
> > +}
> > +
> >   static void cbs_h264_free_sei_payload(H264RawSEIPayload *payload)
> >   {
> >       switch (payload->payload_type) {
> > @@ -1506,6 +1778,55 @@ static const CodedBitstreamUnitTypeDescriptor
> cbs_h265_unit_types[] = {
> >       CBS_UNIT_TYPE_END_OF_LIST
> >   };
> >
> > +static void cbs_h266_free_sei(void *opaque, uint8_t *content)
> > +{
> > +}
> > +
> > +static const CodedBitstreamUnitTypeDescriptor cbs_h266_unit_types[] = {
> > +    CBS_UNIT_TYPE_INTERNAL_REF(H266_NAL_VPS, H266RawVPS,
> extension_data.data),
> > +    CBS_UNIT_TYPE_INTERNAL_REF(H266_NAL_SPS, H266RawSPS,
> extension_data.data),
> > +    CBS_UNIT_TYPE_INTERNAL_REF(H266_NAL_PPS, H266RawPPS,
> extension_data.data),
> > +
> > +    CBS_UNIT_TYPE_POD(H266_NAL_AUD, H266RawAUD),
> > +
> > +    {
> > +        // Slices of non-IRAP pictures.
> > +        .nb_unit_types         = CBS_UNIT_TYPE_RANGE,
> > +        .unit_type_range_start = H266_NAL_TRAIL,
> > +        .unit_type_range_end   = H266_NAL_RASL,
>
> Using the list form would probably be clearer - there isn't the
> proliferation of extra types like H.265.
>
 Done

>
> > +
> > +        .content_type   = CBS_CONTENT_TYPE_INTERNAL_REFS,
> > +        .content_size   = sizeof(H266RawSlice),
> > +        .nb_ref_offsets = 1,
> > +        .ref_offsets    = { offsetof(H266RawSlice, data) },
> > +    },
> > +
> > +    {
> > +        // Slices of IRAP pictures.
> > +        .nb_unit_types         = CBS_UNIT_TYPE_RANGE,
> > +        .unit_type_range_start = H266_NAL_IDR_W_RADL,
> > +        .unit_type_range_end   = H266_NAL_GDR_NUT,
>
> Likewise here.
>
Done

>
> > +
> > +        .content_type   = CBS_CONTENT_TYPE_INTERNAL_REFS,
> > +        .content_size   = sizeof(H266RawSlice),
> > +        .nb_ref_offsets = 1,
> > +        .ref_offsets    = { offsetof(H266RawSlice, data) },
> > +    },
> > +
> > +    {
> > +        .nb_unit_types  = 2,
> > +        .unit_types     = {
> > +            H266_NAL_PREFIX_SEI,
> > +            H266_NAL_SUFFIX_SEI
> > +        },
> > +        .content_type   = CBS_CONTENT_TYPE_COMPLEX,
> > +        .content_size   = sizeof(H266RawSEI),
> > +        .content_free   = &cbs_h266_free_sei,
> > +    },
>
> Don't include these if you didn't implement them.
>
implemented.

>
> >
> > +
> > +enum {
> > +    // This limit is arbitrary - it is sufficient for one message of
> each
> > +    // type plus some repeats, and will therefore easily cover all sane
> > +    // streams.  However, it is possible to make technically-valid
> streams
> > +    // for which it will fail (for example, by including a large number
> of
> > +    // user-data-unregistered messages).
> > +    H266_MAX_SEI_PAYLOADS = 64,
> > +};
> > +
>
> In this file, please horizontally align things to improve readability.  In
> particular, the starts of all normal variables and all the matching arrays
> would help quite a bit.
>
Done

>
> > +typedef struct H266RawNALUnitHeader {
> > +    uint8_t nuh_layer_id;
> > +    uint8_t nal_unit_type;
> > +    uint8_t nuh_temporal_id_plus1;
> > +} H266RawNALUnitHeader;
> > +
> > +typedef struct H266GeneralConstraintsInfo {
> > +    uint8_t gci_present_flag;
> > +} H266GeneralConstraintsInfo;
> > +
> > +typedef struct H266RawProfileTierLevel {
> > +    uint8_t general_profile_idc;
> > +    uint8_t general_tier_flag;
> > +    uint8_t general_level_idc;
> > +    uint8_t ptl_frame_only_constraint_flag;
> > +    uint8_t ptl_multilayer_enabled_flag;
> > +    H266GeneralConstraintsInfo general_constraints_info;
> > +    uint8_t ptl_sublayer_level_present_flag[H266_MAX_SUB_LAYERS - 1];
>
> That constant should be renamed to H266_MAX_SUBLAYERS, the standard never
> uses a space between them.
>
Done

>
> > +    uint8_t sublayer_level_idc[H266_MAX_SUB_LAYERS - 1];
> > +    uint8_t ptl_num_sub_profiles;
> > +    uint32_t general_sub_profile_idc[256];
>
> I think add an H266_MAX_SUB_PROFILES for this size.
>
> Done

> >
> > +    uint8_t num_ref_entries;
> > +    uint8_t ltrp_in_header_flag;
> > +    uint8_t inter_layer_ref_pic_flag[H266_MAX_DPB_SIZE + 13];
> > +    uint8_t st_ref_pic_flag[H266_MAX_DPB_SIZE + 13];
> > +    uint8_t abs_delta_poc_st[H266_MAX_DPB_SIZE + 13];
> > +    uint8_t strp_entry_sign_flag[H266_MAX_DPB_SIZE + 13];
> > +    uint8_t rpls_poc_lsb_lt[H266_MAX_DPB_SIZE + 13];
> > +    uint8_t ilrp_idx[H266_MAX_DPB_SIZE + 13];
> > +
> > +    //calculated values;
> > +    uint8_t num_ltrp_entries;
>
> Derived values really shouldn't be in the bitstream struct if it can be
> avoided.  In this case, it's calculated and used inline so you don't need
> to store it here.
>
Done, but I leave
num_tile_columns, num_tile_rows, num_tiles_in_pic,slice_height_in_ctus,
num_slices_in_subpic in H266RawPPS
They are needed by later functions

>
>
> > +
> > +static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx,
> RWContext *rw,
> > +                                    H266RawProfileTierLevel *current,
> > +                                    int profile_tire_present_flag,
>
> tire?
>
Fixed

>
>
> > +        fixed(1, ptl_reserved_zero_bit, 0);
> > +    for( i = max_num_sub_layers_minus1 - 1; i >= 0; i-- )
>
> The styling in this is inconsistent.  Put a space after a keyword, but not
> around parentheses (also in many more places below).
>
Fixed.

>
>
> > +
> > +    left = vui_payload_size * 8 - (end_pos - start_pos);
> > +    skip_bits(rw, left);
>
> This needs to record and regenerate the extension data to avoid breaking
> passthrough.  (Like other extension data cases.)
>
Done

>
>
> > +
> > +static int FUNC(dpb_parameters)(CodedBitstreamContext *ctx, RWContext
> *rw,
> > +                     H266DpbParameters *current, uint8_t
> max_sublayers_minus1, uint8_t sublayer_info_flag)
> > +{
> > +    int err, i;
> > +    for(i = ( sublayer_info_flag ? 0 : max_sublayers_minus1 ); i <=
> max_sublayers_minus1; i++ ) {
> > +        ues(dpb_max_dec_pic_buffering_minus1[i], 0, H266_MAX_DPB_SIZE -
> 1, 1, i);
> > +        ues(dpb_max_num_reorder_pics[i], 0,
> current->dpb_max_dec_pic_buffering_minus1[i], 1, i);
> > +        ues(dpb_max_latency_increase_plus1[i],  0, UINT32_MAX - 1, 1,
> i);
>
> Split lines to keep this to 80 characters.  Aligning the matching fields
> would be nice too.
>
Done

>
> > +
> > +static int FUNC(ref_pic_list_struct)(CodedBitstreamContext *ctx,
> RWContext *rw,
> > +                     H266RefPicListStruct *current, uint8_t list_idx,
> uint8_t rpls_idx,
> > +                     const H266RawSPS* const sps)
>
> * is part of the declarator, not the type.  We generally don't put
> redundant const on variables, either.
>
Fixed.

>
> > +{
> > +
> > +    int err, i, j;
> > +    ue(num_ref_entries, 0, H266_MAX_DPB_SIZE + 13);
>
> These fields all have more subscripts than you've included here.  Is there
> a sensible way to make the trace output match the standard?
>
This will make the code more complex.

> > +    CodedBitstreamH266Context *h266 = ctx->priv_data;
> > +    const H266RawSPS *sps = h266->active_sps;
> > +    const H266RawPPS *pps = h266->active_pps;
> > +    const H266RefPicListStruct* ref_list;
>
>   *
>
Done.

>
> > +    int err, i, j;
> > +    for (i = 0; i < 2; i++) {
> > +        if (sps->sps_num_ref_pic_lists[i] > 0 && (i == 0 || (i == 1 &&
> pps->pps_rpl1_idx_present_flag))) {
> > +            flags(rpl_sps_flag[i], 1, i);
> > +        } else {
> > +            if (!sps->sps_num_ref_pic_lists[i]) {
> > +                infer(rpl_sps_flag[i], 0);
> > +            } else {
> > +                if (!pps->pps_rpl1_idx_present_flag && i == 1)
> > +                    infer(rpl_sps_flag[1], current->rpl_sps_flag[0]);
> > +            }
> > +        }
> > +        if (current->rpl_sps_flag[i]) {
> > +            if(sps->sps_num_ref_pic_lists[i] > 1 && (i == 0 || ( i == 1
> && pps->pps_rpl1_idx_present_flag))) {
> > +                us(ceil(log2(sps->sps_num_ref_pic_lists[i])),
> rpl_idx[i], 0, sps->sps_num_ref_pic_lists[i] - 1, 1, i);
>
> Don't use floating point arithmetic.  There is av_log2() for integers.
>
Fixed.

>
> > +            } else if (sps->sps_num_ref_pic_lists[i] == 1) {
> > +                infer(rpl_idx[i], 0);
> > +            } else if (i == 1 && !pps->pps_rpl1_idx_present_flag){
> > +                infer(rpl_idx[1], current->rpl_idx[0]);
> > +            } else {
> > +                //how to handle this? or never happpend?
>
> This sort of thing needs to be resolved.
>
> I think the other conditions are a cover?
>
not sure, if this true,  we can change "if (i == 1 &&
!pps->pps_rpl1_idx_present_flag)"  to "else"
Let us leave it here, maybe we can find some clips that goes to this
branch, it will help us find the issue quickly.

>
>
> > +        if(current->general_du_hrd_params_present_flag)
> > +            ub(8, tick_divisor_minus2);
> > +        ub(4, bit_rate_scale);
> > +        ub(4, cpb_size_scale);
> > +        if(current->general_du_hrd_params_present_flag)
> > +            ub(4, cpb_size_du_scale);
> > +        ue(hrd_cpb_cnt_minus1, 0, 31);
> > +    } else {
> > +        //infer general_same_pic_timing_in_all_ols_flag?
>
> Looks like it should be, though the standard doesn't actually state it the
> way it does with general_du_hrd_params_present_flag.
>
But not many places use this flag. let us leave the question mark here, it
may help debug later.

>
>
> > +
> > +    ub(4, sps_seq_parameter_set_id);
> > +    ub(4, sps_video_parameter_set_id);
> > +    h266->active_vps = vps =
> h266->vps[current->sps_video_parameter_set_id];
>
> Not if sps_video_parameter_set_id == 0.
>
> Should we be making an implied VPS in that case?
>
done

>
>
> > +
> > +    flag(sps_conformance_window_flag);
> > +    if (current->sps_conformance_window_flag) {
> > +        ue(sps_conf_win_left_offset,    0,
> current->sps_pic_width_max_in_luma_samples);
> > +        ue(sps_conf_win_right_offset,   0,
> current->sps_pic_width_max_in_luma_samples);
> > +        ue(sps_conf_win_top_offset,     0,
> current->sps_pic_height_max_in_luma_samples);
> > +        ue(sps_conf_win_bottom_offset,   0,
> current->sps_pic_height_max_in_luma_samples);
>
> These bounds aren't right, because the value is post-subsampling.  Divide
> by SubWidthC.
>
Fixed.

>
> > +    } else {
> > +        infer(sps_conf_win_left_offset,     0);
> > +        infer(sps_conf_win_right_offset,    0);
> > +        infer(sps_conf_win_top_offset,      0);
> > +        infer(sps_conf_win_bottom_offset,    0);
> > +    }
> > +    flag(sps_subpic_info_present_flag);
> > +    if (current->sps_subpic_info_present_flag) {
> > +        av_log(ctx->log_ctx, AV_LOG_ERROR, "subpic is not supported
> yet\n");
> > +        return AVERROR_PATCHWELCOME;
> > +    } else {
> > +        infer(sps_num_subpics_minus1, 0);
> > +        infer(sps_independent_subpics_flag, 1);
> > +        infer(sps_subpic_same_size_flag, 0);
> > +        //?sps_subpic_id_len_minus1;
>
> Doesn't matter, because subpic_id fields don't appear if no subpics.
>
Fixed

>
> > +        infer(sps_subpic_id_mapping_explicitly_signalled_flag, 0);
> > +
> > +    }
> > +
> > +    ue(sps_bitdepth_minus8,   0, 2);
> > +    current->qp_bd_offset = 6 * current->sps_bitdepth_minus8;
>
> QpBdOffset isn't a bitstream value and is only used in this function, so
> put it on the stack.
>
Fixed.

>
>
> > +    u(2, sps_num_extra_sh_bytes, 0, 0);
> > +    for (i = 0; i < (current->sps_num_extra_sh_bytes * 8 ); i++) {
> > +        flags(sps_extra_sh_bit_present_flag[i], 1, i);
> > +    }
> > +    current->num_extra_sh_bits =
> get_extra_bits(current->sps_extra_sh_bit_present_flag,
> current->sps_num_extra_sh_bytes);
>
> Don't include the derived NumExtra[PS]hBits fields in the raw SPS
> structure.  They can trivially be recalculated when used, so I think do it
> there.
>
Fixed

>
>
> > +
> > +    ue(sps_log2_diff_min_qt_min_cb_intra_slice_luma, 0, FFMIN(6,
> ctb_log2_size_y) - min_cb_log2_size_y);
> > +    min_qt_log2_size_intra_y =
> current->sps_log2_diff_min_qt_min_cb_intra_slice_luma + min_cb_log2_size_y;
> > +
> > +    ue(sps_max_mtt_hierarchy_depth_intra_slice_luma, 0, 2 *
> (ctb_log2_size_y - min_cb_log2_size_y));
> > +
> > +    if (current->sps_max_mtt_hierarchy_depth_intra_slice_luma) {
>
> Try to use the same styling as the standard as far as possible, so != 0 if
> it isn't a flag.
>
Done

>
>
> > +
> > +    flag(sps_transform_skip_enabled_flag);
> > +    if (current->sps_transform_skip_enabled_flag) {
> > +        ue(sps_log2_transform_skip_max_size_minus2, 0, 3);
> > +        flag(sps_bdpcm_enabled_flag);
> > +    }
> > +
> > +    ...
>
> I haven't read through all of this in detail.  It needs at least one other
> person to check through and compare against the standard.
>
>
> > +    }
> > +
> > +    flag(sps_extension_flag);
> > +    if (current->sps_extension_flag) {
> > +        return AVERROR_PATCHWELCOME;
>
> Also wanted for passthrough.
>
Done

>
>
> > +static const uint8_t h266_sub_width_c[] = {
> > +    1, 2, 2, 1
> > +};
> > +
> > +static const uint8_t h266_sub_height_c[] = {
> > +    1, 2, 1, 1
> > +};
>
> You can't put fixed tables here, because the file is included twice.
>
> These can be inside the function below.
>
Fixed

>
> > +
> > +static int get_num_tile(const uint16_t* pps_tile_size_minus1, uint16_t
> num_exp_tile_minus1, unsigned int pic_size_in_ctbs_y, unsigned int
> exp_tile_size)
> > +{
> > +    uint16_t uniform_size = pps_tile_size_minus1[num_exp_tile_minus1] +
> 1;
> > +    unsigned int left = pic_size_in_ctbs_y - exp_tile_size;
> > +    return num_exp_tile_minus1 + 1 + (left + uniform_size - 1) /
> uniform_size;
> > +}
>
> Likewise functions.
>
> The derived tile values don't want to go in the bitstream value structure,
> anyway.  They can be calculated locally here.
>
It's not so easy to calc, also if cbs became the start point of the native
decoder, we may need to put more derived value to sps,pps, slice header.


> >
> > +
> > +    if(!current->pps_no_pic_partition_flag ) {
> > +        unsigned int exp_tile_width = 0, exp_tile_height = 0;
> > +        pic_width_in_ctbs_y =
> ceil(current->pps_pic_width_in_luma_samples / (double)ctb_size_y);
> > +        pic_height_in_ctbs_y =
> ceil(current->pps_pic_height_in_luma_samples / (double)ctb_size_y);
>
> Don't use floating point.  (int)ceil((double)a/b) == (a + b - 1) / b
>
Fixed.

>
> > +
> > +
> > +    flag(aud_irap_or_gdr_flag);
> > +    ub(3, aud_pic_type);
>
> Range is 0 .. 2.
>
Fixed

>
>
> > +    flag(ph_inter_slice_allowed_flag);
> > +    if (current->ph_inter_slice_allowed_flag)
> > +        flag(ph_intra_slice_allowed_flag);
> > +    else
> > +        infer(ph_intra_slice_allowed_flag, 1);
> > +    ue(ph_pic_parameter_set_id, 0, 63);
>
> H266_MAX_PPS_COUNT - 1
>
Fixed

>
> > +
> > +    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, &h266->ph));
>
> That's not going to work.  The picture header needs to be a substructure
> of slice header to regenerate correctly.
>
> To fill in other slices, a copy might be needed.  I'm not sure what the
> best way of doing that is - maybe the other slices should fill their own
> picture header with the original one as if inferred?
>
See  description for sh_picture_header_in_slice_header_flag.  One PU can
only have one picture header,
In the second version, I will read/write to slice->*sh_picture_header and
copy back to *h266->ph

> > +    }
> > +    sps = h266->active_sps;
> > +    pps = h266->active_pps;
> > +    ph  = &h266->ph;
> > +
> > +    if (!sps || !pps) {
> > +        av_log(ctx->log_ctx, AV_LOG_ERROR, "no sps(%p) or pps(%p).\n",
> sps, pps);
> > +        return AVERROR_INVALIDDATA;
> > +    }
> > +
> > +    if(sps->sps_subpic_info_present_flag)
> > +        ub(sps->sps_subpic_id_len_minus1 + 1, sh_subpic_id);
> > +    if (pps->pps_rect_slice_flag)
> > +        return AVERROR_PATCHWELCOME;
> > +    if((!pps->pps_rect_slice_flag && pps->num_tiles_in_pic > 1)) {
> > +        unsigned int bits, max;
> > +        if (!pps->pps_rect_slice_flag) {
> > +            bits = ceil(log2(pps->num_tiles_in_pic));
>
> Floating point.
>
Fixed

>
> > +            max = pps->num_tiles_in_pic - 1;
> > +        } else {
> > +            return AVERROR_PATCHWELCOME;
> > +        }
> > +        u(bits, sh_slice_address, 0, max);
> > +    } else {
> > +        infer(sh_slice_address, 0);
> > +    }
> > +
> > +    ...
> > +    if(pps->pps_slice_header_extension_present_flag) {
> > +        return AVERROR_PATCHWELCOME;
> > +    }
> > +    if(sps->sps_entry_point_offsets_present_flag)  {
> > +        unsigned int num_entry_points = 0;
> > +        if (pps->pps_rect_slice_flag) {
> > +            return AVERROR_PATCHWELCOME;
> > +        } else {
> > +            unsigned int tile_idx;
> > +            for (tile_idx = current->sh_slice_address; tile_idx <=
> current->sh_slice_address + current->sh_num_tiles_in_slice_minus1;
> tile_idx++) {
> > +                unsigned int tile_y, height;
> > +                tile_y = tile_idx / pps->num_tile_rows;
> > +                height = pps->pps_tile_row_height_minus1[FFMIN(tile_y,
> pps->pps_num_exp_tile_rows_minus1)] + 1;
> > +                num_entry_points +=
> (sps->sps_entropy_coding_sync_enabled_flag ? height : 1);
> > +            }
> > +            num_entry_points--;
> > +        }
> > +        infer(num_entry_point_offsets, num_entry_points);
> > +        if (num_entry_points > H266_MAX_ENTRY_POINT_OFFSETS) {
> > +            av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many entry points: "
> > +               "%"PRIu16".\n", current->num_entry_point_offsets);
> > +            return AVERROR_PATCHWELCOME;
> > +        }
> > +        if (num_entry_points > 0) {
> > +            ue(sh_entry_offset_len_minus1, 0, 31);
> > +            for (i = 0; i < num_entry_points; i++) {
> > +                ubs(current->sh_entry_offset_len_minus1,
> sh_entry_point_offset_minus1[i], 1, i);
> > +            }
> > +        }
> > +    }
> > +    CHECK(FUNC(byte_alignment)(ctx, rw));
> > +
> > +    return 0;
> > +}
> > +
> > +static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw,
> > +                     H266RawSEI *current, int prefix)
> > +{
> > +    return 0;
> > +}
>
> - Mark
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-devel mailing list