blob: 1832ed0eb5ec51e6d679812501ca6f4c27331d00 [file] [log] [blame] [edit]
/*
* Copyright (c) 2021, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* aomedia.org/license/patent-license/.
*/
#include <assert.h>
#include "config/aom_config.h"
#include "config/aom_scale_rtcd.h"
#include "aom/aom_codec.h"
#include "aom_dsp/bitreader_buffer.h"
#include "aom_ports/mem_ops.h"
#include "av1/common/common.h"
#include "av1/common/obu_util.h"
#include "av1/common/timing.h"
#include "av1/decoder/decoder.h"
#include "av1/decoder/decodeframe.h"
#include "av1/decoder/obu.h"
#include "av1/common/scan.h"
#include "av1/common/quant_common.h"
#if CONFIG_F255_QMOBU
void alloc_qmatrix(struct quantization_matrix_set *qm_set, int num_planes) {
const TX_SIZE fund_tsize[3] = { TX_8X8, TX_8X4, TX_4X8 };
if (qm_set->quantizer_matrix != NULL) {
return;
}
qm_set->quantizer_matrix =
(qm_val_t ***)aom_malloc(3 * sizeof(qm_val_t **)); // 8x8,8x4,4x8
for (int t = 0; t < 3; t++) {
const TX_SIZE tsize = fund_tsize[t];
const int width = tx_size_wide[tsize];
const int height = tx_size_high[tsize];
qm_set->quantizer_matrix[t] =
(qm_val_t **)aom_malloc(num_planes * sizeof(qm_val_t *)); // y/u/v
for (int c = 0; c < num_planes; c++) {
qm_set->quantizer_matrix[t][c] =
(qm_val_t *)aom_malloc(width * height * sizeof(qm_val_t));
}
}
qm_set->quantizer_matrix_allocated = true;
}
static void read_qm_data(AV1Decoder *pbi, int obu_tlayer_id, int obu_mlayer_id,
int qm_pos, int qm_id, int num_planes,
bool store_at_intermediate_location,
struct aom_read_bit_buffer *rb) {
pbi->common.error.error_code = AOM_CODEC_OK;
const TX_SIZE fund_tsize[3] = { TX_8X8, TX_8X4, TX_4X8 };
struct quantization_matrix_set *qmset =
store_at_intermediate_location
? &pbi->qmobu_list[pbi->total_qmobu_count].qm_list[qm_pos]
: &pbi->qm_list[qm_pos];
if (!qmset->quantizer_matrix_allocated) alloc_qmatrix(qmset, num_planes);
qmset->qm_id = qm_id;
qmset->qm_tlayer_id = obu_tlayer_id;
qmset->qm_mlayer_id = obu_mlayer_id;
qmset->quantizer_matrix_num_planes = num_planes;
const bool qm_is_default_flag = (bool)aom_rb_read_bit(rb);
if (qm_is_default_flag) {
const int qm_default_index = aom_rb_read_literal(rb, 4);
qmset->qm_default_index = qm_default_index;
// copy predefined[qm_default_index] to qmset
for (int c = 0; c < num_planes; ++c) {
// plane_type: 0:luma, 1:chroma
const int plane_type = (c >= 1);
memcpy(qmset->quantizer_matrix[0][c],
predefined_8x8_iwt_base_matrix[qm_default_index][plane_type],
8 * 8 * sizeof(qm_val_t));
memcpy(qmset->quantizer_matrix[1][c],
predefined_8x4_iwt_base_matrix[qm_default_index][plane_type],
8 * 4 * sizeof(qm_val_t));
memcpy(qmset->quantizer_matrix[2][c],
predefined_4x8_iwt_base_matrix[qm_default_index][plane_type],
4 * 8 * sizeof(qm_val_t));
}
return;
} else {
qmset->qm_default_index = -1;
}
for (int t = 0; t < 3; t++) {
const TX_SIZE tsize = fund_tsize[t];
const int width = tx_size_wide[tsize];
const int height = tx_size_high[tsize];
const SCAN_ORDER *s = get_scan(tsize, DCT_DCT);
for (int c = 0; c < num_planes; c++) {
if (c > 0) {
const bool qm_copy_from_previous_plane = aom_rb_read_bit(rb);
if (qm_copy_from_previous_plane) {
memcpy(qmset->quantizer_matrix[t][c],
qmset->quantizer_matrix[t][c - 1],
width * height * sizeof(qm_val_t));
continue;
}
}
bool qm_8x8_is_symmetric;
if (tsize == TX_8X8) {
qm_8x8_is_symmetric = aom_rb_read_bit(rb);
} else if (tsize == TX_4X8) {
const bool qm_4x8_is_transpose_of_8x4 = aom_rb_read_bit(rb);
if (qm_4x8_is_transpose_of_8x4) {
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
qmset->quantizer_matrix[t][c][i * width + j] =
qmset->quantizer_matrix[t - 1][c][j * height + i];
}
}
continue;
}
}
bool coef_repeat_until_end = false;
qm_val_t prev = 32;
for (int i = 0; i < tx_size_2d[tsize]; i++) {
const int pos = s->scan[i];
if (tsize == TX_8X8 && qm_8x8_is_symmetric) {
const int row = pos / width;
const int col = pos % width;
if (col > row) {
prev = qmset->quantizer_matrix[t][c][col * width + row];
qmset->quantizer_matrix[t][c][pos] = prev;
continue;
}
}
if (!coef_repeat_until_end) {
const int32_t delta = aom_rb_read_svlc(rb);
// The valid range of quantization matrix coefficients is 1..255.
// Therefore the valid range of delta values is -254..254. Because of
// the % 256 operation, the valid range of delta values can be reduced
// to -128..127 to shorten the svlc() code.
if (delta < -128 || delta > 127) {
aom_internal_error(&pbi->common.error, AOM_CODEC_CORRUPT_FRAME,
"Invalid matrix_coef_delta: %d", delta);
}
const qm_val_t coef = (prev + delta + 256) % 256;
if (coef == 0) {
coef_repeat_until_end = true;
} else {
prev = coef;
}
}
qmset->quantizer_matrix[t][c][pos] = prev;
} // coeff
} // num_planes
} // t
}
void av1_copy_predefined_qmatrices_to_list(
AV1Decoder *pbi, int num_planes, bool store_at_intermediate_location) {
for (int qm_pos = 0; qm_pos < NUM_CUSTOM_QMS; qm_pos++) {
struct quantization_matrix_set *qmset =
store_at_intermediate_location
? &pbi->qmobu_list[pbi->total_qmobu_count].qm_list[qm_pos]
: &pbi->qm_list[qm_pos];
if (!qmset->quantizer_matrix_allocated) {
alloc_qmatrix(qmset, num_planes);
}
int qm_default_index = qm_pos;
qmset->qm_id = qm_pos;
qmset->qm_default_index = qm_pos;
qmset->qm_mlayer_id = -1;
qmset->qm_tlayer_id = -1;
qmset->quantizer_matrix_num_planes = num_planes;
// copy predefined[qm_default_index] to qmset
for (int c = 0; c < num_planes; ++c) {
// plane_type: 0:luma, 1:chroma
const int plane_type = (c >= 1);
memcpy(qmset->quantizer_matrix[0][c],
predefined_8x8_iwt_base_matrix[qm_default_index][plane_type],
8 * 8 * sizeof(qm_val_t));
memcpy(qmset->quantizer_matrix[1][c],
predefined_8x4_iwt_base_matrix[qm_default_index][plane_type],
8 * 4 * sizeof(qm_val_t));
memcpy(qmset->quantizer_matrix[2][c],
predefined_4x8_iwt_base_matrix[qm_default_index][plane_type],
4 * 8 * sizeof(qm_val_t));
}
} // qm_pos
}
// If store_at_intermediate_location is true, save the QM OBU in the
// intermediate location pbi->qmobu_list[pbi->total_qmobu_count].qm_list[].
// Otherwise, save the QM OBU in pbi->qm_list[]. Pass
// store_at_intermediate_location=true if a QM OBU is in a temporal unit with a
// sequence header.
//
// acc_qm_id_bitmap is an in/out parameter. The caller should set
// *acc_qm_id_bitmap to 0 before the first call to read_qm_obu(). Each
// read_qm_obu() call updates *acc_qm_id_bitmap by bitwise-ORing the
// qm_id_bitmap from the QM OBU with *acc_qm_id_bitmap.
uint32_t read_qm_obu(AV1Decoder *pbi, int obu_tlayer_id, int obu_mlayer_id,
bool store_at_intermediate_location,
uint32_t *acc_qm_id_bitmap,
struct aom_read_bit_buffer *rb) {
// multiple qms in one obu with id
const uint32_t saved_bit_offset = rb->bit_offset;
int qm_bit_map = aom_rb_read_literal(rb, NUM_CUSTOM_QMS);
if (*acc_qm_id_bitmap & (uint32_t)qm_bit_map) {
aom_internal_error(&pbi->common.error, AOM_CODEC_INVALID_PARAM,
"qm_bit_map(%d) overlaps the accumulated qm_bit_map(%d)",
qm_bit_map, acc_qm_id_bitmap);
} else {
*acc_qm_id_bitmap |= qm_bit_map;
}
bool qm_chroma_info_present_flag = aom_rb_read_bit(rb);
if (store_at_intermediate_location) {
if (pbi->total_qmobu_count >= NELEMENTS(pbi->qmobu_list)) {
aom_internal_error(&pbi->common.error, AOM_CODEC_UNSUP_BITSTREAM,
"too many QM OBUs");
}
pbi->qmobu_list[pbi->total_qmobu_count].qm_bit_map = qm_bit_map;
pbi->qmobu_list[pbi->total_qmobu_count].qm_chroma_info_present_flag =
qm_chroma_info_present_flag;
}
if (qm_bit_map == 0) {
av1_copy_predefined_qmatrices_to_list(pbi,
(qm_chroma_info_present_flag ? 3 : 1),
store_at_intermediate_location);
} else {
for (int j = 0; j < NUM_CUSTOM_QMS; j++) {
if (qm_bit_map & (1 << j)) {
int qm_id = j;
int qm_pos = qm_id;
read_qm_data(pbi, obu_tlayer_id, obu_mlayer_id, qm_pos, qm_id,
(qm_chroma_info_present_flag ? 3 : 1),
store_at_intermediate_location, rb);
}
}
} // qm_bit_map != 0
if (store_at_intermediate_location) pbi->total_qmobu_count++;
if (av1_check_trailing_bits(pbi, rb) != 0) {
return 0;
}
return ((rb->bit_offset - saved_bit_offset + 7) >> 3);
}
#endif // CONFIG_F255_QMOBU