mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2026-10-28 18:15:24 +08:00
Samples made following the current (for now) faulty specification may not
include alignment bits at the end of VUI parameters, so instead of erroring
out, warn about it and keep going.
In a writing scenario, like the lcevc_metadata bsf, the output bitstream will
be written with them.
Signed-off-by: James Almer <jamrial@gmail.com>
(cherry picked from commit 0f7eec026c)
680 lines
21 KiB
C
680 lines
21 KiB
C
/*
|
|
* This file is part of FFmpeg.
|
|
*
|
|
* FFmpeg is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* FFmpeg is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with FFmpeg; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw)
|
|
{
|
|
int err;
|
|
|
|
// ISO/IEC 23094-2:2021/FDAM 1:2023(E) 7.3.12
|
|
while (byte_alignment(rw) != 0)
|
|
fixed(1, alignment_bit_equal_to_zero, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw)
|
|
{
|
|
int err;
|
|
|
|
fixed(1, rbsp_stop_one_bit, 1);
|
|
while (byte_alignment(rw) != 0)
|
|
fixed(1, rbsp_alignment_zero_bit, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawNALUnitHeader *current,
|
|
uint32_t valid_type_mask)
|
|
{
|
|
int err;
|
|
|
|
fixed(1, forbidden_zero_bit, 0);
|
|
fixed(1, forbidden_one_bit, 1);
|
|
ub(5, nal_unit_type);
|
|
|
|
if (!(1 << current->nal_unit_type & valid_type_mask)) {
|
|
av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid NAL unit type %d.\n",
|
|
current->nal_unit_type);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
ub(9, reserved_flag);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LCEVC_BLOCK_FUNC(global_config, (CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawGlobalConfig *current,
|
|
LCEVCProcessBlockState *state,
|
|
int nal_unit_type))
|
|
{
|
|
CodedBitstreamLCEVCContext *priv = ctx->priv_data;
|
|
int err;
|
|
|
|
HEADER("Global Config");
|
|
|
|
flag(processed_planes_type_flag);
|
|
ub(6, resolution_type);
|
|
ub(1, transform_type);
|
|
ub(2, chroma_sampling_type);
|
|
ub(2, base_depth_type);
|
|
ub(2, enhancement_depth_type);
|
|
flag(temporal_step_width_modifier_signalled_flag);
|
|
flag(predicted_residual_mode_flag);
|
|
flag(temporal_tile_intra_signalling_enabled_flag);
|
|
flag(temporal_enabled_flag);
|
|
ub(3, upsample_type);
|
|
flag(level1_filtering_signalled_flag);
|
|
ub(2, scaling_mode_level1);
|
|
ub(2, scaling_mode_level2);
|
|
ub(2, tile_dimensions_type);
|
|
ub(2, user_data_enabled);
|
|
flag(level1_depth_flag);
|
|
flag(chroma_step_width_flag);
|
|
|
|
if (current->processed_planes_type_flag) {
|
|
ub(4, planes_type);
|
|
ub(4, reserved_zeros_4bit);
|
|
} else
|
|
infer(planes_type, 0);
|
|
|
|
if (current->temporal_step_width_modifier_signalled_flag) {
|
|
ub(8, temporal_step_width_modifier);
|
|
}
|
|
|
|
if (current->upsample_type == 4) {
|
|
ub(16, upsampler_coeff1);
|
|
ub(16, upsampler_coeff2);
|
|
ub(16, upsampler_coeff3);
|
|
ub(16, upsampler_coeff4);
|
|
}
|
|
|
|
if (current->level1_filtering_signalled_flag) {
|
|
ub(4, level1_filtering_first_coefficient);
|
|
ub(4, level1_filtering_second_coefficient);
|
|
}
|
|
|
|
if (current->tile_dimensions_type > 0) {
|
|
if (current->tile_dimensions_type == 3) {
|
|
ub(16, custom_tile_width);
|
|
ub(16, custom_tile_height);
|
|
}
|
|
ub(5, reserved_zeros_5bit);
|
|
flag(compression_type_entropy_enabled_per_tile_flag);
|
|
ub(2, compression_type_size_per_tile);
|
|
}
|
|
|
|
if (current->resolution_type == 63) {
|
|
ub(16, custom_resolution_width);
|
|
ub(16, custom_resolution_height);
|
|
}
|
|
if (current->chroma_step_width_flag) {
|
|
ub(8, chroma_step_width_multiplier);
|
|
} else {
|
|
infer(chroma_step_width_multiplier, 64);
|
|
}
|
|
|
|
av_refstruct_replace(&priv->gc, current);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LCEVC_BLOCK_FUNC(sequence_config, (CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawSequenceConfig *current,
|
|
LCEVCProcessBlockState *state,
|
|
int nal_unit_type))
|
|
{
|
|
CodedBitstreamLCEVCContext *priv = ctx->priv_data;
|
|
int err;
|
|
|
|
HEADER("Sequence Config");
|
|
|
|
ub(4, profile_idc);
|
|
ub(4, level_idc);
|
|
ub(2, sublevel_idc);
|
|
flag(conformance_window_flag);
|
|
ub(5, reserved_zeros_5bit);
|
|
|
|
if (current->profile_idc == 15 || current->level_idc == 15) {
|
|
ub(3, profile_idc);
|
|
ub(4, level_idc);
|
|
ub(1, reserved_zeros_1bit);
|
|
}
|
|
if (current->conformance_window_flag == 1) {
|
|
mb(conf_win_left_offset);
|
|
mb(conf_win_right_offset);
|
|
mb(conf_win_top_offset);
|
|
mb(conf_win_bottom_offset);
|
|
}
|
|
|
|
av_refstruct_replace(&priv->sc, current);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LCEVC_BLOCK_FUNC(picture_config, (CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawPictureConfig *current,
|
|
LCEVCProcessBlockState *state,
|
|
int nal_unit_type))
|
|
{
|
|
CodedBitstreamLCEVCContext *priv = ctx->priv_data;
|
|
int nlayers, err;
|
|
|
|
HEADER("Picture Config");
|
|
|
|
if (!priv->gc)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
flag(no_enhancement_bit_flag);
|
|
if (current->no_enhancement_bit_flag == 0) {
|
|
ub(3, quant_matrix_mode);
|
|
flag(dequant_offset_signalled_flag);
|
|
flag(picture_type_bit_flag);
|
|
flag(temporal_refresh_bit_flag);
|
|
flag(step_width_sublayer1_enabled_flag);
|
|
ub(15, step_width_sublayer2);
|
|
flag(dithering_control_flag);
|
|
priv->dithering_control_flag = current->dithering_control_flag;
|
|
infer(temporal_signalling_present_flag, priv->gc->temporal_enabled_flag &&
|
|
!current->temporal_refresh_bit_flag);
|
|
} else {
|
|
infer(quant_matrix_mode, 0);
|
|
infer(dequant_offset_signalled_flag, 0);
|
|
ub(4, reserved_zeros_4bit);
|
|
flag(picture_type_bit_flag);
|
|
flag(temporal_refresh_bit_flag);
|
|
infer(step_width_sublayer1_enabled_flag, 0);
|
|
infer(dithering_control_flag, nal_unit_type == LCEVC_IDR_NUT
|
|
? 0
|
|
: priv->dithering_control_flag);
|
|
priv->dithering_control_flag = current->dithering_control_flag;
|
|
flag(temporal_signalling_present_flag);
|
|
}
|
|
|
|
if (current->picture_type_bit_flag == 1) {
|
|
flag(field_type_bit_flag);
|
|
ub(7, reserved_zeros_7bit);
|
|
}
|
|
|
|
if (current->step_width_sublayer1_enabled_flag == 1) {
|
|
ub(15, step_width_sublayer1);
|
|
flag(level1_filtering_enabled_flag);
|
|
} else
|
|
infer(level1_filtering_enabled_flag, 0);
|
|
|
|
nlayers = priv->gc->transform_type ? 16 : 4;
|
|
if (current->quant_matrix_mode == 2 ||
|
|
current->quant_matrix_mode == 3 ||
|
|
current->quant_matrix_mode == 5) {
|
|
for (int layer_idx = 0; layer_idx < nlayers; layer_idx++)
|
|
ubs(8, qm_coefficient_0[layer_idx], 1, layer_idx);
|
|
}
|
|
|
|
if (current->quant_matrix_mode == 4 || current->quant_matrix_mode == 5) {
|
|
for (int layer_idx = 0; layer_idx < nlayers; layer_idx++)
|
|
ubs(8, qm_coefficient_1[layer_idx], 1, layer_idx);
|
|
}
|
|
|
|
if (current->dequant_offset_signalled_flag) {
|
|
flag(dequant_offset_mode_flag);
|
|
ub(7, dequant_offset);
|
|
}
|
|
|
|
if (current->dithering_control_flag == 1) {
|
|
ub(2, dithering_type);
|
|
ub(1, reserverd_zero);
|
|
if (current->dithering_type != 0) {
|
|
ub(5, dithering_strength);
|
|
} else {
|
|
ub(5, reserved_zeros_5bit);
|
|
}
|
|
}
|
|
|
|
av_refstruct_replace(&priv->pc, current);
|
|
av_refstruct_replace(¤t->gc, priv->gc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
LCEVC_BLOCK_FUNC(encoded_data, (CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawEncodedData *current,
|
|
LCEVCProcessBlockState *state,
|
|
int nal_unit_type))
|
|
{
|
|
CodedBitstreamLCEVCContext *priv = ctx->priv_data;
|
|
int nplanes, nlayers, err;
|
|
#ifdef READ
|
|
int start = get_bits_count(rw);
|
|
#endif
|
|
|
|
HEADER("Encoded Data");
|
|
|
|
if (!priv->gc || !priv->pc)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
nplanes = priv->gc->planes_type ? 3 : 1;
|
|
nlayers = priv->gc->transform_type ? 16 : 4;
|
|
for (int plane_idx = 0; plane_idx < nplanes; plane_idx++) {
|
|
if (priv->pc->no_enhancement_bit_flag == 0) {
|
|
for (int level_idx = 1; level_idx <= 2; level_idx++) {
|
|
for (int layer_idx = 0; layer_idx < nlayers; layer_idx++) {
|
|
ubs(1, surfaces_entropy_enabled_flag[plane_idx][level_idx][layer_idx], 3, plane_idx, level_idx, layer_idx);
|
|
ubs(1, surfaces_rle_only_flag[plane_idx][level_idx][layer_idx], 3, plane_idx, level_idx, layer_idx);
|
|
}
|
|
}
|
|
}
|
|
if (priv->pc->temporal_signalling_present_flag == 1) {
|
|
ubs(1, temporal_surfaces_entropy_enabled_flag[plane_idx], 1, plane_idx);
|
|
ubs(1, temporal_surfaces_rle_only_flag[plane_idx], 1, plane_idx);
|
|
}
|
|
}
|
|
|
|
CHECK(FUNC(byte_alignment)(ctx, rw));
|
|
|
|
#ifdef READ
|
|
if (!ff_cbs_h2645_read_more_rbsp_data(rw))
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
int pos = get_bits_count(rw) - start;
|
|
int len = state->payload_size;
|
|
|
|
current->header_size = pos / 8;
|
|
current->data_size = len - pos / 8;
|
|
skip_bits_long(rw, current->data_size * 8);
|
|
#else
|
|
err = ff_cbs_h2645_write_slice_data(ctx, rw, current->data,
|
|
current->data_size, 0);
|
|
if (err < 0)
|
|
return err;
|
|
#endif
|
|
|
|
av_refstruct_replace(¤t->sc, priv->sc);
|
|
av_refstruct_replace(¤t->gc, priv->gc);
|
|
av_refstruct_replace(¤t->pc, priv->pc);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawSEI *current, int payload_size)
|
|
{
|
|
SEIRawMessage *message = ¤t->message;
|
|
int sei_type;
|
|
int i, err;
|
|
|
|
ub(8, payload_type);
|
|
|
|
if (current->payload_type == 1)
|
|
sei_type = SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME;
|
|
else if (current->payload_type == 2)
|
|
sei_type = SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO;
|
|
else if (current->payload_type == 4)
|
|
sei_type = SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35;
|
|
else if (current->payload_type == 5)
|
|
sei_type = SEI_TYPE_USER_DATA_UNREGISTERED;
|
|
else {
|
|
uint8_t *data;
|
|
|
|
#ifdef READ
|
|
current->payload_size = payload_size;
|
|
allocate(current->payload_ref, current->payload_size);
|
|
current->payload = current->payload_ref;
|
|
#else
|
|
allocate(current->payload, current->payload_size);
|
|
#endif
|
|
data = current->payload;
|
|
|
|
for (i = 0; i < current->payload_size; i++)
|
|
xu(8, reserved_sei_message_payload_byte[i], data[i], 0, 255, 1, i);
|
|
|
|
return 0;
|
|
}
|
|
|
|
message->payload_type = sei_type;
|
|
message->payload_size = payload_size;
|
|
|
|
CHECK(FUNC_SEI(message)(ctx, rw, message));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawVUI *current)
|
|
{
|
|
int err;
|
|
|
|
HEADER("VUI Parameters");
|
|
|
|
flag(aspect_ratio_info_present_flag);
|
|
if (current->aspect_ratio_info_present_flag) {
|
|
ub(8, aspect_ratio_idc);
|
|
|
|
if (current->aspect_ratio_idc == 255) {
|
|
ub(16, sar_width);
|
|
ub(16, sar_height);
|
|
}
|
|
} else {
|
|
infer(aspect_ratio_idc, 0);
|
|
}
|
|
|
|
flag(overscan_info_present_flag);
|
|
if (current->overscan_info_present_flag)
|
|
flag(overscan_appropriate_flag);
|
|
else
|
|
infer(overscan_appropriate_flag, 0);
|
|
|
|
flag(video_signal_type_present_flag);
|
|
if (current->video_signal_type_present_flag) {
|
|
u(3, video_format, 0, 5);
|
|
flag(video_full_range_flag);
|
|
flag(colour_description_present_flag);
|
|
if (current->colour_description_present_flag) {
|
|
ub(8, colour_primaries);
|
|
ub(8, transfer_characteristics);
|
|
ub(8, matrix_coefficients);
|
|
} else {
|
|
infer(colour_primaries, 2);
|
|
infer(transfer_characteristics, 2);
|
|
infer(matrix_coefficients, 2);
|
|
}
|
|
} else {
|
|
infer(video_format, 5);
|
|
infer(video_full_range_flag, 0);
|
|
infer(colour_description_present_flag, 0);
|
|
infer(colour_primaries, 2);
|
|
infer(transfer_characteristics, 2);
|
|
infer(matrix_coefficients, 2);
|
|
}
|
|
flag(chroma_loc_info_present_flag);
|
|
if (current->chroma_loc_info_present_flag) {
|
|
ue(chroma_sample_loc_type_top_field, 0, 5);
|
|
ue(chroma_sample_loc_type_bottom_field, 0, 5);
|
|
} else {
|
|
infer(chroma_sample_loc_type_top_field, 0);
|
|
infer(chroma_sample_loc_type_bottom_field, 0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LCEVC_BLOCK_FUNC(additional_info, (CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawAdditionalInfo *current,
|
|
LCEVCProcessBlockState *state,
|
|
int nal_unit_type))
|
|
{
|
|
int i, err;
|
|
|
|
HEADER("Additional Info");
|
|
|
|
ub(8, additional_info_type);
|
|
|
|
if (current->additional_info_type == LCEVC_ADDITIONAL_INFO_TYPE_SEI) {
|
|
CHECK(FUNC(sei_payload)(ctx, rw, ¤t->sei, state->payload_size - 2));
|
|
} else if (current->additional_info_type == LCEVC_ADDITIONAL_INFO_TYPE_VUI)
|
|
CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui));
|
|
else {
|
|
uint8_t *data;
|
|
|
|
#ifdef READ
|
|
current->payload_size = state->payload_size - 1;
|
|
allocate(current->payload_ref, current->payload_size);
|
|
current->payload = current->payload_ref;
|
|
#else
|
|
allocate(current->payload, current->payload_size);
|
|
#endif
|
|
data = current->payload;
|
|
|
|
for (i = 0; i < current->payload_size; i++)
|
|
xu(8, additional_info_byte[i], data[i], 0, 255, 1, i);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
LCEVC_BLOCK_FUNC(filler, (CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawFiller *current,
|
|
LCEVCProcessBlockState *state,
|
|
int nal_unit_type))
|
|
{
|
|
int err;
|
|
|
|
HEADER("Filler");
|
|
|
|
|
|
#ifdef READ
|
|
while (show_bits(rw, 8) == 0xaa) {
|
|
fixed(8, filler_byte, 0xaa);
|
|
++current->filler_size;
|
|
}
|
|
if (state->payload_size != current->filler_size)
|
|
return AVERROR_INVALIDDATA;
|
|
|
|
#else
|
|
for (int i = 0; i < current->filler_size; i++)
|
|
fixed(8, filler_byte, 0xaa);
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(process_block)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawProcessBlock *current,
|
|
int nal_unit_type)
|
|
{
|
|
const LCEVCProcessBlockTypeDescriptor *desc;
|
|
int err, i;
|
|
|
|
desc = ff_cbs_lcevc_process_block_find_type(ctx, current->payload_type);
|
|
if (desc) {
|
|
LCEVCProcessBlockState state = {
|
|
.payload_type = current->payload_type,
|
|
.payload_size = current->payload_size,
|
|
.extension_present = current->extension_bit_length > 0,
|
|
};
|
|
int start_position, current_position, bits_written;
|
|
|
|
#ifdef READ
|
|
CHECK(ff_cbs_lcevc_alloc_process_block_payload(current, desc));
|
|
#endif
|
|
|
|
start_position = bit_position(rw);
|
|
|
|
CHECK(desc->READWRITE(ctx, rw, current->payload, &state, nal_unit_type));
|
|
|
|
current_position = bit_position(rw);
|
|
bits_written = current_position - start_position;
|
|
|
|
if (byte_alignment(rw) || state.extension_present ||
|
|
bits_written < 8 * current->payload_size) {
|
|
size_t bits_left;
|
|
|
|
#ifdef READ
|
|
GetBitContext tmp = *rw;
|
|
int trailing_bits, trailing_zero_bits;
|
|
|
|
bits_left = 8 * current->payload_size - bits_written;
|
|
if (bits_left > 8)
|
|
skip_bits_long(&tmp, bits_left - 8);
|
|
trailing_bits = get_bits(&tmp, FFMIN(bits_left, 8));
|
|
if (trailing_bits == 0) {
|
|
// The trailing bits must contain a payload_bit_equal_to_one, so
|
|
// they can't all be zero.
|
|
// Don't error out as encodings following a faulty specification
|
|
// syntax trigger this.
|
|
av_log(ctx->log_ctx, AV_LOG_DEBUG, "Missing alignment bits in Process Block\n");
|
|
return 0;
|
|
}
|
|
trailing_zero_bits = ff_ctz(trailing_bits);
|
|
current->extension_bit_length =
|
|
bits_left - 1 - trailing_zero_bits;
|
|
#endif
|
|
|
|
if (current->extension_bit_length > 0) {
|
|
allocate(current->extension_data,
|
|
(current->extension_bit_length + 7) / 8);
|
|
|
|
bits_left = current->extension_bit_length;
|
|
for (i = 0; bits_left > 0; i++) {
|
|
int length = FFMIN(bits_left, 8);
|
|
xu(length, reserved_payload_extension_data,
|
|
current->extension_data[i],
|
|
0, MAX_UINT_BITS(length), 0);
|
|
bits_left -= length;
|
|
}
|
|
}
|
|
|
|
fixed(1, payload_bit_equal_to_one, 1);
|
|
while (byte_alignment(rw))
|
|
fixed(1, payload_bit_equal_to_zero, 0);
|
|
}
|
|
|
|
#ifdef WRITE
|
|
current->payload_size = (put_bits_count(rw) - start_position) / 8;
|
|
#endif
|
|
} else {
|
|
uint8_t *data;
|
|
|
|
#ifdef READ
|
|
allocate(current->payload_ref, current->payload_size);
|
|
current->payload = current->payload_ref;
|
|
#else
|
|
allocate(current->payload, current->payload_size);
|
|
#endif
|
|
data = current->payload;
|
|
|
|
for (i = 0; i < current->payload_size; i++)
|
|
xu(8, payload_byte[i], data[i], 0, 255, 1, i);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(process_block_list)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawProcessBlockList *current,
|
|
int nal_unit_type)
|
|
{
|
|
LCEVCRawProcessBlock *block;
|
|
int err, k;
|
|
|
|
#ifdef READ
|
|
for (k = 0;; k++) {
|
|
int payload_size_type;
|
|
int payload_type;
|
|
uint32_t payload_size;
|
|
uint32_t tmp;
|
|
GetBitContext payload_gbc;
|
|
|
|
HEADER("Process Block");
|
|
|
|
xu(3, payload_size_type, tmp, 0, MAX_UINT_BITS(3), 0);
|
|
payload_size_type = tmp;
|
|
xu(5, payload_type, tmp, 0, MAX_UINT_BITS(5), 0);
|
|
payload_type = tmp;
|
|
|
|
if (payload_size_type == 6) {
|
|
av_log(ctx->log_ctx, AV_LOG_ERROR, "payload_size_type == 6\n");
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
|
|
payload_size = payload_size_type;
|
|
if (payload_size_type == 7)
|
|
xmb(custom_byte_size, payload_size);
|
|
|
|
// There must be space remaining for the payload
|
|
if (payload_size > get_bits_left(rw) / 8) {
|
|
av_log(ctx->log_ctx, AV_LOG_ERROR,
|
|
"Invalid process block: payload_size too large "
|
|
"(%"PRIu32" bytes).\n", payload_size);
|
|
return AVERROR_INVALIDDATA;
|
|
}
|
|
CHECK(init_get_bits(&payload_gbc, rw->buffer,
|
|
get_bits_count(rw) + 8 * payload_size));
|
|
skip_bits_long(&payload_gbc, get_bits_count(rw));
|
|
|
|
CHECK(ff_cbs_lcevc_list_add(current, -1));
|
|
block = ¤t->blocks[k];
|
|
|
|
block->payload_type = payload_type;
|
|
block->payload_size = payload_size;
|
|
|
|
CHECK(FUNC(process_block)(ctx, &payload_gbc, block, nal_unit_type));
|
|
|
|
skip_bits_long(rw, 8 * payload_size);
|
|
|
|
if (!ff_cbs_h2645_read_more_rbsp_data(rw))
|
|
break;
|
|
}
|
|
#else
|
|
for (k = 0; k < current->nb_blocks; k++) {
|
|
PutBitContext start_state;
|
|
uint32_t tmp;
|
|
int trace, i;
|
|
|
|
block = ¤t->blocks[k];
|
|
|
|
// We write the payload twice in order to find the size. Trace
|
|
// output is switched off for the first write.
|
|
trace = ctx->trace_enable;
|
|
ctx->trace_enable = 0;
|
|
|
|
start_state = *rw;
|
|
for (i = 0; i < 2; i++) {
|
|
*rw = start_state;
|
|
|
|
tmp = FFMIN(block->payload_size, 7);
|
|
if (tmp == 6)
|
|
tmp = 7;
|
|
xu(3, payload_size_type, tmp, 0, 7, 0);
|
|
xu(5, payload_type, block->payload_type, 0, MAX_UINT_BITS(5), 0);
|
|
|
|
if (tmp == 7)
|
|
xmb(custom_byte_size, block->payload_size);
|
|
|
|
err = FUNC(process_block)(ctx, rw, block, nal_unit_type);
|
|
ctx->trace_enable = trace;
|
|
if (err < 0)
|
|
return err;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int FUNC(nal)(CodedBitstreamContext *ctx, RWContext *rw,
|
|
LCEVCRawNAL *current, int nal_unit_type)
|
|
{
|
|
int err;
|
|
|
|
if (nal_unit_type == LCEVC_NON_IDR_NUT)
|
|
HEADER("Non IDR");
|
|
else
|
|
HEADER("IDR");
|
|
|
|
CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header,
|
|
(1 << LCEVC_IDR_NUT) | (1 << LCEVC_NON_IDR_NUT)));
|
|
|
|
CHECK(FUNC(process_block_list) (ctx, rw, ¤t->process_block_list,
|
|
current->nal_unit_header.nal_unit_type));
|
|
|
|
CHECK(FUNC(rbsp_trailing_bits)(ctx, rw));
|
|
|
|
return 0;
|
|
}
|