| /* |
| * Copyright (c) 2021, Alliance for Open Media. All rights reserved |
| * |
| * This source code is subject to the terms of the BSD 3-Clause Clear License |
| * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear |
| * License was not distributed with this source code in the LICENSE file, you |
| * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the |
| * Alliance for Open Media Patent License 1.0 was not distributed with this |
| * source code in the PATENTS file, you can obtain it at |
| * aomedia.org/license/patent-license/. |
| */ |
| |
| #include <assert.h> |
| |
| #include "config/avm_config.h" |
| #include "av2/common/banding_metadata.h" |
| #include "config/avm_scale_rtcd.h" |
| |
| #include "avm/avm_codec.h" |
| #include "avm_dsp/bitreader_buffer.h" |
| #include "avm_mem/avm_mem.h" |
| #include "avm_ports/mem_ops.h" |
| |
| #include "av2/common/common.h" |
| #include "av2/common/obu_util.h" |
| #include "av2/common/level.h" |
| #include "av2/common/timing.h" |
| #include "av2/decoder/decoder.h" |
| #include "av2/decoder/decodeframe.h" |
| #include "av2/decoder/obu.h" |
| #include "av2/common/enums.h" |
| #include "av2/common/annexA.h" |
| #include "av2/decoder/annexF.h" |
| |
| static uint32_t read_temporal_delimiter_obu() { return 0; } |
| |
| // Returns a boolean that indicates success. |
| static int read_bitstream_level(AV2_LEVEL *seq_level_idx, |
| struct avm_read_bit_buffer *rb) { |
| *seq_level_idx = avm_rb_read_literal(rb, LEVEL_BITS); |
| if (!is_valid_seq_level_idx(*seq_level_idx)) return 0; |
| return 1; |
| } |
| |
| static void av2_read_tlayer_dependency_info(SequenceHeader *const seq, |
| struct avm_read_bit_buffer *rb) { |
| const int max_mlayer_id = seq->max_mlayer_id; |
| const int max_tlayer_id = seq->max_tlayer_id; |
| const int multi_tlayer_flag = seq->multi_tlayer_dependency_map_present_flag; |
| for (int curr_mlayer_id = 0; curr_mlayer_id <= max_mlayer_id; |
| curr_mlayer_id++) { |
| for (int curr_tlayer_id = 1; curr_tlayer_id <= max_tlayer_id; |
| curr_tlayer_id++) { |
| for (int ref_tlayer_id = curr_tlayer_id; ref_tlayer_id >= 0; |
| ref_tlayer_id--) { |
| if (multi_tlayer_flag > 0 || curr_mlayer_id == 0) { |
| seq->tlayer_dependency_map[curr_mlayer_id][curr_tlayer_id] |
| [ref_tlayer_id] = avm_rb_read_bit(rb); |
| } else { |
| seq->tlayer_dependency_map[curr_mlayer_id][curr_tlayer_id] |
| [ref_tlayer_id] = |
| seq->tlayer_dependency_map[0][curr_tlayer_id][ref_tlayer_id]; |
| } |
| } |
| } |
| } |
| } |
| |
| static void av2_read_mlayer_dependency_info(SequenceHeader *const seq, |
| struct avm_read_bit_buffer *rb) { |
| const int max_mlayer_id = seq->max_mlayer_id; |
| for (int curr_mlayer_id = 1; curr_mlayer_id <= max_mlayer_id; |
| curr_mlayer_id++) { |
| for (int ref_mlayer_id = curr_mlayer_id; ref_mlayer_id >= 0; |
| ref_mlayer_id--) { |
| seq->mlayer_dependency_map[curr_mlayer_id][ref_mlayer_id] = |
| avm_rb_read_bit(rb); |
| } |
| } |
| } |
| |
| // This function validates the conformance window params |
| static void av2_validate_seq_conformance_window( |
| const struct SequenceHeader *seq_params, |
| struct avm_internal_error_info *error_info) { |
| const struct CropWindow *conf = &seq_params->conf; |
| if (!conf->conf_win_enabled_flag) return; |
| |
| if (conf->conf_win_left_offset >= seq_params->max_frame_width) { |
| avm_internal_error( |
| error_info, AVM_CODEC_UNSUP_BITSTREAM, |
| "Conformance window left offset %d exceeds max width %d\n", |
| conf->conf_win_left_offset, seq_params->max_frame_width); |
| } |
| |
| if (conf->conf_win_right_offset >= seq_params->max_frame_width) { |
| avm_internal_error( |
| error_info, AVM_CODEC_UNSUP_BITSTREAM, |
| "Conformance window right offset %d exceeds max width %d\n", |
| conf->conf_win_right_offset, seq_params->max_frame_width); |
| } |
| |
| if (conf->conf_win_top_offset >= seq_params->max_frame_height) { |
| avm_internal_error( |
| error_info, AVM_CODEC_UNSUP_BITSTREAM, |
| "Conformance window top offset %d exceeds max height %d\n", |
| conf->conf_win_top_offset, seq_params->max_frame_height); |
| } |
| |
| if (conf->conf_win_bottom_offset >= seq_params->max_frame_height) { |
| avm_internal_error( |
| error_info, AVM_CODEC_UNSUP_BITSTREAM, |
| "Conformance window bottom offset %d exceeds max height %d\n", |
| conf->conf_win_bottom_offset, seq_params->max_frame_height); |
| } |
| } |
| |
| // Returns whether two sequence headers are consistent with each other. |
| // Note that the 'op_params' field is not compared per Section 7.5 in the spec: |
| // Within a particular coded video sequence, the contents of |
| // sequence_header_obu must be bit-identical each time the sequence header |
| // appears except for the contents of operating_parameters_info. |
| int are_seq_headers_consistent(const SequenceHeader *seq_params_old, |
| const SequenceHeader *seq_params_new) { |
| return !memcmp(seq_params_old, seq_params_new, |
| offsetof(SequenceHeader, op_params)); |
| } |
| |
| void av2_read_color_info(int *color_description_idc, int *color_primaries, |
| int *transfer_characteristics, |
| int *matrix_coefficients, int *full_range_flag, |
| struct avm_read_bit_buffer *rb) { |
| // color_description_idc: indicates the combination of color primaries, |
| // transfer characteristics and matrix coefficients as defined in Section |
| // 6.10.4 (Operating point set color info semantics) in the spec. |
| // The value of color_description_idc shall be in the range of 0 to 127, |
| // inclusive. Values larger than 5 are reserved for future use by AOMedia and |
| // should be ignored by decoders conforming to this version of this |
| // specification. |
| *color_description_idc = avm_rb_read_rice_golomb(rb, 2); |
| if (*color_description_idc > 127) { |
| rb->error_handler(rb->error_handler_data, AVM_CODEC_UNSUP_BITSTREAM, |
| "color_description_idc is not in the range of 0 to 127"); |
| } |
| switch (*color_description_idc) { |
| case AVM_COLOR_DESC_IDC_EXPLICIT: // 0 |
| *color_primaries = avm_rb_read_literal(rb, 8); |
| *transfer_characteristics = avm_rb_read_literal(rb, 8); |
| *matrix_coefficients = avm_rb_read_literal(rb, 8); |
| break; |
| case AVM_COLOR_DESC_IDC_BT709SDR: // 1 |
| *color_primaries = AVM_CICP_CP_BT_709; // 1 |
| *transfer_characteristics = AVM_CICP_TC_BT_709; // 1 |
| *matrix_coefficients = AVM_CICP_MC_BT_709; // 1 |
| break; |
| case AVM_COLOR_DESC_IDC_BT2100PQ: // 2 |
| *color_primaries = AVM_CICP_CP_BT_2020; // 9 |
| *transfer_characteristics = AVM_CICP_TC_SMPTE_2084; // 16 |
| *matrix_coefficients = AVM_CICP_MC_BT_2020_NCL; // 9 |
| break; |
| case AVM_COLOR_DESC_IDC_BT2100HLG: // 3 |
| *color_primaries = AVM_CICP_CP_BT_2020; // 9 |
| *transfer_characteristics = AVM_CICP_TC_HLG; // 18 |
| *matrix_coefficients = AVM_CICP_MC_BT_2020_NCL; // 9 |
| break; |
| case AVM_COLOR_DESC_IDC_SRGB: // 4 |
| *color_primaries = AVM_CICP_CP_BT_709; // 1 |
| *transfer_characteristics = AVM_CICP_TC_SRGB; // 13 |
| *matrix_coefficients = AVM_CICP_MC_IDENTITY; // 0 |
| break; |
| case AVM_COLOR_DESC_IDC_SYCC: // 5 |
| *color_primaries = AVM_CICP_CP_BT_709; // 1 |
| *transfer_characteristics = AVM_CICP_TC_SRGB; // 13 |
| *matrix_coefficients = AVM_CICP_MC_BT_470_B_G; // 5 |
| break; |
| default: |
| // Values larger than 5 are reserved for future use by AOMedia and should |
| // be ignored by decoders. |
| *color_primaries = AVM_CICP_CP_UNSPECIFIED; |
| *transfer_characteristics = AVM_CICP_TC_UNSPECIFIED; |
| *matrix_coefficients = AVM_CICP_MC_UNSPECIFIED; |
| break; |
| } |
| *full_range_flag = avm_rb_read_bit(rb); |
| } |
| |
| // Helper function to store xlayer context |
| // Helper function to map xlayer_id to stream_id array index |
| int av2_get_stream_index(const AV2_COMMON *cm, int xlayer_id) { |
| // GLOBAL_XLAYER_ID doesn't use stream_info |
| if (xlayer_id == GLOBAL_XLAYER_ID) { |
| return -1; |
| } |
| |
| // Find which index in stream_ids matches this xlayer_id |
| for (int i = 0; i < cm->num_streams; i++) { |
| if (cm->stream_ids[i] == xlayer_id) { |
| return i; |
| } |
| } |
| |
| // Should never happen with valid bitstream |
| return -1; |
| } |
| |
| void av2_store_xlayer_context(AV2Decoder *pbi, AV2_COMMON *cm, int xlayer_id) { |
| int stream_idx = av2_get_stream_index(cm, xlayer_id); |
| if (stream_idx < 0) return; // Invalid or GLOBAL_XLAYER_ID |
| |
| for (int i = 0; i < REF_FRAMES; i++) { |
| pbi->stream_info[stream_idx].ref_frame_map_buf[i] = cm->ref_frame_map[i]; |
| pbi->stream_info[stream_idx].valid_for_referencing_buf[i] = |
| pbi->valid_for_referencing[i]; |
| } |
| for (int i = 0; i < INTER_REFS_PER_FRAME; i++) { |
| pbi->stream_info[stream_idx].remapped_ref_idx_buf[i] = |
| cm->remapped_ref_idx[i]; |
| } |
| for (int i = 0; i < MAX_MFH_NUM; i++) { |
| pbi->stream_info[stream_idx].mfh_params_buf[i] = cm->mfh_params[i]; |
| } |
| |
| // Global OBUs (xlayer_id=31) excluded from per-layer save/restore |
| pbi->stream_info[stream_idx].lcr_counter_buf = pbi->lcr_counter; |
| pbi->stream_info[stream_idx].active_lcr_buf = pbi->active_lcr; |
| pbi->stream_info[stream_idx].active_atlas_segment_info_buf = |
| pbi->active_atlas_segment_info; |
| pbi->stream_info[stream_idx].ops_counter_buf = pbi->ops_counter; |
| |
| for (int i = 0; i < NUM_CUSTOM_QMS; i++) { |
| pbi->stream_info[stream_idx].qm_list_buf[i] = pbi->qm_list[i]; |
| pbi->stream_info[stream_idx].qm_protected_buf[i] = pbi->qm_protected[i]; |
| } |
| pbi->stream_info[stream_idx].olk_encountered_buf = pbi->olk_encountered; |
| pbi->stream_info[stream_idx].random_access_point_index_buf = |
| pbi->random_access_point_index; |
| pbi->stream_info[stream_idx].random_access_point_count_buf = |
| pbi->random_access_point_count; |
| for (int i = 0; i < MAX_FGM_NUM; i++) { |
| pbi->stream_info[stream_idx].fgm_list_buf[i] = pbi->fgm_list[i]; |
| } |
| pbi->stream_info[stream_idx].prev_frame_buf = cm->prev_frame; |
| pbi->stream_info[stream_idx].last_frame_seg_map_buf = cm->last_frame_seg_map; |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) { |
| pbi->stream_info[stream_idx].ci_params_per_layer_buf[i] = |
| cm->ci_params_per_layer[i]; |
| } |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) { |
| pbi->stream_info[stream_idx].olk_refresh_frame_flags_buf[i] = |
| cm->olk_refresh_frame_flags[i]; |
| pbi->stream_info[stream_idx].olk_co_vcl_refresh_frame_flags_buf[i] = |
| cm->olk_co_vcl_refresh_frame_flags[i]; |
| } |
| pbi->stream_info[stream_idx].seq_params_buf = cm->seq_params; |
| for (int i = 0; i < MAX_MFH_NUM; i++) { |
| pbi->stream_info[stream_idx].mfh_valid_buf[i] = cm->mfh_valid[i]; |
| } |
| |
| pbi->stream_info[stream_idx].decoding_first_frame = pbi->decoding_first_frame; |
| pbi->stream_info[stream_idx].last_olk_tu_display_order_hint = |
| pbi->last_olk_tu_display_order_hint; |
| } |
| |
| // Helper function to restore xlayer context |
| void av2_restore_xlayer_context(AV2Decoder *pbi, AV2_COMMON *cm, |
| int xlayer_id) { |
| int stream_idx = av2_get_stream_index(cm, xlayer_id); |
| if (stream_idx < 0) return; // Invalid or GLOBAL_XLAYER_ID |
| |
| // Check if stream_info is valid |
| if (pbi->stream_info == NULL) { |
| return; |
| } |
| |
| for (int i = 0; i < REF_FRAMES; i++) { |
| cm->ref_frame_map[i] = pbi->stream_info[stream_idx].ref_frame_map_buf[i]; |
| pbi->valid_for_referencing[i] = |
| pbi->stream_info[stream_idx].valid_for_referencing_buf[i]; |
| } |
| for (int i = 0; i < INTER_REFS_PER_FRAME; i++) { |
| cm->remapped_ref_idx[i] = |
| pbi->stream_info[stream_idx].remapped_ref_idx_buf[i]; |
| } |
| for (int i = 0; i < MAX_MFH_NUM; i++) { |
| cm->mfh_params[i] = pbi->stream_info[stream_idx].mfh_params_buf[i]; |
| } |
| |
| // Global OBUs (xlayer_id=31) excluded from per-layer save/restore |
| pbi->lcr_counter = pbi->stream_info[stream_idx].lcr_counter_buf; |
| pbi->active_lcr = pbi->stream_info[stream_idx].active_lcr_buf; |
| pbi->active_atlas_segment_info = |
| pbi->stream_info[stream_idx].active_atlas_segment_info_buf; |
| pbi->ops_counter = pbi->stream_info[stream_idx].ops_counter_buf; |
| for (int i = 0; i < NUM_CUSTOM_QMS; i++) { |
| pbi->qm_list[i] = pbi->stream_info[stream_idx].qm_list_buf[i]; |
| pbi->qm_protected[i] = pbi->stream_info[stream_idx].qm_protected_buf[i]; |
| } |
| pbi->olk_encountered = pbi->stream_info[stream_idx].olk_encountered_buf; |
| pbi->random_access_point_index = |
| pbi->stream_info[stream_idx].random_access_point_index_buf; |
| pbi->random_access_point_count = |
| pbi->stream_info[stream_idx].random_access_point_count_buf; |
| for (int i = 0; i < MAX_FGM_NUM; i++) { |
| pbi->fgm_list[i] = pbi->stream_info[stream_idx].fgm_list_buf[i]; |
| } |
| cm->prev_frame = pbi->stream_info[stream_idx].prev_frame_buf; |
| cm->last_frame_seg_map = pbi->stream_info[stream_idx].last_frame_seg_map_buf; |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) { |
| cm->ci_params_per_layer[i] = |
| pbi->stream_info[stream_idx].ci_params_per_layer_buf[i]; |
| } |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) { |
| cm->olk_refresh_frame_flags[i] = |
| pbi->stream_info[stream_idx].olk_refresh_frame_flags_buf[i]; |
| cm->olk_co_vcl_refresh_frame_flags[i] = |
| pbi->stream_info[stream_idx].olk_co_vcl_refresh_frame_flags_buf[i]; |
| } |
| cm->seq_params = pbi->stream_info[stream_idx].seq_params_buf; |
| for (int i = 0; i < MAX_MFH_NUM; i++) { |
| cm->mfh_valid[i] = pbi->stream_info[stream_idx].mfh_valid_buf[i]; |
| } |
| |
| pbi->decoding_first_frame = pbi->stream_info[stream_idx].decoding_first_frame; |
| pbi->last_olk_tu_display_order_hint = |
| pbi->stream_info[stream_idx].last_olk_tu_display_order_hint; |
| } |
| |
| static void init_stream_info(StreamInfo *stream_info) { |
| stream_info->olk_encountered_buf = 0; |
| stream_info->random_access_point_index_buf = -1; |
| stream_info->random_access_point_count_buf = 0; |
| for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) { |
| stream_info->remapped_ref_idx_buf[i] = INVALID_IDX; |
| } |
| for (int i = 0; i < REF_FRAMES; i++) { |
| stream_info->ref_frame_map_buf[i] = NULL; |
| } |
| stream_info->mfh_valid_buf[0] = true; |
| for (int i = 1; i < MAX_MFH_NUM; i++) { |
| stream_info->mfh_valid_buf[i] = false; |
| } |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) { |
| av2_initialize_ci_params(&stream_info->ci_params_per_layer_buf[i]); |
| } |
| stream_info->decoding_first_frame = 1; |
| stream_info->last_olk_tu_display_order_hint = -1; |
| } |
| |
| /*! |
| * \brief Save current MSDO configuration |
| */ |
| static void save_msdo_config(const AV2Decoder *pbi, MsdoConfig *config) { |
| const AV2_COMMON *const cm = &pbi->common; |
| config->multistream_profile_idc = |
| pbi->common.msdo_params.multistream_profile_idc; |
| config->multistream_tier_idx = pbi->common.msdo_params.multistream_tier_idx; |
| config->multistream_level_idx = pbi->common.msdo_params.multistream_level_idx; |
| config->num_streams = cm->num_streams; |
| memcpy(config->stream_ids, cm->stream_ids, cm->num_streams * sizeof(int)); |
| } |
| |
| /*! |
| * \brief Compare two MSDO configurations |
| * \return true if configurations are identical, false otherwise |
| */ |
| static bool msdo_config_equal(const MsdoConfig *a, const MsdoConfig *b) { |
| if (a->multistream_profile_idc != b->multistream_profile_idc) return false; |
| if (a->multistream_tier_idx != b->multistream_tier_idx) return false; |
| if (a->multistream_level_idx != b->multistream_level_idx) return false; |
| if (a->num_streams != b->num_streams) return false; |
| |
| return true; |
| } |
| |
| avm_codec_err_t flush_all_xlayer_frames(struct AV2Decoder *pbi, AV2_COMMON *cm, |
| bool release_dpb) { |
| BufferPool *const pool = cm->buffer_pool; |
| int saved_xlayer_id = cm->xlayer_id; |
| avm_codec_err_t err = AVM_CODEC_OK; |
| |
| for (int xlayer = 0; xlayer < AVM_MAX_NUM_STREAMS; xlayer++) { |
| if (xlayer == GLOBAL_XLAYER_ID) continue; // Global context is not a stream |
| if (pbi->xlayer_id_map[xlayer] > 0) { |
| if (xlayer != cm->xlayer_id) { |
| av2_store_xlayer_context(pbi, cm, cm->xlayer_id); |
| cm->xlayer_id = xlayer; |
| av2_restore_xlayer_context(pbi, cm, xlayer); |
| } |
| size_t num_before = pbi->num_output_frames; |
| err = flush_remaining_frames(pbi, INT_MAX); |
| if (err != AVM_CODEC_OK) break; |
| for (size_t j = num_before; j < pbi->num_output_frames; j++) { |
| decrease_ref_count(pbi->output_frames[j], pool); |
| } |
| if (release_dpb) { |
| for (int r = 0; r < REF_FRAMES; r++) { |
| decrease_ref_count(cm->ref_frame_map[r], pool); |
| cm->ref_frame_map[r] = NULL; |
| } |
| } |
| } |
| } |
| |
| if (cm->xlayer_id != saved_xlayer_id) { |
| av2_store_xlayer_context(pbi, cm, cm->xlayer_id); |
| cm->xlayer_id = saved_xlayer_id; |
| av2_restore_xlayer_context(pbi, cm, saved_xlayer_id); |
| } |
| return err; |
| } |
| |
| static uint32_t read_multi_stream_decoder_operation_obu( |
| AV2Decoder *pbi, struct avm_read_bit_buffer *rb) { |
| AV2_COMMON *const cm = &pbi->common; |
| const uint32_t saved_bit_offset = rb->bit_offset; |
| |
| // Verify rb has been configured to report errors. |
| assert(rb->error_handler); |
| |
| // Save previous configuration if it exists |
| MsdoConfig prev_config; |
| bool has_previous = false; |
| |
| if (pbi->stream_info != NULL) { |
| save_msdo_config(pbi, &prev_config); |
| has_previous = true; |
| } |
| |
| const int num_streams = |
| avm_rb_read_literal(rb, 3) + 2; // read number of streams |
| if (num_streams > AVM_MAX_NUM_STREAMS) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "The number of streams cannot exceed the max value (4)."); |
| } |
| cm->num_streams = num_streams; |
| |
| pbi->common.msdo_params.multistream_profile_idc = |
| avm_rb_read_literal(rb, PROFILE_BITS); // read profile of multistream |
| |
| pbi->common.msdo_params.multistream_level_idx = |
| avm_rb_read_literal(rb, LEVEL_BITS); // read level of multistream |
| |
| pbi->common.msdo_params.multistream_tier_idx = |
| avm_rb_read_bit(rb); // read tier of multistream |
| |
| const int multistream_even_allocation_flag = |
| avm_rb_read_bit(rb); // read multistream_even_allocation_flag |
| |
| if (!multistream_even_allocation_flag) { |
| const int multistream_large_picture_idc = |
| avm_rb_read_literal(rb, 3); // read multistream_large_picture_idc |
| (void)multistream_large_picture_idc; |
| } |
| |
| for (int i = 0; i < num_streams; i++) { |
| cm->stream_ids[i] = avm_rb_read_literal(rb, XLAYER_BITS); // read stream ID |
| const int substream_profile_idc = |
| avm_rb_read_literal(rb, PROFILE_BITS); // read profile of multistream |
| (void)substream_profile_idc; |
| |
| const int substream_level_idx = |
| avm_rb_read_literal(rb, LEVEL_BITS); // read level of multistream |
| (void)substream_level_idx; |
| |
| const int substream_tier_idx = |
| avm_rb_read_bit(rb); // read tier of multistream |
| (void)substream_tier_idx; |
| } |
| |
| cm->msdo_params.msdo_doh_constraint_flag = avm_rb_read_bit(rb); |
| |
| // Check if configuration changed |
| MsdoConfig new_config; |
| save_msdo_config(pbi, &new_config); |
| bool config_changed = |
| !has_previous || !msdo_config_equal(&prev_config, &new_config); |
| |
| // Flush remaining frames from all active streams before switching config |
| if (pbi->stream_info != NULL && config_changed) { |
| flush_all_xlayer_frames(pbi, cm, true); |
| avm_free(pbi->stream_info); |
| pbi->stream_info = NULL; |
| |
| // Reset xlayer_id_map so only the new segment's layers are active |
| for (int i = 0; i < AVM_MAX_NUM_STREAMS; i++) { |
| pbi->xlayer_id_map[i] = 0; |
| } |
| } |
| |
| // Only allocate if stream_info is NULL (first time OR after freeing due to |
| // config change) |
| if (pbi->stream_info == NULL) { |
| pbi->stream_info = |
| (StreamInfo *)avm_malloc(num_streams * sizeof(StreamInfo)); |
| if (pbi->stream_info == NULL) { |
| avm_internal_error(&cm->error, AVM_CODEC_MEM_ERROR, |
| "Memory allocation failed for pbi->stream_info\n"); |
| } |
| memset(pbi->stream_info, 0, num_streams * sizeof(StreamInfo)); |
| for (int i = 0; i < num_streams; i++) { |
| init_stream_info(&pbi->stream_info[i]); |
| } |
| } |
| |
| pbi->msdo_is_present_in_tu = 1; |
| |
| if (av2_check_trailing_bits(pbi, rb) != 0) { |
| return 0; |
| } |
| |
| return ((rb->bit_offset - saved_bit_offset + 7) >> 3); |
| } |
| |
| // On success, returns the number of bytes read from 'rb'. |
| // On failure, sets pbi->common.error.error_code and returns 0. |
| static uint32_t read_sequence_header_obu(AV2Decoder *pbi, int xlayer_id, |
| struct avm_read_bit_buffer *rb, |
| uint16_t *acc_sh_id_bitmap) { |
| AV2_COMMON *const cm = &pbi->common; |
| const uint32_t saved_bit_offset = rb->bit_offset; |
| |
| // Verify rb has been configured to report errors. |
| assert(rb->error_handler); |
| |
| // Use an element in the pbi->seq_list array to store the information as we |
| // decode. At the end, if no errors have occurred, cm->seq_params is updated. |
| uint32_t seq_header_id = avm_rb_read_uvlc(rb); |
| if (seq_header_id >= MAX_SEQ_NUM) { |
| cm->error.error_code = AVM_CODEC_UNSUP_BITSTREAM; |
| return 0; |
| } |
| |
| struct SequenceHeader *seq_params = &pbi->seq_list[xlayer_id][seq_header_id]; |
| seq_params->seq_header_id = seq_header_id; |
| seq_params->sh_from_leading = 0; |
| acc_sh_id_bitmap[xlayer_id] |= (1 << seq_header_id); |
| |
| seq_params->seq_profile_idc = av2_read_profile(rb); |
| if (seq_params->seq_profile_idc >= MAX_PROFILES) { |
| cm->error.error_code = AVM_CODEC_UNSUP_BITSTREAM; |
| return 0; |
| } |
| |
| seq_params->single_picture_header_flag = avm_rb_read_bit(rb); |
| if (!read_bitstream_level(&seq_params->seq_max_level_idx, rb)) { |
| cm->error.error_code = AVM_CODEC_UNSUP_BITSTREAM; |
| return 0; |
| } |
| if (seq_params->seq_max_level_idx >= SEQ_LEVEL_4_0 && |
| !seq_params->single_picture_header_flag) |
| seq_params->seq_tier = avm_rb_read_bit(rb); |
| else |
| seq_params->seq_tier = 0; |
| av2_read_chroma_format_bitdepth(rb, seq_params, &cm->error); |
| if (seq_params->single_picture_header_flag) { |
| seq_params->seq_lcr_id = LCR_ID_UNSPECIFIED; |
| seq_params->still_picture = 1; |
| seq_params->max_tlayer_id = 0; |
| seq_params->max_mlayer_id = 0; |
| seq_params->seq_max_mlayer_cnt = 1; |
| seq_params->monotonic_output_order_flag = 1; |
| } else { |
| int seq_lcr_id = avm_rb_read_literal(rb, 3); |
| if (seq_lcr_id > MAX_NUM_SEQ_LCR_ID) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Unsupported LCR id in the Sequence Header.\n"); |
| } |
| seq_params->seq_lcr_id = seq_lcr_id; |
| seq_params->still_picture = avm_rb_read_bit(rb); |
| seq_params->max_tlayer_id = avm_rb_read_literal(rb, TLAYER_BITS); |
| seq_params->max_mlayer_id = avm_rb_read_literal(rb, MLAYER_BITS); |
| if (seq_params->max_mlayer_id > 0) { |
| int n = avm_ceil_log2(seq_params->max_mlayer_id + 1); |
| int seq_max_mlayer_cnt_minus_1 = avm_rb_read_literal(rb, n); |
| if (seq_max_mlayer_cnt_minus_1 > seq_params->max_mlayer_id) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "seq_max_mlayer_cnt_minus_1 %d is greater than max_mlayer_id %d", |
| seq_max_mlayer_cnt_minus_1, seq_params->max_mlayer_id); |
| } |
| seq_params->seq_max_mlayer_cnt = seq_max_mlayer_cnt_minus_1 + 1; |
| } else { |
| seq_params->seq_max_mlayer_cnt = 1; |
| } |
| seq_params->monotonic_output_order_flag = avm_rb_read_bit(rb); |
| } |
| |
| const int num_bits_width = avm_rb_read_literal(rb, 4) + 1; |
| const int num_bits_height = avm_rb_read_literal(rb, 4) + 1; |
| const int max_frame_width = avm_rb_read_literal(rb, num_bits_width) + 1; |
| const int max_frame_height = avm_rb_read_literal(rb, num_bits_height) + 1; |
| |
| seq_params->num_bits_width = num_bits_width; |
| seq_params->num_bits_height = num_bits_height; |
| seq_params->max_frame_width = max_frame_width; |
| seq_params->max_frame_height = max_frame_height; |
| |
| av2_read_conformance_window(rb, seq_params); |
| av2_validate_seq_conformance_window(seq_params, &cm->error); |
| |
| if (seq_params->single_picture_header_flag) { |
| seq_params->decoder_model_info_present_flag = 0; |
| seq_params->display_model_info_present_flag = 0; |
| } else { |
| seq_params->seq_max_display_model_info_present_flag = avm_rb_read_bit(rb); |
| seq_params->seq_max_initial_display_delay_minus_1 = |
| BUFFER_POOL_MAX_SIZE - 1; |
| if (seq_params->seq_max_display_model_info_present_flag) |
| seq_params->seq_max_initial_display_delay_minus_1 = |
| avm_rb_read_literal(rb, 4); |
| seq_params->decoder_model_info_present_flag = avm_rb_read_bit(rb); |
| if (seq_params->decoder_model_info_present_flag) { |
| seq_params->decoder_model_info.num_units_in_decoding_tick = |
| avm_rb_read_unsigned_literal(rb, 32); |
| seq_params->seq_max_decoder_model_present_flag = avm_rb_read_bit(rb); |
| if (seq_params->seq_max_decoder_model_present_flag) { |
| seq_params->seq_max_decoder_buffer_delay = avm_rb_read_uvlc(rb); |
| seq_params->seq_max_encoder_buffer_delay = avm_rb_read_uvlc(rb); |
| seq_params->seq_max_low_delay_mode_flag = avm_rb_read_bit(rb); |
| } else { |
| seq_params->seq_max_decoder_buffer_delay = 70000; |
| seq_params->seq_max_encoder_buffer_delay = 20000; |
| seq_params->seq_max_low_delay_mode_flag = 0; |
| } |
| } else { |
| seq_params->decoder_model_info.num_units_in_decoding_tick = 1; |
| seq_params->seq_max_decoder_buffer_delay = 70000; |
| seq_params->seq_max_encoder_buffer_delay = 20000; |
| seq_params->seq_max_low_delay_mode_flag = 0; |
| } |
| // Configurable profile does not define bitrate and buffer size constraints |
| if (seq_params->seq_profile_idc != CONFIGURABLE) { |
| int64_t seq_bitrate = av2_max_level_bitrate( |
| seq_params->seq_profile_idc, seq_params->seq_max_level_idx, |
| seq_params->seq_tier, seq_params->subsampling_x, |
| seq_params->subsampling_y, seq_params->monochrome); |
| if (seq_bitrate == 0) |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "AV2 does not support this combination of " |
| "profile, level, and tier."); |
| // Buffer size in bits/s is bitrate in bits/s * 1 s |
| int64_t buffer_size = seq_bitrate; |
| if (buffer_size == 0) |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "AV2 does not support this combination of " |
| "profile, level, and tier."); |
| } |
| } |
| |
| // setup default embedded layer dependency |
| setup_default_embedded_layer_dependency_structure(seq_params); |
| // setup default temporal layer dependency |
| setup_default_temporal_layer_dependency_structure(seq_params); |
| |
| // mlayer dependency description |
| seq_params->mlayer_dependency_present_flag = 0; |
| if (seq_params->max_mlayer_id > 0) { |
| seq_params->mlayer_dependency_present_flag = avm_rb_read_bit(rb); |
| if (seq_params->mlayer_dependency_present_flag) { |
| av2_read_mlayer_dependency_info(seq_params, rb); |
| } |
| } |
| |
| // tlayer dependency description |
| seq_params->tlayer_dependency_present_flag = 0; |
| seq_params->multi_tlayer_dependency_map_present_flag = 0; |
| if (seq_params->max_tlayer_id > 0) { |
| seq_params->tlayer_dependency_present_flag = avm_rb_read_bit(rb); |
| if (seq_params->tlayer_dependency_present_flag) { |
| if (seq_params->max_mlayer_id > 0) { |
| seq_params->multi_tlayer_dependency_map_present_flag = |
| avm_rb_read_bit(rb); |
| } |
| av2_read_tlayer_dependency_info(seq_params, rb); |
| } |
| } |
| |
| if (!av2_check_profile_interop_conformance(seq_params, &cm->error, 1)) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Unsupported Bitdepth, Chroma format or number of embedded layers"); |
| } |
| |
| av2_read_sequence_header(rb, seq_params); |
| |
| seq_params->film_grain_params_present = avm_rb_read_bit(rb); |
| |
| size_t bits_before_ext = rb->bit_offset - saved_bit_offset; |
| seq_params->seq_extension_present_flag = avm_rb_read_bit(rb); |
| if (seq_params->seq_extension_present_flag) { |
| // Extension data bits = total - bits_read_before_extension -1 (ext flag) - |
| // trailing bits |
| int extension_bits = read_obu_extension_bits( |
| rb->bit_buffer, rb->bit_buffer_end - rb->bit_buffer, bits_before_ext, |
| &cm->error); |
| if (extension_bits > 0) { |
| // skip over the extension bits |
| rb->bit_offset += extension_bits; |
| } else { |
| // No extension data is present |
| } |
| } |
| |
| if (av2_check_trailing_bits(pbi, rb) != 0) { |
| // cm->error.error_code is already set. |
| return 0; |
| } |
| return ((rb->bit_offset - saved_bit_offset + 7) >> 3); |
| } |
| |
| static uint32_t read_multi_frame_header_obu(AV2Decoder *pbi, |
| uint32_t *acc_mfh_id_bitmap, |
| struct avm_read_bit_buffer *rb) { |
| AV2_COMMON *const cm = &pbi->common; |
| const uint32_t saved_bit_offset = rb->bit_offset; |
| |
| const uint32_t cur_mfh_id = av2_read_multi_frame_header(cm, rb); |
| assert(cur_mfh_id < MAX_MFH_NUM); |
| if (acc_mfh_id_bitmap) { |
| *acc_mfh_id_bitmap |= (1 << cur_mfh_id); |
| } |
| |
| size_t bits_before_ext = rb->bit_offset - saved_bit_offset; |
| cm->mfh_params[cur_mfh_id].mfh_extension_present_flag = avm_rb_read_bit(rb); |
| if (cm->mfh_params[cur_mfh_id].mfh_extension_present_flag) { |
| // Extension data bits = total - bits_read_before_extension -1 (ext flag) - |
| // trailing bits |
| int extension_bits = read_obu_extension_bits( |
| rb->bit_buffer, rb->bit_buffer_end - rb->bit_buffer, bits_before_ext, |
| &cm->error); |
| if (extension_bits > 0) { |
| // skip over the extension bits |
| rb->bit_offset += extension_bits; |
| } else { |
| // No extension data present |
| } |
| } |
| |
| if (av2_check_trailing_bits(pbi, rb) != 0) { |
| // cm->error.error_code is already set. |
| return 0; |
| } |
| |
| return ((rb->bit_offset - saved_bit_offset + 7) >> 3); |
| } |
| |
| static uint32_t read_tilegroup_obu(AV2Decoder *pbi, |
| struct avm_read_bit_buffer *rb, |
| const uint8_t *data, const uint8_t *data_end, |
| const uint8_t **p_data_end, |
| OBU_TYPE obu_type, int obu_xlayer_id, |
| int *is_first_tg, int *is_last_tg) { |
| AV2_COMMON *const cm = &pbi->common; |
| int start_tile, end_tile; |
| int32_t header_size, tg_payload_size; |
| |
| assert(rb->bit_offset == 0); |
| assert(rb->bit_buffer == data); |
| *is_first_tg = 1; // it is updated by av2_read_tilegroup_header() |
| header_size = av2_read_tilegroup_header(pbi, rb, data, p_data_end, |
| is_first_tg, &start_tile, &end_tile, |
| obu_type, obu_xlayer_id); |
| |
| bool skip_payload = false; |
| skip_payload |= (obu_type == OBU_LEADING_SEF); |
| skip_payload |= (obu_type == OBU_REGULAR_SEF); |
| skip_payload |= (obu_type == OBU_LEADING_TIP); |
| skip_payload |= (obu_type == OBU_REGULAR_TIP); |
| skip_payload |= cm->bru.frame_inactive_flag; |
| skip_payload |= cm->bridge_frame_info.is_bridge_frame; |
| |
| if (skip_payload) { |
| *is_last_tg = 1; |
| tg_payload_size = 0; |
| if (av2_check_trailing_bits(pbi, rb) != 0) { |
| // cm->error.error_code is already set. |
| return 0; |
| } |
| header_size = (int32_t)avm_rb_bytes_read(rb); |
| } else { |
| if (av2_check_byte_alignment(cm, rb)) return 0; |
| data += header_size; |
| |
| av2_decode_tg_tiles_and_wrapup(pbi, data, data_end, p_data_end, start_tile, |
| end_tile, *is_first_tg); |
| |
| tg_payload_size = (uint32_t)(*p_data_end - data); |
| *is_last_tg = end_tile == cm->tiles.rows * cm->tiles.cols - 1; |
| } |
| return header_size + tg_payload_size; |
| } |
| |
| // Returns the last nonzero byte index in 'data'. If there is no nonzero byte in |
| // 'data', returns -1. |
| static int get_last_nonzero_byte_index(const uint8_t *data, size_t sz) { |
| // Scan backward and return on the first nonzero byte. |
| int i = (int)sz - 1; |
| while (i >= 0 && data[i] == 0) { |
| --i; |
| } |
| return i; |
| } |
| |
| // Allocates metadata that was read and adds it to the decoders metadata array. |
| static void alloc_read_metadata(AV2Decoder *const pbi, |
| OBU_METADATA_TYPE metadata_type, |
| const uint8_t *data, size_t sz, |
| avm_metadata_insert_flags_t insert_flag) { |
| AV2_COMMON *const cm = &pbi->common; |
| if (!pbi->metadata) { |
| pbi->metadata = avm_img_metadata_array_alloc(0); |
| if (!pbi->metadata) { |
| avm_internal_error(&cm->error, AVM_CODEC_MEM_ERROR, |
| "Failed to allocate metadata array"); |
| } |
| } |
| avm_metadata_t *metadata = |
| avm_img_metadata_alloc(metadata_type, data, sz, insert_flag); |
| if (!metadata) { |
| avm_internal_error(&cm->error, AVM_CODEC_MEM_ERROR, |
| "Error allocating metadata"); |
| } |
| avm_metadata_t **metadata_array = |
| (avm_metadata_t **)realloc(pbi->metadata->metadata_array, |
| (pbi->metadata->sz + 1) * sizeof(metadata)); |
| if (!metadata_array) { |
| avm_img_metadata_free(metadata); |
| avm_internal_error(&cm->error, AVM_CODEC_MEM_ERROR, |
| "Error growing metadata array"); |
| } |
| pbi->metadata->metadata_array = metadata_array; |
| pbi->metadata->metadata_array[pbi->metadata->sz] = metadata; |
| pbi->metadata->sz++; |
| } |
| |
| // On failure, calls avm_internal_error() and does not return. |
| static void read_metadata_itut_t35(AV2Decoder *const pbi, const uint8_t *data, |
| size_t sz) { |
| AV2_COMMON *const cm = &pbi->common; |
| if (sz == 0) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "itu_t_t35_country_code is missing"); |
| } |
| int country_code_size = 1; |
| if (*data == 0xFF) { |
| if (sz == 1) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "itu_t_t35_country_code_extension_byte is missing"); |
| } |
| ++country_code_size; |
| } |
| const int end_index = (int)sz; |
| if (end_index < country_code_size) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "No trailing bits found in ITU-T T.35 metadata OBU"); |
| } |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_ITUT_T35, data, end_index, |
| AVM_MIF_ANY_FRAME); |
| } |
| |
| // On failure, calls avm_internal_error() and does not return. |
| static void read_metadata_itut_t35_short(AV2Decoder *const pbi, |
| const uint8_t *data, size_t sz) { |
| AV2_COMMON *const cm = &pbi->common; |
| if (sz == 0) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "itu_t_t35_country_code is missing"); |
| } |
| int country_code_size = 1; |
| if (*data == 0xFF) { |
| if (sz == 1) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "itu_t_t35_country_code_extension_byte is missing"); |
| } |
| ++country_code_size; |
| } |
| int end_index = get_last_nonzero_byte_index(data, sz); |
| if (end_index < country_code_size) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "No trailing bits found in ITU-T T.35 metadata OBU"); |
| } |
| // itu_t_t35_payload_bytes is byte aligned. Section 6.7.2 of the spec says: |
| // itu_t_t35_payload_bytes shall be bytes containing data registered as |
| // specified in Recommendation ITU-T T.35. |
| // Therefore the first trailing byte should be 0x80. |
| if (data[end_index] != 0x80) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "The last nonzero byte of the ITU-T T.35 metadata OBU " |
| "is 0x%02x, should be 0x80.", |
| data[end_index]); |
| } |
| |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_ITUT_T35, data, end_index, |
| AVM_MIF_ANY_FRAME); |
| } |
| // On success, returns the number of bytes read from 'data'. On failure, calls |
| // avm_internal_error() and does not return. |
| static size_t read_metadata_hdr_cll(AV2Decoder *const pbi, const uint8_t *data, |
| size_t sz) { |
| const size_t kHdrCllPayloadSize = 4; |
| AV2_COMMON *const cm = &pbi->common; |
| if (sz < kHdrCllPayloadSize) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Incorrect HDR CLL metadata payload size"); |
| } |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_HDR_CLL, data, kHdrCllPayloadSize, |
| AVM_MIF_ANY_FRAME); |
| return kHdrCllPayloadSize; |
| } |
| |
| // On success, returns the number of bytes read from 'data'. On failure, calls |
| // avm_internal_error() and does not return. |
| static size_t read_metadata_hdr_mdcv(AV2Decoder *const pbi, const uint8_t *data, |
| size_t sz) { |
| const size_t kMdcvPayloadSize = 24; |
| AV2_COMMON *const cm = &pbi->common; |
| if (sz < kMdcvPayloadSize) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Incorrect HDR MDCV metadata payload size"); |
| } |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_HDR_MDCV, data, kMdcvPayloadSize, |
| AVM_MIF_ANY_FRAME); |
| return kMdcvPayloadSize; |
| } |
| |
| // On success, returns the number of bytes read from 'data'. On failure, calls |
| // avm_internal_error() and does not return. |
| static size_t read_metadata_banding_hints(AV2Decoder *const pbi, |
| const uint8_t *data, size_t sz) { |
| AV2_COMMON *const cm = &pbi->common; |
| |
| // Validate minimum payload size (at least 3 bits for basic flags) |
| if (sz == 0) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Empty banding hints metadata payload"); |
| } |
| |
| // Decode the banding hints metadata payload |
| if (avm_decode_banding_hints_metadata(data, sz, &pbi->band_metadata) == 0) { |
| // Successfully decoded |
| pbi->band_metadata_present = 1; |
| } else { |
| pbi->band_metadata_present = 0; |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Failed to decode banding hints metadata"); |
| } |
| |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_BANDING_HINTS, data, sz, |
| AVM_MIF_ANY_FRAME); |
| |
| return sz; |
| } |
| |
| // Helper function to read banding hints from a bit buffer (short metadata path) |
| static void read_metadata_banding_hints_from_rb( |
| AV2Decoder *const pbi, struct avm_read_bit_buffer *rb) { |
| avm_banding_hints_metadata_t *md = &pbi->band_metadata; |
| memset(md, 0, sizeof(*md)); |
| |
| md->coding_banding_present_flag = avm_rb_read_bit(rb); |
| md->source_banding_present_flag = avm_rb_read_bit(rb); |
| |
| if (md->coding_banding_present_flag) { |
| md->banding_hints_flag = avm_rb_read_bit(rb); |
| |
| if (md->banding_hints_flag) { |
| md->three_color_components = avm_rb_read_bit(rb); |
| const int num_components = md->three_color_components ? 3 : 1; |
| |
| for (int plane = 0; plane < num_components; plane++) { |
| md->banding_in_component_present_flag[plane] = avm_rb_read_bit(rb); |
| if (md->banding_in_component_present_flag[plane]) { |
| md->max_band_width_minus4[plane] = avm_rb_read_literal(rb, 6); |
| md->max_band_step_minus1[plane] = avm_rb_read_literal(rb, 4); |
| } |
| } |
| |
| md->band_units_information_present_flag = avm_rb_read_bit(rb); |
| if (md->band_units_information_present_flag) { |
| md->num_band_units_rows_minus_1 = avm_rb_read_literal(rb, 5); |
| md->num_band_units_cols_minus_1 = avm_rb_read_literal(rb, 5); |
| md->varying_size_band_units_flag = avm_rb_read_bit(rb); |
| |
| if (md->varying_size_band_units_flag) { |
| md->band_block_in_luma_samples = avm_rb_read_literal(rb, 3); |
| |
| for (int r = 0; r <= md->num_band_units_rows_minus_1; r++) { |
| md->vert_size_in_band_blocks_minus1[r] = avm_rb_read_literal(rb, 5); |
| } |
| |
| for (int c = 0; c <= md->num_band_units_cols_minus_1; c++) { |
| md->horz_size_in_band_blocks_minus1[c] = avm_rb_read_literal(rb, 5); |
| } |
| } |
| |
| for (int r = 0; r <= md->num_band_units_rows_minus_1; r++) { |
| for (int c = 0; c <= md->num_band_units_cols_minus_1; c++) { |
| md->banding_in_band_unit_present_flag[r][c] = avm_rb_read_bit(rb); |
| } |
| } |
| } |
| } |
| } |
| |
| pbi->band_metadata_present = 1; |
| |
| // Re-encode to raw payload and store in metadata array |
| uint8_t payload_buf[256]; |
| size_t payload_size = sizeof(payload_buf); |
| if (avm_encode_banding_hints_metadata(md, payload_buf, &payload_size) == 0) { |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_BANDING_HINTS, payload_buf, |
| payload_size, AVM_MIF_ANY_FRAME); |
| } |
| } |
| |
| // On success, returns the number of bytes read from 'data'. On failure, calls |
| // avm_internal_error() and does not return. |
| static size_t read_metadata_icc_profile(AV2Decoder *const pbi, |
| const uint8_t *data, size_t sz) { |
| const size_t kMinIccProfileHeaderSize = 128; |
| AV2_COMMON *const cm = &pbi->common; |
| if (sz < kMinIccProfileHeaderSize) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Incorrect ICC profile metadata payload size"); |
| } |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_ICC_PROFILE, data, sz, |
| AVM_MIF_ANY_FRAME); |
| return sz; |
| } |
| |
| // On failure, calls avm_internal_error() and does not return. |
| static void read_metadata_user_data_unregistered(AV2Decoder *const pbi, |
| const uint8_t *data, |
| size_t sz) { |
| AV2_COMMON *const cm = &pbi->common; |
| // uuid_iso_iec_11578 is 128 bits (16 bytes) |
| const size_t uuid_size = 16; |
| if (sz < uuid_size) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "uuid_iso_iec_11578 is missing or incomplete"); |
| } |
| const int end_index = (int)sz; |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_USER_DATA_UNREGISTERED, data, |
| end_index, AVM_MIF_ANY_FRAME); |
| } |
| |
| // On success, returns the number of bytes read from 'data'. On failure, calls |
| // avm_internal_error() and does not return. |
| static void read_metadata_scan_type(AV2Decoder *const pbi, |
| struct avm_read_bit_buffer *rb) { |
| AV2_COMMON *const cm = &pbi->common; |
| cm->pic_struct_metadata_params.mps_pic_struct_type = |
| avm_rb_read_literal(rb, 5); |
| cm->pic_struct_metadata_params.mps_source_scan_type_idc = |
| avm_rb_read_literal(rb, 2); |
| cm->pic_struct_metadata_params.mps_duplicate_flag = avm_rb_read_bit(rb); |
| |
| uint8_t payload[1]; |
| payload[0] = (cm->pic_struct_metadata_params.mps_pic_struct_type << 3) | |
| (cm->pic_struct_metadata_params.mps_source_scan_type_idc << 1) | |
| cm->pic_struct_metadata_params.mps_duplicate_flag; |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_SCAN_TYPE, payload, 1, |
| AVM_MIF_ANY_FRAME); |
| } |
| |
| // On success, returns the number of bytes read from 'data'. On failure, calls |
| // avm_internal_error() and does not return. |
| static void read_metadata_temporal_point_info(AV2Decoder *const pbi, |
| struct avm_read_bit_buffer *rb) { |
| AV2_COMMON *const cm = &pbi->common; |
| cm->temporal_point_info_metadata.mtpi_frame_presentation_time = |
| avm_rb_read_uleb(rb); |
| uint8_t payload[1]; |
| payload[0] = |
| (cm->temporal_point_info_metadata.mtpi_frame_presentation_time & 0XFF); |
| alloc_read_metadata(pbi, OBU_METADATA_TYPE_TEMPORAL_POINT_INFO, payload, 1, |
| AVM_MIF_ANY_FRAME); |
| } |
| |
| static int read_metadata_frame_hash(AV2Decoder *const pbi, |
| struct avm_read_bit_buffer *rb) { |
| AV2_COMMON *const cm = &pbi->common; |
| const unsigned hash_type = avm_rb_read_literal(rb, 4); |
| const unsigned per_plane = avm_rb_read_bit(rb); |
| const unsigned has_grain = avm_rb_read_bit(rb); |
| const unsigned is_monochrome = avm_rb_read_bit(rb); |
| avm_rb_read_literal(rb, 1); // reserved |
| |
| // If hash_type is reserved for future use, ignore the entire OBU |
| if (hash_type) return -1; |
| |
| FrameHash *const frame_hash = has_grain ? &cm->cur_frame->grain_frame_hash |
| : &cm->cur_frame->raw_frame_hash; |
| memset(frame_hash, 0, sizeof(*frame_hash)); |
| |
| frame_hash->hash_type = hash_type; |
| frame_hash->per_plane = per_plane; |
| frame_hash->has_grain = has_grain; |
| if (per_plane) { |
| const int num_planes = is_monochrome ? 1 : 3; |
| for (int i = 0; i < num_planes; ++i) { |
| PlaneHash *plane = &frame_hash->plane[i]; |
| for (size_t j = 0; j < 16; ++j) |
| plane->md5[j] = avm_rb_read_literal(rb, 8); |
| } |
| } else { |
| PlaneHash *plane = &frame_hash->plane[0]; |
| for (size_t i = 0; i < 16; ++i) plane->md5[i] = avm_rb_read_literal(rb, 8); |
| } |
| frame_hash->is_present = 1; |
| |
| return 0; |
| } |
| |
| static void read_metadata_timecode(struct avm_read_bit_buffer *rb) { |
| avm_rb_read_literal(rb, 5); // counting_type f(5) |
| const int full_timestamp_flag = |
| avm_rb_read_bit(rb); // full_timestamp_flag f(1) |
| avm_rb_read_bit(rb); // discontinuity_flag (f1) |
| avm_rb_read_bit(rb); // cnt_dropped_flag f(1) |
| avm_rb_read_literal(rb, 9); // n_frames f(9) |
| if (full_timestamp_flag) { |
| avm_rb_read_literal(rb, 6); // seconds_value f(6) |
| avm_rb_read_literal(rb, 6); // minutes_value f(6) |
| avm_rb_read_literal(rb, 5); // hours_value f(5) |
| } else { |
| const int seconds_flag = avm_rb_read_bit(rb); // seconds_flag f(1) |
| if (seconds_flag) { |
| avm_rb_read_literal(rb, 6); // seconds_value f(6) |
| const int minutes_flag = avm_rb_read_bit(rb); // minutes_flag f(1) |
| if (minutes_flag) { |
| avm_rb_read_literal(rb, 6); // minutes_value f(6) |
| const int hours_flag = avm_rb_read_bit(rb); // hours_flag f(1) |
| if (hours_flag) { |
| avm_rb_read_literal(rb, 5); // hours_value f(5) |
| } |
| } |
| } |
| } |
| // time_offset_length f(5) |
| const int time_offset_length = avm_rb_read_literal(rb, 5); |
| if (time_offset_length) { |
| // time_offset_value f(time_offset_length) |
| avm_rb_read_literal(rb, time_offset_length); |
| } |
| } |
| |
| // Returns the last nonzero byte in 'data'. If there is no nonzero byte in |
| // 'data', returns 0. |
| // |
| // Call this function to check the following requirement in the spec: |
| // This implies that when any payload data is present for this OBU type, at |
| // least one byte of the payload data (including the trailing bit) shall not |
| // be equal to 0. |
| static uint8_t get_last_nonzero_byte(const uint8_t *data, size_t sz) { |
| // Scan backward and return on the first nonzero byte. |
| size_t i = sz; |
| while (i != 0) { |
| --i; |
| if (data[i] != 0) return data[i]; |
| } |
| return 0; |
| } |
| |
| // Skip metadata_unit_remaining_bits: decoders conforming to this version of |
| // the specification shall ignore metadata_unit_remaining_bits. |
| static void skip_remaining_mu_payload_bits(struct avm_read_bit_buffer *rb, |
| size_t parsed_payload_bits, |
| size_t total_payload_bits) { |
| if (parsed_payload_bits < total_payload_bits) { |
| size_t remaining_bits = total_payload_bits - parsed_payload_bits; |
| while (remaining_bits > 0) { |
| const int chunk = (remaining_bits > 31) ? 31 : (int)remaining_bits; |
| avm_rb_read_literal(rb, chunk); |
| remaining_bits -= chunk; |
| } |
| } |
| } |
| |
| // Checks the metadata for correct syntax but ignores the parsed metadata. |
| // |
| // On success, returns the number of bytes read from 'data'. On failure, sets |
| // pbi->common.error.error_code and returns 0, or calls avm_internal_error() |
| // and does not return. |
| static size_t read_metadata_unit_payload(AV2Decoder *pbi, const uint8_t *data, |
| avm_metadata_t *metadata) { |
| AV2_COMMON *const cm = &pbi->common; |
| size_t type_length = 0; |
| const OBU_METADATA_TYPE metadata_type = metadata->type; |
| const size_t sz = metadata->sz; |
| |
| int known_metadata_type = metadata_type >= OBU_METADATA_TYPE_HDR_CLL && |
| metadata_type < NUM_OBU_METADATA_TYPES; |
| known_metadata_type |= metadata_type == OBU_METADATA_TYPE_ICC_PROFILE; |
| known_metadata_type |= metadata_type == OBU_METADATA_TYPE_SCAN_TYPE; |
| known_metadata_type |= metadata_type == OBU_METADATA_TYPE_TEMPORAL_POINT_INFO; |
| known_metadata_type |= |
| metadata_type == OBU_METADATA_TYPE_USER_DATA_UNREGISTERED; |
| if (!known_metadata_type) { |
| return sz; |
| } |
| // Temporal point info metadata is only valid in SHORT format, not GROUP. |
| if (metadata_type == OBU_METADATA_TYPE_TEMPORAL_POINT_INFO) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Temporal point info metadata shall only appear in " |
| "OBU_METADATA_SHORT, not OBU_METADATA_GROUP"); |
| } |
| // Track bits consumed by the type-specific metadata reader, matching the |
| // proposal's parsedPayloadBits = currentPosition - startPosition. |
| size_t parsed_payload_bits = 0; |
| struct avm_read_bit_buffer rb; |
| if (metadata_type == OBU_METADATA_TYPE_ITUT_T35) { |
| read_metadata_itut_t35(pbi, data + type_length, sz - type_length); |
| parsed_payload_bits = sz * 8; |
| } else if (metadata_type == OBU_METADATA_TYPE_HDR_CLL) { |
| read_metadata_hdr_cll(pbi, data + type_length, sz - type_length); |
| parsed_payload_bits = sz * 8; |
| } else if (metadata_type == OBU_METADATA_TYPE_HDR_MDCV) { |
| read_metadata_hdr_mdcv(pbi, data + type_length, sz - type_length); |
| parsed_payload_bits = sz * 8; |
| } else if (metadata_type == OBU_METADATA_TYPE_BANDING_HINTS) { |
| read_metadata_banding_hints(pbi, data + type_length, sz - type_length); |
| parsed_payload_bits = sz * 8; |
| } else if (metadata_type == OBU_METADATA_TYPE_SCAN_TYPE) { |
| av2_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); |
| read_metadata_scan_type(pbi, &rb); |
| parsed_payload_bits = rb.bit_offset; |
| } else if (metadata_type == OBU_METADATA_TYPE_TEMPORAL_POINT_INFO) { |
| av2_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); |
| read_metadata_temporal_point_info(pbi, &rb); |
| parsed_payload_bits = rb.bit_offset; |
| } else if (metadata_type == OBU_METADATA_TYPE_ICC_PROFILE) { |
| read_metadata_icc_profile(pbi, data + type_length, sz - type_length); |
| parsed_payload_bits = sz * 8; |
| } else if (metadata_type == OBU_METADATA_TYPE_USER_DATA_UNREGISTERED) { |
| read_metadata_user_data_unregistered(pbi, data + type_length, |
| sz - type_length); |
| parsed_payload_bits = sz * 8; |
| } else { |
| // Remaining types: TIMECODE, DECODED_FRAME_HASH, SCALABILITY. |
| av2_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); |
| if (metadata_type == OBU_METADATA_TYPE_DECODED_FRAME_HASH) { |
| if (read_metadata_frame_hash(pbi, &rb)) { |
| return sz; |
| } |
| } else { |
| assert(metadata_type == OBU_METADATA_TYPE_TIMECODE); |
| read_metadata_timecode(&rb); |
| } |
| parsed_payload_bits = rb.bit_offset; |
| } |
| |
| // Compute remaining payload bits and skip them. |
| const size_t total_payload_bits = (sz - type_length) * 8; |
| av2_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); |
| rb.bit_offset = (uint32_t)parsed_payload_bits; |
| skip_remaining_mu_payload_bits(&rb, parsed_payload_bits, total_payload_bits); |
| |
| return sz; |
| } |
| |
| static size_t read_metadata_obsp(AV2Decoder *pbi, const uint8_t *data, |
| size_t sz, |
| avm_metadata_array_t *metadata_array, |
| avm_metadata_t *metadata_base, |
| int expected_suffix) { |
| AV2_COMMON *const cm = &pbi->common; |
| |
| struct avm_read_bit_buffer rb; |
| av2_init_read_bit_buffer(pbi, &rb, data, data + sz); |
| |
| metadata_base->is_suffix = avm_rb_read_literal(&rb, 1); |
| |
| // Validate suffix bit if requested |
| if (expected_suffix >= 0 && metadata_base->is_suffix != expected_suffix) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| |
| metadata_base->necessity_idc = |
| (avm_metadata_necessity_t)avm_rb_read_literal(&rb, 2); |
| metadata_base->application_id = |
| (avm_metadata_application_id_t)avm_rb_read_literal(&rb, 5); |
| |
| const size_t bytes_read = avm_rb_bytes_read(&rb); |
| assert(bytes_read == 1); |
| |
| size_t count_length; |
| uint64_t count_minus_1; |
| if (avm_uleb_decode(data + bytes_read, sz - bytes_read, &count_minus_1, |
| &count_length) < 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| |
| metadata_array->sz = count_minus_1 + 1; |
| |
| // Ensure metadata_unit_cnt doesn't exceed 2^14 (uleb128 <= 2 bytes) |
| if (metadata_array->sz > 16384) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| |
| return bytes_read + count_length; |
| } |
| |
| static size_t read_metadata_unit_header(AV2Decoder *pbi, const uint8_t *data, |
| size_t sz, avm_metadata_t *metadata, |
| const ObuHeader *obu_header) { |
| AV2_COMMON *const cm = &pbi->common; |
| size_t type_length; |
| uint64_t type_value; |
| if (avm_uleb_decode(data, sz, &type_value, &type_length) < 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| metadata->type = (uint32_t)type_value; |
| size_t bytes_read = type_length; |
| |
| struct avm_read_bit_buffer rb; |
| av2_init_read_bit_buffer(pbi, &rb, data + bytes_read, data + sz); |
| |
| const size_t muh_header_size = avm_rb_read_literal(&rb, 7); |
| metadata->cancel_flag = avm_rb_read_literal(&rb, 1); |
| assert(avm_rb_bytes_read(&rb) == 1); |
| bytes_read += avm_rb_bytes_read(&rb); |
| |
| const size_t total_size = bytes_read + muh_header_size; |
| assert(total_size <= sz); |
| |
| if (!metadata->cancel_flag) { |
| size_t size_length; |
| uint64_t size_value = 0; |
| if (avm_uleb_decode(data + bytes_read, sz - bytes_read, &size_value, |
| &size_length) < 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| metadata->sz = size_value; |
| bytes_read += size_length; |
| |
| av2_init_read_bit_buffer(pbi, &rb, data + bytes_read, data + sz); |
| |
| metadata->layer_idc = (avm_metadata_layer_t)avm_rb_read_literal(&rb, 3); |
| metadata->persistence_idc = |
| (avm_metadata_persistence_t)avm_rb_read_literal(&rb, 3); |
| metadata->priority = avm_rb_read_literal(&rb, 8); |
| avm_rb_read_literal(&rb, 2); // reserved bits |
| |
| assert(avm_rb_bytes_read(&rb) == 2); |
| |
| if (metadata->layer_idc == AVM_LAYER_VALUES) { |
| if (obu_header->obu_xlayer_id == 31) { |
| metadata->xlayer_map = avm_rb_read_unsigned_literal(&rb, 32); |
| assert((metadata->xlayer_map & (1u << 31)) == 0); |
| for (int n = 0; n < 31; n++) { |
| if (metadata->xlayer_map & (1u << n)) { |
| metadata->mlayer_map[n] = avm_rb_read_unsigned_literal(&rb, 8); |
| } |
| } |
| } else { |
| metadata->mlayer_map[obu_header->obu_xlayer_id] = |
| avm_rb_read_unsigned_literal(&rb, 8); |
| } |
| } |
| |
| bytes_read += avm_rb_bytes_read(&rb); |
| } |
| |
| assert(bytes_read <= total_size); |
| return total_size; |
| } |
| |
| static size_t read_metadata_obu(AV2Decoder *pbi, const uint8_t *data, size_t sz, |
| ObuHeader *obu_header, int expected_suffix) { |
| AV2_COMMON *const cm = &pbi->common; |
| |
| avm_metadata_array_t metadata_array = { 0 }; |
| avm_metadata_t metadata_base; |
| memset(&metadata_base, 0, sizeof(metadata_base)); |
| size_t bytes_read = read_metadata_obsp(pbi, data, sz, &metadata_array, |
| &metadata_base, expected_suffix); |
| |
| for (uint32_t i = 0; i < metadata_array.sz; i++) { |
| avm_metadata_t metadata = { 0 }; |
| // copy shared fields read in `read_metadata_obsp` |
| memcpy(&metadata, &metadata_base, sizeof(metadata)); |
| |
| const size_t muh_size = read_metadata_unit_header( |
| pbi, data + bytes_read, sz - bytes_read, &metadata, obu_header); |
| if (muh_size == 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| bytes_read += muh_size; |
| if (!metadata.cancel_flag) { |
| if (sz - bytes_read < metadata.sz) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| const size_t mup_size = |
| read_metadata_unit_payload(pbi, data + bytes_read, &metadata); |
| bytes_read += mup_size; |
| } |
| } |
| |
| if (bytes_read >= sz || data[bytes_read] != 0x80) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| return bytes_read + 1; |
| } |
| |
| // Checks the metadata for correct syntax but ignores the parsed metadata. |
| // |
| // On success, returns the number of bytes read from 'data'. On failure, sets |
| // pbi->common.error.error_code and returns 0, or calls avm_internal_error() |
| // and does not return. |
| // expected_suffix: 0 for prefix metadata, 1 for suffix metadata, -1 for no |
| // validation |
| static size_t read_metadata_short(AV2Decoder *pbi, const uint8_t *data, |
| size_t sz, int expected_suffix) { |
| AV2_COMMON *const cm = &pbi->common; |
| size_t type_length; |
| uint64_t type_value; |
| struct avm_read_bit_buffer rb; |
| av2_init_read_bit_buffer(pbi, &rb, data, data + sz); |
| |
| uint8_t metadata_is_suffix = avm_rb_read_bit(&rb); |
| |
| // Validate suffix bit if requested |
| if (expected_suffix >= 0 && metadata_is_suffix != expected_suffix) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| |
| uint8_t muh_layer_idc = avm_rb_read_literal(&rb, 3); |
| uint8_t muh_cancel_flag = avm_rb_read_bit(&rb); |
| uint8_t muh_persistence_idc = avm_rb_read_literal(&rb, 3); |
| if (avm_uleb_decode( |
| data + 1, // read type from the position data + 1 |
| sz - 1, // one less bytes available due to extra parameters |
| &type_value, &type_length) < 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| |
| const OBU_METADATA_TYPE metadata_type = (OBU_METADATA_TYPE)type_value; |
| |
| // Increase the type_length by 1 byte since there is one prefix byte added |
| // before the type |
| ++type_length; |
| if (muh_cancel_flag) return sz; |
| |
| // Update the metadata with the header fields we read |
| if (pbi->metadata && pbi->metadata->sz > 0) { |
| avm_metadata_t *last_metadata = |
| pbi->metadata->metadata_array[pbi->metadata->sz - 1]; |
| if (last_metadata && last_metadata->type == OBU_METADATA_TYPE_ITUT_T35) { |
| last_metadata->is_suffix = metadata_is_suffix; |
| last_metadata->layer_idc = muh_layer_idc; |
| last_metadata->cancel_flag = muh_cancel_flag; |
| last_metadata->persistence_idc = muh_persistence_idc; |
| } |
| } |
| |
| const bool known_metadata_type = |
| (metadata_type > OBU_METADATA_TYPE_AVM_RESERVED_0) && |
| (metadata_type < NUM_OBU_METADATA_TYPES); |
| if (!known_metadata_type) { |
| // If metadata_type is reserved for future use or a user private value, |
| // ignore the entire OBU and just check trailing bits. |
| if (get_last_nonzero_byte(data + type_length, sz - type_length) == 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| return sz; |
| } |
| if (metadata_type == OBU_METADATA_TYPE_ITUT_T35) { |
| // read_metadata_itut_t35() checks trailing bits. |
| read_metadata_itut_t35_short(pbi, data + type_length, sz - type_length); |
| // Update the metadata with the header fields we read |
| if (pbi->metadata && pbi->metadata->sz > 0) { |
| avm_metadata_t *last_metadata = |
| pbi->metadata->metadata_array[pbi->metadata->sz - 1]; |
| if (last_metadata && last_metadata->type == OBU_METADATA_TYPE_ITUT_T35) { |
| last_metadata->is_suffix = metadata_is_suffix; |
| last_metadata->layer_idc = muh_layer_idc; |
| last_metadata->cancel_flag = muh_cancel_flag; |
| last_metadata->persistence_idc = muh_persistence_idc; |
| } |
| } |
| return sz; |
| } else if (metadata_type == OBU_METADATA_TYPE_HDR_CLL) { |
| size_t bytes_read = |
| type_length + |
| read_metadata_hdr_cll(pbi, data + type_length, sz - type_length); |
| if (get_last_nonzero_byte(data + bytes_read, sz - bytes_read) != 0x80) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| // Update the metadata with the header fields we read |
| if (pbi->metadata && pbi->metadata->sz > 0) { |
| avm_metadata_t *last_metadata = |
| pbi->metadata->metadata_array[pbi->metadata->sz - 1]; |
| if (last_metadata && last_metadata->type == OBU_METADATA_TYPE_HDR_CLL) { |
| last_metadata->is_suffix = metadata_is_suffix; |
| last_metadata->layer_idc = muh_layer_idc; |
| last_metadata->cancel_flag = muh_cancel_flag; |
| last_metadata->persistence_idc = muh_persistence_idc; |
| } |
| } |
| return sz; |
| } else if (metadata_type == OBU_METADATA_TYPE_HDR_MDCV) { |
| size_t bytes_read = |
| type_length + |
| read_metadata_hdr_mdcv(pbi, data + type_length, sz - type_length); |
| if (get_last_nonzero_byte(data + bytes_read, sz - bytes_read) != 0x80) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| // Update the metadata with the header fields we read |
| if (pbi->metadata && pbi->metadata->sz > 0) { |
| avm_metadata_t *last_metadata = |
| pbi->metadata->metadata_array[pbi->metadata->sz - 1]; |
| if (last_metadata && last_metadata->type == OBU_METADATA_TYPE_HDR_MDCV) { |
| last_metadata->is_suffix = metadata_is_suffix; |
| last_metadata->layer_idc = muh_layer_idc; |
| last_metadata->cancel_flag = muh_cancel_flag; |
| last_metadata->persistence_idc = muh_persistence_idc; |
| } |
| } |
| return sz; |
| } else if (metadata_type == OBU_METADATA_TYPE_SCAN_TYPE) { |
| const size_t kMinScanTypeHeaderSize = 1; |
| if (sz < kMinScanTypeHeaderSize) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Incorrect scan type metadata payload size"); |
| } |
| av2_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); |
| read_metadata_scan_type(pbi, &rb); |
| return sz; |
| } else if (metadata_type == OBU_METADATA_TYPE_TEMPORAL_POINT_INFO) { |
| const size_t kMinTemporalPointInfoHeaderSize = 1; |
| if (sz < kMinTemporalPointInfoHeaderSize) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "Incorrect temporal point info metadata payload size"); |
| } |
| av2_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); |
| read_metadata_temporal_point_info(pbi, &rb); |
| return sz; |
| } |
| |
| av2_init_read_bit_buffer(pbi, &rb, data + type_length, data + sz); |
| if (metadata_type == OBU_METADATA_TYPE_DECODED_FRAME_HASH) { |
| if (read_metadata_frame_hash(pbi, &rb)) { |
| // Unsupported Decoded Frame Hash metadata. Ignoring the entire OBU and |
| // just checking trailing bits |
| if (get_last_nonzero_byte(data + type_length, sz - type_length) == 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| return sz; |
| } |
| } else if (metadata_type == OBU_METADATA_TYPE_BANDING_HINTS) { |
| // Banding hints metadata is variable bits, not byte-aligned |
| read_metadata_banding_hints_from_rb(pbi, &rb); |
| // Update the metadata with the header fields we read |
| if (pbi->metadata && pbi->metadata->sz > 0) { |
| avm_metadata_t *last_metadata = |
| pbi->metadata->metadata_array[pbi->metadata->sz - 1]; |
| if (last_metadata && |
| last_metadata->type == OBU_METADATA_TYPE_BANDING_HINTS) { |
| last_metadata->is_suffix = metadata_is_suffix; |
| last_metadata->layer_idc = muh_layer_idc; |
| last_metadata->cancel_flag = muh_cancel_flag; |
| last_metadata->persistence_idc = muh_persistence_idc; |
| } |
| } |
| } else if (metadata_type == OBU_METADATA_TYPE_ICC_PROFILE) { |
| // ICC profile is byte-aligned binary data |
| // Find the last nonzero byte (should be 0x80 trailing byte) |
| const int last_nonzero_idx = |
| get_last_nonzero_byte_index(data + type_length, sz - type_length); |
| if (last_nonzero_idx < 0 || data[type_length + last_nonzero_idx] != 0x80) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| // ICC payload size excludes the trailing 0x80 byte |
| const size_t icc_payload_size = last_nonzero_idx; |
| read_metadata_icc_profile(pbi, data + type_length, icc_payload_size); |
| return sz; |
| } else if (metadata_type == OBU_METADATA_TYPE_USER_DATA_UNREGISTERED) { |
| // User data unregistered is byte-aligned binary data |
| // Find the last nonzero byte (should be 0x80 trailing byte) |
| const int last_nonzero_idx = |
| get_last_nonzero_byte_index(data + type_length, sz - type_length); |
| if (last_nonzero_idx < 0 || data[type_length + last_nonzero_idx] != 0x80) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| // User data payload size excludes the trailing 0x80 byte |
| const size_t user_data_payload_size = last_nonzero_idx; |
| read_metadata_user_data_unregistered(pbi, data + type_length, |
| user_data_payload_size); |
| return sz; |
| } else { |
| assert(metadata_type == OBU_METADATA_TYPE_TIMECODE); |
| read_metadata_timecode(&rb); |
| } |
| { |
| // Compute remaining payload bits and skip them. |
| // Subtract 1 from sz to exclude the trailing 0x80 byte, which is part of |
| // metadata_short_obu() trailing_bits() syntax, not metadata_unit() payload. |
| const size_t parsed_payload_bits = rb.bit_offset; |
| const size_t total_payload_bits = (sz - type_length - 1) * 8; |
| skip_remaining_mu_payload_bits(&rb, parsed_payload_bits, |
| total_payload_bits); |
| } |
| if (av2_check_trailing_bits(pbi, &rb) != 0) { |
| // cm->error.error_code is already set. |
| return 0; |
| } |
| assert((rb.bit_offset & 7) == 0); |
| return type_length + (rb.bit_offset >> 3); |
| } |
| // On success, returns 'sz'. On failure, sets pbi->common.error.error_code and |
| // returns 0. |
| static size_t read_padding(AV2_COMMON *const cm, const uint8_t *data, |
| size_t sz) { |
| // The spec allows a padding OBU to be header-only (i.e., obu_size = 0). So |
| // check trailing bits only if sz > 0. |
| if (sz > 0) { |
| // The payload of a padding OBU is byte aligned. Therefore the first |
| // trailing byte should be 0x80. See https://crbug.com/aomedia/2393. |
| const uint8_t last_nonzero_byte = get_last_nonzero_byte(data, sz); |
| if (last_nonzero_byte != 0x80) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return 0; |
| } |
| } |
| return sz; |
| } |
| |
| int av2_is_leading_vcl_obu(OBU_TYPE obu_type) { |
| return (obu_type == OBU_LEADING_TILE_GROUP || obu_type == OBU_LEADING_SEF || |
| obu_type == OBU_LEADING_TIP); |
| } |
| |
| // Check if any obu is present between two tile groups of one frame unit. |
| static void check_tilegroup_obus_in_a_frame_unit(AV2_COMMON *const cm, |
| obu_info *current_obu, |
| obu_info *prev_obu) { |
| if (current_obu->obu_type != prev_obu->obu_type || |
| current_obu->immediate_output_picture != |
| prev_obu->immediate_output_picture || |
| current_obu->showable_frame != prev_obu->showable_frame || |
| current_obu->display_order_hint != prev_obu->display_order_hint || |
| current_obu->mlayer_id != prev_obu->mlayer_id) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "%s : no non-padding obu is allowed between tilegroup obus in a frame " |
| "unit (current obu %s, current oh %d previous obu %s previous oh %d)", |
| __func__, avm_obu_type_to_string(current_obu->obu_type), |
| current_obu->display_order_hint, |
| avm_obu_type_to_string(prev_obu->obu_type), |
| prev_obu->display_order_hint); |
| } |
| } |
| |
| // TU validation: Check if an OBU type is metadata obu |
| static int is_metadata_obu(OBU_TYPE obu_type) { |
| return (obu_type == OBU_METADATA_SHORT || obu_type == OBU_METADATA_GROUP); |
| } |
| |
| // TU validation: Check if an OBU type is global configuration information |
| static int is_global_config_obu(OBU_TYPE obu_type, int xlayer_id) { |
| return obu_type == OBU_MULTI_STREAM_DECODER_OPERATION || |
| (obu_type == OBU_LAYER_CONFIGURATION_RECORD && |
| xlayer_id == GLOBAL_XLAYER_ID) || |
| (obu_type == OBU_OPERATING_POINT_SET && |
| xlayer_id == GLOBAL_XLAYER_ID) || |
| (obu_type == OBU_ATLAS_SEGMENT && xlayer_id == GLOBAL_XLAYER_ID) || |
| (obu_type == OBU_METADATA_SHORT && xlayer_id == GLOBAL_XLAYER_ID) || |
| (obu_type == OBU_METADATA_GROUP && xlayer_id == GLOBAL_XLAYER_ID); |
| } |
| |
| // TU validation: Check if an OBU type is local configuration information |
| static int is_local_config_obu(OBU_TYPE obu_type, int xlayer_id) { |
| return (obu_type == OBU_LAYER_CONFIGURATION_RECORD && |
| xlayer_id != GLOBAL_XLAYER_ID) || |
| (obu_type == OBU_OPERATING_POINT_SET && |
| xlayer_id != GLOBAL_XLAYER_ID) || |
| (obu_type == OBU_ATLAS_SEGMENT && xlayer_id != GLOBAL_XLAYER_ID); |
| } |
| |
| // TU validation: Check if an OBU type is not global or local configuration |
| // information, not sequence header or not padding |
| static int is_frame_unit(OBU_TYPE obu_type, int xlayer_id) { |
| // OBU_MULTI_FRAME_HEADER, |
| // OBU_BUFFER_REMOVAL_TIMING, |
| // OBU_QUANTIZATION_MATRIX, |
| // OBU_FILM_GRAIN_MODEL, |
| // OBU_CONTENT_INTERPRETATION, |
| // OBU_METADATA_SHORT, |
| // OBU_METADATA_GROUP, |
| // OBU_CLOSED_LOOP_KEY, |
| // OBU_OPEN_LOOP_KEY, |
| // OBU_LEADING_TILE_GROUP, |
| // OBU_REGULAR_TILE_GROUP, |
| // OBU_SWITCH, |
| // OBU_LEADING_SEF, |
| // OBU_REGULAR_SEF, |
| // OBU_LEADING_TIP, |
| // OBU_REGULAR_TIP, |
| // OBU_BRIDGE_FRAME, |
| // OBU_RAS_FRAME |
| int non_frame_unit_obu = is_global_config_obu(obu_type, xlayer_id) || |
| is_local_config_obu(obu_type, xlayer_id) || |
| obu_type == OBU_SEQUENCE_HEADER || |
| obu_type == OBU_PADDING; |
| |
| return !non_frame_unit_obu; |
| } |
| |
| static int is_coded_frame(OBU_TYPE obu_type) { |
| return is_multi_tile_vcl_obu(obu_type) || is_single_tile_vcl_obu(obu_type); |
| } |
| // Validates OBU order within a Temporal Unit with state machine. |
| // Returns 1 if OBU is valid for the current state, 0 if it violates rules. |
| // Note: The caller is responsible for filtering out padding OBUs and reserved |
| // OBUs before calling this function. |
| // |
| // After the global information phase, all remaining OBUs are grouped by |
| // xlayer_id in strictly increasing order. Within each xlayer group the full |
| // phase progression is enforced: |
| // local config (LCR -> OPS -> Atlas) -> SH -> frame unit data |
| // When the xlayer_id increases, the state resets to TU_STATE_LOCAL_INFO so |
| // the new xlayer group may begin with local config, SH, or frame unit data. |
| int check_temporal_unit_structure(temporal_unit_state_t *state, int obu_type, |
| int xlayer_id, int metadata_is_suffix, |
| int prev_obu_type, int prev_xlayer_id) { |
| // Validate input parameters |
| if (!state) return 0; |
| |
| // After the global phase, detect an xlayer_id increase and reset the |
| // per-xlayer state machine so the new group starts fresh. |
| if (*state == TU_STATE_LOCAL_INFO || *state == TU_STATE_SEQUENCE_HEADER || |
| *state == TU_STATE_FRAME_UINT_DATA) { |
| if (xlayer_id != GLOBAL_XLAYER_ID && prev_xlayer_id != GLOBAL_XLAYER_ID && |
| xlayer_id != prev_xlayer_id) { |
| if (xlayer_id < prev_xlayer_id) return 0; // Must be increasing |
| // New xlayer group: reset to local info phase. |
| *state = TU_STATE_LOCAL_INFO; |
| } |
| } |
| |
| switch (*state) { |
| case TU_STATE_START: |
| case TU_STATE_TEMPORAL_DELIMITER: |
| if (obu_type == OBU_TEMPORAL_DELIMITER) { |
| if (*state == TU_STATE_TEMPORAL_DELIMITER) |
| return 0; // Only one allowed |
| *state = TU_STATE_TEMPORAL_DELIMITER; |
| return 1; |
| } else if (is_global_config_obu(obu_type, |
| xlayer_id)) { // First OBU: global config |
| *state = TU_STATE_GLOBAL_INFO; |
| return 1; |
| } else if (is_local_config_obu(obu_type, |
| xlayer_id)) { // First OBU: local config |
| *state = TU_STATE_LOCAL_INFO; |
| return 1; |
| } else if (obu_type == OBU_SEQUENCE_HEADER) { |
| *state = TU_STATE_SEQUENCE_HEADER; |
| return 1; |
| } else if (is_frame_unit(obu_type, xlayer_id)) { |
| *state = TU_STATE_FRAME_UINT_DATA; |
| return 1; |
| } else { // Invalid OBU type for start of temporal unit |
| return 0; |
| } |
| |
| case TU_STATE_GLOBAL_INFO: |
| if (is_global_config_obu(obu_type, xlayer_id)) { |
| // 0 or 1 OBU_MULTI_STREAM_DECODER_OPERATION, |
| // 0 or more: OBU_LAYER_CONFIGURATION_RECORD |
| // 0 or more: OBU_OPERATING_POINT_SET |
| // 0 or more: OBU_ATLAS_SEGMENT |
| // 0 or more: OBU_METADATA(obu_xlayer_id = 0x1F) |
| // MSDO -> LCR -> LCR -> OPS -> OPS -> ATS -> ATS -> METADATA -> |
| // METADATA |
| if (obu_type == OBU_MULTI_STREAM_DECODER_OPERATION) |
| return 0; // Only one allowed |
| else if (obu_type == OBU_LAYER_CONFIGURATION_RECORD && |
| (prev_obu_type == OBU_OPERATING_POINT_SET || |
| prev_obu_type == OBU_ATLAS_SEGMENT || |
| is_metadata_obu(prev_obu_type))) { |
| return 0; |
| } else if (obu_type == OBU_OPERATING_POINT_SET && |
| (prev_obu_type == OBU_ATLAS_SEGMENT || |
| is_metadata_obu(prev_obu_type))) { |
| return 0; |
| } else if (obu_type == OBU_ATLAS_SEGMENT && |
| is_metadata_obu(prev_obu_type)) { |
| return 0; |
| } else |
| return 1; |
| } else if (is_local_config_obu(obu_type, xlayer_id)) { |
| *state = TU_STATE_LOCAL_INFO; // Transition from global to local |
| return 1; |
| } else if (obu_type == OBU_SEQUENCE_HEADER) { |
| *state = TU_STATE_SEQUENCE_HEADER; |
| return 1; |
| } else if (is_frame_unit(obu_type, xlayer_id)) { |
| *state = TU_STATE_FRAME_UINT_DATA; |
| return 1; |
| } else { |
| // Invalid OBU type during global info phase or wrong xlayer_id |
| return 0; |
| } |
| |
| case TU_STATE_LOCAL_INFO: |
| if (is_local_config_obu(obu_type, xlayer_id)) { |
| // Within the same xlayer group: LCR -> OPS -> Atlas (no going back). |
| if (xlayer_id == prev_xlayer_id) { |
| if (obu_type == OBU_LAYER_CONFIGURATION_RECORD && |
| prev_obu_type != OBU_LAYER_CONFIGURATION_RECORD) { |
| return 0; |
| } else if (obu_type == OBU_OPERATING_POINT_SET && |
| prev_obu_type == OBU_ATLAS_SEGMENT) { |
| return 0; |
| } |
| } |
| // First OBU in a new xlayer group: any local config type is valid. |
| return 1; |
| } else if (obu_type == OBU_SEQUENCE_HEADER) { |
| *state = TU_STATE_SEQUENCE_HEADER; |
| return 1; |
| } else if (is_frame_unit(obu_type, xlayer_id)) { |
| *state = TU_STATE_FRAME_UINT_DATA; |
| return 1; |
| } else { |
| return 0; // Invalid OBU type(such as global obus) during local info |
| // phase |
| } |
| |
| case TU_STATE_SEQUENCE_HEADER: |
| if (obu_type == OBU_SEQUENCE_HEADER) { |
| return 1; |
| } else if (is_frame_unit(obu_type, xlayer_id)) { |
| *state = TU_STATE_FRAME_UINT_DATA; |
| return 1; |
| } else { |
| return 0; // Invalid OBU type(such as global obus) during sequence |
| // header phase |
| } |
| |
| case TU_STATE_FRAME_UINT_DATA: |
| if (is_frame_unit(obu_type, xlayer_id)) { |
| // Within the same xlayer group: enforce existing type ordering. |
| // CI -> CI -> MFH -> MFH -> (BRT, QM, FGM, METADATA_prefix, |
| // METADATA_SHORT_prefix) -> coded_frame -> METADATA_suffix, |
| // METADATA_SHORT_suffix) |
| if (obu_type == OBU_CONTENT_INTERPRETATION && |
| prev_obu_type != OBU_CONTENT_INTERPRETATION) |
| return 0; |
| else if (obu_type == OBU_MULTI_FRAME_HEADER && |
| (prev_obu_type != OBU_CONTENT_INTERPRETATION && |
| prev_obu_type != OBU_MULTI_FRAME_HEADER)) |
| return 0; |
| else if (((is_metadata_obu(obu_type) && |
| metadata_is_suffix == 0) || // prefix |
| obu_type == OBU_BUFFER_REMOVAL_TIMING || |
| obu_type == OBU_QUANTIZATION_MATRIX || |
| obu_type == OBU_FILM_GRAIN_MODEL) && |
| (is_coded_frame(prev_obu_type) || |
| (is_metadata_obu(prev_obu_type) && |
| metadata_is_suffix == 1))) // suffix |
| return 0; |
| else // other cases may be evaluated later |
| return 1; |
| } else { |
| return 0; |
| } |
| |
| default: |
| // Invalid state |
| return 0; |
| } |
| } |
| |
| // Check if the CLK is the first frame of a mlayer. |
| static void check_clk_in_a_layer(AV2_COMMON *const cm, |
| obu_info *current_frame_unit, |
| obu_info *last_frame_unit) { |
| if (current_frame_unit->obu_type == OBU_CLOSED_LOOP_KEY && |
| last_frame_unit->obu_type != OBU_CLOSED_LOOP_KEY && |
| current_frame_unit->mlayer_id == last_frame_unit->mlayer_id && |
| current_frame_unit->display_order_hint == |
| last_frame_unit->display_order_hint) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "%s : a CLK should be the first frame of a mlayer. " |
| "current obu %s, current oh " |
| "%d, current mlayer_id %d, " |
| "previous obu %s previous oh %d previous mlayer_id %d ", |
| __func__, avm_obu_type_to_string(current_frame_unit->obu_type), |
| current_frame_unit->display_order_hint, current_frame_unit->mlayer_id, |
| avm_obu_type_to_string(last_frame_unit->obu_type), |
| last_frame_unit->display_order_hint, last_frame_unit->mlayer_id); |
| } |
| } |
| |
| // Check the mlayer ids of frame units before the current hidden frame. |
| static void check_layerid_hidden_frame_units(AV2_COMMON *const cm, |
| obu_info *current_frame_unit, |
| obu_info *last_frame_unit) { |
| //[H:layer0][H:layer1] not allowed |
| //[H:layer1][H:layer1] checked later : [H:layer1][H:layer1][S:layer1] ok, |
| //[H:layer1][H:layer1][S:layer0] not allowed [H:layer2][H:layer1] not allowed |
| //[S:layer0][H:layer1] checked later: |
| // 1) [S:layer0][H:layer1][S:layer1] maybe ok, |
| // 2) [S:layer0][H:layer1][S:layer0] not allowed |
| //[S:layer1][H:layer1] checked later : |
| // 1) [S:layer1][H:layer1][S:layer1] maybe ok (e.g. CLK[0], Bridge[0], TG[1]) |
| // 2) [S:layer1][H:layer1][S:layer0] not allowed |
| // 3) [S:layer1][H:layer1][S:layer2] not allowed |
| //[S:layer2][H:layer1] allowed |
| if ((last_frame_unit->showable_frame == 0 && |
| current_frame_unit->mlayer_id != last_frame_unit->mlayer_id)) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "%s : hidden frames should proceed displayable frames in a " |
| "layer:\n\tcurrent : " |
| "(%s, OH%d, L%d, S%d)\n\t" |
| "previous : (%s, OH%d, L%d, S%d)", |
| __func__, avm_obu_type_to_string(current_frame_unit->obu_type), |
| current_frame_unit->display_order_hint, current_frame_unit->mlayer_id, |
| current_frame_unit->showable_frame, |
| avm_obu_type_to_string(last_frame_unit->obu_type), |
| last_frame_unit->display_order_hint, last_frame_unit->mlayer_id, |
| last_frame_unit->showable_frame); |
| } |
| } |
| |
| // Check the mlayer ids of frame units before the current showable frame. |
| static void check_layerid_showable_frame_units( |
| AV2_COMMON *const cm, obu_info *current_frame_unit, |
| obu_info *last_frame_unit, obu_info *last_displayable_frame_unit) { |
| //[H:layer0][*S:layer1] not allowed |
| // 3) [S:layer1][H:layer1][*S:layer2] not allowed |
| //[H:layer1][*S:layer1] check last displayable frame unit |
| // 1) [S:layer0][H:layer1][*S:layer1] is allowed |
| // 1) [S:layer1][H:layer1][*S:layer1] maybe okay - doh comparison required |
| // betwee S and S |
| //[H:layer2][*S:layer1] check last displayable frame unit |
| // 2) [S:layer0][H:layer1][*S:layer0] not allowed |
| // 2) [S:layer1][H:layer1][*S:layer0] not allowed |
| |
| //[S:layer0][*S:layer1] allowed |
| //[S:layer1][*S:layer1] check orderhint of [S:layer1] and [S:layer1] |
| //[S:layer2][*S:layer1] check orderhint of [S:layer2] and [S:layer1] |
| |
| if (last_frame_unit->showable_frame == 0 && |
| current_frame_unit->mlayer_id != last_frame_unit->mlayer_id) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "%s : hidden frames should proceed displayable frames in a " |
| "layer:\n\tcurrent : " |
| "(%s, OH%d, L%d, S%d)\n\t" |
| "previous : (%s, OH%d, L%d, S%d)", |
| __func__, avm_obu_type_to_string(current_frame_unit->obu_type), |
| current_frame_unit->display_order_hint, current_frame_unit->mlayer_id, |
| current_frame_unit->showable_frame, |
| avm_obu_type_to_string(last_frame_unit->obu_type), |
| last_frame_unit->display_order_hint, last_frame_unit->mlayer_id, |
| last_frame_unit->showable_frame); |
| } else if (last_frame_unit->showable_frame == 0 && |
| current_frame_unit->mlayer_id == last_frame_unit->mlayer_id && |
| current_frame_unit->mlayer_id == |
| last_displayable_frame_unit->mlayer_id) { |
| if (current_frame_unit->display_order_hint == |
| last_displayable_frame_unit->display_order_hint) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "%s: mlayer_id should be in ascending order or order_hint should be " |
| "different:\n" |
| "\tcurrent : (%s, OH%d, L%d, S%d)\n" |
| "\tprevious : (%s, S%d)\n" |
| "\tlast_displayable : (%s, OH%d, L%d)", |
| __func__, avm_obu_type_to_string(current_frame_unit->obu_type), |
| current_frame_unit->display_order_hint, current_frame_unit->mlayer_id, |
| current_frame_unit->showable_frame, |
| avm_obu_type_to_string(last_frame_unit->obu_type), |
| last_frame_unit->showable_frame, |
| avm_obu_type_to_string(last_displayable_frame_unit->obu_type), |
| last_displayable_frame_unit->display_order_hint, |
| last_displayable_frame_unit->mlayer_id); |
| } |
| } else if (last_frame_unit->showable_frame == 1 && |
| current_frame_unit->mlayer_id <= last_frame_unit->mlayer_id) { |
| if (current_frame_unit->display_order_hint == |
| last_frame_unit->display_order_hint) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "%s: mlayer_id should be in ascending order or order_hint should be " |
| "different:\n\tcurrent obu %s, current oh " |
| "%d, current mlayer_id %d\n\t" |
| "previous obu %s previous oh %d previous mlayer_id %d", |
| __func__, avm_obu_type_to_string(current_frame_unit->obu_type), |
| current_frame_unit->display_order_hint, current_frame_unit->mlayer_id, |
| avm_obu_type_to_string(last_frame_unit->obu_type), |
| last_frame_unit->display_order_hint, last_frame_unit->mlayer_id); |
| } |
| } |
| } |
| |
| // Check xlayer_id, mlayer_id, and tlayer_id of the obu is valid for the |
| // obu_type. Reports with avm_internal_error. |
| static void check_valid_layer_id(ObuHeader obu_header, AV2_COMMON *const cm) { |
| // Ignore reserved OBUs. |
| if (!avm_obu_type_is_valid(obu_header.type)) return; |
| |
| if (obu_header.obu_xlayer_id == GLOBAL_XLAYER_ID && |
| (obu_header.obu_tlayer_id != 0 || obu_header.obu_mlayer_id != 0)) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Incorrect layer_id for %s: tlayer_id %d mlayer_id %d xlayer_id %d", |
| avm_obu_type_to_string(obu_header.type), obu_header.obu_tlayer_id, |
| obu_header.obu_mlayer_id, obu_header.obu_xlayer_id); |
| } |
| if (obu_header.type == OBU_MULTI_STREAM_DECODER_OPERATION && |
| obu_header.obu_xlayer_id != GLOBAL_XLAYER_ID) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Incorrect obu_xlayer_id for MSDO: %d", |
| obu_header.obu_xlayer_id); |
| } |
| if (obu_header.type == OBU_SEQUENCE_HEADER || |
| obu_header.type == OBU_TEMPORAL_DELIMITER || |
| obu_header.type == OBU_LAYER_CONFIGURATION_RECORD || |
| obu_header.type == OBU_OPERATING_POINT_SET || |
| obu_header.type == OBU_ATLAS_SEGMENT) { |
| if (obu_header.obu_tlayer_id != 0 || obu_header.obu_mlayer_id != 0) |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Incorrect layer_id for %s: " |
| "tlayer_id %d mlayer_id %d", |
| avm_obu_type_to_string(obu_header.type), |
| obu_header.obu_tlayer_id, obu_header.obu_mlayer_id); |
| } |
| |
| // MSDO, LCR, OPS, Atlas, Short Metadata OBU, Metadata Group OBU, Padding, |
| // Temporal Delimiter, and Buffer removal timing. |
| if (obu_header.obu_xlayer_id == GLOBAL_XLAYER_ID && |
| !(obu_header.type == OBU_TEMPORAL_DELIMITER || |
| obu_header.type == OBU_METADATA_SHORT || |
| obu_header.type == OBU_METADATA_GROUP || |
| obu_header.type == OBU_BUFFER_REMOVAL_TIMING || |
| obu_header.type == OBU_LAYER_CONFIGURATION_RECORD || |
| obu_header.type == OBU_ATLAS_SEGMENT || |
| obu_header.type == OBU_OPERATING_POINT_SET || |
| obu_header.type == OBU_MULTI_STREAM_DECODER_OPERATION || |
| obu_header.type == OBU_PADDING)) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Incorrect layer_id for %s: xlayer_id %d", |
| avm_obu_type_to_string(obu_header.type), |
| obu_header.obu_xlayer_id); |
| } |
| |
| // CLK/OLK are only present in temporal layer 0 |
| if ((obu_header.type == OBU_CLOSED_LOOP_KEY || |
| obu_header.type == OBU_OPEN_LOOP_KEY) && |
| obu_header.obu_tlayer_id != 0) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Incorrect tlayer_id for %s: tlayer_id %d", |
| avm_obu_type_to_string(obu_header.type), |
| obu_header.obu_tlayer_id); |
| } |
| } |
| |
| static BITSTREAM_PROFILE get_msdo_profile(struct AV2Decoder *pbi) { |
| return pbi->common.msdo_params.multistream_profile_idc; |
| } |
| |
| static BITSTREAM_PROFILE get_lcr_global_profile(struct AV2Decoder *pbi) { |
| // Return the lcr_max_interop from the first valid global LCR's aggregate PTL. |
| // lcr_max_interop maps directly to the IOP (0, 1, 2) which corresponds to |
| // MAIN_420_10_IP0, MAIN_420_10_IP1, MAIN_420_10_IP2 respectively. |
| for (int j = 0; j < MAX_NUM_LCR; j++) { |
| if (pbi->lcr_list[GLOBAL_XLAYER_ID][j].valid) { |
| const struct GlobalLayerConfigurationRecord *glcr = |
| &pbi->lcr_list[GLOBAL_XLAYER_ID][j].global_lcr; |
| if (glcr->lcr_aggregate_info_present_flag) |
| return (BITSTREAM_PROFILE)glcr->aggregate_ptl.lcr_max_interop; |
| // Fall back to the first seq PTL if aggregate PTL is not present. |
| if (glcr->lcr_seq_profile_tier_level_info_present_flag && |
| glcr->LcrMaxNumXLayerCount > 0) |
| return (BITSTREAM_PROFILE)glcr->seq_ptl[glcr->LcrXLayerID[0]] |
| .lcr_seq_profile_idc; |
| } |
| } |
| (void)pbi; |
| return MAIN_420_10_IP2; // Fallback |
| } |
| |
| static BITSTREAM_PROFILE get_lcr_local_profile(struct AV2Decoder *pbi) { |
| // Return the lcr_seq_profile_idc from the first valid local LCR. |
| for (int i = 0; i < GLOBAL_XLAYER_ID; i++) { |
| for (int j = 0; j < MAX_NUM_LCR; j++) { |
| if (pbi->lcr_list[i][j].valid) { |
| const struct LocalLayerConfigurationRecord *llcr = |
| &pbi->lcr_list[i][j].local_lcr; |
| if (llcr->lcr_profile_tier_level_info_present_flag) |
| return (BITSTREAM_PROFILE)llcr->seq_ptl.lcr_seq_profile_idc; |
| } |
| } |
| } |
| (void)pbi; |
| return MAIN_420_10_IP2; // Fallback |
| } |
| |
| // Conformance check for the presence of MSDO and LCR. |
| // The OBU requirements table in Annex A only applies when IOP < 3, i.e. |
| // when the MSDO profile or LCR profile is one of the IP profiles (0, 1, 2). |
| // For profile == 31 (CONFIGURABLE) the table does |
| // not impose additional constraints, so we return true. |
| bool conformance_check_msdo_lcr(struct AV2Decoder *pbi, bool global_lcr_present, |
| bool local_lcr_present) { |
| int msdo_present = pbi->multistream_decoder_mode; |
| int num_extended_layers = 0; |
| int num_embedded_layers = 0; |
| |
| for (int i = 0; i < AVM_MAX_NUM_STREAMS - 1; i++) { |
| if (pbi->xlayer_id_map[i] > 0) num_extended_layers++; |
| } |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) { |
| bool found = false; |
| for (int x = 0; x < AVM_MAX_NUM_STREAMS; x++) { |
| if (pbi->mlayer_id_map[x][i] > 0) { |
| found = true; |
| break; |
| } |
| } |
| if (found) num_embedded_layers++; |
| } |
| assert(num_extended_layers > 0 && num_embedded_layers > 0); |
| |
| // Determine the effective MSDO and LCR profiles. |
| const BITSTREAM_PROFILE msdo_prof = get_msdo_profile(pbi); |
| const BITSTREAM_PROFILE glcr_prof = get_lcr_global_profile(pbi); |
| const BITSTREAM_PROFILE llcr_prof = get_lcr_local_profile(pbi); |
| |
| // The IOP table only applies for IOPs 0-2 (profiles IP0, IP1, IP2). |
| // If the signaled profile is >= 3, the table does not apply. |
| if (msdo_present && msdo_prof == CONFIGURABLE) return true; |
| if (global_lcr_present && glcr_prof == CONFIGURABLE) return true; |
| if (!msdo_present && !global_lcr_present && local_lcr_present && |
| llcr_prof == CONFIGURABLE) { |
| return true; |
| } |
| if (!msdo_present && !global_lcr_present && !local_lcr_present && |
| pbi->common.seq_params.seq_profile_idc == CONFIGURABLE) { |
| return true; |
| } |
| |
| if (num_extended_layers == 1 && num_embedded_layers == 1) { |
| if (!msdo_present) return true; |
| } |
| |
| if (num_extended_layers > 1 && num_embedded_layers == 1) { |
| if (msdo_present && |
| (msdo_prof == MAIN_420_10_IP0 || msdo_prof == MAIN_420_10_IP1 || |
| msdo_prof == MAIN_420_10_IP2 || msdo_prof == MAIN_422_10_IP1 || |
| msdo_prof == MAIN_444_10_IP1)) |
| return true; |
| |
| if (global_lcr_present && glcr_prof == MAIN_420_10_IP2) return true; |
| } |
| |
| if (num_extended_layers == 1 && num_embedded_layers > 1) { |
| if (!msdo_present && local_lcr_present && |
| (llcr_prof == MAIN_420_10_IP1 || llcr_prof == MAIN_422_10_IP1 || |
| llcr_prof == MAIN_444_10_IP1)) |
| return true; |
| |
| if (!msdo_present && (global_lcr_present || local_lcr_present) && |
| (glcr_prof == MAIN_420_10_IP2 || llcr_prof == MAIN_420_10_IP2)) |
| return true; |
| } |
| |
| if (num_extended_layers > 1 && num_embedded_layers > 1) { |
| if (msdo_present && local_lcr_present && msdo_prof == MAIN_420_10_IP2) |
| return true; |
| |
| if (global_lcr_present && glcr_prof == MAIN_420_10_IP2) return true; |
| } |
| return false; |
| } |
| |
| static int get_ops_mlayer_count(const struct OpsMLayerInfo *mlayer_info, |
| int xlayer_id) { |
| if (mlayer_info == NULL) return 0; |
| if (xlayer_id < 0 || xlayer_id >= MAX_NUM_XLAYERS) return 0; |
| return mlayer_info->OPMLayerCount[xlayer_id]; |
| } |
| |
| static int get_ops_tlayer_count(const struct OpsMLayerInfo *mlayer_info, |
| int xlayer_id, int mlayer_id) { |
| if (mlayer_info == NULL) return 0; |
| if (xlayer_id < 0 || xlayer_id >= MAX_NUM_XLAYERS) return 0; |
| if (mlayer_id < 0 || mlayer_id >= MAX_NUM_MLAYERS) return 0; |
| |
| return mlayer_info->OPTLayerCount[xlayer_id][mlayer_id]; |
| } |
| |
| // Default operating point set id |
| static const int default_ops_id = 0; |
| // Default operating point index |
| static const int default_op_index = 0; |
| |
| // Select the operating point for the current xlayer. |
| // If the user has explicitly set an OPS via codec control, use that; |
| // otherwise fall back to the default (ops_id=0, op_index=0). |
| // This function determines the OPS ID to use: |
| // 1. selected_ops_id if >= 0 (user-specified via AV2D_SET_SELECTED_OPS) |
| // 2. otherwise, default_ops_id (0) |
| // |
| // When sbe_state.retention_map_ready is set, num_mlayers and num_tlayers are |
| // derived directly from the SBE retention map so that the decoder layer counts |
| // are consistent with the OBU-level filtering already applied by Annex F. |
| // When the retention map is not ready (no OPS selected, SBE disabled, or map |
| // not yet built), the decoder decodes all layers in the bitstream. |
| static void avm_set_current_operating_point(struct AV2Decoder *pbi, |
| int xlayer_id) { |
| struct DecOperatingPointParams *dec_op_params = &pbi->dec_op_params; |
| |
| // If the Annex F retention map is ready, derive num_mlayers and num_tlayers |
| // from it so that the decoder layer counts match the OBU filter exactly. |
| // This ensures avm_set_current_operating_point and the SBE are always |
| // consistent and share the same source of truth. |
| if (pbi->sbe_state.retention_map_ready && pbi->sbe_state.extraction_enabled) { |
| int xid = xlayer_id; |
| if (xid < 0 || xid >= MAX_NUM_XLAYERS) { |
| avm_internal_error(&pbi->common.error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Invalid xlayer_id %d for operating point selection", |
| xid); |
| } |
| |
| // Count distinct mlayers retained for this xlayer. |
| unsigned int num_mlayers = 0; |
| for (int j = 0; j < MAX_NUM_MLAYERS; j++) { |
| for (int k = 0; k < MAX_NUM_TLAYERS; k++) { |
| if (pbi->sbe_state.retention_map[xid][j][k]) { |
| num_mlayers = j + 1; |
| break; |
| } |
| } |
| } |
| |
| // Count distinct tlayers retained for the base mlayer of this xlayer. |
| unsigned int num_tlayers = 0; |
| for (int k = 0; k < MAX_NUM_TLAYERS; k++) { |
| for (int j = 0; j < MAX_NUM_MLAYERS; j++) { |
| if (pbi->sbe_state.retention_map[xid][j][k]) { |
| num_tlayers = k + 1; |
| break; |
| } |
| } |
| } |
| |
| dec_op_params->num_mlayers = num_mlayers > 0 ? num_mlayers : 1; |
| dec_op_params->num_tlayers = num_tlayers > 0 ? num_tlayers : 1; |
| dec_op_params->isValid = 1; |
| // dec_ops/dec_op/DecOpSetId etc. are still populated below from the OPS |
| // for use by other decoder subsystems that inspect those fields. |
| } |
| |
| int target_ops_id = |
| pbi->selected_ops_id >= 0 ? pbi->selected_ops_id : default_ops_id; |
| |
| // Only proceed to check for the operating point iff the ops id is valid |
| if (target_ops_id < 0 || target_ops_id >= MAX_NUM_OPS_ID) return; |
| |
| // Determine the target op point index. |
| int target_op_index = |
| (pbi->selected_ops_id >= 0) ? pbi->selected_op_index : default_op_index; |
| |
| struct OperatingPointSet *ops = &pbi->ops_list[xlayer_id][target_ops_id]; |
| dec_op_params->dec_ops = ops; |
| dec_op_params->dec_op = dec_op_params->dec_ops->op; |
| if (!ops->valid || ops->ops_id != target_ops_id) { |
| dec_op_params->DecOpSetId = 0; |
| dec_op_params->DecOpCount = 0; |
| dec_op_params->DecOpIndex = 0; |
| // If SBE retention map is not ready or not enabled, decode all layers. |
| if (!pbi->sbe_state.retention_map_ready || |
| !pbi->sbe_state.extraction_enabled) { |
| dec_op_params->num_mlayers = MAX_NUM_MLAYERS; |
| dec_op_params->num_tlayers = MAX_NUM_TLAYERS; |
| } |
| dec_op_params->isValid = 0; // No matching OPS |
| dec_op_params->dec_ops = NULL; |
| dec_op_params->dec_op = NULL; |
| // No OPS was available, all layers to be decoded. |
| return; |
| } |
| |
| // NOTE: if a GLOBAL vs. LOCAL OPS is to be used, then |
| // Additional logic can be placed here to differentiate between |
| // the global and local OPS |
| if (target_op_index >= 0 && target_op_index < ops->ops_cnt) { |
| struct OperatingPoint *op = &ops->op[target_op_index]; |
| dec_op_params->DecOpSetId = ops->ops_id; |
| dec_op_params->DecOpCount = ops->ops_cnt; |
| dec_op_params->DecOpIndex = target_op_index; |
| dec_op_params->DecXlayerId = ops->obu_xlayer_id; |
| int xlayer = dec_op_params->DecXlayerId; |
| // Only overwrite num_mlayers/num_tlayers from OPS if the SBE retention |
| // map has not already set them. The SBE map is the authoritative source |
| // when Annex F extraction is active. |
| if (!pbi->sbe_state.retention_map_ready || |
| !pbi->sbe_state.extraction_enabled) { |
| dec_op_params->num_mlayers = |
| get_ops_mlayer_count(&op->mlayer_info, xlayer); |
| dec_op_params->num_tlayers = |
| get_ops_tlayer_count(&op->mlayer_info, xlayer, pbi->common.mlayer_id); |
| if (dec_op_params->num_mlayers == 0) dec_op_params->num_mlayers = 1; |
| if (dec_op_params->num_tlayers == 0) dec_op_params->num_tlayers = 1; |
| } |
| dec_op_params->dec_op = op; |
| dec_op_params->isValid = 1; |
| return; |
| } |
| return; |
| } |
| |
| // On success, sets *p_data_end and returns a boolean that indicates whether |
| // the decoding of the current frame is finished. On failure, sets |
| // cm->error.error_code and returns -1. |
| int avm_decode_frame_from_obus(struct AV2Decoder *pbi, const uint8_t *data, |
| const uint8_t *data_end, |
| const uint8_t **p_data_end) { |
| #if CONFIG_COLLECT_COMPONENT_TIMING |
| start_timing(pbi, avm_decode_frame_from_obus_time); |
| #endif |
| AV2_COMMON *const cm = &pbi->common; |
| int frame_decoding_finished = 0; |
| ObuHeader obu_header; |
| memset(&obu_header, 0, sizeof(obu_header)); |
| |
| // Enable is_multistream if multiple extended layers are present. |
| // Enable multistream_decoder_mode only when an MSDO OBU is present. |
| if (pbi->obus_in_frame_unit_data[0][0][OBU_MULTI_STREAM_DECODER_OPERATION]) { |
| pbi->is_multistream = 1; |
| pbi->multistream_decoder_mode = 1; |
| } else if (pbi->glcr_is_present_in_tu) { |
| pbi->is_multistream = 1; |
| } |
| |
| // Reset is_multistream at a random access point TU without MSDO/GLCR. |
| // obus_in_frame_unit_data reflects the current frame unit (populated before |
| // decode). |
| if (pbi->is_multistream) { |
| int tid = pbi->current_tlayer_id; |
| int mid = pbi->current_mlayer_id; |
| if (tid >= 0 && mid >= 0 && |
| pbi->obus_in_frame_unit_data[0][0][OBU_TEMPORAL_DELIMITER] && |
| !pbi->obus_in_frame_unit_data[0][0] |
| [OBU_MULTI_STREAM_DECODER_OPERATION] && |
| !pbi->glcr_obu_in_frame_unit && |
| (pbi->obus_in_frame_unit_data[tid][mid][OBU_CLOSED_LOOP_KEY] || |
| pbi->obus_in_frame_unit_data[tid][mid][OBU_OPEN_LOOP_KEY] || |
| pbi->obus_in_frame_unit_data[tid][mid][OBU_RAS_FRAME])) { |
| // Flush and reset like a config change |
| if (pbi->stream_info != NULL) { |
| flush_all_xlayer_frames(pbi, cm, true); |
| avm_free(pbi->stream_info); |
| pbi->stream_info = NULL; |
| } |
| cm->num_streams = 0; |
| for (int i = 0; i < AVM_MAX_NUM_STREAMS; i++) pbi->xlayer_id_map[i] = 0; |
| |
| pbi->is_multistream = 0; |
| pbi->multistream_decoder_mode = 0; |
| } |
| } |
| |
| // Per-TU conformance check: validate the PREVIOUS TU's accumulated |
| // xlayer/mlayer maps before resetting them for the current TU. |
| // This must run once per TU (here), not per-OBU (inside the loop). |
| if (pbi->random_accessed) { |
| int num_xlayers = 0; |
| int num_mlayers = 0; |
| for (int i = 0; i < AVM_MAX_NUM_STREAMS - 1; i++) { |
| if (pbi->xlayer_id_map[i] > 0) num_xlayers++; |
| } |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) { |
| bool found = false; |
| for (int x = 0; x < AVM_MAX_NUM_STREAMS; x++) { |
| if (pbi->mlayer_id_map[x][i] > 0) { |
| found = true; |
| break; |
| } |
| } |
| if (found) num_mlayers++; |
| } |
| |
| if (num_xlayers > 0 && num_mlayers > 0) { |
| bool global_lcr_present = false; |
| bool local_lcr_present = false; |
| for (int j = 0; j < MAX_NUM_LCR; j++) { |
| if (pbi->lcr_list[GLOBAL_XLAYER_ID][j].valid) global_lcr_present = true; |
| } |
| for (int i = 0; i < GLOBAL_XLAYER_ID && !local_lcr_present; i++) { |
| for (int j = 0; j < MAX_NUM_LCR; j++) { |
| if (pbi->lcr_list[i][j].valid) { |
| local_lcr_present = true; |
| break; |
| } |
| } |
| } |
| |
| if (!conformance_check_msdo_lcr(pbi, global_lcr_present, |
| local_lcr_present)) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "An MSDO or LCR OBU in the current CVS violates the requirements " |
| "of bitstream conformance for MSDO and LCR"); |
| } |
| } |
| |
| // Reset maps for the current TU |
| for (int i = 0; i < AVM_MAX_NUM_STREAMS - 1; i++) pbi->xlayer_id_map[i] = 0; |
| for (int x = 0; x < AVM_MAX_NUM_STREAMS; x++) |
| for (int i = 0; i < MAX_NUM_MLAYERS; i++) pbi->mlayer_id_map[x][i] = 0; |
| } |
| |
| pbi->seen_frame_header = 0; |
| pbi->next_start_tile = 0; |
| pbi->num_tile_groups = 0; |
| pbi->msdo_is_present_in_tu = 0; |
| pbi->glcr_is_present_in_tu = 0; |
| |
| if (data_end < data) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| |
| int count_obus_with_frame_unit = 0; |
| obu_info *obu_list = pbi->obu_list; |
| uint32_t acc_qm_id_bitmap = 0; |
| int qm_bit_map_zero_signalled = 0; |
| // acc_fgm_id_bitmap accumulates fgm_id_bitmap in FGM OBU to check if film |
| // grain models signalled before a coded frame have the same fgm_id |
| uint32_t acc_fgm_id_bitmap = 0; |
| uint32_t acc_mfh_id_bitmap = 0; |
| uint16_t acc_sh_id_bitmap[MAX_NUM_XLAYERS] = { 0 }; |
| uint8_t acc_lcr_id_bitmap[MAX_NUM_XLAYERS] = { 0 }; |
| int prev_obu_xlayer_id = -1; |
| // prev_obu_type, prev_xlayer_id and tu_validation_state are used to compare |
| // obus in this "data" |
| OBU_TYPE prev_obu_type = NUM_OBU_TYPES; |
| int prev_xlayer_id = -1; |
| temporal_unit_state_t tu_validation_state = TU_STATE_START; |
| |
| // decode frame as a series of OBUs |
| while (!frame_decoding_finished && cm->error.error_code == AVM_CODEC_OK) { |
| struct avm_read_bit_buffer rb; |
| size_t payload_size = 0; |
| size_t decoded_payload_size = 0; |
| size_t obu_payload_offset = 0; |
| size_t bytes_read = 0; |
| const size_t bytes_available = data_end - data; |
| |
| if (bytes_available == 0 && !pbi->seen_frame_header) { |
| cm->error.error_code = AVM_CODEC_OK; |
| break; |
| } |
| |
| avm_codec_err_t status = avm_read_obu_header_and_size( |
| data, bytes_available, &obu_header, &payload_size, &bytes_read); |
| |
| if (status != AVM_CODEC_OK) { |
| cm->error.error_code = status; |
| return -1; |
| } |
| |
| // Note: avm_read_obu_header_and_size() takes care of checking that this |
| // doesn't cause 'data' to advance past 'data_end'. |
| data += bytes_read; |
| |
| if ((size_t)(data_end - data) < payload_size) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| |
| // Annex F: Sub-bitstream extraction. |
| // When extraction is enabled, trigger retention map construction when |
| // transitioning from structural OBUs to non-structural OBUs, then |
| // filter OBUs based on the retention map. |
| if (pbi->sbe_state.extraction_enabled) { |
| if (!pbi->sbe_state.retention_map_ready && |
| !is_sbe_structural_obu(obu_header.type)) { |
| av2_sbe_build_retention_map(&pbi->sbe_state, pbi); |
| } |
| if (pbi->sbe_state.retention_map_ready) { |
| if (!av2_sbe_should_retain_obu( |
| &pbi->sbe_state, obu_header.type, obu_header.obu_xlayer_id, |
| obu_header.obu_mlayer_id, obu_header.obu_tlayer_id)) { |
| pbi->sbe_state.obus_removed++; |
| data += payload_size; |
| continue; |
| } |
| pbi->sbe_state.obus_retained++; |
| } |
| } |
| |
| if (is_single_tile_vcl_obu(obu_header.type) || |
| is_multi_tile_vcl_obu(obu_header.type)) { |
| if (!pbi->seen_vcl_obu_in_this_tu) { |
| pbi->this_is_first_vcl_obu_in_tu = 1; |
| pbi->seen_vcl_obu_in_this_tu = 1; |
| } else { |
| pbi->this_is_first_vcl_obu_in_tu = 0; |
| } |
| } |
| |
| if (obu_header.type == OBU_CLOSED_LOOP_KEY || |
| obu_header.type == OBU_OPEN_LOOP_KEY) { |
| if (pbi->this_is_first_vcl_obu_in_tu) |
| pbi->this_is_first_keyframe_unit_in_tu = 1; |
| } |
| |
| if (av2_is_leading_vcl_obu(obu_header.type)) |
| cm->is_leading_picture = 1; |
| else if (av2_is_regular_vcl_obu(obu_header.type)) |
| cm->is_leading_picture = 0; |
| else |
| cm->is_leading_picture = -1; |
| pbi->xlayer_id_map[obu_header.obu_xlayer_id] = 1; |
| pbi->mlayer_id_map[obu_header.obu_xlayer_id][obu_header.obu_mlayer_id] = 1; |
| |
| obu_info *const curr_obu_info = &obu_list[count_obus_with_frame_unit]; |
| curr_obu_info->obu_type = obu_header.type; |
| curr_obu_info->is_vcl = is_single_tile_vcl_obu(obu_header.type) || |
| is_multi_tile_vcl_obu(obu_header.type); |
| if (curr_obu_info->is_vcl) { |
| assert(curr_obu_info->xlayer_id == obu_header.obu_xlayer_id); |
| assert(curr_obu_info->mlayer_id == obu_header.obu_mlayer_id); |
| assert(curr_obu_info->tlayer_id == obu_header.obu_tlayer_id); |
| } |
| curr_obu_info->first_tile_group = -1; |
| curr_obu_info->immediate_output_picture = -1; |
| curr_obu_info->showable_frame = -1; |
| curr_obu_info->display_order_hint = -1; |
| |
| // Extract metadata_is_suffix for metadata OBUs |
| // Per spec sections 5.17.2 and 5.17.3, metadata_is_suffix is f(1) - the |
| // first bit of the payload |
| int metadata_is_suffix = -1; // -1 means not applicable |
| if (obu_header.type == OBU_METADATA_SHORT || |
| obu_header.type == OBU_METADATA_GROUP) { |
| if (payload_size == 0) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "OBU_METADATA_x has an empty payload"); |
| } |
| // data has been advanced by bytes_read, so data[0] is first payload byte |
| metadata_is_suffix = (data[0] & 0x80) >> 7; |
| } |
| |
| // Validate OBU ordering within temporal units. Ignore padding OBUs and |
| // reserved OBUs in this check. |
| if (avm_obu_type_is_valid(obu_header.type) && |
| obu_header.type != OBU_PADDING) { |
| if (!check_temporal_unit_structure( |
| &tu_validation_state, obu_header.type, obu_header.obu_xlayer_id, |
| metadata_is_suffix, prev_obu_type, prev_xlayer_id)) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "OBU order violation: current OBU %s with xlayer_id %d mlayer_id " |
| "%d previous OBU %s(xlayer_id=%d) invalid in current state", |
| avm_obu_type_to_string(obu_header.type), obu_header.obu_xlayer_id, |
| obu_header.obu_mlayer_id, avm_obu_type_to_string(prev_obu_type), |
| prev_xlayer_id); |
| } |
| prev_obu_type = obu_header.type; |
| prev_xlayer_id = obu_header.obu_xlayer_id; |
| } |
| |
| check_valid_layer_id(obu_header, cm); |
| |
| pbi->obu_type = obu_header.type; |
| |
| cm->tlayer_id = obu_header.obu_tlayer_id; |
| cm->mlayer_id = obu_header.obu_mlayer_id; |
| |
| if (!pbi->is_multistream || (obu_header.obu_xlayer_id == GLOBAL_XLAYER_ID && |
| cm->xlayer_id == GLOBAL_XLAYER_ID)) { |
| cm->xlayer_id = obu_header.obu_xlayer_id; |
| } else if (cm->xlayer_id != GLOBAL_XLAYER_ID && |
| obu_header.obu_xlayer_id == GLOBAL_XLAYER_ID) { |
| // Store xlayer context |
| av2_store_xlayer_context(pbi, cm, cm->xlayer_id); |
| cm->xlayer_id = obu_header.obu_xlayer_id; |
| } else if (cm->xlayer_id == GLOBAL_XLAYER_ID && |
| obu_header.obu_xlayer_id != GLOBAL_XLAYER_ID) { |
| // Restore xlayer context |
| cm->xlayer_id = obu_header.obu_xlayer_id; |
| av2_restore_xlayer_context(pbi, cm, cm->xlayer_id); |
| } else if (cm->xlayer_id != obu_header.obu_xlayer_id) { |
| // Store and restore xlayer context |
| av2_store_xlayer_context(pbi, cm, cm->xlayer_id); |
| cm->xlayer_id = obu_header.obu_xlayer_id; |
| av2_restore_xlayer_context(pbi, cm, cm->xlayer_id); |
| } |
| |
| if (obu_header.type == OBU_LEADING_TILE_GROUP || |
| obu_header.type == OBU_REGULAR_TILE_GROUP) { |
| if (prev_obu_xlayer_id == -1) { |
| prev_obu_xlayer_id = obu_header.obu_xlayer_id; |
| } else { |
| if (pbi->is_multistream && prev_obu_xlayer_id >= 0 && |
| obu_header.obu_xlayer_id != prev_obu_xlayer_id) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "tile group OBUs with the same stream_id shall " |
| "be contiguous within a temporal unit"); |
| } |
| } |
| } |
| // Set is_bridge_frame flag based on OBU type |
| if (obu_header.type == OBU_BRIDGE_FRAME) { |
| cm->bridge_frame_info.is_bridge_frame = 1; |
| } else { |
| cm->bridge_frame_info.is_bridge_frame = 0; |
| } |
| |
| // Flush remaining frames after xlayer context is correctly set. |
| // This must happen after xlayer switching but before processing frame OBUs. |
| // Skip flush while in GLOBAL_XLAYER_ID context -- the target layer's |
| // context has not been restored yet; flush will run once a non-global |
| // OBU restores it. |
| if (pbi->this_is_first_keyframe_unit_in_tu && |
| cm->xlayer_id != GLOBAL_XLAYER_ID && |
| pbi->obus_in_frame_unit_data[cm->tlayer_id][cm->mlayer_id] |
| [OBU_CLOSED_LOOP_KEY]) { |
| flush_remaining_frames(pbi, INT_MAX); |
| // Reset last_output_doh for this xlayer only, after flushing so that |
| // the flushed frames' DOH values are still checked against the old |
| // last_output_doh. Other xlayers may still be mid-sequence. |
| for (int ml = 0; ml < MAX_NUM_MLAYERS; ml++) |
| pbi->last_output_doh[cm->xlayer_id][ml] = -1; |
| } |
| |
| // Flush leading frames (doh < last_olk_tu_display_order_hint) at the start |
| // of the first regular temporal unit after an OLK, before |
| // reset_buffer_other_than_OLK() clears their DPB slots. |
| if (pbi->olk_encountered && pbi->this_is_first_vcl_obu_in_tu && |
| !pbi->seen_frame_header && cm->is_leading_picture == 0) { |
| flush_remaining_frames(pbi, pbi->last_olk_tu_display_order_hint); |
| } |
| |
| av2_init_read_bit_buffer(pbi, &rb, data, data + payload_size); |
| switch (obu_header.type) { |
| case OBU_TEMPORAL_DELIMITER: |
| decoded_payload_size = read_temporal_delimiter_obu(); |
| pbi->seen_frame_header = 0; |
| pbi->next_start_tile = 0; |
| pbi->seen_vcl_obu_in_this_tu = 0; |
| pbi->this_is_first_vcl_obu_in_tu = 0; |
| pbi->doh_tu_order_hint_bits_set = 0; |
| for (int i = 0; i < NUM_CUSTOM_QMS; i++) pbi->qm_protected[i] = 0; |
| break; |
| case OBU_MULTI_STREAM_DECODER_OPERATION: |
| decoded_payload_size = |
| read_multi_stream_decoder_operation_obu(pbi, &rb); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| if (pbi->sbe_state.extraction_enabled) { |
| av2_sbe_process_msdo(&pbi->sbe_state, cm->num_streams, |
| cm->stream_ids); |
| } |
| break; |
| case OBU_SEQUENCE_HEADER: |
| cm->xlayer_id = obu_header.obu_xlayer_id; |
| decoded_payload_size = read_sequence_header_obu( |
| pbi, obu_header.obu_xlayer_id, &rb, acc_sh_id_bitmap); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| if (pbi->sbe_state.extraction_enabled) { |
| av2_sbe_extract_seq_header_params( |
| &pbi->sbe_state, obu_header.obu_xlayer_id, |
| cm->seq_params.seq_profile_idc, cm->seq_params.seq_max_level_idx, |
| cm->seq_params.seq_tier, cm->seq_params.seq_max_mlayer_cnt); |
| } |
| break; |
| case OBU_BUFFER_REMOVAL_TIMING: |
| decoded_payload_size = |
| av2_read_buffer_removal_timing_obu(pbi, &rb, cm->xlayer_id); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_LAYER_CONFIGURATION_RECORD: |
| decoded_payload_size = av2_read_layer_configuration_record_obu( |
| pbi, cm->xlayer_id, &rb, acc_lcr_id_bitmap); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| // Allocate stream_info if Global LCR triggers multi-stream mode |
| // (i.e., LcrMaxNumXLayerCount > 1 and no MSDO present) |
| if (cm->xlayer_id == GLOBAL_XLAYER_ID && pbi->glcr_is_present_in_tu && |
| !pbi->msdo_is_present_in_tu && pbi->stream_info == NULL) { |
| const int num_streams = pbi->glcr_num_xlayers; |
| pbi->stream_info = |
| (StreamInfo *)avm_malloc(num_streams * sizeof(StreamInfo)); |
| if (pbi->stream_info == NULL) { |
| avm_internal_error(&cm->error, AVM_CODEC_MEM_ERROR, |
| "Memory allocation failed for pbi->stream_info " |
| "(GLCR)\n"); |
| } |
| memset(pbi->stream_info, 0, num_streams * sizeof(StreamInfo)); |
| for (int i = 0; i < num_streams; i++) { |
| init_stream_info(&pbi->stream_info[i]); |
| } |
| } |
| if (pbi->sbe_state.extraction_enabled && |
| cm->xlayer_id == GLOBAL_XLAYER_ID) { |
| av2_sbe_process_global_lcr(&pbi->sbe_state, cm->num_streams, |
| cm->stream_ids); |
| } |
| break; |
| case OBU_ATLAS_SEGMENT: |
| decoded_payload_size = |
| av2_read_atlas_segment_info_obu(pbi, cm->xlayer_id, &rb); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_OPERATING_POINT_SET: |
| decoded_payload_size = |
| av2_read_operating_point_set_obu(pbi, cm->xlayer_id, &rb); |
| avm_set_current_operating_point(pbi, cm->xlayer_id); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| if (pbi->sbe_state.extraction_enabled) { |
| if (cm->xlayer_id == GLOBAL_XLAYER_ID) { |
| // Check if the user-selected global OPS is now available |
| if (pbi->selected_ops_id >= 0 && |
| pbi->selected_ops_id < MAX_NUM_OPS_ID) { |
| const struct OperatingPointSet *sel_ops = |
| &pbi->ops_list[GLOBAL_XLAYER_ID][pbi->selected_ops_id]; |
| if (sel_ops->valid) { |
| av2_sbe_process_global_ops( |
| &pbi->sbe_state, sel_ops->ops_id, sel_ops->ops_cnt, |
| pbi->selected_ops_id, pbi->selected_op_index, |
| (sel_ops->ops_cnt > 0 && pbi->selected_op_index >= 0 && |
| pbi->selected_op_index < sel_ops->ops_cnt) |
| ? sel_ops->op[pbi->selected_op_index].ops_xlayer_map |
| : 0, |
| sel_ops->ops_mlayer_info_idc); |
| } |
| } |
| } else { |
| av2_sbe_process_local_ops(&pbi->sbe_state, pbi, cm->xlayer_id, |
| pbi->dec_op_params.DecOpSetId, |
| pbi->dec_op_params.DecOpCount); |
| } |
| } |
| break; |
| case OBU_CONTENT_INTERPRETATION: |
| decoded_payload_size = av2_read_content_interpretation_obu(pbi, &rb); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_MULTI_FRAME_HEADER: |
| decoded_payload_size = |
| read_multi_frame_header_obu(pbi, &acc_mfh_id_bitmap, &rb); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_CLOSED_LOOP_KEY: |
| case OBU_OPEN_LOOP_KEY: |
| case OBU_LEADING_TILE_GROUP: |
| case OBU_REGULAR_TILE_GROUP: |
| case OBU_SWITCH: |
| case OBU_LEADING_SEF: |
| case OBU_REGULAR_SEF: |
| case OBU_LEADING_TIP: |
| case OBU_REGULAR_TIP: |
| case OBU_RAS_FRAME: |
| case OBU_BRIDGE_FRAME: |
| // Constraint 4: Switch frames shall be at the base temporal layer. |
| if ((obu_header.type == OBU_SWITCH || |
| obu_header.type == OBU_RAS_FRAME) && |
| obu_header.obu_tlayer_id != 0) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Switch frame (obu_type=%d) must have obu_tlayer_id equal to " |
| "0, got %d.", |
| obu_header.type, obu_header.obu_tlayer_id); |
| } |
| if (obu_header.type == OBU_SWITCH || obu_header.type == OBU_RAS_FRAME) { |
| const int mid = obu_header.obu_mlayer_id; |
| for (int j = 0; j < MAX_NUM_MLAYERS; j++) { |
| if (j != mid && cm->seq_params.mlayer_dependency_map[mid][j] != 0) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "Switch frame at mlayer_id=%d depends on mlayer %d. " |
| "Switch frames must be in independent embedded layers.", |
| mid, j); |
| } |
| } |
| } |
| // Drop picture unit HLS state that was derived exclusively from leading |
| // frame picture units when the first regular VCL OBU is encountered. |
| if (av2_is_leading_vcl_obu(obu_header.type)) { |
| // Tag every MFH/QM/FGM/CI/BRT signalled in the leading temporal |
| // unit so we can identify and discard them at the transition. |
| const int leading_mlayer_id = cm->mlayer_id; |
| for (int i = 0; i < MAX_MFH_NUM; i++) |
| if (acc_mfh_id_bitmap & (1 << i)) |
| cm->mfh_params[i].mfh_from_leading = 1; |
| for (int i = 0; i < NUM_CUSTOM_QMS; i++) |
| if ((acc_qm_id_bitmap & (1 << i)) || qm_bit_map_zero_signalled) { |
| pbi->qm_list[i].qm_from_leading = 1; |
| } |
| for (int i = 0; i < MAX_FGM_NUM; i++) |
| if (acc_fgm_id_bitmap & (1 << i)) { |
| pbi->fgm_list[i].fgm_from_leading = 1; |
| } |
| if (pbi->obus_in_frame_unit_data[obu_header.obu_tlayer_id] |
| [leading_mlayer_id] |
| [OBU_CONTENT_INTERPRETATION]) |
| cm->ci_params_per_layer[leading_mlayer_id].ci_from_leading = true; |
| if (pbi->obus_in_frame_unit_data[obu_header.obu_tlayer_id] |
| [leading_mlayer_id] |
| [OBU_BUFFER_REMOVAL_TIMING]) |
| cm->brt_info.brt_from_leading = true; |
| for (int x = 0; x < MAX_NUM_XLAYERS; x++) |
| for (int s = 0; s < MAX_SEQ_NUM; s++) |
| if (acc_sh_id_bitmap[x] & (1 << s)) |
| pbi->seq_list[x][s].sh_from_leading = 1; |
| for (int x = 0; x < MAX_NUM_XLAYERS; x++) |
| for (int l = 0; l < MAX_NUM_LCR; l++) |
| if (acc_lcr_id_bitmap[x] & (1 << l)) |
| pbi->lcr_list[x][l].lcr_from_leading = true; |
| } else if (pbi->this_is_first_vcl_obu_in_tu == 1) { |
| // SEF, TIP, SWITCH, RAS, BRIDGE, TG (not CLK) |
| // MFH, QM, FGM, BRT, CI signalled in leading temporal unit cannot |
| // be used. Drop state not re-signalled in the regular picture unit. |
| const int regular_mlayer_id = cm->mlayer_id; |
| const int num_planes = av2_num_planes(cm); |
| |
| for (int i = 0; i < NUM_CUSTOM_QMS; i++) { |
| struct quantization_matrix_set *qmset = &pbi->qm_list[i]; |
| if (qmset->qm_from_leading == 1 && !(acc_qm_id_bitmap & (1 << i)) && |
| !qm_bit_map_zero_signalled) { |
| qmset->qm_id = -1; |
| qmset->qm_mlayer_id = -1; |
| qmset->qm_tlayer_id = -1; |
| qmset->quantizer_matrix_num_planes = num_planes; |
| qmset->is_user_defined_qm = false; |
| pbi->qm_protected[i] = 0; |
| } |
| qmset->qm_from_leading = 0; |
| } |
| |
| for (int i = 0; i < MAX_FGM_NUM; i++) { |
| if (pbi->fgm_list[i].fgm_from_leading == 1 && |
| !(acc_fgm_id_bitmap & (1 << i))) { |
| pbi->fgm_list[i].fgm_id = -1; |
| pbi->fgm_list[i].fgm_tlayer_id = -1; |
| pbi->fgm_list[i].fgm_mlayer_id = -1; |
| } |
| pbi->fgm_list[i].fgm_from_leading = 0; |
| } |
| |
| if (cm->ci_params_per_layer[regular_mlayer_id].ci_from_leading == 1 && |
| !pbi->obus_in_frame_unit_data[obu_header.obu_tlayer_id] |
| [regular_mlayer_id] |
| [OBU_CONTENT_INTERPRETATION]) { |
| av2_initialize_ci_params( |
| &cm->ci_params_per_layer[regular_mlayer_id]); |
| } |
| cm->ci_params_per_layer[regular_mlayer_id].ci_from_leading = false; |
| for (int i = 0; i < MAX_MFH_NUM; i++) { |
| if (cm->mfh_params[i].mfh_from_leading == 1 && |
| !(acc_mfh_id_bitmap & (1 << i))) { |
| cm->mfh_valid[i] = false; |
| } |
| cm->mfh_params[i].mfh_from_leading = 0; |
| } |
| if (cm->brt_info.brt_from_leading == 1 && |
| !pbi->obus_in_frame_unit_data[obu_header.obu_tlayer_id] |
| [regular_mlayer_id] |
| [OBU_BUFFER_REMOVAL_TIMING]) { |
| memset(&cm->brt_info, 0, sizeof(cm->brt_info)); |
| } |
| cm->brt_info.brt_from_leading = false; |
| for (int x = 0; x < MAX_NUM_XLAYERS; x++) { |
| for (int s = 0; s < MAX_SEQ_NUM; s++) { |
| if (!(pbi->seq_list[x][s].sh_from_leading == 1 && |
| !(acc_sh_id_bitmap[x] & (1 << s)))) |
| pbi->seq_list[x][s].sh_from_leading = 0; |
| } |
| for (int l = 0; l < MAX_NUM_LCR; l++) { |
| if (!(pbi->lcr_list[x][l].lcr_from_leading && |
| !(acc_lcr_id_bitmap[x] & (1 << l)))) |
| pbi->lcr_list[x][l].lcr_from_leading = false; |
| } |
| } |
| } |
| |
| // It is a requirement that if multiple QM OBUs are present |
| // consecutively prior to a coded frame, other than a QM OBU with |
| // qm_bit_map equal to 0, such QM OBUs will not set the same QM ID more |
| // than once. |
| acc_qm_id_bitmap = 0; |
| qm_bit_map_zero_signalled = 0; |
| // It is a requirement that if multiple FGM OBUs are present |
| // consecutively prior to a coded frame, such FGM OBUs will not set |
| // the same FGM ID more than once. |
| acc_fgm_id_bitmap = 0; |
| acc_mfh_id_bitmap = 0; |
| memset(acc_sh_id_bitmap, 0, sizeof(acc_sh_id_bitmap)); |
| memset(acc_lcr_id_bitmap, 0, sizeof(acc_lcr_id_bitmap)); |
| decoded_payload_size = read_tilegroup_obu( |
| pbi, &rb, data, data + payload_size, p_data_end, obu_header.type, |
| obu_header.obu_xlayer_id, &curr_obu_info->first_tile_group, |
| &frame_decoding_finished); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| curr_obu_info->immediate_output_picture = cm->immediate_output_picture; |
| curr_obu_info->showable_frame = |
| cm->immediate_output_picture || cm->implicit_output_picture; |
| curr_obu_info->display_order_hint = |
| cm->current_frame.display_order_hint; |
| int num_mlayers = 0; |
| for (int i = 0; i < MAX_NUM_MLAYERS; ++i) { |
| if (pbi->mlayer_id_map[obu_header.obu_xlayer_id][i] == 1) |
| num_mlayers++; |
| } |
| if (num_mlayers > 1 && |
| num_mlayers > cm->seq_params.seq_max_mlayer_cnt) { |
| avm_internal_error( |
| &cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "The number of embedded layers (%d) in the current video " |
| "sequence is larger than the seq_max_mlayer_cnt (%d).", |
| num_mlayers, cm->seq_params.seq_max_mlayer_cnt); |
| } |
| if (cm->bru.frame_inactive_flag || |
| cm->bridge_frame_info.is_bridge_frame) { |
| pbi->seen_frame_header = 0; |
| frame_decoding_finished = 1; |
| CommonTileParams *const tiles = &cm->tiles; |
| av2_get_tile_limits( |
| &cm->tiles, cm->mi_params.mi_rows, cm->mi_params.mi_cols, |
| cm->mib_size_log2, cm->seq_params.mib_size_log2, |
| cm->seq_params.seq_max_level_idx, cm->seq_params.seq_tier); |
| tiles->uniform_spacing = 1; |
| tiles->log2_cols = 0; |
| av2_calculate_tile_cols(tiles); |
| tiles->log2_rows = 0; |
| av2_calculate_tile_rows(tiles); |
| const int num_tiles = cm->tiles.cols * cm->tiles.rows; |
| const int end_tile = num_tiles - 1; |
| // skip parsing and go directly to decode |
| av2_decode_tg_tiles_and_wrapup(pbi, data, data + payload_size, |
| p_data_end, 0, end_tile, 0); |
| if (cm->bridge_frame_info.is_bridge_frame) { |
| *p_data_end = data + payload_size; |
| } |
| break; |
| } |
| if (obu_payload_offset > payload_size) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| if (frame_decoding_finished) pbi->seen_frame_header = 0; |
| pbi->num_tile_groups++; |
| break; |
| case OBU_QUANTIZATION_MATRIX: |
| decoded_payload_size = |
| read_qm_obu(pbi, obu_header.obu_tlayer_id, obu_header.obu_mlayer_id, |
| &acc_qm_id_bitmap, &qm_bit_map_zero_signalled, &rb); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_METADATA_SHORT: |
| decoded_payload_size = read_metadata_short(pbi, data, payload_size, 0); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_METADATA_GROUP: |
| decoded_payload_size = |
| read_metadata_obu(pbi, data, payload_size, &obu_header, 0); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_FILM_GRAIN_MODEL: |
| decoded_payload_size = |
| read_fgm_obu(pbi, obu_header.obu_tlayer_id, |
| obu_header.obu_mlayer_id, &acc_fgm_id_bitmap, &rb); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| case OBU_PADDING: |
| decoded_payload_size = read_padding(cm, data, payload_size); |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| break; |
| default: |
| // Skip unrecognized OBUs |
| if (payload_size > 0 && |
| get_last_nonzero_byte(data, payload_size) == 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| decoded_payload_size = payload_size; |
| break; |
| } |
| |
| // Spec 6.2.2: |
| // "At the end of reading the OBU, it is a requirement of bitstream " |
| // "conformance that obu_mlayer_id is less than or equal to max_mlayer_id." |
| if (obu_header.obu_mlayer_id > cm->seq_params.max_mlayer_id && |
| (!pbi->decoding_first_frame || frame_decoding_finished)) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "obu_mlayer_id (%d) must be less than or equal to " |
| "max_mlayer_id (%d).", |
| obu_header.obu_mlayer_id, |
| cm->seq_params.max_mlayer_id); |
| } |
| |
| // Check that the signalled OBU size matches the actual amount of data read |
| if (decoded_payload_size > payload_size) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| |
| // If there are extra padding bytes, they should all be zero |
| while (decoded_payload_size < payload_size) { |
| uint8_t padding_byte = data[decoded_payload_size++]; |
| if (padding_byte != 0) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| } |
| |
| data += payload_size; |
| count_obus_with_frame_unit++; |
| } |
| |
| // check whether suffix metadata OBUs are present |
| while (cm->error.error_code == AVM_CODEC_OK && data < data_end) { |
| size_t payload_size = 0; |
| size_t decoded_payload_size = 0; |
| size_t bytes_read = 0; |
| const size_t bytes_available = data_end - data; |
| avm_codec_err_t status = avm_read_obu_header_and_size( |
| data, bytes_available, &obu_header, &payload_size, &bytes_read); |
| |
| if (status != AVM_CODEC_OK) { |
| cm->error.error_code = status; |
| return -1; |
| } |
| |
| // Accept both OBU_METADATA_SHORT and OBU_METADATA_GROUP for suffix metadata |
| if (!(is_metadata_obu(obu_header.type) || (obu_header.type == OBU_PADDING))) |
| break; |
| |
| // Note: avm_read_obu_header_and_size() takes care of checking that this |
| // doesn't cause 'data' to advance past 'data_end'. |
| data += bytes_read; |
| |
| if ((size_t)(data_end - data) < payload_size) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| |
| if (obu_header.type == OBU_PADDING) { |
| decoded_payload_size = read_padding(cm, data, payload_size); |
| obu_info *const curr_obu_info = &obu_list[count_obus_with_frame_unit]; |
| curr_obu_info->obu_type = obu_header.type; |
| curr_obu_info->first_tile_group = -1; |
| curr_obu_info->immediate_output_picture = -1; |
| curr_obu_info->showable_frame = -1; |
| curr_obu_info->display_order_hint = -1; |
| count_obus_with_frame_unit++; |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| } else if (is_metadata_obu(obu_header.type)) { |
| // check whether it is a suffix metadata OBU |
| if (payload_size == 0) { |
| avm_internal_error(&cm->error, AVM_CODEC_CORRUPT_FRAME, |
| "OBU_METADATA_x has an empty payload"); |
| } |
| if (!(data[0] & 0x80)) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "OBU order violation: OBU_METADATA_x(prefix) cannot " |
| "be present after a coded frame"); |
| } |
| |
| // Call the appropriate read function based on OBU type |
| if (obu_header.type == OBU_METADATA_GROUP) { |
| decoded_payload_size = |
| read_metadata_obu(pbi, data, payload_size, &obu_header, 1); |
| } else { |
| decoded_payload_size = read_metadata_short(pbi, data, payload_size, 1); |
| } |
| obu_info *const curr_obu_info = &obu_list[count_obus_with_frame_unit]; |
| curr_obu_info->obu_type = obu_header.type; |
| curr_obu_info->first_tile_group = -1; |
| curr_obu_info->immediate_output_picture = -1; |
| curr_obu_info->showable_frame = -1; |
| curr_obu_info->display_order_hint = -1; |
| count_obus_with_frame_unit++; |
| } |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| |
| // Spec 6.2.2: |
| // "At the end of reading the OBU, it is a requirement of bitstream " |
| // "conformance that obu_mlayer_id is less than or equal to max_mlayer_id." |
| if (obu_header.obu_mlayer_id > cm->seq_params.max_mlayer_id && |
| (!pbi->decoding_first_frame || frame_decoding_finished)) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "obu_mlayer_id (%d) must be less than or equal to " |
| "max_mlayer_id (%d).", |
| obu_header.obu_mlayer_id, |
| cm->seq_params.max_mlayer_id); |
| } |
| |
| // Check that the signalled OBU size matches the actual amount of data read |
| if (decoded_payload_size > payload_size) { |
| cm->error.error_code = AVM_CODEC_CORRUPT_FRAME; |
| return -1; |
| } |
| |
| data += payload_size; |
| } |
| |
| if (cm->error.error_code != AVM_CODEC_OK) return -1; |
| |
| *p_data_end = data; |
| |
| #if CONFIG_COLLECT_COMPONENT_TIMING |
| end_timing(pbi, avm_decode_frame_from_obus_time); |
| |
| // Print out timing information. |
| int i; |
| fprintf(stderr, "\n Frame number: %d, Frame type: %s, Show Frame: %d\n", |
| cm->current_frame.frame_number, |
| get_frame_type_enum(cm->current_frame.frame_type), |
| cm->immediate_output_picture); |
| for (i = 0; i < kTimingComponents; i++) { |
| pbi->component_time[i] += pbi->frame_component_time[i]; |
| fprintf(stderr, " %s: %" PRId64 " us (total: %" PRId64 " us)\n", |
| get_component_name(i), pbi->frame_component_time[i], |
| pbi->component_time[i]); |
| pbi->frame_component_time[i] = 0; |
| } |
| #endif |
| |
| obu_info current_frame_unit; |
| memset(¤t_frame_unit, -1, sizeof(current_frame_unit)); |
| for (int obu_idx = 0; obu_idx < count_obus_with_frame_unit; obu_idx++) { |
| obu_info *this_obu = &obu_list[obu_idx]; |
| |
| if (this_obu->first_tile_group == 1) { |
| current_frame_unit = *this_obu; |
| pbi->num_displayable_frame_unit[this_obu->mlayer_id]++; |
| } |
| if (is_multi_tile_vcl_obu(this_obu->obu_type) && |
| this_obu->first_tile_group == 0) { |
| // Allow padding OBUs between tile group OBUs. |
| int prev_obu_idx = obu_idx - 1; |
| while (prev_obu_idx >= 0 && |
| obu_list[prev_obu_idx].obu_type == OBU_PADDING) { |
| prev_obu_idx--; |
| } |
| if (prev_obu_idx < 0) { |
| avm_internal_error(&cm->error, AVM_CODEC_UNSUP_BITSTREAM, |
| "The first non-padding OBU in a frame unit cannot " |
| "be a tile group with is_first_tile_group == 0"); |
| } |
| check_tilegroup_obus_in_a_frame_unit(cm, this_obu, |
| &obu_list[prev_obu_idx]); |
| } |
| } |
| |
| // When SBE filters out all frame OBUs in a temporal unit, no frame was |
| // found: skip the consistency checks. |
| int xId = current_frame_unit.xlayer_id; |
| if (current_frame_unit.display_order_hint != -1 && |
| pbi->last_frame_unit[xId].display_order_hint != -1 && |
| (pbi->last_frame_unit[xId].xlayer_id == current_frame_unit.xlayer_id)) { |
| check_clk_in_a_layer(cm, ¤t_frame_unit, &pbi->last_frame_unit[xId]); |
| |
| if (current_frame_unit.showable_frame == 0) { |
| check_layerid_hidden_frame_units(cm, ¤t_frame_unit, |
| &pbi->last_frame_unit[xId]); |
| } else { |
| check_layerid_showable_frame_units( |
| cm, ¤t_frame_unit, &pbi->last_frame_unit[xId], |
| &pbi->last_displayable_frame_unit[xId]); |
| } |
| } |
| |
| return frame_decoding_finished; |
| } |