blob: 940b2336c35429692168ad858c2ec38308182e5d [file] [edit]
/*
* Copyright (c) 2026, 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 <cstring>
#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
#include "av2/encoder/lcr_syntax.h"
#include "av2/encoder/atlas_syntax.h"
#include "av2/decoder/decoder.h"
#include "av2/decoder/decodeframe.h"
extern "C" {
#include "av2/decoder/obu.h"
}
#include "avm_dsp/bitwriter_buffer.h"
#include "avm_dsp/bitreader_buffer.h"
#include "avm_mem/avm_mem.h"
namespace {
static void rb_error_handler(void *data, avm_codec_err_t error,
const char *detail) {
(void)data;
(void)error;
(void)detail;
}
// Write an LCR OBU: body + extension_flag(0) + trailing bits.
static uint32_t write_lcr_obu(struct LayerConfigurationRecord *lcr,
int xlayer_id, uint8_t *dst) {
struct avm_write_bit_buffer wb = { dst, 0 };
if (xlayer_id == GLOBAL_XLAYER_ID) {
av2_write_lcr_global_info(lcr, &wb);
} else {
av2_write_lcr_local_info(lcr, &wb);
}
avm_wb_write_bit(&wb, 0); // lcr_extension_present_flag
avm_wb_write_bit(&wb, 1); // trailing stop bit
int pad = (8 - wb.bit_offset % 8) % 8;
if (pad > 0) {
avm_wb_write_literal(&wb, 0, pad);
}
return avm_wb_bytes_written(&wb);
}
static void populate_global_lcr(LayerConfigurationRecord *lcr) {
memset(lcr, 0, sizeof(*lcr));
lcr->valid = 1;
lcr->is_global = true;
lcr->xlayer_id = GLOBAL_XLAYER_ID;
lcr->lcr_id = 1;
GlobalLayerConfigurationRecord *g = &lcr->global_lcr;
g->lcr_global_config_record_id = 1;
g->lcr_xlayer_map = 0x3;
g->LcrMaxNumXLayerCount = 2;
g->LcrXLayerID[0] = 0;
g->LcrXLayerID[1] = 1;
g->lcr_aggregate_info_present_flag = 1;
g->lcr_seq_profile_tier_level_info_present_flag = 1;
g->lcr_global_payload_present_flag = 1;
g->lcr_global_atlas_id_present_flag = 1;
g->lcr_global_purpose_id = 5;
g->lcr_doh_constraint_flag = 1;
g->lcr_global_atlas_id = 2;
g->aggregate_ptl.lcr_config_idc = 3;
g->aggregate_ptl.lcr_aggregate_level_idx = 5;
g->aggregate_ptl.lcr_max_tier_flag = 1;
g->aggregate_ptl.lcr_max_interop = 2;
for (int i = 0; i < 2; i++) {
g->seq_ptl[i].lcr_seq_profile_idc = 4 + i;
g->seq_ptl[i].lcr_max_level_idx = 10 + i;
g->seq_ptl[i].lcr_tier_flag = i;
g->seq_ptl[i].lcr_max_mlayer_count = 2;
}
for (int i = 0; i < 2; i++) {
g->lcr_data_size[i] = 4;
g->xlayer_info[i].lcr_xlayer_atlas_segment_id = i + 1;
g->xlayer_info[i].lcr_xlayer_priority_order = i;
}
}
static void populate_local_lcr(LayerConfigurationRecord *lcr) {
memset(lcr, 0, sizeof(*lcr));
lcr->valid = 1;
lcr->is_global = false;
lcr->xlayer_id = 0;
lcr->lcr_id = 1;
LocalLayerConfigurationRecord *l = &lcr->local_lcr;
l->lcr_global_id = 1;
l->lcr_local_id = 1;
l->lcr_profile_tier_level_info_present_flag = 1;
l->lcr_local_atlas_id_present_flag = 1;
l->lcr_local_atlas_id = 3;
l->seq_ptl.lcr_seq_profile_idc = 7;
l->seq_ptl.lcr_max_level_idx = 12;
l->seq_ptl.lcr_tier_flag = 1;
l->seq_ptl.lcr_max_mlayer_count = 3;
LCRXLayerInfo *xi = &l->xlayer_info;
xi->lcr_rep_info_present_flag = 1;
xi->lcr_embedded_layer_info_present_flag = 1;
xi->rep_params.lcr_max_pic_width = 1920;
xi->rep_params.lcr_max_pic_height = 1080;
xi->rep_params.lcr_format_info_present_flag = 1;
xi->rep_params.lcr_bit_depth_idc = 10;
xi->rep_params.lcr_chroma_format_idc = 1;
EmbeddedLayerInfo *ml = &xi->mlayer_params;
ml->lcr_mlayer_map = 0x3;
for (int i = 0; i < 2; i++) {
ml->lcr_tlayer_map[i] = 0x1;
ml->lcr_layer_type[i] = STEREO_LAYER;
ml->lcr_view_type[i] = VIEW_EXPLICIT;
ml->lcr_view_id[i] = i;
ml->lcr_same_sh_max_resolution_flag[i] = 1;
}
}
static void compare_global_lcr(const GlobalLayerConfigurationRecord *a,
const GlobalLayerConfigurationRecord *b) {
EXPECT_EQ(a->lcr_global_config_record_id, b->lcr_global_config_record_id);
EXPECT_EQ(a->lcr_xlayer_map, b->lcr_xlayer_map);
EXPECT_EQ(a->LcrMaxNumXLayerCount, b->LcrMaxNumXLayerCount);
for (int i = 0; i < a->LcrMaxNumXLayerCount; i++) {
EXPECT_EQ(a->LcrXLayerID[i], b->LcrXLayerID[i]);
}
EXPECT_EQ(a->lcr_aggregate_info_present_flag,
b->lcr_aggregate_info_present_flag);
EXPECT_EQ(a->lcr_global_payload_present_flag,
b->lcr_global_payload_present_flag);
EXPECT_EQ(a->lcr_global_atlas_id_present_flag,
b->lcr_global_atlas_id_present_flag);
EXPECT_EQ(a->lcr_global_purpose_id, b->lcr_global_purpose_id);
EXPECT_EQ(a->lcr_doh_constraint_flag, b->lcr_doh_constraint_flag);
if (a->lcr_global_atlas_id_present_flag) {
EXPECT_EQ(a->lcr_global_atlas_id, b->lcr_global_atlas_id);
}
if (a->lcr_aggregate_info_present_flag) {
EXPECT_EQ(a->aggregate_ptl.lcr_config_idc, b->aggregate_ptl.lcr_config_idc);
EXPECT_EQ(a->aggregate_ptl.lcr_aggregate_level_idx,
b->aggregate_ptl.lcr_aggregate_level_idx);
EXPECT_EQ(a->aggregate_ptl.lcr_max_tier_flag,
b->aggregate_ptl.lcr_max_tier_flag);
EXPECT_EQ(a->aggregate_ptl.lcr_max_interop,
b->aggregate_ptl.lcr_max_interop);
}
if (a->lcr_seq_profile_tier_level_info_present_flag) {
for (int i = 0; i < a->LcrMaxNumXLayerCount; i++) {
EXPECT_EQ(a->seq_ptl[i].lcr_seq_profile_idc,
b->seq_ptl[i].lcr_seq_profile_idc);
EXPECT_EQ(a->seq_ptl[i].lcr_max_level_idx,
b->seq_ptl[i].lcr_max_level_idx);
EXPECT_EQ(a->seq_ptl[i].lcr_tier_flag, b->seq_ptl[i].lcr_tier_flag);
EXPECT_EQ(a->seq_ptl[i].lcr_max_mlayer_count,
b->seq_ptl[i].lcr_max_mlayer_count);
}
}
}
static void compare_local_lcr(const LocalLayerConfigurationRecord *a,
const LocalLayerConfigurationRecord *b) {
EXPECT_EQ(a->lcr_global_id, b->lcr_global_id);
EXPECT_EQ(a->lcr_local_id, b->lcr_local_id);
EXPECT_EQ(a->lcr_profile_tier_level_info_present_flag,
b->lcr_profile_tier_level_info_present_flag);
EXPECT_EQ(a->lcr_local_atlas_id_present_flag,
b->lcr_local_atlas_id_present_flag);
if (a->lcr_profile_tier_level_info_present_flag) {
EXPECT_EQ(a->seq_ptl.lcr_seq_profile_idc, b->seq_ptl.lcr_seq_profile_idc);
EXPECT_EQ(a->seq_ptl.lcr_max_level_idx, b->seq_ptl.lcr_max_level_idx);
EXPECT_EQ(a->seq_ptl.lcr_tier_flag, b->seq_ptl.lcr_tier_flag);
EXPECT_EQ(a->seq_ptl.lcr_max_mlayer_count, b->seq_ptl.lcr_max_mlayer_count);
}
if (a->lcr_local_atlas_id_present_flag) {
EXPECT_EQ(a->lcr_local_atlas_id, b->lcr_local_atlas_id);
}
}
static void compare_embedded_layer_info(const EmbeddedLayerInfo *a,
const EmbeddedLayerInfo *b) {
EXPECT_EQ(a->lcr_mlayer_map, b->lcr_mlayer_map);
for (int i = 0; i < MAX_NUM_MLAYERS; i++) {
if (!(a->lcr_mlayer_map & (1 << i))) continue;
EXPECT_EQ(a->lcr_tlayer_map[i], b->lcr_tlayer_map[i]);
EXPECT_EQ(a->lcr_layer_type[i], b->lcr_layer_type[i]);
EXPECT_EQ(a->lcr_view_type[i], b->lcr_view_type[i]);
if (a->lcr_view_type[i] == VIEW_EXPLICIT) {
EXPECT_EQ(a->lcr_view_id[i], b->lcr_view_id[i]);
}
if (i > 0) {
EXPECT_EQ(a->lcr_dependent_layer_map[i], b->lcr_dependent_layer_map[i]);
}
EXPECT_EQ(a->lcr_same_sh_max_resolution_flag[i],
b->lcr_same_sh_max_resolution_flag[i]);
if (!a->lcr_same_sh_max_resolution_flag[i]) {
EXPECT_EQ(a->lcr_max_expected_width[i], b->lcr_max_expected_width[i]);
EXPECT_EQ(a->lcr_max_expected_height[i], b->lcr_max_expected_height[i]);
}
}
}
class LcrTest : public ::testing::Test {
protected:
void SetUp() override {
pbi_ = static_cast<AV2Decoder *>(avm_memalign(32, sizeof(AV2Decoder)));
ASSERT_NE(pbi_, nullptr);
memset(pbi_, 0, sizeof(*pbi_));
memset(buf_, 0, sizeof(buf_));
}
void TearDown() override { avm_free(pbi_); }
AV2Decoder *pbi_;
uint8_t buf_[4096];
};
TEST_F(LcrTest, LocalLcrObuRoundtrip) {
LayerConfigurationRecord src;
populate_local_lcr(&src);
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const LayerConfigurationRecord *dst = &pbi_->lcr_list[0][1];
ASSERT_TRUE(dst->valid);
ASSERT_FALSE(dst->is_global);
compare_local_lcr(&src.local_lcr, &dst->local_lcr);
compare_embedded_layer_info(&src.local_lcr.xlayer_info.mlayer_params,
&dst->local_lcr.xlayer_info.mlayer_params);
EXPECT_EQ(src.local_lcr.xlayer_info.rep_params.lcr_max_pic_width,
dst->local_lcr.xlayer_info.rep_params.lcr_max_pic_width);
EXPECT_EQ(src.local_lcr.xlayer_info.rep_params.lcr_max_pic_height,
dst->local_lcr.xlayer_info.rep_params.lcr_max_pic_height);
EXPECT_EQ(src.local_lcr.xlayer_info.rep_params.lcr_bit_depth_idc,
dst->local_lcr.xlayer_info.rep_params.lcr_bit_depth_idc);
EXPECT_EQ(src.local_lcr.xlayer_info.rep_params.lcr_chroma_format_idc,
dst->local_lcr.xlayer_info.rep_params.lcr_chroma_format_idc);
}
TEST_F(LcrTest, GlobalLcrObuRoundtrip) {
LayerConfigurationRecord src;
populate_global_lcr(&src);
uint32_t written = write_lcr_obu(&src, GLOBAL_XLAYER_ID, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(
pbi_, GLOBAL_XLAYER_ID, &rb, bitmap);
ASSERT_EQ(read, written);
const LayerConfigurationRecord *dst = &pbi_->lcr_list[GLOBAL_XLAYER_ID][1];
ASSERT_TRUE(dst->valid);
ASSERT_TRUE(dst->is_global);
compare_global_lcr(&src.global_lcr, &dst->global_lcr);
}
TEST_F(LcrTest, EmbeddedLayerInfoRoundtrip) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 2;
LCRXLayerInfo *xi = &src.local_lcr.xlayer_info;
xi->lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &xi->mlayer_params;
ml->lcr_mlayer_map = 0x7;
ml->lcr_tlayer_map[0] = 0x3;
ml->lcr_layer_type[0] = TEXTURE_LAYER;
ml->lcr_view_type[0] = VIEW_EXPLICIT;
ml->lcr_view_id[0] = 0;
ml->lcr_same_sh_max_resolution_flag[0] = 1;
ml->lcr_tlayer_map[1] = 0x1;
ml->lcr_layer_type[1] = AUX_LAYER;
ml->lcr_auxiliary_type[1] = LCR_ALPHA_AUX;
ml->lcr_view_type[1] = VIEW_EXPLICIT;
ml->lcr_view_id[1] = 0;
ml->lcr_dependent_layer_map[1] = 0x1;
ml->lcr_same_sh_max_resolution_flag[1] = 0;
ml->lcr_max_expected_width[1] = 960;
ml->lcr_max_expected_height[1] = 540;
ml->lcr_tlayer_map[2] = 0x1;
ml->lcr_layer_type[2] = STEREO_LAYER;
ml->lcr_view_type[2] = VIEW_EXPLICIT;
ml->lcr_view_id[2] = 1;
ml->lcr_dependent_layer_map[2] = 0x1;
ml->lcr_same_sh_max_resolution_flag[2] = 0;
ml->lcr_max_expected_width[2] = 1920;
ml->lcr_max_expected_height[2] = 1080;
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const EmbeddedLayerInfo *dst =
&pbi_->lcr_list[0][2].local_lcr.xlayer_info.mlayer_params;
compare_embedded_layer_info(ml, dst);
EXPECT_EQ(dst->lcr_layer_type[1], AUX_LAYER);
EXPECT_EQ(dst->lcr_auxiliary_type[1], LCR_ALPHA_AUX);
EXPECT_EQ(dst->lcr_max_expected_width[1], 960);
EXPECT_EQ(dst->lcr_max_expected_height[1], 540);
EXPECT_EQ(dst->lcr_max_expected_width[2], 1920);
EXPECT_EQ(dst->lcr_max_expected_height[2], 1080);
}
TEST_F(LcrTest, ConformanceCheckNoMetadata) {
pbi_->xlayer_id_map[0] = 1;
pbi_->mlayer_id_map[0][0] = 1;
pbi_->mlayer_id_map[0][1] = 1;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, false, false));
}
TEST_F(LcrTest, ConformanceCheckSingleLayer) {
pbi_->xlayer_id_map[0] = 1;
pbi_->mlayer_id_map[0][0] = 1;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, false, false));
}
TEST_F(LcrTest, ColorInfoRoundtrip) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
LCRXLayerInfo *xi = &src.local_lcr.xlayer_info;
xi->lcr_xlayer_color_info_present_flag = 1;
xi->xlayer_col_params.layer_color_description_idc = 0; // explicit
xi->xlayer_col_params.layer_color_primaries = 1;
xi->xlayer_col_params.layer_transfer_characteristics = 13;
xi->xlayer_col_params.layer_matrix_coefficients = 6;
xi->xlayer_col_params.layer_full_range_flag = 1;
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const LCRXLayerInfo *dxi = &pbi_->lcr_list[0][1].local_lcr.xlayer_info;
EXPECT_EQ(dxi->lcr_xlayer_color_info_present_flag, 1);
EXPECT_EQ(dxi->xlayer_col_params.layer_color_description_idc, 0);
EXPECT_EQ(dxi->xlayer_col_params.layer_color_primaries, 1);
EXPECT_EQ(dxi->xlayer_col_params.layer_transfer_characteristics, 13);
EXPECT_EQ(dxi->xlayer_col_params.layer_matrix_coefficients, 6);
EXPECT_EQ(dxi->xlayer_col_params.layer_full_range_flag, 1);
}
TEST_F(LcrTest, CropWindowRoundtrip) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
LCRXLayerInfo *xi = &src.local_lcr.xlayer_info;
xi->lcr_rep_info_present_flag = 1;
xi->rep_params.lcr_max_pic_width = 1920;
xi->rep_params.lcr_max_pic_height = 1080;
xi->rep_params.lcr_format_info_present_flag = 0;
xi->crop_win.crop_window_present_flag = 1;
xi->crop_win.crop_win_left_offset = 8;
xi->crop_win.crop_win_right_offset = 8;
xi->crop_win.crop_win_top_offset = 4;
xi->crop_win.crop_win_bottom_offset = 4;
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const LCRXLayerInfo *dxi = &pbi_->lcr_list[0][1].local_lcr.xlayer_info;
EXPECT_EQ(dxi->crop_win.crop_window_present_flag, 1);
EXPECT_EQ(dxi->crop_win.crop_win_left_offset, 8);
EXPECT_EQ(dxi->crop_win.crop_win_right_offset, 8);
EXPECT_EQ(dxi->crop_win.crop_win_top_offset, 4);
EXPECT_EQ(dxi->crop_win.crop_win_bottom_offset, 4);
}
TEST_F(LcrTest, XlayerPurposeRoundtrip) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
LCRXLayerInfo *xi = &src.local_lcr.xlayer_info;
xi->lcr_xlayer_purpose_present_flag = 1;
xi->lcr_xlayer_purpose_id = 42;
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const LCRXLayerInfo *dxi = &pbi_->lcr_list[0][1].local_lcr.xlayer_info;
EXPECT_EQ(dxi->lcr_xlayer_purpose_present_flag, 1);
EXPECT_EQ(dxi->lcr_xlayer_purpose_id, 42);
}
TEST_F(LcrTest, GlobalLcrWithEmbeddedLayerInfo) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.is_global = true;
src.xlayer_id = GLOBAL_XLAYER_ID;
GlobalLayerConfigurationRecord *g = &src.global_lcr;
g->lcr_global_config_record_id = 1;
g->lcr_xlayer_map = 0x1; // xlayer 0 only
g->LcrMaxNumXLayerCount = 1;
g->LcrXLayerID[0] = 0;
g->lcr_global_payload_present_flag = 1;
g->lcr_global_atlas_id_present_flag = 0;
LCRXLayerInfo *xi = &g->xlayer_info[0];
xi->lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &xi->mlayer_params;
ml->lcr_mlayer_map = 0x3;
ml->lcr_tlayer_map[0] = 0x1;
ml->lcr_layer_type[0] = TEXTURE_LAYER;
ml->lcr_view_type[0] = VIEW_EXPLICIT;
ml->lcr_view_id[0] = 0;
ml->lcr_same_sh_max_resolution_flag[0] = 1;
ml->lcr_tlayer_map[1] = 0x1;
ml->lcr_layer_type[1] = STEREO_LAYER;
ml->lcr_view_type[1] = VIEW_EXPLICIT;
ml->lcr_view_id[1] = 1;
ml->lcr_same_sh_max_resolution_flag[1] = 1;
// Compute data_size: write to temp buffer to get exact size.
uint8_t tmp[256];
struct avm_write_bit_buffer twb = { tmp, 0 };
// xlayer_info: 4 flag bits (rep=0, purpose=0, color=0, embedded=1)
avm_wb_write_bit(&twb, 0);
avm_wb_write_bit(&twb, 0);
avm_wb_write_bit(&twb, 0);
avm_wb_write_bit(&twb, 1);
// byte alignment: 4 pad bits
avm_wb_write_literal(&twb, 0, 4);
// embedded layer info for 2 mlayers (same_sh=1, no atlas):
// mlayer_map(8) + [tlayer(4)+type(8)+view_type(8)+view_id(8)+same(1)+pad(3)]
// +
// [tlayer(4)+type(8)+view_type(8)+view_id(8)+dep(1)+same(1)+pad(2)]
// = 8 + 32 + 32 = 72 bits = 9 bytes. Total = 1 + 9 = 10 bytes
g->lcr_data_size[0] = 10;
uint32_t written = write_lcr_obu(&src, GLOBAL_XLAYER_ID, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(
pbi_, GLOBAL_XLAYER_ID, &rb, bitmap);
ASSERT_EQ(read, written);
const GlobalLayerConfigurationRecord *dg =
&pbi_->lcr_list[GLOBAL_XLAYER_ID][1].global_lcr;
const EmbeddedLayerInfo *dml = &dg->xlayer_info[0].mlayer_params;
EXPECT_EQ(dml->lcr_mlayer_map, 0x3);
EXPECT_EQ(dml->lcr_layer_type[0], TEXTURE_LAYER);
EXPECT_EQ(dml->lcr_view_id[0], 0);
EXPECT_EQ(dml->lcr_layer_type[1], STEREO_LAYER);
EXPECT_EQ(dml->lcr_view_id[1], 1);
}
// Sweep all 16 combinations of xlayer_info present flags.
TEST_F(LcrTest, XlayerInfoFlagCombinations) {
for (int flags = 0; flags < 16; flags++) {
bool rep = flags & 1;
bool purpose = (flags >> 1) & 1;
bool color = (flags >> 2) & 1;
bool embedded = (flags >> 3) & 1;
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
LCRXLayerInfo *xi = &src.local_lcr.xlayer_info;
xi->lcr_rep_info_present_flag = rep;
xi->lcr_xlayer_purpose_present_flag = purpose;
xi->lcr_xlayer_color_info_present_flag = color;
xi->lcr_embedded_layer_info_present_flag = embedded;
if (rep) {
xi->rep_params.lcr_max_pic_width = 640;
xi->rep_params.lcr_max_pic_height = 480;
}
if (purpose) {
xi->lcr_xlayer_purpose_id = 10;
}
if (color) {
xi->xlayer_col_params.layer_full_range_flag = 1;
}
if (embedded) {
xi->mlayer_params.lcr_mlayer_map = 0x1;
xi->mlayer_params.lcr_tlayer_map[0] = 0x1;
xi->mlayer_params.lcr_layer_type[0] = TEXTURE_LAYER;
xi->mlayer_params.lcr_view_type[0] = VIEW_LEFT;
xi->mlayer_params.lcr_same_sh_max_resolution_flag[0] = 1;
}
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u) << "flags=" << flags;
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written) << "flags=" << flags;
const LCRXLayerInfo *dxi = &pbi_->lcr_list[0][1].local_lcr.xlayer_info;
EXPECT_EQ(dxi->lcr_rep_info_present_flag, rep) << "flags=" << flags;
EXPECT_EQ(dxi->lcr_xlayer_purpose_present_flag, purpose)
<< "flags=" << flags;
EXPECT_EQ(dxi->lcr_xlayer_color_info_present_flag, color)
<< "flags=" << flags;
EXPECT_EQ(dxi->lcr_embedded_layer_info_present_flag, embedded)
<< "flags=" << flags;
}
}
// Implicit view type (VIEW_LEFT) — no view_id written.
TEST_F(LcrTest, ImplicitViewType) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.xlayer_info.lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &src.local_lcr.xlayer_info.mlayer_params;
ml->lcr_mlayer_map = 0x1;
ml->lcr_tlayer_map[0] = 0x1;
ml->lcr_layer_type[0] = STEREO_LAYER;
ml->lcr_view_type[0] = VIEW_LEFT;
ml->lcr_same_sh_max_resolution_flag[0] = 1;
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const EmbeddedLayerInfo *dml =
&pbi_->lcr_list[0][1].local_lcr.xlayer_info.mlayer_params;
EXPECT_EQ(dml->lcr_view_type[0], VIEW_LEFT);
}
TEST_F(LcrTest, GlobalLcrMinimalFields) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.is_global = true;
GlobalLayerConfigurationRecord *g = &src.global_lcr;
g->lcr_global_config_record_id = 1;
g->lcr_xlayer_map = 0x1;
g->LcrMaxNumXLayerCount = 1;
g->LcrXLayerID[0] = 0;
// All present flags = 0
uint32_t written = write_lcr_obu(&src, GLOBAL_XLAYER_ID, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(
pbi_, GLOBAL_XLAYER_ID, &rb, bitmap);
ASSERT_EQ(read, written);
const GlobalLayerConfigurationRecord *dg =
&pbi_->lcr_list[GLOBAL_XLAYER_ID][1].global_lcr;
EXPECT_EQ(dg->lcr_aggregate_info_present_flag, 0);
EXPECT_EQ(dg->lcr_seq_profile_tier_level_info_present_flag, 0);
EXPECT_EQ(dg->lcr_global_payload_present_flag, 0);
EXPECT_EQ(dg->lcr_global_atlas_id_present_flag, 0);
}
TEST_F(LcrTest, LocalLcrMinimalFields) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
// PTL and atlas_id both absent
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const LocalLayerConfigurationRecord *dl = &pbi_->lcr_list[0][1].local_lcr;
EXPECT_EQ(dl->lcr_profile_tier_level_info_present_flag, 0);
EXPECT_EQ(dl->lcr_local_atlas_id_present_flag, 0);
}
// Color info with implicit idc (idc > 0, no primaries written).
TEST_F(LcrTest, ColorInfoImplicit) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.xlayer_info.lcr_xlayer_color_info_present_flag = 1;
src.local_lcr.xlayer_info.xlayer_col_params.layer_color_description_idc = 1;
src.local_lcr.xlayer_info.xlayer_col_params.layer_full_range_flag = 0;
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const XLayerColorInfo *dc =
&pbi_->lcr_list[0][1].local_lcr.xlayer_info.xlayer_col_params;
EXPECT_EQ(dc->layer_color_description_idc, 1);
EXPECT_EQ(dc->layer_full_range_flag, 0);
}
TEST_F(LcrTest, HigherLayerCounts) {
const int mlayer_counts[] = { 4, 8 };
const int tlayer_maps[] = { 0x3, 0xF }; // 2 and 4 tlayers
for (int mi = 0; mi < 2; mi++) {
for (int ti = 0; ti < 2; ti++) {
int num_ml = mlayer_counts[mi];
int tmap = tlayer_maps[ti];
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.xlayer_info.lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &src.local_lcr.xlayer_info.mlayer_params;
ml->lcr_mlayer_map = (1 << num_ml) - 1;
for (int i = 0; i < num_ml; i++) {
ml->lcr_tlayer_map[i] = tmap;
ml->lcr_layer_type[i] = TEXTURE_LAYER;
ml->lcr_view_type[i] = VIEW_LEFT;
ml->lcr_same_sh_max_resolution_flag[i] = 1;
if (i > 0) ml->lcr_dependent_layer_map[i] = 1;
}
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u) << "ml=" << num_ml << " tl=" << tmap;
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written) << "ml=" << num_ml << " tl=" << tmap;
const EmbeddedLayerInfo *dml =
&pbi_->lcr_list[0][1].local_lcr.xlayer_info.mlayer_params;
EXPECT_EQ(dml->lcr_mlayer_map, (1 << num_ml) - 1);
for (int i = 0; i < num_ml; i++) {
EXPECT_EQ(dml->lcr_tlayer_map[i], tmap);
}
}
}
}
TEST_F(LcrTest, EmbeddedLayerWithAtlasId) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.lcr_local_atlas_id_present_flag = 1;
src.local_lcr.lcr_local_atlas_id = 2;
src.local_lcr.xlayer_info.lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &src.local_lcr.xlayer_info.mlayer_params;
ml->lcr_mlayer_map = 0x1;
ml->lcr_tlayer_map[0] = 0x1;
ml->lcr_layer_type[0] = TEXTURE_LAYER;
ml->lcr_view_type[0] = VIEW_LEFT;
ml->lcr_same_sh_max_resolution_flag[0] = 1;
ml->lcr_layer_atlas_segment_id[0] = 5;
ml->lcr_priority_order[0] = 3;
ml->lcr_rendering_method[0] = 1;
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
const EmbeddedLayerInfo *dml =
&pbi_->lcr_list[0][1].local_lcr.xlayer_info.mlayer_params;
EXPECT_EQ(dml->lcr_layer_atlas_segment_id[0], 5);
EXPECT_EQ(dml->lcr_priority_order[0], 3);
EXPECT_EQ(dml->lcr_rendering_method[0], 1);
}
TEST_F(LcrTest, AuxiliaryTypeSweep) {
const int aux_types[] = { LCR_ALPHA_AUX, LCR_DEPTH_AUX, LCR_SEGMENTATION_AUX,
LCR_GAIN_MAP_AUX };
for (int ai = 0; ai < 4; ai++) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.xlayer_info.lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &src.local_lcr.xlayer_info.mlayer_params;
ml->lcr_mlayer_map = 0x1;
ml->lcr_tlayer_map[0] = 0x1;
ml->lcr_layer_type[0] = AUX_LAYER;
ml->lcr_auxiliary_type[0] = aux_types[ai];
ml->lcr_view_type[0] = VIEW_LEFT;
ml->lcr_same_sh_max_resolution_flag[0] = 1;
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u) << "aux_type=" << aux_types[ai];
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written) << "aux_type=" << aux_types[ai];
EXPECT_EQ(pbi_->lcr_list[0][1]
.local_lcr.xlayer_info.mlayer_params.lcr_auxiliary_type[0],
aux_types[ai]);
}
}
TEST_F(LcrTest, DependentXlayersRoundtrip) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.is_global = true;
GlobalLayerConfigurationRecord *g = &src.global_lcr;
g->lcr_global_config_record_id = 1;
g->lcr_xlayer_map = 0x3; // xlayers 0 and 1
g->LcrMaxNumXLayerCount = 2;
g->LcrXLayerID[0] = 0;
g->LcrXLayerID[1] = 1;
g->lcr_dependent_xlayers_flag = 1;
g->lcr_global_payload_present_flag = 1;
// xlayer 0: n=0, no dependent map written
// xlayer 1: n=1, 1-bit dependent map
g->lcr_num_dependent_xlayer_map[0] = 0;
g->lcr_num_dependent_xlayer_map[1] = 0x1; // depends on xlayer 0
// Payload: xlayer_info with all flags off, no atlas
// xlayer 0: 4 flag bits + 4 pad = 1 byte
g->lcr_data_size[0] = 1;
// xlayer 1: 1-bit dep map + 4 flag bits + 3 pad = 1 byte
g->lcr_data_size[1] = 1;
uint32_t written = write_lcr_obu(&src, GLOBAL_XLAYER_ID, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(
pbi_, GLOBAL_XLAYER_ID, &rb, bitmap);
ASSERT_EQ(read, written);
const GlobalLayerConfigurationRecord *dg =
&pbi_->lcr_list[GLOBAL_XLAYER_ID][1].global_lcr;
EXPECT_EQ(dg->lcr_dependent_xlayers_flag, 1);
EXPECT_EQ(dg->lcr_num_dependent_xlayer_map[1], 0x1u);
}
TEST_F(LcrTest, ConformanceCheckMsdoConfigurable) {
pbi_->multistream_decoder_mode = 1;
pbi_->common.msdo_params.multistream_profile_idc = CONFIGURABLE;
pbi_->xlayer_id_map[0] = 1;
pbi_->mlayer_id_map[0][0] = 1;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, false, false));
}
TEST_F(LcrTest, ConformanceCheckGlobalLcrConfigurable) {
pbi_->xlayer_id_map[0] = 1;
pbi_->mlayer_id_map[0][0] = 1;
pbi_->lcr_list[GLOBAL_XLAYER_ID][1].valid = 1;
pbi_->lcr_list[GLOBAL_XLAYER_ID][1].is_global = true;
pbi_->lcr_list[GLOBAL_XLAYER_ID][1]
.global_lcr.lcr_aggregate_info_present_flag = 1;
pbi_->lcr_list[GLOBAL_XLAYER_ID][1].global_lcr.aggregate_ptl.lcr_max_interop =
CONFIGURABLE;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, true, false));
}
TEST_F(LcrTest, ConformanceCheckLocalLcrConfigurable) {
pbi_->xlayer_id_map[0] = 1;
pbi_->mlayer_id_map[0][0] = 1;
pbi_->lcr_list[0][1].valid = 1;
pbi_->lcr_list[0][1].is_global = false;
pbi_->lcr_list[0][1].local_lcr.lcr_profile_tier_level_info_present_flag = 1;
pbi_->lcr_list[0][1].local_lcr.seq_ptl.lcr_seq_profile_idc = CONFIGURABLE;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, false, true));
}
TEST_F(LcrTest, ConformanceCheckMultiXlayerMsdo) {
pbi_->multistream_decoder_mode = 1;
pbi_->common.msdo_params.multistream_profile_idc = MAIN_420_10_IP0;
pbi_->xlayer_id_map[0] = 1;
pbi_->xlayer_id_map[1] = 1;
pbi_->mlayer_id_map[0][0] = 1;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, false, false));
}
TEST_F(LcrTest, ConformanceCheckMultiMlayerLocalLcr) {
pbi_->xlayer_id_map[0] = 1;
pbi_->mlayer_id_map[0][0] = 1;
pbi_->mlayer_id_map[0][1] = 1;
pbi_->lcr_list[0][1].valid = 1;
pbi_->lcr_list[0][1].is_global = false;
pbi_->lcr_list[0][1].local_lcr.lcr_profile_tier_level_info_present_flag = 1;
pbi_->lcr_list[0][1].local_lcr.seq_ptl.lcr_seq_profile_idc = MAIN_420_10_IP1;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, false, true));
}
TEST_F(LcrTest, LcrIdBoundarySweep) {
const int lcr_ids[] = { 1, 4, 7 };
for (int li = 0; li < 3; li++) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = lcr_ids[li];
src.local_lcr.lcr_global_id = lcr_ids[(li + 1) % 3];
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u) << "lcr_id=" << lcr_ids[li];
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written) << "lcr_id=" << lcr_ids[li];
EXPECT_EQ(pbi_->lcr_list[0][lcr_ids[li]].local_lcr.lcr_local_id,
lcr_ids[li]);
}
}
TEST_F(LcrTest, ProfileLevelBoundarySweep) {
const int profiles[] = { 0, 31 };
const int levels[] = { 0, 31 };
for (int pi = 0; pi < 2; pi++) {
for (int lvi = 0; lvi < 2; lvi++) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.lcr_profile_tier_level_info_present_flag = 1;
src.local_lcr.seq_ptl.lcr_seq_profile_idc = profiles[pi];
src.local_lcr.seq_ptl.lcr_max_level_idx = levels[lvi];
src.local_lcr.seq_ptl.lcr_max_mlayer_count = 7;
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
EXPECT_EQ(pbi_->lcr_list[0][1].local_lcr.seq_ptl.lcr_seq_profile_idc,
profiles[pi]);
EXPECT_EQ(pbi_->lcr_list[0][1].local_lcr.seq_ptl.lcr_max_level_idx,
levels[lvi]);
EXPECT_EQ(pbi_->lcr_list[0][1].local_lcr.seq_ptl.lcr_max_mlayer_count, 7);
}
}
}
TEST_F(LcrTest, RepInfoUvlcExtremes) {
const int widths[] = { 0, 1, 7680, 65535 };
const int heights[] = { 0, 1, 4320, 65535 };
for (int wi = 0; wi < 4; wi++) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.xlayer_info.lcr_rep_info_present_flag = 1;
src.local_lcr.xlayer_info.rep_params.lcr_max_pic_width = widths[wi];
src.local_lcr.xlayer_info.rep_params.lcr_max_pic_height = heights[wi];
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u) << "w=" << widths[wi];
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written) << "w=" << widths[wi];
EXPECT_EQ(
pbi_->lcr_list[0][1].local_lcr.xlayer_info.rep_params.lcr_max_pic_width,
widths[wi]);
EXPECT_EQ(pbi_->lcr_list[0][1]
.local_lcr.xlayer_info.rep_params.lcr_max_pic_height,
heights[wi]);
}
}
TEST_F(LcrTest, NonContiguousMlayerMaps) {
const int maps[] = { 0x05, 0x80, 0x55, 0xA1 };
for (int mi = 0; mi < 4; mi++) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.xlayer_info.lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &src.local_lcr.xlayer_info.mlayer_params;
ml->lcr_mlayer_map = maps[mi];
for (int i = 0; i < MAX_NUM_MLAYERS; i++) {
if (!(maps[mi] & (1 << i))) continue;
ml->lcr_tlayer_map[i] = 0x1;
ml->lcr_layer_type[i] = TEXTURE_LAYER;
ml->lcr_view_type[i] = VIEW_LEFT;
ml->lcr_same_sh_max_resolution_flag[i] = 1;
if (i > 0) ml->lcr_dependent_layer_map[i] = 1;
}
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u) << "map=0x" << std::hex << maps[mi];
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written) << "map=0x" << std::hex << maps[mi];
EXPECT_EQ(
pbi_->lcr_list[0][1].local_lcr.xlayer_info.mlayer_params.lcr_mlayer_map,
maps[mi]);
}
}
TEST_F(LcrTest, ColorIdcHighValues) {
const int idc_values[] = { 0, 1, 4, 8, 20 };
for (int ci = 0; ci < 5; ci++) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = 1;
src.local_lcr.xlayer_info.lcr_xlayer_color_info_present_flag = 1;
src.local_lcr.xlayer_info.xlayer_col_params.layer_color_description_idc =
idc_values[ci];
if (idc_values[ci] == 0) {
src.local_lcr.xlayer_info.xlayer_col_params.layer_color_primaries = 9;
src.local_lcr.xlayer_info.xlayer_col_params
.layer_transfer_characteristics = 16;
src.local_lcr.xlayer_info.xlayer_col_params.layer_matrix_coefficients = 9;
}
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u) << "idc=" << idc_values[ci];
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read =
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written) << "idc=" << idc_values[ci];
EXPECT_EQ(pbi_->lcr_list[0][1]
.local_lcr.xlayer_info.xlayer_col_params
.layer_color_description_idc,
idc_values[ci]);
}
}
TEST_F(LcrTest, MultipleLcrIdsOnSameXlayer) {
const int ids[] = { 1, 3, 7 };
for (int i = 0; i < 3; i++) {
LayerConfigurationRecord src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.local_lcr.lcr_local_id = ids[i];
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_lcr_obu(&src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
}
// All three should be stored in different slots.
for (int i = 0; i < 3; i++) {
EXPECT_TRUE(pbi_->lcr_list[0][ids[i]].valid) << "id=" << ids[i];
EXPECT_EQ(pbi_->lcr_list[0][ids[i]].local_lcr.lcr_local_id, ids[i]);
}
}
// Writes an Atlas OBU and an LCR OBU referencing the same atlas_segment_id,
// then verifies cross-reference integrity after reading both.
TEST_F(LcrTest, CrossObuLcrAtlasConsistency) {
const int atlas_seg_id = 5;
const int xlayer_id = 0;
// Write Atlas OBU with atlas_segment_id = 5.
AtlasSegmentInfo atlas_src;
memset(&atlas_src, 0, sizeof(atlas_src));
atlas_src.valid = 1;
atlas_src.atlas_segment_id = atlas_seg_id;
atlas_src.atlas_segment_mode_idc = SINGLE_ATLAS;
atlas_src.ats_nominal_width_minus1 = 1919;
atlas_src.ats_nominal_height_minus1 = 1079;
uint8_t atlas_buf[512];
struct avm_write_bit_buffer awb = { atlas_buf, 0 };
av2_write_atlas_segment_info(&atlas_src, &awb);
avm_wb_write_bit(&awb, 0);
avm_wb_write_bit(&awb, 1);
int apad = (8 - awb.bit_offset % 8) % 8;
if (apad > 0) avm_wb_write_literal(&awb, 0, apad);
uint32_t atlas_written = avm_wb_bytes_written(&awb);
// Write LCR OBU referencing atlas_segment_id = 5 via embedded layer info.
LayerConfigurationRecord lcr_src;
memset(&lcr_src, 0, sizeof(lcr_src));
lcr_src.valid = 1;
lcr_src.local_lcr.lcr_local_id = 1;
lcr_src.local_lcr.lcr_local_atlas_id_present_flag = 1;
lcr_src.local_lcr.lcr_local_atlas_id = atlas_seg_id;
lcr_src.local_lcr.xlayer_info.lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &lcr_src.local_lcr.xlayer_info.mlayer_params;
ml->lcr_mlayer_map = 0x1;
ml->lcr_tlayer_map[0] = 0x1;
ml->lcr_layer_type[0] = TEXTURE_LAYER;
ml->lcr_view_type[0] = VIEW_LEFT;
ml->lcr_same_sh_max_resolution_flag[0] = 1;
ml->lcr_layer_atlas_segment_id[0] = atlas_seg_id;
ml->lcr_priority_order[0] = 0;
ml->lcr_rendering_method[0] = 0;
uint32_t lcr_written = write_lcr_obu(&lcr_src, xlayer_id, buf_);
ASSERT_GT(lcr_written, 0u);
// Read Atlas OBU.
struct avm_read_bit_buffer arb = { atlas_buf, atlas_buf + atlas_written, 0,
nullptr, rb_error_handler };
uint32_t atlas_read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &arb);
ASSERT_EQ(atlas_read, atlas_written);
// Read LCR OBU.
struct avm_read_bit_buffer lrb = { buf_, buf_ + lcr_written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t lcr_read =
av2_read_layer_configuration_record_obu(pbi_, xlayer_id, &lrb, bitmap);
ASSERT_EQ(lcr_read, lcr_written);
// Verify cross-reference: Atlas segment ID matches LCR's reference.
EXPECT_EQ(pbi_->atlas_list[xlayer_id][0].atlas_segment_id, atlas_seg_id);
EXPECT_EQ(
pbi_->lcr_list[xlayer_id][1]
.local_lcr.xlayer_info.mlayer_params.lcr_layer_atlas_segment_id[0],
atlas_seg_id);
EXPECT_EQ(pbi_->lcr_list[xlayer_id][1].local_lcr.lcr_local_atlas_id,
atlas_seg_id);
}
// Exercises (num_xlayers==1, num_mlayers>1, local_lcr+IP1) conformance branch
// with real LCR data in decoder state rather than manually set fields.
TEST_F(LcrTest, ConformanceIntegrationOpsAndLcr) {
LayerConfigurationRecord lcr_src;
memset(&lcr_src, 0, sizeof(lcr_src));
lcr_src.valid = 1;
lcr_src.local_lcr.lcr_local_id = 1;
lcr_src.local_lcr.lcr_profile_tier_level_info_present_flag = 1;
lcr_src.local_lcr.seq_ptl.lcr_seq_profile_idc = MAIN_420_10_IP1;
lcr_src.local_lcr.seq_ptl.lcr_max_level_idx = 5;
lcr_src.local_lcr.xlayer_info.lcr_embedded_layer_info_present_flag = 1;
EmbeddedLayerInfo *ml = &lcr_src.local_lcr.xlayer_info.mlayer_params;
ml->lcr_mlayer_map = 0x3;
for (int i = 0; i < 2; i++) {
ml->lcr_tlayer_map[i] = 0x1;
ml->lcr_layer_type[i] = STEREO_LAYER;
ml->lcr_view_type[i] = VIEW_LEFT;
ml->lcr_same_sh_max_resolution_flag[i] = 1;
}
uint32_t written = write_lcr_obu(&lcr_src, 0, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint8_t bitmap[MAX_NUM_XLAYERS] = { 0 };
uint32_t read = av2_read_layer_configuration_record_obu(pbi_, 0, &rb, bitmap);
ASSERT_EQ(read, written);
pbi_->xlayer_id_map[0] = 1;
pbi_->mlayer_id_map[0][0] = 1;
pbi_->mlayer_id_map[0][1] = 1;
EXPECT_TRUE(conformance_check_msdo_lcr(pbi_, false, true));
}
} // namespace