diff --git a/src/Makefile.am b/src/Makefile.am index 9b467a7f51..fb2b14be4f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -572,6 +572,8 @@ janus_pp_rec_SOURCES = \ postprocessing/pp-webm.c \ postprocessing/pp-webm.h \ postprocessing/janus-pp-rec.c \ + postprocessing/obuparse.c \ + postprocessing/obuparse.h \ log.c \ utils.c \ version.c \ diff --git a/src/postprocessing/obuparse.c b/src/postprocessing/obuparse.c new file mode 100644 index 0000000000..48284458e8 --- /dev/null +++ b/src/postprocessing/obuparse.c @@ -0,0 +1,2156 @@ +/* + * Copyright (c) 2020, Derek Buitenhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "obuparse.h" + +/************************************ + * Bitreader functions and structs. * + ************************************/ + +typedef struct _OBPBitReader { + uint8_t *buf; + size_t buf_size; + size_t buf_pos; + uint64_t bit_buffer; + uint8_t bits_in_buf; +} _OBPBitReader; + +static inline _OBPBitReader _obp_new_br(uint8_t *buf, size_t buf_size) +{ + _OBPBitReader ret = { buf, buf_size, 0, 0, 0 }; + return ret; +} + +static inline uint64_t _obp_br_unchecked(_OBPBitReader *br, uint8_t n) +{ + assert(n <= 63); + + while (n > br->bits_in_buf) { + br->bit_buffer <<= 8; + br->bit_buffer |= (uint64_t) br->buf[br->buf_pos]; + br->bits_in_buf += 8; + br->buf_pos++; + + if (br->bits_in_buf > 56) { + if (n <= br->bits_in_buf) + break; + + if (n <= 64) + return (_obp_br_unchecked(br, 32) << 32) | (_obp_br_unchecked(br, n - 32)); + } + } + + br->bits_in_buf -= n; + return (br->bit_buffer >> br->bits_in_buf) & ((((uint64_t)1) << n) - 1); +} + +static inline void _obp_br_byte_alignment(_OBPBitReader *br) +{ + br->bits_in_buf -= br->bits_in_buf % 8; +} + +static inline size_t _obp_br_get_pos(_OBPBitReader *br) +{ + return (br->buf_pos * 8) - ((size_t) br->bits_in_buf); +} + +#if OBP_UNCHECKED_BITREADER +#define _obp_br(x, br, n) do { \ + x = _obp_br_unchecked(br, n); \ +} while(0) +#else +#define _obp_br(x, br, n) do { \ + size_t bytes_needed = ((n - br->bits_in_buf) + (1<<3) - 1) >> 3; \ + if (bytes_needed > (br->buf_size - br->buf_pos)) { \ + snprintf(err->error, err->size, "Ran out of bytes in buffer."); \ + return -1; \ + } \ + x = _obp_br_unchecked(br, n); \ +} while(0) +#endif + +/************************************ + * Functions from AV1 specification. * + ************************************/ + +static inline int _obp_leb128(uint8_t *buf, size_t size, uint64_t *value, ptrdiff_t *consumed, OBPError *err) +{ + *value = 0; + *consumed = 0; + + for (uint64_t i = 0; i < 8; i++) { + uint8_t b; + + if (((size_t) (*consumed) + 1) > size) { + snprintf(err->error, err->size, "Buffer too short to read leb128 value."); + return -1; + } + + b = buf[*consumed]; + *value |= ((uint64_t)(b & 0x7F)) << (i * 7); + (*consumed)++; + + if ((b & 0x80) != 0x80) + break; + } + + return 0; +} + +static inline int _obp_uvlc(_OBPBitReader *br, uint32_t *value, OBPError *err) +{ + uint32_t leading_zeroes = 0; + while (leading_zeroes < 32) { + int b; + _obp_br(b, br, 1); + if (b != 0) + break; + leading_zeroes++; + } + if (leading_zeroes == 32) { + snprintf(err->error, err->size, "Invalid VLC."); + return -1; + } + uint32_t val; + _obp_br(val, br, leading_zeroes); + *value = val + ((1 << leading_zeroes) - 1); + return 0; +} + +static inline int32_t _obp_get_relative_dist(int32_t a, int32_t b, OBPSequenceHeader *seq) +{ + int32_t diff, m; + + if (!seq->enable_order_hint) + return 0; + + diff = a - b; + m = 1 << (seq->OrderHintBits - 1); + diff = (diff & (m - 1)) - (diff & m); + + return diff; +} + + + +static inline uint32_t _obp_tile_log2(uint32_t blkSize, uint32_t target) +{ + uint32_t k; + for (k = 0; (blkSize << k) < target; k++) { + } + return k; +} + +static inline uint32_t _obp_floor_log2(uint32_t a) +{ + uint32_t s = 0; + uint32_t x = a; + while (x != 0) { + x = x >> 1; + s++; + } + return s - 1; +} + +static inline uint64_t _obp_le(uint8_t *buf, uint8_t n) +{ + uint64_t t = 0; + size_t pos = 0; + for (uint8_t i = 0; i < n; i++) { + uint8_t byte = buf[pos]; + t += ((uint64_t)byte) << (i * 8); + pos++; + } + return t; +} + +static inline int _obp_ns(_OBPBitReader *br, uint32_t n, uint32_t *out, OBPError *err) +{ + uint32_t w = _obp_floor_log2(n) + 1; + uint32_t m = (((uint32_t)1) << w) - n; + uint32_t v; + uint32_t extra_bit; + + assert(w - 1 <= 32); + _obp_br(v, br, ((uint8_t)(w - 1))); + if (v < m) { + *out = v; + return 0; + } + _obp_br(extra_bit, br, 1); + *out = (v << 1) - m + extra_bit; + return 0; +} + +static inline int _obp_su(_OBPBitReader *br, uint32_t n, int32_t *out, OBPError *err) +{ + int32_t value; + uint32_t signMask; + + _obp_br(value, br, n); + signMask = ((uint32_t)1) << (n - 1); + if (value & signMask) { + value = value - 2 * signMask; + } + *out = value; + return 0; +} + +static inline int _obp_decode_subexp(_OBPBitReader *br, int32_t numSyms, uint32_t *out, OBPError *err) +{ + int32_t i = 0; + int32_t mk = 0; + int32_t k = 3; + while (1) { + int32_t b2 = i ? k + i - 1 : k; + int32_t a = 1 << b2; + if (numSyms <= mk + 3 * a) { + uint32_t val; + int ret = _obp_ns(br, numSyms - mk, &val, err); + if (ret < 0) { + return -1; + } + *out = val; + return 0; + } else { + int subexp_more_bits; + _obp_br(subexp_more_bits, br, 1); + if (subexp_more_bits) { + i++; + mk += a; + } else { + uint32_t subexp_bits; + assert(b2 <= 255); + _obp_br(subexp_bits, br, ((uint8_t)b2)); + *out = subexp_bits + mk; + return 0; + } + } + } +} + +static inline int32_t _obps_inverse_recenter(int32_t r, uint32_t v) +{ + if (((uint64_t)v) > ((uint64_t)(2 * r))) { + return (int32_t) v; + } else if (v & 1) { + return r - ((v + 1) >> 1); + } else { + return r + (v >> 1); + } +} + +static inline int _obp_decode_unsigned_subexp_with_ref(_OBPBitReader *br, int32_t mx, int32_t r, int16_t *out, OBPError *err) { + uint32_t v; + int ret = _obp_decode_subexp(br, mx, &v, err); + if (ret < 0) { + return -1; + } + if (r < 0) { /* avoid signed shift */ + if (-(-r << 1) <= mx) { + *out = _obps_inverse_recenter(r, v); + return 0; + } + } + if ((r << 1) <= mx) { + *out = _obps_inverse_recenter(r, v); + return 0; + } else { + *out = mx - 1 - _obps_inverse_recenter(mx - 1 - r, v); + return 0; + } + + return 0; +} + +static inline int _obp_decode_signed_subexp_with_ref(_OBPBitReader *br, int32_t low, int32_t high, int32_t r, int16_t *out, OBPError *err) { + int16_t val; + int ret = _obp_decode_unsigned_subexp_with_ref(br, high - low, r - low, &val, err); + if (ret < 0) { + return -1; + } + *out = val + low; + return 0; +} + +/********************* + * Helper functions. * + *********************/ + +#define _OBP_MAX(x,y) ((x) > (y) ? x : y) +#define _OBP_MIN(x,y) ((x) < (y) ? x : y) + +static inline int _obp_is_valid_obu(OBPOBUType type) +{ + return type == OBP_OBU_SEQUENCE_HEADER || + type == OBP_OBU_TEMPORAL_DELIMITER || + type == OBP_OBU_FRAME_HEADER || + type == OBP_OBU_TILE_GROUP || + type == OBP_OBU_METADATA || + type == OBP_OBU_FRAME || + type == OBP_OBU_REDUNDANT_FRAME_HEADER || + type == OBP_OBU_TILE_LIST || + type == OBP_OBU_PADDING; +} + +static inline int _obp_set_frame_refs(OBPFrameHeader *fh, OBPSequenceHeader *seq, OBPState *state, OBPError *err) +{ + int usedFrame[8]; + uint32_t curFrameHint, lastOrderHint, goldOrderHint, latestOrderHint, earliestOrderHint; + int32_t ref; + uint8_t shiftedOrderHints[8]; + const int Ref_Frame_List[7 - 2] = { 2, 3, 5, 6, 7 }; /*LAST2_FRAME, LAST3_FRAME, BWDREF_FRAME, ALTREF2_FRAME, ALTREF_FRAME */ + int32_t ref_frame_idx[8]; + + for (int i = 0; i < 7; i++) { + ref_frame_idx[i] = -1; + } + ref_frame_idx[1 - 1] = fh->last_frame_idx; + ref_frame_idx[4 - 1] = fh->gold_frame_idx; + for (int i = 0; i < 8; i++) { + usedFrame[i] = 0; + } + usedFrame[fh->last_frame_idx] = 1; + usedFrame[fh->gold_frame_idx] = 2; + curFrameHint = 1 << (seq->OrderHintBits - 1); + for (int i = 0; i < 8; i++) { + shiftedOrderHints[i] = curFrameHint + _obp_get_relative_dist(state->RefOrderHint[i], fh->order_hint, seq); + } + lastOrderHint = shiftedOrderHints[fh->last_frame_idx]; + goldOrderHint = shiftedOrderHints[fh->gold_frame_idx]; + if (lastOrderHint >= curFrameHint || goldOrderHint >= curFrameHint) { + snprintf(err->error, err->size, "(lastOrderHint >= curFrameHint || goldOrderHint >= curFrameHint) not allowed."); + return -1; + } + /* find_latest_backward() */ + ref = -1; + latestOrderHint = 0; + for (int i = 0; i < 8; i++) { + uint32_t hint = shiftedOrderHints[i]; + if (!usedFrame[i] && (hint >= curFrameHint) && (ref < 0 || hint >= latestOrderHint)) { + ref = i; + latestOrderHint = hint; + } + } + if (ref >= 0) { + ref_frame_idx[7 - 1] = ref; + usedFrame[ref] = 1; + } + /* find_earliest_backward() */ + ref = -1; + earliestOrderHint = 0; + for (int i = 0; i < 8; i++) { + uint32_t hint = shiftedOrderHints[i]; + if (!usedFrame[i] && (hint >= curFrameHint) && (ref < 0 || hint < earliestOrderHint)) { + ref = i; + earliestOrderHint = hint; + } + } + if (ref >= 0) { + ref_frame_idx[5 - 1] = ref; + usedFrame[ref] = 1; + } + /* find_earliest_backward() */ + ref = -1; + earliestOrderHint = 0; + for (int i = 0; i < 8; i++) { + uint32_t hint = shiftedOrderHints[i]; + if (!usedFrame[i] && (hint >= curFrameHint) && (ref < 0 || hint < earliestOrderHint)) { + ref = i; + earliestOrderHint = hint; + } + } + if (ref >= 0) { + ref_frame_idx[6 - 1] = ref; + usedFrame[ref] = 1; + } + for (int i = 0; i < 7 - 2; i++) { + uint8_t refFrame = Ref_Frame_List[i]; + if (ref_frame_idx[refFrame - 1] < 0) { + int32_t subref = -1; + uint32_t subLatestOrderHint = 0; + for (int i = 0; i < 8; i++) { + uint32_t hint = shiftedOrderHints[i]; + if (!usedFrame[i] && (hint < curFrameHint) && (ref < 0 || hint >= subLatestOrderHint)) { + ref = i; + subLatestOrderHint = 0; + } + } + ref = subref; + if (ref >= 0) { + ref_frame_idx[refFrame - 1] = ref; + usedFrame[ref] = 1; + } + } + } + ref = -1; + for (int i = 0; i < 8; i++) { + uint32_t hint = shiftedOrderHints[i]; + if (ref < 0 || hint < earliestOrderHint) { + ref = i; + earliestOrderHint = hint; + } + } + for (int i = 0; i < 7; i++) { + if (ref_frame_idx[i] < 0) { + ref_frame_idx[i] = ref; + } + } + for (int i = 0; i < 7; i++) { + fh->ref_frame_idx[i] = ref_frame_idx[i]; + } + + return 0; +} + +static inline int _obp_read_delta_q(_OBPBitReader *br, int32_t *out, OBPError *err) +{ + int delta_coded; + _obp_br(delta_coded, br, 1); + if (delta_coded) { + int32_t val; + int ret = _obp_su(br, 7, &val, err); + if (ret < 0) + return ret; + *out = val; + } else { + *out = 1; + } + return 0; +} + +static inline uint8_t _obp_get_qindex(int ignoreDeltaQ, int segmentId, int16_t CurrentQIndex, OBPFrameHeader *fh, int FeatureEnabled[8][8], int16_t FeatureData[8][8]) +{ + if (fh->segmentation_params.segmentation_enabled && FeatureEnabled[segmentId][0]) { + int16_t data = FeatureData[segmentId][0]; + int32_t qindex = data + ((int32_t) fh->quantization_params.base_q_idx); + if (ignoreDeltaQ == 0 && fh->delta_q_params.delta_q_present == 1) { + qindex = CurrentQIndex + data; + } + return _OBP_MAX(0, _OBP_MIN(255, qindex)); + } + + if (ignoreDeltaQ == 0 && fh->delta_q_params.delta_q_present == 1) { + return CurrentQIndex; + } + + return fh->quantization_params.base_q_idx; +} + +static inline int _obp_read_global_param(_OBPBitReader *br, OBPFrameHeader *fh, uint8_t type, int ref, int idx, OBPError *err) +{ + uint8_t absBits = 12; + uint8_t precBits = 15; + if (idx < 2) { + if (type == 1) { + absBits = 9 - !fh->allow_high_precision_mv; + precBits = 3 - !fh->allow_high_precision_mv; + } else { + absBits = 12; + precBits = 6; + } + } + int32_t precDiff = 16 - precBits; + int32_t round = ((idx % 3) == 2) ? (1 << 16) : 0; + int32_t sub = ((idx % 3) == 2) ? (1 << precBits) : 0; + int32_t mx = (1 << absBits); + int32_t r = (fh->global_motion_params.prev_gm_params[ref][idx] >> precDiff) - sub; + int16_t val; + int ret = _obp_decode_signed_subexp_with_ref(br, -mx, mx + 1, r, &val, err); + if (ret < 0) { + return -1; + } + if (val < 0) { /* signed shifts are bad. */ + val = -val; + fh->global_motion_params.gm_params[ref][idx] = (-(val << precDiff) + round); + } else { + fh->global_motion_params.gm_params[ref][idx] = (val << precDiff) + round; + } + + return 0; +} + + +/***************************** + * API functions start here. * + *****************************/ + +int obp_get_next_obu(uint8_t *buf, size_t buf_size, OBPOBUType *obu_type, ptrdiff_t *offset, + size_t *size, int *temporal_id, int *spatial_id, OBPError *err) +{ + ptrdiff_t pos = 0; + int obu_extension_flag; + int obu_has_size_field; + + if (buf_size < 1) { + snprintf(err->error, err->size, "Buffer is too small to contain an OBU."); + return -1; + } + + *obu_type = (buf[pos] & 0x78) >> 3; + obu_extension_flag = (buf[pos] & 0x04) >> 2; + obu_has_size_field = (buf[pos] & 0x02) >> 1; + pos++; + + if (!_obp_is_valid_obu(*obu_type)) { + snprintf(err->error, err->size, "OBU header contains invalid OBU type: %d", *obu_type); + return -1; + } + + if (obu_extension_flag) { + if (buf_size < 1) { + snprintf(err->error, err->size, "Buffer is too small to contain an OBU extension header."); + return -1; + } + *temporal_id = (buf[pos] & 0xE0) >> 5; + *spatial_id = (buf[pos] & 0x18) >> 3; + pos++; + } else { + *temporal_id = 0; + *spatial_id = 0; + } + + if (obu_has_size_field) { + char err_buf[1024]; + uint64_t value; + ptrdiff_t consumed; + OBPError error = { &err_buf[0], 1024 }; + + int ret = _obp_leb128(buf + pos, buf_size - (size_t) pos, &value, &consumed, &error); + if (ret < 0) { + snprintf(err->error, err->size, "Failed to read OBU size: %s", &error.error[0]); + return -1; + } + + assert(value < UINT32_MAX); + + *offset = (ptrdiff_t) pos + consumed; + *size = (size_t) value; + } else { + *offset = (ptrdiff_t) pos; + *size = buf_size - (size_t) pos; + } + + if (*size > buf_size - (size_t) offset) { + snprintf(err->error, err->size, "Invalid OBU size: larger than remaining buffer."); + return -1; + } + + return 0; +} + +int obp_parse_sequence_header(uint8_t *buf, size_t buf_size, OBPSequenceHeader *seq_header, OBPError *err) +{ + _OBPBitReader b = _obp_new_br(buf, buf_size); + _OBPBitReader *br = &b; + + _obp_br(seq_header->seq_profile, br, 3); + _obp_br(seq_header->still_picture, br, 1); + _obp_br(seq_header->reduced_still_picture_header, br, 1); + if (seq_header->reduced_still_picture_header) { + seq_header->timing_info_present_flag = 0; + seq_header->decoder_model_info_present_flag = 0; + seq_header->initial_display_delay_present_flag = 0; + seq_header->operating_points_cnt_minus_1 = 0; + seq_header->operating_point_idc[0] = 0; + seq_header->seq_level_idx[0] = 0; + seq_header->seq_tier[0] = 0; + seq_header->decoder_model_present_for_this_op[0] = 0; + seq_header->initial_display_delay_present_for_this_op[0] = 0; + } else { + _obp_br(seq_header->timing_info_present_flag, br, 1); + if (seq_header->timing_info_present_flag) { + /* timing_info() */ + _obp_br(seq_header->timing_info.num_units_in_display_tick, br, 32); + _obp_br(seq_header->timing_info.time_scale, br, 32); + _obp_br(seq_header->timing_info.equal_picture_interval, br, 1); + if (seq_header->timing_info.equal_picture_interval) { + int ret = _obp_uvlc(br, &seq_header->timing_info.num_ticks_per_picture_minus_1, err); + if (ret < 0) + return -1; + } + _obp_br(seq_header->decoder_model_info_present_flag, br, 1); + if (seq_header->decoder_model_info_present_flag) { + /* decoder_model_info() */ + _obp_br(seq_header->decoder_model_info.buffer_delay_length_minus_1, br, 5); + _obp_br(seq_header->decoder_model_info.num_units_in_decoding_tick, br, 32); + _obp_br(seq_header->decoder_model_info.buffer_removal_time_length_minus_1, br, 5); + _obp_br(seq_header->decoder_model_info.frame_presentation_time_length_minus_1, br, 5); + } + } else { + seq_header->decoder_model_info_present_flag = 0; + } + _obp_br(seq_header->initial_display_delay_present_flag, br, 1); + _obp_br(seq_header->operating_points_cnt_minus_1, br, 5); + for (uint8_t i = 0; i <= seq_header->operating_points_cnt_minus_1; i++) { + _obp_br(seq_header->operating_point_idc[i], br, 12); + _obp_br(seq_header->seq_level_idx[i], br, 5); + if (seq_header->seq_level_idx[i] > 7) { + _obp_br(seq_header->seq_tier[i], br, 1); + } else { + seq_header->seq_tier[i] = 0; + } + if (seq_header->decoder_model_info_present_flag) { + _obp_br(seq_header->decoder_model_present_for_this_op[i], br, 1); + if (seq_header->decoder_model_present_for_this_op[i]) { + /* operating_parameters_info() */ + uint8_t n = seq_header->decoder_model_info.buffer_delay_length_minus_1 + 1; + _obp_br(seq_header->operating_parameters_info[i].decoder_buffer_delay, br, n); + _obp_br(seq_header->operating_parameters_info[i].encoder_buffer_delay, br, n); + _obp_br(seq_header->operating_parameters_info[i].low_delay_mode_flag, br, 1); + } + } else { + seq_header->decoder_model_present_for_this_op[i] = 0; + } + if (seq_header->initial_display_delay_present_flag) { + _obp_br(seq_header->initial_display_delay_present_for_this_op[i], br, 1); + if (seq_header->initial_display_delay_present_for_this_op[i]) { + _obp_br(seq_header->initial_display_delay_minus_1[i], br, 4); + } + } + } + } + _obp_br(seq_header->frame_width_bits_minus_1, br, 4); + _obp_br(seq_header->frame_height_bits_minus_1, br, 4); + _obp_br(seq_header->max_frame_width_minus_1, br, seq_header->frame_width_bits_minus_1 + 1); + _obp_br(seq_header->max_frame_height_minus_1, br, seq_header->frame_height_bits_minus_1 + 1); + if (seq_header->reduced_still_picture_header) { + seq_header->frame_id_numbers_present_flag = 0; + } else { + _obp_br(seq_header->frame_id_numbers_present_flag, br, 1); + } + if (seq_header->frame_id_numbers_present_flag) { + _obp_br(seq_header->delta_frame_id_length_minus_2, br, 4); + _obp_br(seq_header->additional_frame_id_length_minus_1, br, 3); + } + _obp_br(seq_header->use_128x128_superblock, br, 1); + _obp_br(seq_header->enable_filter_intra, br, 1); + _obp_br(seq_header->enable_intra_edge_filter, br, 1); + if (seq_header->reduced_still_picture_header) { + seq_header->enable_interintra_compound = 0; + seq_header->enable_masked_compound = 0; + seq_header->enable_warped_motion = 0; + seq_header->enable_dual_filter = 0; + seq_header->enable_order_hint = 0; + seq_header->enable_jnt_comp = 0; + seq_header->enable_ref_frame_mvs = 0; + seq_header->seq_force_screen_content_tools = 2; /* SELECT_SCREEN_CONTENT_TOOLS */ + seq_header->seq_force_integer_mv = 2; /* SELECT_INTEGER_MV */ + seq_header->OrderHintBits = 0; + } else { + _obp_br(seq_header->enable_interintra_compound, br, 1); + _obp_br(seq_header->enable_masked_compound, br, 1); + _obp_br(seq_header->enable_warped_motion, br, 1); + _obp_br(seq_header->enable_dual_filter, br, 1); + _obp_br(seq_header->enable_order_hint, br, 1); + if (seq_header->enable_order_hint) { + _obp_br(seq_header->enable_jnt_comp, br, 1); + _obp_br(seq_header->enable_ref_frame_mvs, br, 1); + } else { + seq_header->enable_jnt_comp = 0; + seq_header->enable_ref_frame_mvs = 0; + } + _obp_br(seq_header->seq_choose_screen_content_tools, br, 1); + if (seq_header->seq_choose_screen_content_tools) { + seq_header->seq_force_screen_content_tools = 2; /* SELECT_SCREEN_CONTENT_TOOLS */ + } else { + _obp_br(seq_header->seq_force_screen_content_tools, br, 1); + } + if (seq_header->seq_force_screen_content_tools > 0) { + _obp_br(seq_header->seq_choose_integer_mv, br, 1); + if (seq_header->seq_choose_integer_mv) { + seq_header->seq_force_integer_mv = 2; /* SELECT_INTEGER_MV */ + } else { + _obp_br(seq_header->seq_force_integer_mv, br, 1); + } + } else { + seq_header->seq_force_integer_mv = 2; /* SELECT_INTEGER_MV */ + } + if (seq_header->enable_order_hint) { + _obp_br(seq_header->order_hint_bits_minus_1, br, 3); + seq_header->OrderHintBits = seq_header->order_hint_bits_minus_1 + 1; + } else { + seq_header->OrderHintBits = 0; + } + } + _obp_br(seq_header->enable_superres, br, 1); + _obp_br(seq_header->enable_cdef, br, 1); + _obp_br(seq_header->enable_restoration, br, 1); + /* color_config() */ + _obp_br(seq_header->color_config.high_bitdepth, br, 1); + if (seq_header->seq_profile == 2 && seq_header->color_config.high_bitdepth) { + _obp_br(seq_header->color_config.twelve_bit, br, 1); + seq_header->color_config.BitDepth = seq_header->color_config.twelve_bit ? 12 : 10; + } else { + seq_header->color_config.BitDepth = seq_header->color_config.high_bitdepth ? 10 : 8; + } + if (seq_header->seq_profile == 1) { + seq_header->color_config.mono_chrome = 0; + } else { + _obp_br(seq_header->color_config.mono_chrome, br, 1); + } + seq_header->color_config.NumPlanes = seq_header->color_config.mono_chrome ? 1 : 3; + _obp_br(seq_header->color_config.color_description_present_flag, br, 1); + if (seq_header->color_config.color_description_present_flag) { + _obp_br(seq_header->color_config.color_primaries, br, 8); + _obp_br(seq_header->color_config.transfer_characteristics, br, 8); + _obp_br(seq_header->color_config.matrix_coefficients, br, 8); + } else { + seq_header->color_config.color_primaries = OBP_CP_UNSPECIFIED; + seq_header->color_config.transfer_characteristics = OBP_TC_UNSPECIFIED; + seq_header->color_config.matrix_coefficients = OBP_MC_UNSPECIFIED; + } + if (seq_header->color_config.mono_chrome) { + _obp_br(seq_header->color_config.color_range, br, 1); + seq_header->color_config.subsampling_x = 1; + seq_header->color_config.subsampling_y = 1; + seq_header->color_config.chroma_sample_position = OBP_CSP_UNKNOWN; + seq_header->color_config.separate_uv_delta_q = 0; + goto color_done; + } else if (seq_header->color_config.color_primaries == OBP_CP_BT_709 && + seq_header->color_config.transfer_characteristics == OBP_TC_SRGB && + seq_header->color_config.matrix_coefficients == OBP_MC_IDENTITY) { + seq_header->color_config.color_range = 1; + seq_header->color_config.subsampling_x = 0; + seq_header->color_config.subsampling_y = 0; + } else { + _obp_br(seq_header->color_config.color_range, br, 1); + if (seq_header->seq_profile == 0) { + seq_header->color_config.subsampling_x = 1; + seq_header->color_config.subsampling_y = 1; + } else if (seq_header->seq_profile == 1) { + seq_header->color_config.subsampling_x = 0; + seq_header->color_config.subsampling_y = 0; + } else { + if (seq_header->color_config.BitDepth == 12) { + _obp_br(seq_header->color_config.subsampling_x, br, 1); + if (seq_header->color_config.subsampling_x) { + _obp_br(seq_header->color_config.subsampling_y, br, 1); + } else { + seq_header->color_config.subsampling_y = 0; + } + } else { + seq_header->color_config.subsampling_x = 1; + seq_header->color_config.subsampling_y = 0; + } + } + if (seq_header->color_config.subsampling_x && seq_header->color_config.subsampling_y) { + _obp_br(seq_header->color_config.chroma_sample_position, br, 2); + } + } + _obp_br(seq_header->color_config.separate_uv_delta_q, br, 1); + +color_done: + _obp_br(seq_header->film_grain_params_present, br, 1); + + return 0; +} + +int obp_parse_tile_list(uint8_t *buf, size_t buf_size, OBPTileList *tile_list, OBPError *err) +{ + size_t pos = 0; + + if (buf_size < 4) { + snprintf(err->error, err->size, "Tile list OBU must be at least 4 bytes."); + return -1; + } + + tile_list->output_frame_width_in_tiles_minus_1 = buf[0]; + tile_list->output_frame_height_in_tiles_minus_1 = buf[1]; + tile_list->tile_count_minus_1 = (((uint16_t) buf[2]) << 8) | buf[3]; + pos += 4; + + for (uint16_t i = 0; i < tile_list->tile_count_minus_1; i++) { + if (pos + 5 > buf_size) { + snprintf(err->error, err->size, "Tile list OBU malformed: Not enough bytes for next tile_list_entry()."); + return -1; + } + + tile_list->tile_list_entry[i].anchor_frame_idx = buf[pos]; + tile_list->tile_list_entry[i].anchor_tile_row = buf[pos + 1]; + tile_list->tile_list_entry[i].anchor_tile_col = buf[pos + 2]; + tile_list->tile_list_entry[i].tile_data_size_minus_1 = (((uint16_t) buf[pos + 3]) << 8) | buf[pos + 4]; + pos += 5; + + size_t N = 8 * (((size_t) tile_list->tile_list_entry[i].tile_data_size_minus_1) + 1); + + if (pos + N > buf_size) { + snprintf(err->error, err->size, "Tile list OBU malformed: Not enough bytes for next tile_list_entry()'s data."); + return -1; + } + + tile_list->tile_list_entry[i].coded_tile_data = buf + pos; + tile_list->tile_list_entry[i].coded_tile_data_size = N; + pos += N; + } + + return 0; +} + +int obp_parse_tile_group(uint8_t *buf, size_t buf_size, OBPFrameHeader *frame_header, OBPTileGroup *tile_group, + int *SeenFrameHeader, OBPError *err) +{ + _OBPBitReader b = _obp_new_br(buf, buf_size); + _OBPBitReader *br = &b; + + tile_group->NumTiles = frame_header->tile_info.TileCols * frame_header->tile_info.TileRows; + size_t startBitPos = 0; + tile_group->tile_start_and_end_present_flag = 0; + + if (tile_group->NumTiles > 1) { + _obp_br(tile_group->tile_start_and_end_present_flag, br, 1); + } + if (tile_group->NumTiles == 1 || !tile_group->tile_start_and_end_present_flag) { + tile_group->tg_start = 0; + tile_group->tg_end = tile_group->NumTiles - 1; + } else { + uint8_t tileBits = _obp_tile_log2(1, frame_header->tile_info.TileCols) + _obp_tile_log2(1, frame_header->tile_info.TileRows); + _obp_br(tile_group->tg_start, br, tileBits); + _obp_br(tile_group->tg_end, br, tileBits); + } + _obp_br_byte_alignment(br); + size_t endBitPos = _obp_br_get_pos(br); + size_t headerBytes = (endBitPos - startBitPos) / 8; + size_t sz = buf_size - headerBytes; + size_t pos = headerBytes; + + for (uint16_t TileNum = tile_group->tg_start; TileNum <= tile_group->tg_end; TileNum++) { + /* tileRow = TileNum / TileCols */ + /* tileCol = TileNum % TileCols */ + int lastTile = (TileNum == tile_group->tg_end); + if (lastTile) { + tile_group->TileSize[TileNum] = sz; + } else { + uint16_t TileSizeBytes = frame_header->tile_info.tile_size_bytes_minus_1 + 1; + uint64_t tile_size_minus_1; + if (sz < TileSizeBytes) { + snprintf(err->error, err->size, "Not enough bytes left to read tile size for tile %"PRIu16".", TileNum); + return -1; + } + tile_size_minus_1 = _obp_le(buf + pos, TileSizeBytes); + tile_group->TileSize[TileNum] = tile_size_minus_1 + 1; + if (sz < tile_group->TileSize[TileNum]) { + snprintf(err->error, err->size, "Not enough bytes to contain TileSize for tile %"PRIu16".", TileNum); + return -1; + } + sz -= tile_group->TileSize[TileNum] + TileSizeBytes; + pos += tile_group->TileSize[TileNum] + TileSizeBytes; + } + /* MiRowStart = MiRowStarts[ tileRow ] */ + /* MiRowEnd = MiRowStarts[ tileRow + 1 ] */ + /* MiColStart = MiColStarts[ tileCol ] */ + /* MiColEnd = MiColStarts[ tileCol + 1 ] */ + /* CurrentQIndex = base_q_idx */ + /* init_symbol( tileSize ) */ + /* decode_tile( ) */ + /* exit_symbol( ) */ + } + if (tile_group->tg_end == tile_group->NumTiles - 1) { + /* if ( !disable_frame_end_update_cdf ) { + frame_end_update_cdf( ) + } + */ + /* decode_frame_wrapup() is handled in obp_parse_frame_header. */ + *SeenFrameHeader = 0; + } + + return 0; +} + +int obp_parse_metadata(uint8_t *buf, size_t buf_size, OBPMetadata *metadata, OBPError *err) +{ + uint64_t val; + ptrdiff_t consumed; + char err_buf[1024]; + _OBPBitReader b; + _OBPBitReader *br; + OBPError error = { &err_buf[0], 1024 }; + + int ret = _obp_leb128(buf, buf_size, &val, &consumed, &error); + if (ret < 0) { + snprintf(err->error, err->size, "Couldn't read metadata type: %s", error.error); + return -1; + } + metadata->metadata_type = val; + + b = _obp_new_br(buf + consumed, buf_size - consumed); + br = &b; + + if (metadata->metadata_type == OBP_METADATA_TYPE_HDR_CLL) { + _obp_br(metadata->metadata_hdr_cll.max_cll, br, 16); + _obp_br(metadata->metadata_hdr_cll.max_fall, br, 16); + } else if (metadata->metadata_type == OBP_METADATA_TYPE_HDR_MDCV) { + for (int i = 0; i < 3; i++) { + _obp_br(metadata->metadata_hdr_mdcv.primary_chromaticity_x[i], br, 16); + _obp_br(metadata->metadata_hdr_mdcv.primary_chromaticity_y[i], br, 16); + } + _obp_br(metadata->metadata_hdr_mdcv.white_point_chromaticity_x, br, 16); + _obp_br(metadata->metadata_hdr_mdcv.white_point_chromaticity_y, br, 16); + _obp_br(metadata->metadata_hdr_mdcv.luminance_max, br, 32); + _obp_br(metadata->metadata_hdr_mdcv.luminance_min, br, 32); + } else if (metadata->metadata_type == OBP_METADATA_TYPE_SCALABILITY) { + _obp_br(metadata->metadata_scalability.scalability_mode_idc, br, 8); + if (metadata->metadata_scalability.scalability_mode_idc) { + /* scalability_structure() */ + _obp_br(metadata->metadata_scalability.scalability_structure.spatial_layers_cnt_minus_1, br, 2); + _obp_br(metadata->metadata_scalability.scalability_structure.spatial_layer_dimensions_present_flag, br, 1); + _obp_br(metadata->metadata_scalability.scalability_structure.spatial_layer_description_present_flag, br, 1); + _obp_br(metadata->metadata_scalability.scalability_structure.temporal_group_description_present_flag, br, 1); + _obp_br(metadata->metadata_scalability.scalability_structure.scalability_structure_reserved_3bits, br, 3); + if (metadata->metadata_scalability.scalability_structure.spatial_layer_dimensions_present_flag) { + for (uint8_t i = 0; i < metadata->metadata_scalability.scalability_structure.spatial_layers_cnt_minus_1; i++) { + _obp_br(metadata->metadata_scalability.scalability_structure.spatial_layer_max_width[i], br, 16); + _obp_br(metadata->metadata_scalability.scalability_structure.spatial_layer_max_height[i], br, 16); + } + } + if (metadata->metadata_scalability.scalability_structure.spatial_layer_description_present_flag) { + for (uint8_t i = 0; i < metadata->metadata_scalability.scalability_structure.spatial_layers_cnt_minus_1; i++) { + _obp_br(metadata->metadata_scalability.scalability_structure.spatial_layer_ref_id[i], br, 8); + } + } + if (metadata->metadata_scalability.scalability_structure.temporal_group_description_present_flag) { + _obp_br(metadata->metadata_scalability.scalability_structure.temporal_group_size, br, 8); + for (uint8_t i = 0; i < metadata->metadata_scalability.scalability_structure.temporal_group_size; i++) { + _obp_br(metadata->metadata_scalability.scalability_structure.temporal_group_temporal_id[i], br, 3); + _obp_br(metadata->metadata_scalability.scalability_structure.temporal_group_temporal_switching_up_point_flag[i], br, 1); + _obp_br(metadata->metadata_scalability.scalability_structure.temporal_group_spatial_switching_up_point_flag[i], br, 1); + _obp_br(metadata->metadata_scalability.scalability_structure.temporal_group_ref_cnt[i], br, 3); + for (uint8_t j = 0; j < metadata->metadata_scalability.scalability_structure.temporal_group_ref_cnt[i]; j++) { + _obp_br(metadata->metadata_scalability.scalability_structure.temporal_group_ref_pic_diff[i][j], br, 8); + } + } + } + } + } else if (metadata->metadata_type == OBP_METADATA_TYPE_ITUT_T35) { + size_t offset = 1; + _obp_br(metadata->metadata_itut_t35.itu_t_t35_country_code, br, 8); + if (metadata->metadata_itut_t35.itu_t_t35_country_code == 0xFF) { + _obp_br(metadata->metadata_itut_t35.itu_t_t35_country_code_extension_byte, br, 8); + offset++; + } + metadata->metadata_itut_t35.itu_t_t35_payload_bytes = buf + consumed + offset; + int non_zero_bytes_seen = 0; + /* + * OBUs with byte payloads at the end have a dumb property where you need to + * know the trailing bits *before* you parse the OBU, despite the way the spec + * the syntax displayed and defined. SO as a result, you need to find the *second* + * non-zero byte at the end of the OBU payload, rather than the last one, as + * the note in the ITU T.35 part of the spec says. + */ + for (size_t i = buf_size - consumed - offset - 1; i > 0; i--) { + if (metadata->metadata_itut_t35.itu_t_t35_payload_bytes[i] != 0) { + non_zero_bytes_seen++; + if (non_zero_bytes_seen == 2) { + metadata->metadata_itut_t35.itu_t_t35_payload_bytes_size = i + 1; + } + } + } + } else if (metadata->metadata_type == OBP_METADATA_TYPE_TIMECODE) { + _obp_br(metadata->metadata_timecode.counting_type, br, 5); + _obp_br(metadata->metadata_timecode.full_timestamp_flag, br, 1); + _obp_br(metadata->metadata_timecode.discontinuity_flag, br, 1); + _obp_br(metadata->metadata_timecode.cnt_dropped_flag, br, 1); + _obp_br(metadata->metadata_timecode.n_frames, br, 9); + if (metadata->metadata_timecode.full_timestamp_flag) { + _obp_br(metadata->metadata_timecode.seconds_value, br, 6); + _obp_br(metadata->metadata_timecode.minutes_value, br, 6); + _obp_br(metadata->metadata_timecode.hours_value, br, 5); + } else { + _obp_br(metadata->metadata_timecode.seconds_flag, br, 1); + if (metadata->metadata_timecode.seconds_flag) { + _obp_br(metadata->metadata_timecode.seconds_value, br, 6); + _obp_br(metadata->metadata_timecode.minutes_flag, br, 1); + if (metadata->metadata_timecode.minutes_flag) { + _obp_br(metadata->metadata_timecode.minutes_value, br, 6); + _obp_br(metadata->metadata_timecode.hours_flag, br, 1); + if (metadata->metadata_timecode.hours_flag) { + _obp_br(metadata->metadata_timecode.hours_value, br, 5); + } + } + } + } + _obp_br(metadata->metadata_timecode.time_offset_length, br, 5); + if (metadata->metadata_timecode.time_offset_length > 0) { + _obp_br(metadata->metadata_timecode.time_offset_value, br, metadata->metadata_timecode.time_offset_length); + } + } else if (metadata->metadata_type >= 6 && metadata->metadata_type <= 31) { + metadata->unregistered.buf = buf + consumed; + metadata->unregistered.buf_size = buf_size - consumed; + } else { + snprintf(err->error, err->size, "Invalid metadata type: %"PRIu32"\n", metadata->metadata_type); + return -1; + } + + return 0; +} + +int obp_parse_frame(uint8_t *buf, size_t buf_size, OBPSequenceHeader *seq, OBPState *state, + int temporal_id, int spatial_id, OBPFrameHeader *fh, OBPTileGroup *tile_group, + int *SeenFrameHeader, OBPError *err) +{ + size_t startBitPos = 0, endBitPos, headerBytes; + int ret = obp_parse_frame_header(buf, buf_size, seq, state, temporal_id, spatial_id, fh, SeenFrameHeader, err); + if (ret < 0) { + return -1; + } + endBitPos = state->frame_header_end_pos; + headerBytes = (endBitPos - startBitPos) / 8; + return obp_parse_tile_group(buf + headerBytes, buf_size - headerBytes, fh, tile_group, SeenFrameHeader, err); +} + +int obp_parse_frame_header(uint8_t *buf, size_t buf_size, OBPSequenceHeader *seq, OBPState *state, + int temporal_id, int spatial_id, OBPFrameHeader *fh, int *SeenFrameHeader, OBPError *err) +{ + _OBPBitReader b = _obp_new_br(buf, buf_size); + _OBPBitReader *br = &b; + + if (*SeenFrameHeader == 1) { + if (!state->prev_filled) { + snprintf(err->error, err->size, "SeenFrameHeader is one, but no previous header exists in state."); + return -1; + } + *fh = state->prev; + return 0; + } + + *SeenFrameHeader = 1; + + /* uncompressed_header() */ + int idLen = 0; /* only set to 0 to shut up a compiler warning. */ + if (seq->frame_id_numbers_present_flag) { + idLen = seq->additional_frame_id_length_minus_1 + seq->delta_frame_id_length_minus_2 + 3; + } + uint8_t allFrames = 255; /* (1 << 8) - 1 */ + int FrameIsIntra; + if (seq->reduced_still_picture_header) { + fh->show_existing_frame = 0; + fh->frame_type = OBP_KEY_FRAME; + FrameIsIntra = 1; + fh->show_frame = 1; + fh->showable_frame = 1; + } else { + _obp_br(fh->show_existing_frame, br, 1); + if (fh->show_existing_frame) { + _obp_br(fh->frame_to_show_map_idx, br, 3); + if (seq->decoder_model_info_present_flag && !seq->timing_info.equal_picture_interval) { + /* temporal_point_info() */ + uint8_t n = seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1; + _obp_br(fh->temporal_point_info.frame_presentation_time, br, n); + } + fh->refresh_frame_flags = 0; + if (seq->frame_id_numbers_present_flag) { + assert(idLen <= 255); + _obp_br(fh->display_frame_id, br, (uint8_t) idLen); + } + fh->frame_type = state->RefFrameType[fh->frame_to_show_map_idx]; + if (fh->frame_type == OBP_KEY_FRAME) { + fh->refresh_frame_flags = allFrames; + } + if (seq->film_grain_params_present) { + /* load_grain_params() */ + fh->film_grain_params = state->RefGrainParams[fh->frame_to_show_map_idx]; + } + return 0; + } + _obp_br(fh->frame_type, br, 2); + FrameIsIntra = (fh->frame_type == OBP_INTRA_ONLY_FRAME || fh->frame_type == OBP_KEY_FRAME); + _obp_br(fh->show_frame, br, 1); + if (fh->show_frame && seq->decoder_model_info_present_flag && !seq->timing_info.equal_picture_interval){ + /* temporal_point_info() */ + uint8_t n = seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1; + _obp_br(fh->temporal_point_info.frame_presentation_time, br, n); + } + if (fh->show_frame) { + fh->showable_frame = (fh->frame_type != OBP_KEY_FRAME); + } else { + _obp_br(fh->showable_frame, br, 1); + } + if (fh->frame_type == OBP_SWITCH_FRAME || (fh->frame_type == OBP_KEY_FRAME && fh->show_frame)) { + fh->error_resilient_mode = 1; + } else { + _obp_br(fh->error_resilient_mode, br, 1); + } + } + if (fh->frame_type == OBP_KEY_FRAME && fh->show_frame) { + for (int i = 0; i < 8; i++) { + state->RefValid[i] = 0; + state->RefOrderHint[i] = 0; + } + for (int i = 0; i < 7; i++) { + state->OrderHint[1 + i] = 0; + } + } + _obp_br(fh->disable_cdf_update, br, 1); + if (seq->seq_force_screen_content_tools == 2) { + _obp_br(fh->allow_screen_content_tools, br, 1); + } else { + fh->allow_screen_content_tools = seq->seq_force_screen_content_tools; + } + if (fh->allow_screen_content_tools) { + if (seq->seq_force_integer_mv == 2) { + _obp_br(fh->force_integer_mv, br, 1); + } else { + fh->force_integer_mv = seq->seq_force_integer_mv; + } + } else { + fh->force_integer_mv = 0; + } + if (FrameIsIntra) { + fh->force_integer_mv = 1; + } + if (seq->frame_id_numbers_present_flag) { + /*PrevFrameID = current_frame_id */ + assert(idLen <= 255); + _obp_br(fh->current_frame_id, br, idLen); + /* mark_ref_frames(idLen) */ + uint8_t diffLen = seq->delta_frame_id_length_minus_2 + 2; + for (int i = 0; i < 8; i++) { + if (fh->current_frame_id > (((uint32_t)1) << diffLen)) { + if (state->RefFrameId[i] > fh->current_frame_id || state->RefFrameId[i] < (fh->current_frame_id - (1 << diffLen))) { + state->RefValid[i] = 0; + } + } else { + if (state->RefFrameId[i] > fh->current_frame_id && state->RefFrameId[i] < ((1 << idLen) + fh->current_frame_id + (1 << diffLen))) { + state->RefValid[i] = 0; + } + } + } + } else { + fh->current_frame_id = 0; + } + if (fh->frame_type == OBP_SWITCH_FRAME) { + fh->frame_size_override_flag = 1; + } else if (seq->reduced_still_picture_header) { + fh->frame_size_override_flag = 0; + } else { + _obp_br(fh->frame_size_override_flag, br, 1); + } + if (seq->OrderHintBits) { /* Added by me. */ + _obp_br(fh->order_hint, br, seq->OrderHintBits); + } else { + fh->order_hint = 0; + } + uint8_t OrderHint = fh->order_hint; + if (FrameIsIntra || fh->error_resilient_mode) { + fh->primary_ref_frame = 7; + } else { + _obp_br(fh->primary_ref_frame, br, 3); + } + if (seq->decoder_model_info_present_flag) { + _obp_br(fh->buffer_removal_time_present_flag, br, 1); + if (fh->buffer_removal_time_present_flag) { + for (uint8_t opNum = 0; opNum <= seq->operating_points_cnt_minus_1; opNum++) { + if (seq->decoder_model_present_for_this_op[opNum]) { + uint8_t opPtIdc = seq->operating_point_idc[opNum]; + int inTemporalLayer = (opPtIdc >> temporal_id) & 1; + int inSpatialLayer = (opPtIdc >> (spatial_id + 8)) & 1; + if (opPtIdc == 0 || (inTemporalLayer && inSpatialLayer)) { + uint8_t n = seq->decoder_model_info.buffer_removal_time_length_minus_1 + 1; + _obp_br(fh->buffer_removal_time[opNum], br, n); + } + } + } + } + } + fh->allow_high_precision_mv = 0; + fh->use_ref_frame_mvs = 0; + fh->allow_intrabc = 0; + if (fh->frame_type == OBP_SWITCH_FRAME || (fh->frame_type == OBP_KEY_FRAME && fh->show_frame)) { + fh->refresh_frame_flags = allFrames; + } else { + _obp_br(fh->refresh_frame_flags, br, 8); + } + if (!FrameIsIntra || fh->refresh_frame_flags != allFrames) { + if (fh->error_resilient_mode && seq->enable_order_hint) { + for (int i = 0; i < 8; i++) { + _obp_br(fh->ref_order_hint[i], br, seq->OrderHintBits); + if (fh->ref_order_hint[i] != state->RefOrderHint[i]) { + state->RefValid[i] = 0; + } + } + } + } + uint32_t FrameWidth = 0, FrameHeight = 0; + uint32_t UpscaledWidth; + uint32_t MiCols, MiRows; + if (FrameIsIntra) { + /* frame_size() */ + if (fh->frame_size_override_flag) { + uint8_t n = seq->frame_width_bits_minus_1 + 1; + _obp_br(fh->frame_width_minus_1, br, n); + n = seq->frame_height_bits_minus_1 + 1; + _obp_br(fh->frame_height_minus_1, br, n); + FrameWidth = fh->frame_width_minus_1 + 1; + FrameHeight = fh->frame_height_minus_1 + 1; + } else { + FrameWidth = seq->max_frame_width_minus_1 + 1; + FrameHeight = seq->max_frame_height_minus_1 + 1; + } + /* superres_params() */ + uint32_t SuperresDenom; + if (seq->enable_superres) { + _obp_br(fh->superres_params.use_superres, br, 1); + } else { + fh->superres_params.use_superres = 0; + } + if (fh->superres_params.use_superres) { + _obp_br(fh->superres_params.coded_denom, br, 3); + SuperresDenom = fh->superres_params.coded_denom + 9; + } else { + SuperresDenom = 8; + } + UpscaledWidth = FrameWidth; + FrameWidth = (UpscaledWidth * 8 + (SuperresDenom / 2)) / SuperresDenom; + /* compute_image_size() */ + MiCols = 2 * ((FrameWidth + 7) >> 3); + MiRows = 2 * ((FrameHeight + 7) >> 3); + /* render_size() */ + _obp_br(fh->render_and_frame_size_different, br, 1); + if (fh->render_and_frame_size_different == 1) { + _obp_br(fh->render_width_minus_1, br, 16); + _obp_br(fh->render_height_minus_1, br, 16); + fh->RenderWidth = fh->render_width_minus_1 + 1; + fh->RenderHeight = fh->render_height_minus_1 + 1; + } else { + fh->RenderWidth = UpscaledWidth; + fh->RenderHeight = FrameHeight; + } + if (fh->allow_screen_content_tools && UpscaledWidth == FrameWidth) { + _obp_br(fh->allow_intrabc, br, 1); + } + } else { + if (!seq->enable_order_hint) { + fh->frame_refs_short_signaling = 0; + } else { + _obp_br(fh->frame_refs_short_signaling, br, 1); + if (fh->frame_refs_short_signaling) { + int ret; + char err_buf[1024]; + OBPError error = { &err_buf[0], 1024 }; + _obp_br(fh->last_frame_idx, br, 3); + _obp_br(fh->gold_frame_idx, br, 3); + ret = _obp_set_frame_refs(fh, seq, state, &error); + if (ret < 0) { + snprintf(err->error, err->size, "Failed to set frame refs: %s", error.error); + return -1; + } + } + } + for (int i = 0; i < 7; i++) { + if (!fh->frame_refs_short_signaling) { + _obp_br(fh->ref_frame_idx[i], br, 3); + } + if (seq->frame_id_numbers_present_flag) { + uint8_t n = seq->delta_frame_id_length_minus_2 + 2; + _obp_br(fh->delta_frame_id_minus_1[i], br, n); + uint8_t DeltaFrameId = fh->delta_frame_id_minus_1[i] + 1; + uint8_t expectedFrameId = ((fh->current_frame_id + (1 << idLen) - DeltaFrameId) % (1 << idLen)); + if (state->RefFrameId[fh->ref_frame_idx[i]] != expectedFrameId) { + snprintf(err->error, err->size, "state->RefFrameId[fh->ref_frame_idx[i]] != expectedFrameId (%"PRIu8" vs %"PRIu8")", + state->RefFrameId[fh->ref_frame_idx[i]], expectedFrameId); + return -1; + } + } + } + if (fh->frame_size_override_flag && !fh->error_resilient_mode) { + for (int i = 0; i < 7; i++) { + _obp_br(fh->found_ref, br, 1); + if (fh->found_ref == 1) { + UpscaledWidth = state->RefUpscaledWidth[fh->ref_frame_idx[i]]; + FrameWidth = UpscaledWidth; + FrameHeight = state->RefFrameHeight[fh->ref_frame_idx[i]]; + fh->RenderWidth = state->RefRenderWidth[fh->ref_frame_idx[i]]; + fh->RenderHeight = state->RefRenderHeight[fh->ref_frame_idx[i]]; + break; + } + } + if (fh->found_ref == 0) { + /* frame_size() */ + if (fh->frame_size_override_flag) { + uint8_t n = seq->frame_width_bits_minus_1 + 1; + _obp_br(fh->frame_width_minus_1, br, n); + n = seq->frame_height_bits_minus_1 + 1; + _obp_br(fh->frame_height_minus_1, br, n); + FrameWidth = fh->frame_width_minus_1 + 1; + FrameHeight = fh->frame_height_minus_1 + 1; + } else { + FrameWidth = seq->max_frame_width_minus_1 + 1; + FrameHeight = seq->max_frame_height_minus_1 + 1; + } + /* superres_params() */ + uint32_t SuperresDenom; + if (seq->enable_superres) { + _obp_br(fh->superres_params.use_superres, br, 1); + } else { + fh->superres_params.use_superres = 0; + } + if (fh->superres_params.use_superres) { + _obp_br(fh->superres_params.coded_denom, br, 3); + SuperresDenom = fh->superres_params.coded_denom + 9; + } else { + SuperresDenom = 8; + } + UpscaledWidth = FrameWidth; + FrameWidth = (UpscaledWidth * 8 + (SuperresDenom / 2)) / SuperresDenom; + /* compute_image_size() */ + MiCols = 2 * ((FrameWidth + 7) >> 3); + MiRows = 2 * ((FrameHeight + 7) >> 3); + /* render_size() */ + _obp_br(fh->render_and_frame_size_different, br, 1); + if (fh->render_and_frame_size_different == 1) { + _obp_br(fh->render_width_minus_1, br, 16); + _obp_br(fh->render_height_minus_1, br, 16); + fh->RenderWidth = fh->render_width_minus_1 + 1; + fh->RenderHeight = fh->render_height_minus_1 + 1; + } else { + fh->RenderWidth = UpscaledWidth; + fh->RenderHeight = FrameHeight; + } + } else { + /* superres_params() */ + uint32_t SuperresDenom; + if (seq->enable_superres) { + _obp_br(fh->superres_params.use_superres, br, 1); + } else { + fh->superres_params.use_superres = 0; + } + if (fh->superres_params.use_superres) { + _obp_br(fh->superres_params.coded_denom, br, 3); + SuperresDenom = fh->superres_params.coded_denom + 9; + } else { + SuperresDenom = 8; + } + UpscaledWidth = FrameWidth; + FrameWidth = (UpscaledWidth * 8 + (SuperresDenom / 2)) / SuperresDenom; + /* compute_image_size() */ + MiCols = 2 * ((FrameWidth + 7) >> 3); + MiRows = 2 * ((FrameHeight + 7) >> 3); + } + } else { + /* frame_size() */ + if (fh->frame_size_override_flag) { + uint8_t n = seq->frame_width_bits_minus_1 + 1; + _obp_br(fh->frame_width_minus_1, br, n); + n = seq->frame_height_bits_minus_1 + 1; + _obp_br(fh->frame_height_minus_1, br, n); + FrameWidth = fh->frame_width_minus_1 + 1; + FrameHeight = fh->frame_height_minus_1 + 1; + } else { + FrameWidth = seq->max_frame_width_minus_1 + 1; + FrameHeight = seq->max_frame_height_minus_1 + 1; + } + /* superres_params() */ + uint32_t SuperresDenom; + if (seq->enable_superres) { + _obp_br(fh->superres_params.use_superres, br, 1); + } else { + fh->superres_params.use_superres = 0; + } + if (fh->superres_params.use_superres) { + _obp_br(fh->superres_params.coded_denom, br, 3); + SuperresDenom = fh->superres_params.coded_denom + 9; + } else { + SuperresDenom = 8; + } + UpscaledWidth = FrameWidth; + FrameWidth = (UpscaledWidth * 8 + (SuperresDenom / 2)) / SuperresDenom; + /* compute_image_size() */ + MiCols = 2 * ((FrameWidth + 7) >> 3); + MiRows = 2 * ((FrameHeight + 7) >> 3); + /* render_size() */ + _obp_br(fh->render_and_frame_size_different, br, 1); + if (fh->render_and_frame_size_different == 1) { + _obp_br(fh->render_width_minus_1, br, 16); + _obp_br(fh->render_height_minus_1, br, 16); + fh->RenderWidth = fh->render_width_minus_1 + 1; + fh->RenderHeight = fh->render_height_minus_1 + 1; + } else { + fh->RenderWidth = UpscaledWidth; + fh->RenderHeight = FrameHeight; + } + } + if (fh->force_integer_mv) { + fh->allow_high_precision_mv = 0; + } else { + _obp_br(fh->allow_high_precision_mv, br, 1); + } + /* read_interpolation_filer() */ + _obp_br(fh->interpolation_filter.is_filter_switchable, br, 1); + if (fh->interpolation_filter.is_filter_switchable) { + fh->interpolation_filter.interpolation_filter = 4; + } else { + _obp_br(fh->interpolation_filter.interpolation_filter, br, 2); + } + _obp_br(fh->is_motion_mode_switchable, br, 1); + if (fh->error_resilient_mode || !seq->enable_ref_frame_mvs) { + fh->use_ref_frame_mvs = 0; + } else { + _obp_br(fh->use_ref_frame_mvs, br, 1); + } + for (int i = 0; i < 7; i++) { + int refFrame = 1 + i; + uint8_t hint = state->RefOrderHint[fh->ref_frame_idx[i]]; + state->OrderHint[refFrame] = hint; + if (!seq->enable_order_hint) { + state->RefFrameSignBias[refFrame] = 0; + } else { + state->RefFrameSignBias[refFrame] = _obp_get_relative_dist((int32_t) hint, (int32_t) OrderHint, seq); + } + } + } + if (seq->reduced_still_picture_header || fh->disable_cdf_update) { + fh->disable_frame_end_update_cdf = 1; + } else { + _obp_br(fh->disable_frame_end_update_cdf, br, 1); + } + int FeatureEnabled[8][8]; + int16_t FeatureData[8][8]; + if (fh->primary_ref_frame == 7) { + /* init_non_coeff_cdfs() not relevant to OBU parsing. */ + /* setup_past_independence() */ + for (int i = 1; i < 7; i++) { + fh->global_motion_params.gm_type[i] = 0; + for (int j = 0; j < 6; j++) { + fh->global_motion_params.gm_params[i][j] = (i % 3 == 2) ? (((uint32_t)1) << 16) : 0; + } + } + fh->loop_filter_params.loop_filter_delta_enabled = 1; + fh->loop_filter_params.loop_filter_ref_deltas[0] = 1; + fh->loop_filter_params.loop_filter_ref_deltas[1] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[2] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[3] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[4] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[5] = -1; + fh->loop_filter_params.loop_filter_ref_deltas[6] = -1; + fh->loop_filter_params.loop_filter_ref_deltas[7] = -1; + for (int i = 0; i < 2; i++) { + fh->loop_filter_params.loop_filter_mode_deltas[i] = 0; + } + } else { + /* load_cdfs() not relevant to OBU parsing. */ + /* load_previous */ + int prevFrame = fh->ref_frame_idx[fh->primary_ref_frame]; + for (int i = 0; i > 8; i++) { + for (int j = 0; j < 6; j++) { + fh->global_motion_params.prev_gm_params[i][j] = state->SavedGmParams[prevFrame][i][j]; + } + } + /* load_loop_filter_params() */ + for (int i = 0; i < 8; i++) { + fh->loop_filter_params.loop_filter_ref_deltas[i] = state->SavedLoopFilterRefDeltas[prevFrame][i]; + fh->loop_filter_params.loop_filter_mode_deltas[i] = state->SavedLoopFilterModeDeltas[prevFrame][i]; + } + /* load_segmentation_params() */ + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + FeatureEnabled[i][j] = state->SavedFeatureEnabled[prevFrame][i][j]; + FeatureData[i][j] = state->SavedFeatureData[prevFrame][i][j]; + } + } + } + /* Not relevant to OBU parsing: + if (fh->use_ref_frame_mvs) { + motion_field_estimation() + } + */ + /* tile_info() */ + uint32_t sbCols = seq->use_128x128_superblock ? ((MiCols + 31) >> 5) : ((MiCols + 15) >> 4); + uint32_t sbRows = seq->use_128x128_superblock ? ((MiRows + 31) >> 5) : ((MiRows + 15) >> 4); + uint32_t sbShift = seq->use_128x128_superblock ? 5 : 4; + uint32_t sbSize = sbShift + 2; + uint32_t maxTileWidthSb = 4096 >> sbSize; + uint32_t maxTileAreaSb = (4096 * 2304) >> (2 * sbSize); + uint32_t minLog2TileCols = _obp_tile_log2(maxTileWidthSb, sbCols); + uint32_t maxLog2TileCols = _obp_tile_log2(1, _OBP_MIN(sbCols, 64)); + uint32_t maxLog2TileRows = _obp_tile_log2(1, _OBP_MIN(sbRows, 64)); + uint32_t minLog2Tiles = _OBP_MAX(minLog2TileCols, _obp_tile_log2(maxTileAreaSb, sbRows * sbCols)); + uint32_t minLog2TileRows, TileColsLog2, TileRowsLog2; + _obp_br(fh->tile_info.uniform_tile_spacing_flag, br, 1); + if (fh->tile_info.uniform_tile_spacing_flag) { + TileColsLog2 = minLog2TileCols; + while (TileColsLog2 < maxLog2TileCols) { + int increment_tile_cols_log2; + _obp_br(increment_tile_cols_log2, br, 1); + if (increment_tile_cols_log2 == 1) { + TileColsLog2++; + } else { + break; + } + } + uint32_t tileWidthSb = (sbCols + (1 << TileColsLog2) - 1) >> TileColsLog2; + int i = 0; + for (uint32_t startSb = 0; startSb < sbCols; startSb += tileWidthSb) { + /* MiColStarts[i] = startSb << sbShift; */ + i += 1; + } + /*MiColStarts[i] = MiCols; */ + fh->tile_info.TileCols = i; + + minLog2TileRows = _OBP_MAX((int64_t)minLog2Tiles - (int64_t)TileColsLog2, 0); + TileRowsLog2 = minLog2TileRows; + while (TileRowsLog2 < maxLog2TileRows) { + int increment_tile_rows_log2; + _obp_br(increment_tile_rows_log2, br, 1); + if (increment_tile_rows_log2 == 1) { + TileRowsLog2++; + } else { + break; + } + } + uint32_t tileHeightSb = (sbRows + (1 << TileRowsLog2) - 1) >> TileRowsLog2; + i = 0; + for (uint32_t startSb = 0; startSb < sbRows; startSb += tileHeightSb) { + /*MiRowStarts[i] = startSb << sbShift;*/ + i += 1; + } + /*MiRowStarts[i] = MiRows;*/ + fh->tile_info.TileRows = i; + } else { + uint32_t widestTileSb = 0; + uint32_t startSb = 0; + uint32_t i, maxTileHeightSb; + for (i = 0; startSb < sbCols; i++) { + int ret; + char err_buf[1024]; + OBPError error = { &err_buf[0], 1024 }; + uint32_t maxWidth, sizeSb; + uint32_t width_in_sbs_minus_1; + /* MiColStarts[i] = startSb << sbShift; */ + maxWidth = _OBP_MIN(sbCols - startSb, maxTileWidthSb); + ret = _obp_ns(br, maxWidth, &width_in_sbs_minus_1, &error); + if (ret < 0) { + snprintf(err->error, err->size, "Couldn't read width_in_sbs_minus_1: %s", error.error); + return -1; + } + sizeSb = width_in_sbs_minus_1 + 1; + widestTileSb = _OBP_MAX(sizeSb, widestTileSb); + startSb += sizeSb; + } + /*MiColStarts[i] = MiCols;*/ + fh->tile_info.TileCols = i; + TileColsLog2 = _obp_tile_log2(1, fh->tile_info.TileCols); + + if (minLog2Tiles > 0) { + maxTileAreaSb = (sbRows * sbCols) >> (minLog2Tiles + 1); + } else { + maxTileAreaSb = sbRows * sbCols; + } + maxTileHeightSb = _OBP_MAX(maxTileAreaSb / widestTileSb, 1); + + startSb = 0; + for (i = 0; startSb < sbRows; i++) { + int ret; + char err_buf[1024]; + OBPError error = { &err_buf[0], 1024 }; + uint32_t maxHeight, sizeSb; + uint32_t height_in_sbs_minus_1; + /*MiRowStarts[i] = startSb << sbShift;*/ + maxHeight = _OBP_MIN(sbRows - startSb, maxTileHeightSb); + ret = _obp_ns(br, maxHeight, &height_in_sbs_minus_1, &error); + if (ret < 0) { + snprintf(err->error, err->size, "Couldn't read height_in_sbs_minus_1: %s", error.error); + return -1; + } + sizeSb = height_in_sbs_minus_1 + 1; + startSb += sizeSb; + } + /*MiRowStarts[i] = MiRows*/; + fh->tile_info.TileRows = i; + TileRowsLog2 = _obp_tile_log2(1, fh->tile_info.TileRows); + } + if (TileColsLog2 > 0 || TileRowsLog2 > 0) { + _obp_br(fh->tile_info.context_update_tile_id, br, (TileColsLog2 + TileRowsLog2)); + _obp_br(fh->tile_info.tile_size_bytes_minus_1, br, 2); + /*TileSizeBytes = fh->tile_info.tile_size_bytes_minus_1 + 1;*/ + } else { + fh->tile_info.context_update_tile_id = 0; + } + /* quantization_params() */ + _obp_br(fh->quantization_params.base_q_idx, br, 8); + int32_t DeltaQYDc, DeltaQUDc, DeltaQUAc, DeltaQVDc, DeltaQVAc; + int ret = _obp_read_delta_q(br, &DeltaQYDc, err); + if (ret < 0) { + return -1; + } + if (seq->color_config.NumPlanes > 1) { + int ret; + if (seq->color_config.separate_uv_delta_q) { + _obp_br(fh->quantization_params.diff_uv_delta, br, 1); + } else { + fh->quantization_params.diff_uv_delta = 0; + } + ret = _obp_read_delta_q(br, &DeltaQUDc, err); + if (ret < 0) { + return -1; + } + ret = _obp_read_delta_q(br, &DeltaQUAc, err); + if (ret < 0) { + return -1; + } + if (fh->quantization_params.diff_uv_delta) { + ret = _obp_read_delta_q(br, &DeltaQVDc, err); + if (ret < 0) { + return -1; + } + ret = _obp_read_delta_q(br, &DeltaQVAc, err); + if (ret < 0) { + return -1; + } + } else { + DeltaQVDc = DeltaQUDc; + DeltaQVAc = DeltaQUAc; + } + } else { + DeltaQUDc = 0; + DeltaQUAc = 0; + DeltaQVDc = 0; + DeltaQVAc = 0; + } + _obp_br(fh->quantization_params.using_qmatrix, br, 1); + if (fh->quantization_params.using_qmatrix) { + _obp_br(fh->quantization_params.qm_y, br, 4); + _obp_br(fh->quantization_params.qm_u, br, 4); + if (!seq->color_config.separate_uv_delta_q) { + fh->quantization_params.qm_v = fh->quantization_params.qm_u; + } else { + _obp_br(fh->quantization_params.qm_v, br, 4); + } + } + /* segmentation_params() */ + const uint8_t Segmentation_Feature_Bits[8] = { 8, 6, 6, 6, 6, 3, 0, 0 }; + const uint8_t Segmentation_Feature_Max[8] = { 255, 63, 63, 63, 63, 7, 0, 0 }; + const int Segmentation_Feature_Signed[8] = { 1, 1, 1, 1, 1, 0, 0, 0 }; + _obp_br(fh->segmentation_params.segmentation_enabled, br, 1); + if (fh->segmentation_params.segmentation_enabled == 1) { + if (fh->primary_ref_frame == 7) { + fh->segmentation_params.segmentation_update_map = 1; + fh->segmentation_params.segmentation_temporal_update = 0; + fh->segmentation_params.segmentation_update_data = 1; + } else { + _obp_br(fh->segmentation_params.segmentation_update_map, br, 1); + if (fh->segmentation_params.segmentation_update_map) { + _obp_br(fh->segmentation_params.segmentation_temporal_update, br, 1); + } + _obp_br(fh->segmentation_params.segmentation_update_data, br, 1); + } + if (fh->segmentation_params.segmentation_update_data == 1) { + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + int16_t clippedValue; + int16_t feature_value = 0; + int feature_enabled; + _obp_br(feature_enabled, br, 1); + FeatureEnabled[i][j] = feature_enabled; + clippedValue = 0; + if (feature_enabled) { + uint8_t bitsToRead = Segmentation_Feature_Bits[j]; + int16_t limit = Segmentation_Feature_Max[j]; + if (Segmentation_Feature_Signed[j] == 1) { + int32_t val; + ret = _obp_su(br, 1 + bitsToRead, &val, err); + if (ret < 0) { + return -1; + } + feature_value = val; + clippedValue = _OBP_MAX(-limit, _OBP_MIN(limit, feature_value)); + } else { + _obp_br(feature_value, br, bitsToRead); + clippedValue = _OBP_MAX(0, _OBP_MIN(limit, feature_value)); + } + } + FeatureData[i][j] = clippedValue; + } + } + } + } else { + for (int i = 0; i < 8; i++) { + for (int j = 0; j > 8; j++) { + FeatureEnabled[i][j] = 0; + FeatureData[i][j] = 0; + } + } + } + /*int SegIdPreSkip = 0; + int LastActiveSegId = 0; + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 8; j++) { + if (FeatureEnabled[i][j]) { + LastActiveSegId = i; + if (j >= 5) { + SegIdPreSkip = 1; + } + } + } + }*/ + /* delta_q_params() */ + fh->delta_q_params.delta_q_res = 0; + fh->delta_q_params.delta_q_present = 0; + if (fh->quantization_params.base_q_idx > 0) { + _obp_br(fh->delta_q_params.delta_q_present, br, 1); + } + if (fh->delta_q_params.delta_q_present) { + _obp_br(fh->delta_q_params.delta_q_res, br, 2); + } + /* delta_lf_params() */ + fh->delta_lf_params.delta_lf_present = 0; + fh->delta_lf_params.delta_lf_res = 0; + fh->delta_lf_params.delta_lf_multi = 0; + if (fh->delta_q_params.delta_q_present) { + if (!fh->allow_intrabc) { + _obp_br(fh->delta_lf_params.delta_lf_present, br, 1); + } + if (fh->delta_lf_params.delta_lf_present) { + _obp_br(fh->delta_lf_params.delta_lf_res, br, 2); + _obp_br(fh->delta_lf_params.delta_lf_multi, br, 1); + } + } + /* skipped because not relevant: + + if (fh->primary_ref_frame == 7) { + init_coeff_cdfs(); + } else { + lnit_coeff_cdfs(); + } + */ + int CodedLossless = 1; + int LosslessArray[8]; + for (int segmentId = 0; segmentId < 8; segmentId++ ) { + uint8_t qindex = _obp_get_qindex(1, segmentId, 0, fh, FeatureEnabled, FeatureData); + LosslessArray[segmentId] = (qindex == 0 && DeltaQYDc == 0 && DeltaQUAc == 0 && DeltaQUDc == 0 && DeltaQVAc == 0 && DeltaQVDc == 0); + if (!LosslessArray[segmentId]) { + CodedLossless = 0; + } + /* SegQMLevel not relevant to OBU parsing.*/ + } + int AllLossless = (CodedLossless && (FrameWidth == UpscaledWidth)); + /* loop_filter_params() */ + if (CodedLossless || fh->allow_intrabc) { + fh->loop_filter_params.loop_filter_delta_enabled = 1; + fh->loop_filter_params.loop_filter_ref_deltas[0] = 1; + fh->loop_filter_params.loop_filter_ref_deltas[1] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[2] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[3] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[4] = 0; + fh->loop_filter_params.loop_filter_ref_deltas[5] = -1; + fh->loop_filter_params.loop_filter_ref_deltas[6] = -1; + fh->loop_filter_params.loop_filter_ref_deltas[7] = -1; + for (int i = 0; i < 2; i++) { + fh->loop_filter_params.loop_filter_mode_deltas[i] = 0; + } + /* return */ + } else { + _obp_br(fh->loop_filter_params.loop_filter_level[0], br, 6); + _obp_br(fh->loop_filter_params.loop_filter_level[1], br, 6); + if (seq->color_config.NumPlanes > 1) { + if (fh->loop_filter_params.loop_filter_level[0] || fh->loop_filter_params.loop_filter_level[1]) { + _obp_br(fh->loop_filter_params.loop_filter_level[2], br, 6); + _obp_br(fh->loop_filter_params.loop_filter_level[3], br, 6); + } + } + _obp_br(fh->loop_filter_params.loop_filter_sharpness, br, 3); + _obp_br(fh->loop_filter_params.loop_filter_delta_enabled, br, 1); + if (fh->loop_filter_params.loop_filter_delta_enabled == 1) { + _obp_br(fh->loop_filter_params.loop_filter_delta_update, br, 1); + if (fh->loop_filter_params.loop_filter_delta_update == 1) { + for (int i = 0; i < 8; i++) { + int update_ref_delta; + _obp_br(update_ref_delta, br, 1); + if (update_ref_delta) { + int32_t val; + ret = _obp_su(br, 7, &val, err); + if (ret < 0) { + return -1; + } + fh->loop_filter_params.loop_filter_ref_deltas[i] = val; + } + } + for (int i = 0; i < 2; i++) { + int update_mode_delta; + _obp_br(update_mode_delta, br, 1); + if (update_mode_delta) { + int32_t val; + ret = _obp_su(br, 7, &val, err); + if (ret < 0) { + return -1; + } + fh->loop_filter_params.loop_filter_mode_deltas[i] = val; + } + } + } + } + } + /* cdef_params() */ + if (CodedLossless || fh->allow_intrabc || !seq->enable_cdef) { + fh->cdef_params.cdef_bits = 0; + fh->cdef_params.cdef_y_pri_strength[0] = 0; + fh->cdef_params.cdef_y_sec_strength[0] = 0; + fh->cdef_params.cdef_uv_pri_strength[0] = 0; + fh->cdef_params.cdef_uv_sec_strength[0] = 0; + /* CdefDamping not relevant to OBU parsing. */ + /* return */ + } else { + _obp_br(fh->cdef_params.cdef_damping_minus_3, br, 2); + /* CdefDamping not relevant to OBU parsing. */ + _obp_br(fh->cdef_params.cdef_bits, br, 2); + for (int i = 0; i < (1 << fh->cdef_params.cdef_bits); i++) { + _obp_br(fh->cdef_params.cdef_y_pri_strength[i], br, 4); + _obp_br(fh->cdef_params.cdef_y_sec_strength[i], br, 2); + if (fh->cdef_params.cdef_y_sec_strength[i] == 3) { + fh->cdef_params.cdef_y_sec_strength[i] += 1; + } + if (seq->color_config.NumPlanes > 1) { + _obp_br(fh->cdef_params.cdef_uv_pri_strength[i], br, 4); + _obp_br(fh->cdef_params.cdef_uv_sec_strength[i], br, 2); + if (fh->cdef_params.cdef_uv_sec_strength[i] == 3) { + fh->cdef_params.cdef_uv_sec_strength[i] += 1; + } + } + } + } + if (AllLossless || fh->allow_intrabc || !seq->enable_restoration) { + fh->lr_params.lr_type[0] = 0; + fh->lr_params.lr_type[1] = 0; + fh->lr_params.lr_type[2] = 0; + } else { + int UsesLr = 0; + int usesChromaLr = 0; + for (int i = 0; i < seq->color_config.NumPlanes; i++) { + _obp_br(fh->lr_params.lr_type[i], br, 2); + if (fh->lr_params.lr_type[i] != 0) { + UsesLr = 1; + if (i > 0) { + usesChromaLr = 1; + } + } + } + if (UsesLr) { + if (seq->use_128x128_superblock) { + _obp_br(fh->lr_params.lr_unit_shift, br, 1); + fh->lr_params.lr_unit_shift++; + } else { + _obp_br(fh->lr_params.lr_unit_shift, br, 1); + if (fh->lr_params.lr_unit_shift) { + uint8_t lr_unit_extra_shift; + _obp_br(lr_unit_extra_shift, br, 1); + fh->lr_params.lr_unit_shift += lr_unit_extra_shift; + } + } + /* LoopRestorationSize not relevant to OBU parsing. */ + if (seq->color_config.subsampling_x && seq->color_config.subsampling_y && usesChromaLr) { + _obp_br(fh->lr_params.lr_uv_shift, br, 1); + } else { + fh->lr_params.lr_uv_shift = 0; + } + /* LoopRestorationSize not relevant to OBU parsing. */ + } + } + /* read_tx_mode */ + if (CodedLossless == 1) { + /* TxMode not relevant to OBU parsing. */ + } else { + _obp_br(fh->tx_mode_select, br, 1); + if (fh->tx_mode_select) { + /* TxMode not relevant to OBU parsing. */ + } else { + /* TxMode not relevant to OBU parsing. */ + } + } + /* frame_reference_mode() */ + if (FrameIsIntra) { + fh->reference_select = 0; + } else { + _obp_br(fh->reference_select, br, 1); + } + /* skip_mode_params() */ + int skipModeAllowed; + if (FrameIsIntra || !fh->reference_select || !seq->enable_order_hint) { + skipModeAllowed = 0; + } else { + int forwardIdx = -1; + int backwardIdx = -1; + int32_t forwardHint = 0; /* Never declare by spec! Bug? */ + int32_t backwardHint = 0; /* Never declare by spec! Bug? */ + for (int i = 0; i < 7; i++) { + int32_t refHint = state->RefOrderHint[fh->ref_frame_idx[i]]; + if(_obp_get_relative_dist(refHint, OrderHint, seq) < 0) { + if (forwardIdx < 0 || _obp_get_relative_dist(refHint, forwardHint, seq) > 0) { + forwardIdx = i; + forwardHint = refHint; + } + } else if (_obp_get_relative_dist(refHint, OrderHint, seq) > 0) { + if (backwardIdx < 0 || _obp_get_relative_dist(refHint, backwardHint, seq) < 0) { + backwardIdx = i; + backwardHint = refHint; + } + } + } + if (forwardIdx < 0) { + skipModeAllowed = 0; + } else if (backwardIdx >= 0) { + skipModeAllowed = 1; + /* SkipModeFrame not relevant to OBU parsing. */ + } else { + int secondForwardIdx = -1; + int32_t secondForwardHint = 0; /* Never declare by spec! Bug? */ + for (int i = 0; i < 7; i++) { + int32_t refHint = state->RefOrderHint[fh->ref_frame_idx[i]]; + if (_obp_get_relative_dist(refHint, forwardHint, seq) < 0) { + if (secondForwardIdx < 0 || _obp_get_relative_dist(refHint, secondForwardHint, seq) > 0) { + secondForwardIdx = i; + secondForwardHint = refHint; + } + } + } + if (secondForwardIdx < 0) { + skipModeAllowed = 0; + } else { + skipModeAllowed = 1; + /* SkipModeFrame not relevant to OBU parsing. */ + } + } + } + if (skipModeAllowed) { + _obp_br(fh->skip_mode_present, br, 1); + } else { + fh->skip_mode_present = 0; + } + if (FrameIsIntra || fh->error_resilient_mode || !seq->enable_warped_motion) { + fh->allow_warped_motion = 0; + } else { + _obp_br(fh->allow_warped_motion, br, 1); + } + _obp_br(fh->reduced_tx_set, br, 1); + /* global_motion_params() */ + for (int ref = 1; ref < 7; ref++) { + fh->global_motion_params.gm_type[ref] = 0; + for(int i = 0; i < 6; i++) { + fh->global_motion_params.gm_params[ref][i] = (i % 3 == 2) ? (((uint32_t)1) << 16) : 0; + } + } + if (FrameIsIntra) { + /* return */ + } else { + for (int ref = 1; ref <= 7; ref++) { + uint8_t type; + int is_global; + _obp_br(is_global, br, 1); + if (is_global) { + int is_rot_zoom; + _obp_br(is_rot_zoom, br, 1); + if (is_rot_zoom) { + type = 2; + } else { + int is_translation; + _obp_br(is_translation, br, 1); + type = is_translation ? 1 : 3; + } + } else { + type = 0; + } + fh->global_motion_params.gm_type[ref] = type; + + if (type >= 2) { + ret = _obp_read_global_param(br, fh, type, ref, 2, err); + if (ret < 0) { + return -1; + } + ret = _obp_read_global_param(br, fh, type, ref, 3, err); + if (ret < 0) { + return -1; + } + if (type == 3) { + ret = _obp_read_global_param(br, fh, type, ref, 4, err); + if (ret < 0) { + return -1; + } + ret = _obp_read_global_param(br, fh, type, ref, 5, err); + if (ret < 0) { + return -1; + } + } else { + fh->global_motion_params.gm_params[ref][4] = -fh->global_motion_params.gm_params[ref][3]; + fh->global_motion_params.gm_params[ref][5] = fh->global_motion_params.gm_params[ref][2]; + } + } + if (type >= 1) { + ret = _obp_read_global_param(br, fh, type, ref, 0, err); + if (ret < 0) { + return -1; + } + ret = _obp_read_global_param(br, fh, type, ref, 1, err); + if (ret < 0) { + return -1; + } + } + } + } + /* film_grain_params() */ + if (!seq->film_grain_params_present || (!fh->show_frame && !fh->showable_frame)) { + /* reset_grain_params() */ + memset(&fh->film_grain_params, 0, sizeof(fh->film_grain_params)); + /* return */ + } else { + _obp_br(fh->film_grain_params.apply_grain, br, 1); + if (!fh->film_grain_params.apply_grain) { + /* reset_grain_params() */ + memset(&fh->film_grain_params, 0, sizeof(fh->film_grain_params)); + /* return */ + } else { + _obp_br(fh->film_grain_params.grain_seed, br, 16); + if (fh->frame_type == OBP_INTER_FRAME) { + _obp_br(fh->film_grain_params.update_grain, br, 1); + } else { + fh->film_grain_params.update_grain = 1; + } + if (!fh->film_grain_params.update_grain) { + _obp_br(fh->film_grain_params.film_grain_params_ref_idx, br, 3); + uint16_t tempGrainSeed = fh->film_grain_params.grain_seed; + /* load_grain_params() */ + fh->film_grain_params = state->RefGrainParams[fh->film_grain_params.film_grain_params_ref_idx]; + fh->film_grain_params.grain_seed = tempGrainSeed; + /* return */ + } else { + uint8_t numPosLuma, numPosChroma; + _obp_br(fh->film_grain_params.num_y_points, br, 4); + for (uint8_t i = 0; i < fh->film_grain_params.num_y_points; i++) { + _obp_br(fh->film_grain_params.point_y_value[i], br, 8); + _obp_br(fh->film_grain_params.point_y_scaling[i], br, 8); + } + if (seq->color_config.mono_chrome) { + fh->film_grain_params.chroma_scaling_from_luma = 0; + } else { + _obp_br(fh->film_grain_params.chroma_scaling_from_luma, br, 1); + } + if (seq->color_config.mono_chrome || fh->film_grain_params.chroma_scaling_from_luma || + (seq->color_config.subsampling_x == 1 && seq->color_config.subsampling_y == 1 && + fh->film_grain_params.num_y_points == 0)) { + fh->film_grain_params.num_cb_points = 0; + fh->film_grain_params.num_cr_points = 0; + } else { + _obp_br(fh->film_grain_params.num_cb_points, br, 4); + for (uint8_t i = 0; i < fh->film_grain_params.num_cb_points; i++) { + _obp_br(fh->film_grain_params.point_cb_value[i], br, 8); + _obp_br(fh->film_grain_params.point_cb_scaling[i], br, 8); + } + _obp_br(fh->film_grain_params.num_cr_points, br, 4); + for (uint8_t i = 0; i < fh->film_grain_params.num_cr_points; i++) { + _obp_br(fh->film_grain_params.point_cr_value[i], br, 8); + _obp_br(fh->film_grain_params.point_cr_scaling[i], br, 8); + } + } + _obp_br(fh->film_grain_params.grain_scaling_minus_8, br, 2); + _obp_br(fh->film_grain_params.ar_coeff_lag, br, 2); + numPosLuma = 2 * fh->film_grain_params.ar_coeff_lag * (fh->film_grain_params.ar_coeff_lag + 1); + if (fh->film_grain_params.num_y_points) { + numPosChroma = numPosLuma + 1; + for (uint8_t i = 0; i < numPosLuma; i++) { + _obp_br(fh->film_grain_params.ar_coeffs_y_plus_128[i], br, 8); + } + } else { + numPosChroma = numPosLuma; + } + if (fh->film_grain_params.chroma_scaling_from_luma || fh->film_grain_params.num_cb_points) { + for (uint8_t i = 0; i < numPosChroma; i++) { + _obp_br(fh->film_grain_params.ar_coeffs_cb_plus_128[i], br, 8); + } + } + if (fh->film_grain_params.chroma_scaling_from_luma || fh->film_grain_params.num_cr_points) { + for (uint8_t i = 0; i < numPosChroma; i++) { + _obp_br(fh->film_grain_params.ar_coeffs_cr_plus_128[i], br, 8); + } + } + _obp_br(fh->film_grain_params.ar_coeff_shift_minus_6, br, 2); + _obp_br(fh->film_grain_params.grain_scale_shift, br, 2); + if (fh->film_grain_params.num_cb_points) { + _obp_br(fh->film_grain_params.cb_mult, br, 8); + _obp_br(fh->film_grain_params.cb_luma_mult, br, 8); + _obp_br(fh->film_grain_params.cb_offset, br, 9); + } + if (fh->film_grain_params.num_cr_points) { + _obp_br(fh->film_grain_params.cr_mult, br, 8); + _obp_br(fh->film_grain_params.cr_luma_mult, br, 8); + _obp_br(fh->film_grain_params.cr_offset, br, 9); + } + _obp_br(fh->film_grain_params.overlap_flag, br, 1); + _obp_br(fh->film_grain_params.clip_to_restricted_range, br, 1); + } + } + } + + /* Stash refs for future frame use. */ + /* decode_frame_wrapup() */ + for (int i = 0; i < 8; i++) { + if ((fh->refresh_frame_flags >> i) & 1) { + state->RefOrderHint[i] = fh->order_hint; + state->RefFrameType[i] = fh->frame_type; + state->RefUpscaledWidth[i] = UpscaledWidth; + state->RefFrameHeight[i] = FrameHeight; + state->RefRenderWidth[i] = fh->RenderWidth; + state->RefRenderHeight[i] = fh->RenderHeight; + state->RefFrameId[i] = fh->current_frame_id; + state->RefGrainParams[i] = fh->film_grain_params; + /* save_grain_params() */ + for (int j = 0; j < 8; j++) { + for (int k = 0; k < 6; k++) { + state->SavedGmParams[i][j][k] = fh->global_motion_params.gm_params[j][k]; + } + } + /* save_segmentation_params() */ + for (int j = 0; j < 8; j++) { + for (int k = 0; k < 8; k++) { + state->SavedFeatureEnabled[i][j][k] = FeatureEnabled[j][k]; + state->SavedFeatureData[i][j][k] = FeatureData[j][k]; + } + } + /* save_loop_filter_params() */ + for (int j = 0; j < 8; j++) { + state->SavedLoopFilterRefDeltas[i][j] = fh->loop_filter_params.loop_filter_ref_deltas[j]; + state->SavedLoopFilterModeDeltas[i][j] = fh->loop_filter_params.loop_filter_mode_deltas[j]; + } + } + } + + /* Handle show_existing_frame semantics. */ + /* decode_frame_wrapup() */ + if (fh->show_existing_frame && fh->frame_type == OBP_KEY_FRAME) { + fh->order_hint = state->RefOrderHint[fh->frame_to_show_map_idx]; + for (int i = 0; i < 8; i++) { + for (int j = 0; j < 6; j++) { + fh->global_motion_params.gm_params[i][j] = state->SavedGmParams[fh->frame_to_show_map_idx][i][j]; + } + } + } + if (fh->show_existing_frame) { + *SeenFrameHeader = 0; + state->prev_filled = 0; + } else { + state->prev = *fh; + state->prev_filled = 1; + } + + /* Stash byte position for use in OBU_FRAME parsing. */ + _obp_br_byte_alignment(br); + state->frame_header_end_pos = _obp_br_get_pos(br); + + return 0; +} diff --git a/src/postprocessing/obuparse.h b/src/postprocessing/obuparse.h new file mode 100644 index 0000000000..e77f9371a6 --- /dev/null +++ b/src/postprocessing/obuparse.h @@ -0,0 +1,672 @@ +/* + * Copyright (c) 2020, Derek Buitenhuis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef OBUPARSE_H +#define OBUPARSE_H + +#include +#include + +/********************************************* + * Various enums from the AV1 specification. * + *********************************************/ + +/* + * OBU types. + */ +typedef enum { + /* 0 Reserved */ + OBP_OBU_SEQUENCE_HEADER = 1, + OBP_OBU_TEMPORAL_DELIMITER = 2, + OBP_OBU_FRAME_HEADER = 3, + OBP_OBU_TILE_GROUP = 4, + OBP_OBU_METADATA = 5, + OBP_OBU_FRAME = 6, + OBP_OBU_REDUNDANT_FRAME_HEADER = 7, + OBP_OBU_TILE_LIST = 8, + /* 9-14 Reserved */ + OBP_OBU_PADDING = 15 +} OBPOBUType; + +/* + * Metadata types for the Metadata OBU. + */ +typedef enum { + /* 0 Reserved */ + OBP_METADATA_TYPE_HDR_CLL = 1, + OBP_METADATA_TYPE_HDR_MDCV = 2, + OBP_METADATA_TYPE_SCALABILITY = 3, + OBP_METADATA_TYPE_ITUT_T35 = 4, + OBP_METADATA_TYPE_TIMECODE = 5 + /* 6-31 Unregistered user private */ + /* 32 and greater Reserved for AOM use */ +} OBPMetadataType; + +/* + * Color primaries. + * + * These match ISO/IEC 23091-4/ITU-T H.273. + */ +typedef enum { + OBP_CP_BT_709 = 1, + OBP_CP_UNSPECIFIED = 2, + OBP_CP_BT_470_M = 4, + OBP_CP_BT_470_B_G = 5, + OBP_CP_BT_601 = 6, + OBP_CP_SMPTE_240 = 7, + OBP_CP_GENERIC_FILM = 8, + OBP_CP_BT_2020 = 9, + OBP_CP_XYZ = 10, + OBP_CP_SMPTE_431 = 11, + OBP_CP_SMPTE_432 = 12, + OBP_CP_EBU_3213 = 22 +} OBPColorPrimaries; + +/* + * Transfer characteristics. + * + * These match ISO/IEC 23091-4/ITU-T H.273. + */ +typedef enum { + OBP_TC_RESERVED_0 = 0, + OBP_TC_BT_709 = 1, + OBP_TC_UNSPECIFIED = 2, + OBP_TC_RESERVED_3 = 3, + OBP_TC_BT_470_M = 4, + OBP_TC_BT_470_B_G = 5, + OBP_TC_BT_601 = 6, + OBP_TC_SMPTE_240 = 7, + OBP_TC_LINEAR = 8, + OBP_TC_LOG_100 = 9, + OBP_TC_LOG_100_SQRT10 = 10, + OBP_TC_IEC_61966 = 11, + OBP_TC_BT_1361 = 12, + OBP_TC_SRGB = 13, + OBP_TC_BT_2020_10_BIT = 14, + OBP_TC_BT_2020_12_BIT = 15, + OBP_TC_SMPTE_2084 = 16, + OBP_TC_SMPTE_428 = 17, + OBP_TC_HLG = 18 +} OBPTransferCharacteristics; + +/* + * Color matrix coefficients. + * + * These match ISO/IEC 23091-4/ITU-T H.273. + */ +typedef enum { + OBP_MC_IDENTITY = 0, + OBP_MC_BT_709 = 1, + OBP_MC_UNSPECIFIED = 2, + OBP_MC_RESERVED_3 = 3, + OBP_MC_FCC = 4, + OBP_MC_BT_470_B_G = 5, + OBP_MC_BT_601 = 6, + OBP_MC_SMPTE_240 = 7, + OBP_MC_SMPTE_YCGCO = 8, + OBP_MC_BT_2020_NCL = 9, + OBP_MC_BT_2020_CL = 10, + OBP_MC_SMPTE_2085 = 11, + OBP_MC_CHROMAT_NCL = 12, + OBP_MC_CHROMAT_CL = 13, + OBP_MC_ICTCP = 14 +} OBPMatrixCoefficients; + +/* + * Chroma sample position. + */ +typedef enum { + OBP_CSP_UNKNOWN = 0, + OBP_CSP_VERTICAL = 1, + OBP_CSP_COLOCATED = 2 + /* 3 Reserved */ +} OBPChromaSamplePosition; + +/* + * Frame types. + */ +typedef enum { + OBP_KEY_FRAME = 0, + OBP_INTER_FRAME = 1, + OBP_INTRA_ONLY_FRAME = 2, + OBP_SWITCH_FRAME = 3 +} OBPFrameType; + +/************************************************** + * Various structures from the AV1 specification. * + **************************************************/ + +/* + * Sequence Header OBU + */ +typedef struct OBPSequenceHeader { + uint8_t seq_profile; + int still_picture; + int reduced_still_picture_header; + int timing_info_present_flag; + struct { + uint32_t num_units_in_display_tick; + uint32_t time_scale; + int equal_picture_interval; + uint32_t num_ticks_per_picture_minus_1; + } timing_info; + int decoder_model_info_present_flag; + struct { + uint8_t buffer_delay_length_minus_1; + uint32_t num_units_in_decoding_tick; + uint8_t buffer_removal_time_length_minus_1; + uint8_t frame_presentation_time_length_minus_1; + } decoder_model_info; + int initial_display_delay_present_flag; + uint8_t operating_points_cnt_minus_1; + uint8_t operating_point_idc[32]; + uint8_t seq_level_idx[32]; + uint8_t seq_tier[32]; + int decoder_model_present_for_this_op[32]; + struct { + uint64_t decoder_buffer_delay; + uint64_t encoder_buffer_delay; + int low_delay_mode_flag; + } operating_parameters_info[32]; + int initial_display_delay_present_for_this_op[32]; + uint8_t initial_display_delay_minus_1[32]; + uint8_t frame_width_bits_minus_1; + uint8_t frame_height_bits_minus_1; + uint32_t max_frame_width_minus_1; + uint32_t max_frame_height_minus_1; + int frame_id_numbers_present_flag; + uint8_t delta_frame_id_length_minus_2; + uint8_t additional_frame_id_length_minus_1; + int use_128x128_superblock; + int enable_filter_intra; + int enable_intra_edge_filter; + int enable_interintra_compound; + int enable_masked_compound; + int enable_warped_motion; + int enable_dual_filter; + int enable_order_hint; + int enable_jnt_comp; + int enable_ref_frame_mvs; + int seq_choose_screen_content_tools; + int seq_force_screen_content_tools; + int seq_choose_integer_mv; + int seq_force_integer_mv; + uint8_t order_hint_bits_minus_1; + uint8_t OrderHintBits; + int enable_superres; + int enable_cdef; + int enable_restoration; + struct { + int high_bitdepth; + int twelve_bit; + uint8_t BitDepth; + int mono_chrome; + uint8_t NumPlanes; + int color_description_present_flag; + OBPColorPrimaries color_primaries; + OBPTransferCharacteristics transfer_characteristics; + OBPMatrixCoefficients matrix_coefficients; + int color_range; + int subsampling_x; + int subsampling_y; + OBPChromaSamplePosition chroma_sample_position; + int separate_uv_delta_q; + } color_config; + int film_grain_params_present; +} OBPSequenceHeader; + +/* + * Film Grain Parameters. + */ +typedef struct OBPFilmGrainParameters { + int apply_grain; + uint16_t grain_seed; + int update_grain; + uint8_t film_grain_params_ref_idx; + uint8_t num_y_points; + uint8_t point_y_value[16]; + uint8_t point_y_scaling[16]; + int chroma_scaling_from_luma; + uint8_t num_cb_points; + uint8_t point_cb_value[16]; + uint8_t point_cb_scaling[16]; + uint8_t num_cr_points; + uint8_t point_cr_value[16]; + uint8_t point_cr_scaling[16]; + uint8_t grain_scaling_minus_8; + uint8_t ar_coeff_lag; + uint8_t ar_coeffs_y_plus_128[24]; + uint8_t ar_coeffs_cb_plus_128[25]; + uint8_t ar_coeffs_cr_plus_128[25]; + uint8_t ar_coeff_shift_minus_6; + uint8_t grain_scale_shift; + uint8_t cb_mult; + uint8_t cb_luma_mult; + uint16_t cb_offset; + uint8_t cr_mult; + uint8_t cr_luma_mult; + uint16_t cr_offset; + int overlap_flag; + int clip_to_restricted_range; +} OBPFilmGrainParameters; + +/* + * Frame Header OBU + */ +typedef struct OBPFrameHeader { + int show_existing_frame; + uint8_t frame_to_show_map_idx; + struct { + uint32_t frame_presentation_time; + } temporal_point_info; + uint32_t display_frame_id; + /* load_grain_params() unimplemented. */ + OBPFrameType frame_type; + int show_frame; + int showable_frame; + int error_resilient_mode; + int disable_cdf_update; + int allow_screen_content_tools; + int force_integer_mv; + uint32_t current_frame_id; + int frame_size_override_flag; + uint8_t order_hint; + uint8_t primary_ref_frame; + int buffer_removal_time_present_flag; + uint32_t buffer_removal_time[32]; + uint8_t refresh_frame_flags; + uint8_t ref_order_hint[8]; + uint32_t frame_width_minus_1; + uint32_t frame_height_minus_1; + struct { + int use_superres; + uint8_t coded_denom; + } superres_params; + int render_and_frame_size_different; + uint16_t render_width_minus_1; + uint16_t render_height_minus_1; + uint32_t RenderWidth; + uint32_t RenderHeight; + int allow_intrabc; + int frame_refs_short_signaling; + uint8_t last_frame_idx; + uint8_t gold_frame_idx; + uint8_t ref_frame_idx[7]; + uint8_t delta_frame_id_minus_1[7]; + int found_ref; + int allow_high_precision_mv; + struct { + int is_filter_switchable; + uint8_t interpolation_filter; + } interpolation_filter; + int is_motion_mode_switchable; + int use_ref_frame_mvs; + int disable_frame_end_update_cdf; + struct { + int uniform_tile_spacing_flag; + uint16_t TileRows; + uint16_t TileCols; + uint32_t context_update_tile_id; + uint8_t tile_size_bytes_minus_1; + } tile_info; + struct { + uint8_t base_q_idx; + int diff_uv_delta; + int using_qmatrix; + uint8_t qm_y; + uint8_t qm_u; + uint8_t qm_v; + } quantization_params; + struct { + int segmentation_enabled; + int segmentation_update_map; + int segmentation_temporal_update; + int segmentation_update_data; + } segmentation_params; + struct { + int delta_q_present; + uint8_t delta_q_res; + } delta_q_params; + struct { + int delta_lf_present; + uint8_t delta_lf_res; + int delta_lf_multi; + } delta_lf_params; + struct { + uint8_t loop_filter_level[4]; + uint8_t loop_filter_sharpness; + int loop_filter_delta_enabled; + int loop_filter_delta_update; + int update_ref_delta[8]; + int8_t loop_filter_ref_deltas[8]; + int update_mode_delta[8]; + int8_t loop_filter_mode_deltas[8]; + } loop_filter_params; + struct { + uint8_t cdef_damping_minus_3; + uint8_t cdef_bits; + uint8_t cdef_y_pri_strength[8]; + uint8_t cdef_y_sec_strength[8]; + uint8_t cdef_uv_pri_strength[8]; + uint8_t cdef_uv_sec_strength[8]; + } cdef_params; + struct { + uint8_t lr_type[3]; + uint8_t lr_unit_shift; + int lr_uv_shift; + } lr_params; + int tx_mode_select; + int skip_mode_present; + int reference_select; + int allow_warped_motion; + int reduced_tx_set; + struct { + uint8_t gm_type[8]; + int32_t gm_params[8][6]; + uint32_t prev_gm_params[8][6]; + } global_motion_params; + OBPFilmGrainParameters film_grain_params; +} OBPFrameHeader; + +/* + * Tile Group OBU. + */ +typedef struct OBPTileGroup { + uint16_t NumTiles; + int tile_start_and_end_present_flag; + uint16_t tg_start; + uint16_t tg_end; + uint64_t TileSize[4096]; +} OBPTileGroup; + +/* + * Tile List OBU + */ +typedef struct OBPTileList { + uint8_t output_frame_width_in_tiles_minus_1; + uint8_t output_frame_height_in_tiles_minus_1; + uint16_t tile_count_minus_1; + struct { + uint8_t anchor_frame_idx; + uint8_t anchor_tile_row; + uint8_t anchor_tile_col; + uint16_t tile_data_size_minus_1; + uint8_t *coded_tile_data; + size_t coded_tile_data_size; + } tile_list_entry[65536]; +} OBPTileList; + +/* + * Metadata OBU + */ +typedef struct OBPMetadata { + OBPMetadataType metadata_type; + struct { + uint8_t itu_t_t35_country_code; /* Annex A of Recommendation ITU-T T.35. */ + uint8_t itu_t_t35_country_code_extension_byte; + uint8_t *itu_t_t35_payload_bytes; + size_t itu_t_t35_payload_bytes_size; + } metadata_itut_t35; + struct { + uint16_t max_cll; + uint16_t max_fall; + } metadata_hdr_cll; + struct { + uint16_t primary_chromaticity_x[3]; + uint16_t primary_chromaticity_y[3]; + uint16_t white_point_chromaticity_x; + uint16_t white_point_chromaticity_y; + uint32_t luminance_max; + uint32_t luminance_min; + } metadata_hdr_mdcv; + struct { + uint8_t scalability_mode_idc; + struct { + uint8_t spatial_layers_cnt_minus_1; + int spatial_layer_dimensions_present_flag; + int spatial_layer_description_present_flag; + int temporal_group_description_present_flag; + uint8_t scalability_structure_reserved_3bits; + uint16_t spatial_layer_max_width[3]; + uint16_t spatial_layer_max_height[3]; + uint8_t spatial_layer_ref_id[3]; + uint8_t temporal_group_size; + uint8_t temporal_group_temporal_id[256]; + int temporal_group_temporal_switching_up_point_flag[256]; + int temporal_group_spatial_switching_up_point_flag[256]; + uint8_t temporal_group_ref_cnt[256]; + uint8_t temporal_group_ref_pic_diff[256][8]; + } scalability_structure; + } metadata_scalability; + struct { + uint8_t counting_type; + int full_timestamp_flag; + int discontinuity_flag; + int cnt_dropped_flag; + uint16_t n_frames; + uint8_t seconds_value; + uint8_t minutes_value; + uint8_t hours_value; + int seconds_flag; + int minutes_flag; + int hours_flag; + uint8_t time_offset_length; + uint32_t time_offset_value; + } metadata_timecode; + struct { + uint8_t *buf; + size_t buf_size; + } unregistered; +} OBPMetadata; + +/******************* + * API structures. * + *******************/ + +/* + * OBPError contains a user-provided buffer and buffer size + * where obuparse can write error messages to. + */ +typedef struct OBPError { + char *error; + size_t size; +} OBPError; + +/*************************** + * Private API Structures. * + ***************************/ + + /* + * Various bits of state required for parsing uncompressed_header(), such as reference + * management. + * + * Do not touch the values of these members. They are for internal obuparser use only. + */ + typedef struct OBPState { + /* Redundant Frame Header things. */ + OBPFrameHeader prev; + int prev_filled; + + /* For use only on OBU_FRAME parsing. */ + size_t frame_header_end_pos; + + /* Frame state. */ + OBPFrameType RefFrameType[8]; + uint8_t RefValid[8]; + uint8_t RefOrderHint[8]; + uint8_t OrderHint[8]; + uint8_t RefFrameId[8]; + uint32_t RefUpscaledWidth[8]; + uint32_t RefFrameHeight[8]; + uint32_t RefRenderWidth[8]; + uint32_t RefRenderHeight[8]; + int32_t RefFrameSignBias[8]; + OBPFilmGrainParameters RefGrainParams[8]; + uint8_t order_hint; + uint32_t SavedGmParams[8][8][6]; + int SavedFeatureEnabled[8][8][8]; + int16_t SavedFeatureData[8][8][8]; + int8_t SavedLoopFilterRefDeltas[8][8]; + int8_t SavedLoopFilterModeDeltas[8][8]; + } OBPState; + +/****************** + * API functions. * + ******************/ + +/* + * obp_get_next_obu parses the next OBU header in a packet containing a set of one or more OBUs + * (e.g. an IVF or ISOBMFF packet) and returns its location in the buffer, as well as all + * relevant data from the header. + * + * Input: + * buf - Input packet buffer. + * buf_size - Size of the input packet buffer. + * err - An error buffer and buffer size to write any error messages into. + * + * Output: + * obu_type - The type of OBU. + * offset - The offset into the buffer where this OBU starts, excluding the OBU header. + * obu_size - The size of the OBU, excluding the size of the OBU header. + * temporal_id - The temporal ID of the OBU. + * spatial_id - The spatial ID of the OBU. + * + * Returns: + * 0 on success, -1 on error. + */ +int obp_get_next_obu(uint8_t *buf, size_t buf_size, OBPOBUType *obu_type, ptrdiff_t *offset, + size_t *obu_size, int *temporal_id, int *spatial_id, OBPError *err); + +/* + * obp_parse_sequence_header parses a sequence header OBU and fills out the fields in a + * user-provided OBPSequenceHeader structure. + * + * Input: + * buf - Input OBU buffer. This is expected to *NOT* contain the OBU header. + * buf_size - Size of the input OBU buffer. + * err - An error buffer and buffer size to write any error messages into. + * + * Output: + * seq_header - A user provided structure that will be filled in with all the parsed data. + * + * Returns: + * 0 on success, -1 on error. + */ +int obp_parse_sequence_header(uint8_t *buf, size_t buf_size, OBPSequenceHeader *seq_header, OBPError *err); + +/* + * obp_parse_frame_header parses a frame header OBU and fills out the fields in a user-provided + * OBPFrameHeader structure. + * + * Input: + * buf - Input OBU buffer. This is expected to *NOT* contain the OBU header. + * buf_size - Size of the input OBU buffer. + * state - An opaque state structure. Must be zeroed by the user on first use. + * temporal_id - A temporal ID previously obtained from obu_parse_sequence header. + * spatial_id - A spatial ID previously obtained from obu_parse_sequence header. + * err - An error buffer and buffer size to write any error messages into. + * + * Output: + * frame_header - A user provided structure that will be filled in with all the parsed data. + * SeenFrameHeader - Whether or not a frame header has beee seen. Tracking variable as per AV1 spec. + * + * Returns: + * 0 on success, -1 on error. + */ +int obp_parse_frame_header(uint8_t *buf, size_t buf_size, OBPSequenceHeader *seq_header, OBPState *state, + int temporal_id, int spatial_id, OBPFrameHeader *frame_header, int *SeenFrameHeader, OBPError *err); + +/* + * obp_parse_frame parses a frame OBU and fills out the fields in user-provided OBPFrameHeader + * and OBPTileGroup structures. + * + * Input: + * buf - Input OBU buffer. This is expected to *NOT* contain the OBU header. + * buf_size - Size of the input OBU buffer. + * state - An opaque state structure. Must be zeroed by the user on first use. + * temporal_id - A temporal ID previously obtained from obu_parse_sequence header. + * spatial_id - A spatial ID previously obtained from obu_parse_sequence header. + * err - An error buffer and buffer size to write any error messages into. + * + * Output: + * frame_header - A user provided structure that will be filled in with all the parsed data. + * tile_group - A user provided structure that will be filled in with all the parsed data. + * SeenFrameHeader - Whether or not a frame header has been seen. Tracking variable as per AV1 spec. + * + * Returns: + * 0 on success, -1 on error. + */ +int obp_parse_frame(uint8_t *buf, size_t buf_size, OBPSequenceHeader *seq_header, OBPState *state, + int temporal_id, int spatial_id, OBPFrameHeader *frame_header, OBPTileGroup *tile_group, + int *SeenFrameHeader, OBPError *err); + +/* + * obp_parse_tile_group parses a tile group OBU and fills out the fields in a + * user-provided OBPTileGroup structure. + * + * Input: + * buf - Input OBU buffer. This is expected to *NOT* contain the OBU header. + * buf_size - Size of the input OBU buffer. + * frame_header - A filled in frame header OBU previously seen. + * err - An error buffer and buffer size to write any error messages into. + * + * Output: + * tile_group - A user provided structure that will be filled in with all the parsed data. + * SeenFrameHeader - Whether or not a frame header has been seen. Tracking variable as per AV1 spec. + * + * Returns: + * 0 on success, -1 on error. + */ +int obp_parse_tile_group(uint8_t *buf, size_t buf_size, OBPFrameHeader *frame_header, OBPTileGroup *tile_group, + int *SeenFrameHeader, OBPError *err); + +/* + * obp_parse_metadata parses a metadata OBU and fills out the fields in a user-provided OBPMetadata + * structure. This OBU's returned payload is *NOT* safe to use once the user-provided 'buf' has + * been freed, since it may fill the structure with pointers to offsets in that data. + * + * Input: + * buf - Input OBU buffer. This is expected to *NOT* contain the OBU header. + * buf_size - Size of the input OBU buffer. + * err - An error buffer and buffer size to write any error messages into. + * + * Output: + * metadata - A user provided structure that will be filled in with all the parsed data. + * + * Returns: + * 0 on success, -1 on error. + */ +int obp_parse_metadata(uint8_t *buf, size_t buf_size, OBPMetadata *metadata, OBPError *err); + +/* + * obp_parse_tile_list parses a tile list OBU and fills out the fields in a user-provided OBPTileList + * structure. This OBU's returned payload is *NOT* safe to use once the user-provided 'buf' has + * been freed, since it may fill the structure with pointers to offsets in that data. + * + * Input: + * buf - Input OBU buffer. This is expected to *NOT* contain the OBU header. + * buf_size - Size of the input OBU buffer. + * err - An error buffer and buffer size to write any error messages into. + * + * Output: + * tile_list - A user provided structure that will be filled in with all the parsed data. + * + * Returns: + * 0 on success, -1 on error. + */ +int obp_parse_tile_list(uint8_t *buf, size_t buf_size, OBPTileList *tile_list, OBPError *err); + +#endif diff --git a/src/postprocessing/pp-av1.c b/src/postprocessing/pp-av1.c index 35f9f8a6f3..c717725b46 100644 --- a/src/postprocessing/pp-av1.c +++ b/src/postprocessing/pp-av1.c @@ -23,6 +23,8 @@ #include "pp-av1.h" #include "../debug.h" +#include "obuparse.h" + /* MP4 output */ static AVFormatContext *fctx; #if LIBAVCODEC_VER_AT_LEAST(58, 18) @@ -104,102 +106,18 @@ static void janus_pp_av1_lev128_encode(uint32_t value, uint8_t *base, size_t *wr *written = (cur-base)+1; } -/* Helpers to read a bit, or group of bits, in a Sequence Header */ -static uint32_t janus_pp_av1_getbit(uint8_t *base, uint32_t offset) { - return ((*(base + (offset >> 0x3))) >> (0x7 - (offset & 0x7))) & 0x1; -} -static uint32_t janus_pp_av1_getbits(uint8_t *base, uint8_t num, uint32_t *offset) { - uint32_t res = 0; - int32_t i = 0; - for(i=num-1; i>=0; i--) { - res |= janus_pp_av1_getbit(base, (*offset)++) << i; - } - return res; -} /* Helper to parse a Sequence Header (only to get the video resolution) */ -static void janus_pp_av1_parse_sh(char *buffer, uint16_t *width, uint16_t *height) { - /* Evaluate/skip everything until we get to the resolution */ - uint32_t offset = 0, value = 0, i = 0; - uint8_t *base = (uint8_t *)(buffer); - /* Skip seq_profile (3 bits) */ - janus_pp_av1_getbits(base, 3, &offset); - /* Skip still_picture (1 bit) */ - janus_pp_av1_getbit(base, offset++); - /* Skip reduced_still_picture_header (1 bit) */ - value = janus_pp_av1_getbit(base, offset++); - if(value) { - /* Skip seq_level_idx (5 bits) */ - janus_pp_av1_getbits(base, 5, &offset); - } else { - gboolean decoder_model_info = FALSE, initial_display_delay = FALSE; - uint32_t bdlm1 = 0; - /* Skip timing_info_present_flag (1 bit) */ - value = janus_pp_av1_getbit(base, offset++); - if(value) { - /* Skip num_units_in_display_tick (32 bits) */ - janus_pp_av1_getbits(base, 32, &offset); - /* Skip time_scale (32 bits) */ - janus_pp_av1_getbits(base, 32, &offset); - /* Skip equal_picture_interval (1 bit)*/ - value = janus_pp_av1_getbit(base, offset++); - if(value) { - /* TODO Skip num_ticks_per_picture_minus_1 (uvlc) */ - } - /* Skip decoder_model_info_present_flag (1 bit) */ - value = janus_pp_av1_getbit(base, offset++); - if(value) { - decoder_model_info = TRUE; - /* Skip buffer_delay_length_minus_1 (5 bits) */ - bdlm1 = janus_pp_av1_getbits(base, 5, &offset); - /* Skip num_units_in_decoding_tick (32 bits) */ - janus_pp_av1_getbits(base, 32, &offset); - /* Skip buffer_removal_time_length_minus_1 (5 bits) */ - janus_pp_av1_getbits(base, 5, &offset); - /* Skip frame_presentation_time_length_minus_1 (5 bits) */ - janus_pp_av1_getbits(base, 5, &offset); - } - } - /* Skip initial_display_delay_present_flag (1 bit) */ - value = janus_pp_av1_getbit(base, offset++); - if(value) - initial_display_delay = TRUE; - /* Skip operating_points_cnt_minus_1 (5 bits) */ - uint32_t opcm1 = janus_pp_av1_getbits(base, 5, &offset)+1; - for(i=0; i 7) { - /* Skip seq_tier[i] (1 bit) */ - janus_pp_av1_getbit(base, offset++); - } - if(decoder_model_info) { - /* Skip decoder_model_present_for_this_op[i] (1 bit) */ - value = janus_pp_av1_getbit(base, offset++); - if(value) { - /* Skip operating_parameters_info(i) */ - janus_pp_av1_getbits(base, (2*bdlm1)+1, &offset); - } - } - if(initial_display_delay) { - /* Skip initial_display_delay_present_for_this_op[i] (1 bit) */ - value = janus_pp_av1_getbit(base, offset++); - if(value) { - /* Skip initial_display_delay_minus_1[i] (4 bits) */ - janus_pp_av1_getbits(base, 4, &offset); - } - } - } +static void janus_pp_av1_parse_sh(char *buffer, size_t buf_size, uint16_t *width, uint16_t *height) { + OBPSequenceHeader seq_header; + OBPError err; + + if (obp_parse_sequence_header((uint8_t *)buffer, buf_size, &seq_header, &err) < 0) { + JANUS_LOG(LOG_ERR, "Error parsing sequence header\n"); + return; } - /* Read frame_width_bits_minus_1 (4 bits) */ - uint32_t fwbm1 = janus_pp_av1_getbits(base, 4, &offset); - /* Read frame_height_bits_minus_1 (4 bits) */ - uint32_t fhbm1 = janus_pp_av1_getbits(base, 4, &offset); - /* Read max_frame_width_minus_1 (n bits) */ - *width = janus_pp_av1_getbits(base, fwbm1+1, &offset)+1; - /* Read max_frame_height_minus_1 (n bits) */ - *height = janus_pp_av1_getbits(base, fhbm1+1, &offset)+1; + + *width = seq_header.max_frame_width_minus_1 + 1; + *height = seq_header.max_frame_height_minus_1 + 1; } int janus_pp_av1_preprocess(FILE *file, janus_pp_frame_packet *list, json_t *info) { @@ -282,11 +200,21 @@ int janus_pp_av1_preprocess(FILE *file, janus_pp_frame_packet *list, json_t *inf len--; obusize--; } - if(type == 1) { + + OBPOBUType obutype; + ptrdiff_t offset; + size_t obu_size; + int temporal_id; + int spatial_id; + OBPError err; + + if (obp_get_next_obu((uint8_t *)payload, len, &obutype, &offset, &obu_size, &temporal_id, &spatial_id, &err) < 0) { + JANUS_LOG(LOG_ERR, "Failed to parse OBU header: %s\n", err.error); + } + if(obutype == OBP_OBU_SEQUENCE_HEADER) { /* Sequence header */ uint16_t width = 0, height = 0; - /* TODO Fix currently broken parsing of SH */ - janus_pp_av1_parse_sh(payload+1, &width, &height); + janus_pp_av1_parse_sh(payload+offset, obusize, &width, &height); if(width*height > max_width*max_height) { max_width = width; max_height = height; @@ -307,8 +235,8 @@ int janus_pp_av1_preprocess(FILE *file, janus_pp_frame_packet *list, json_t *inf json_array_append_new(resolutions, resolution); } } - payload += obusize; - len -= obusize; + payload += obusize + offset; + len -= obusize + offset; } if(tmp->drop) { /* We marked this packet as one to drop, before */