blob: 186956abfe929c0d266be7705aa10e083c7fbd19 [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/atlas_syntax.h"
#include "av2/decoder/decoder.h"
#include "av2/decoder/decodeframe.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 Atlas OBU: body + extension_flag(0) + trailing bits.
static uint32_t write_atlas_obu(struct AtlasSegmentInfo *atlas, uint8_t *dst) {
struct avm_write_bit_buffer wb = { dst, 0 };
av2_write_atlas_segment_info(atlas, &wb);
avm_wb_write_bit(&wb, 0); // ats_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);
}
class AtlasTest : 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(AtlasTest, SingleAtlasRoundtrip) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = SINGLE_ATLAS;
src.ats_nominal_width_minus1 = 1919;
src.ats_nominal_height_minus1 = 1079;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
const int xlayer_id = 0;
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
ASSERT_TRUE(dst->valid);
EXPECT_EQ(dst->atlas_segment_id, 1);
EXPECT_EQ(dst->atlas_segment_mode_idc, SINGLE_ATLAS);
EXPECT_EQ(dst->ats_nominal_width_minus1, 1919);
EXPECT_EQ(dst->ats_nominal_height_minus1, 1079);
}
TEST_F(AtlasTest, MultistreamAtlasRoundtrip) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 2;
src.atlas_segment_mode_idc = MULTISTREAM_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_atlas_width = 3840;
basic.ats_atlas_height = 2160;
basic.ats_num_atlas_segments_minus_1 = 1; // 2 segments
basic.ats_background_info_present_flag = 1;
basic.ats_background_red_value = 128;
basic.ats_background_green_value = 64;
basic.ats_background_blue_value = 32;
basic.ats_input_stream_id[0] = 0;
basic.ats_segment_top_left_pos_x[0] = 0;
basic.ats_segment_top_left_pos_y[0] = 0;
basic.ats_segment_width[0] = 1920;
basic.ats_segment_height[0] = 2160;
basic.ats_input_stream_id[1] = 1;
basic.ats_segment_top_left_pos_x[1] = 1920;
basic.ats_segment_top_left_pos_y[1] = 0;
basic.ats_segment_width[1] = 1920;
basic.ats_segment_height[1] = 2160;
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
const int xlayer_id = 0;
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
ASSERT_TRUE(dst->valid);
EXPECT_EQ(dst->atlas_segment_id, 2);
EXPECT_EQ(dst->atlas_segment_mode_idc, MULTISTREAM_ATLAS);
const AtlasBasicInfo *db = dst->ats_basic_info;
ASSERT_NE(db, nullptr);
EXPECT_EQ(db->ats_atlas_width, 3840);
EXPECT_EQ(db->ats_atlas_height, 2160);
EXPECT_EQ(db->ats_num_atlas_segments_minus_1, 1);
EXPECT_EQ(db->ats_background_info_present_flag, 1);
EXPECT_EQ(db->ats_background_red_value, 128);
EXPECT_EQ(db->ats_background_green_value, 64);
EXPECT_EQ(db->ats_background_blue_value, 32);
EXPECT_EQ(db->ats_input_stream_id[0], 0);
EXPECT_EQ(db->ats_segment_width[0], 1920);
EXPECT_EQ(db->ats_input_stream_id[1], 1);
EXPECT_EQ(db->ats_segment_top_left_pos_x[1], 1920);
EXPECT_EQ(db->ats_segment_width[1], 1920);
}
TEST_F(AtlasTest, MultistreamAlphaAtlasRoundtrip) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 3;
src.atlas_segment_mode_idc = MULTISTREAM_ALPHA_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_atlas_width = 1920;
basic.ats_atlas_height = 1080;
basic.ats_num_atlas_segments_minus_1 = 1; // 2 segments
basic.ats_alpha_segments_present_flag = 1;
basic.ats_input_stream_id[0] = 0;
basic.ats_segment_width[0] = 1920;
basic.ats_segment_height[0] = 1080;
basic.ats_alpha_segment_flag[0] = 1;
basic.ats_input_stream_id[1] = 1;
basic.ats_segment_width[1] = 1920;
basic.ats_segment_height[1] = 1080;
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
const int xlayer_id = 0;
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
ASSERT_TRUE(dst->valid);
EXPECT_EQ(dst->atlas_segment_mode_idc, MULTISTREAM_ALPHA_ATLAS);
EXPECT_EQ(dst->ats_basic_info->ats_alpha_segments_present_flag, 1);
EXPECT_EQ(dst->ats_basic_info->ats_alpha_segment_flag[0], 1);
}
TEST_F(AtlasTest, BasicAtlasRoundtrip) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = BASIC_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_stream_id_present = 1;
basic.ats_atlas_width = 1920;
basic.ats_atlas_height = 1080;
basic.ats_num_atlas_segments_minus_1 = 0; // 1 segment
basic.ats_input_stream_id[0] = 0;
basic.ats_segment_top_left_pos_x[0] = 0;
basic.ats_segment_top_left_pos_y[0] = 0;
basic.ats_segment_width[0] = 1920;
basic.ats_segment_height[0] = 1080;
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
const int xlayer_id = 0;
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
ASSERT_TRUE(dst->valid);
EXPECT_EQ(dst->atlas_segment_mode_idc, BASIC_ATLAS);
EXPECT_EQ(dst->ats_basic_info->ats_stream_id_present, 1);
EXPECT_EQ(dst->ats_basic_info->ats_atlas_width, 1920);
EXPECT_EQ(dst->ats_basic_info->ats_atlas_height, 1080);
EXPECT_EQ(dst->ats_basic_info->ats_segment_width[0], 1920);
EXPECT_EQ(dst->ats_basic_info->ats_segment_height[0], 1080);
}
TEST_F(AtlasTest, LabelSegmentInfoRoundtrip) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = SINGLE_ATLAS;
src.ats_nominal_width_minus1 = 255;
src.ats_nominal_height_minus1 = 255;
src.ats_label_seg.ats_signalled_atlas_segment_ids_flag = 1;
src.ats_label_seg.ats_atlas_segment_id[0] = 42;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
const int xlayer_id = 0;
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
EXPECT_EQ(dst->ats_label_seg.ats_signalled_atlas_segment_ids_flag, 1);
EXPECT_EQ(dst->ats_label_seg.ats_atlas_segment_id[0], 42);
}
TEST_F(AtlasTest, EnhancedAtlasUniformRoundtrip) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = ENHANCED_ATLAS;
// 2x2 uniform region grid, each region 960x540
src.ats_reg_params.ats_num_region_columns_minus_1 = 1;
src.ats_reg_params.ats_num_region_rows_minus_1 = 1;
src.ats_reg_params.ats_uniform_spacing_flag = 1;
src.ats_reg_params.ats_region_width_minus_1 = 959;
src.ats_reg_params.ats_region_height_minus_1 = 539;
src.ats_reg_params.NumRegionsInAtlas = 4;
// Single region per segment → 4 segments
src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 1;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[0][0];
ASSERT_TRUE(dst->valid);
EXPECT_EQ(dst->atlas_segment_mode_idc, ENHANCED_ATLAS);
EXPECT_EQ(dst->ats_reg_params.ats_uniform_spacing_flag, 1);
EXPECT_EQ(dst->ats_reg_params.ats_region_width_minus_1, 959);
EXPECT_EQ(dst->ats_reg_params.ats_region_height_minus_1, 539);
EXPECT_EQ(dst->ats_reg_params.NumRegionsInAtlas, 4);
EXPECT_EQ(dst->ats_reg_seg_map.ats_single_region_per_atlas_segment_flag, 1);
EXPECT_EQ(dst->ats_reg_seg_map.ats_num_atlas_segments_minus_1, 3);
}
TEST_F(AtlasTest, EnhancedAtlasNonUniformRoundtrip) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = ENHANCED_ATLAS;
// 2 columns, 1 row, non-uniform: col widths 640 and 1280
src.ats_reg_params.ats_num_region_columns_minus_1 = 1;
src.ats_reg_params.ats_num_region_rows_minus_1 = 0;
src.ats_reg_params.ats_uniform_spacing_flag = 0;
src.ats_reg_params.ats_column_width_minus_1[0] = 639;
src.ats_reg_params.ats_column_width_minus_1[1] = 1279;
src.ats_reg_params.ats_row_height_minus_1[0] = 1079;
src.ats_reg_params.NumRegionsInAtlas = 2;
// Multi-region mapping: 1 segment spanning both regions
src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 0;
src.ats_reg_seg_map.ats_num_atlas_segments_minus_1 = 0;
src.ats_reg_seg_map.ats_top_left_region_column[0] = 0;
src.ats_reg_seg_map.ats_top_left_region_row[0] = 0;
src.ats_reg_seg_map.ats_bottom_right_region_column_offset[0] = 1;
src.ats_reg_seg_map.ats_bottom_right_region_row_offset[0] = 0;
// Derived values required by encoder assert
src.ats_reg_seg_map.ats_bottom_right_region_column[0] = 0 + 1;
src.ats_reg_seg_map.ats_bottom_right_region_row[0] = 0 + 0;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[0][0];
ASSERT_TRUE(dst->valid);
EXPECT_EQ(dst->ats_reg_params.ats_uniform_spacing_flag, 0);
EXPECT_EQ(dst->ats_reg_params.ats_column_width_minus_1[0], 639);
EXPECT_EQ(dst->ats_reg_params.ats_column_width_minus_1[1], 1279);
EXPECT_EQ(dst->ats_reg_params.ats_row_height_minus_1[0], 1079);
EXPECT_EQ(dst->ats_reg_seg_map.ats_single_region_per_atlas_segment_flag, 0);
EXPECT_EQ(dst->ats_reg_seg_map.ats_bottom_right_region_column[0], 1);
EXPECT_EQ(dst->ats_reg_seg_map.ats_bottom_right_region_row[0], 0);
}
TEST_F(AtlasTest, MultipleAtlasObus) {
// Write first Atlas OBU (segment_id = 1)
AtlasSegmentInfo src1;
memset(&src1, 0, sizeof(src1));
src1.valid = 1;
src1.atlas_segment_id = 1;
src1.atlas_segment_mode_idc = SINGLE_ATLAS;
src1.ats_nominal_width_minus1 = 1919;
src1.ats_nominal_height_minus1 = 1079;
uint32_t w1 = write_atlas_obu(&src1, buf_);
ASSERT_GT(w1, 0u);
// Write second Atlas OBU (segment_id = 2) after the first
AtlasSegmentInfo src2;
memset(&src2, 0, sizeof(src2));
src2.valid = 1;
src2.atlas_segment_id = 2;
src2.atlas_segment_mode_idc = SINGLE_ATLAS;
src2.ats_nominal_width_minus1 = 639;
src2.ats_nominal_height_minus1 = 479;
uint32_t w2 = write_atlas_obu(&src2, buf_ + w1);
ASSERT_GT(w2, 0u);
// Read first
struct avm_read_bit_buffer rb1 = { buf_, buf_ + w1, 0, nullptr,
rb_error_handler };
uint32_t r1 = av2_read_atlas_segment_info_obu(pbi_, 0, &rb1);
ASSERT_EQ(r1, w1);
// Read second
struct avm_read_bit_buffer rb2 = { buf_ + w1, buf_ + w1 + w2, 0, nullptr,
rb_error_handler };
uint32_t r2 = av2_read_atlas_segment_info_obu(pbi_, 0, &rb2);
ASSERT_EQ(r2, w2);
EXPECT_EQ(pbi_->atlas_counter[0], 2);
EXPECT_EQ(pbi_->atlas_list[0][0].atlas_segment_id, 1);
EXPECT_EQ(pbi_->atlas_list[0][0].ats_nominal_width_minus1, 1919);
EXPECT_EQ(pbi_->atlas_list[0][1].atlas_segment_id, 2);
EXPECT_EQ(pbi_->atlas_list[0][1].ats_nominal_width_minus1, 639);
}
TEST_F(AtlasTest, MultistreamSegmentCountSweep) {
const int seg_counts[] = { 1, 2, 4 };
for (int si = 0; si < 3; si++) {
int n = seg_counts[si];
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = MULTISTREAM_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_atlas_width = 1920 * n;
basic.ats_atlas_height = 1080;
basic.ats_num_atlas_segments_minus_1 = n - 1;
for (int i = 0; i < n; i++) {
basic.ats_input_stream_id[i] = i;
basic.ats_segment_top_left_pos_x[i] = 1920 * i;
basic.ats_segment_width[i] = 1920;
basic.ats_segment_height[i] = 1080;
}
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u) << "segments=" << n;
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written) << "segments=" << n;
const AtlasBasicInfo *db = pbi_->atlas_list[0][0].ats_basic_info;
ASSERT_NE(db, nullptr);
EXPECT_EQ(db->ats_num_atlas_segments_minus_1, n - 1);
for (int i = 0; i < n; i++) {
EXPECT_EQ(db->ats_input_stream_id[i], i);
}
}
}
TEST_F(AtlasTest, BasicAtlasNoStreamId) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = BASIC_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_stream_id_present = 0;
basic.ats_atlas_width = 1920;
basic.ats_atlas_height = 1080;
basic.ats_num_atlas_segments_minus_1 = 0;
basic.ats_segment_width[0] = 1920;
basic.ats_segment_height[0] = 1080;
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
EXPECT_EQ(pbi_->atlas_list[0][0].ats_basic_info->ats_stream_id_present, 0);
}
TEST_F(AtlasTest, MultistreamNoBackground) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = MULTISTREAM_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_atlas_width = 1920;
basic.ats_atlas_height = 1080;
basic.ats_num_atlas_segments_minus_1 = 0;
basic.ats_background_info_present_flag = 0;
basic.ats_input_stream_id[0] = 0;
basic.ats_segment_width[0] = 1920;
basic.ats_segment_height[0] = 1080;
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
EXPECT_EQ(
pbi_->atlas_list[0][0].ats_basic_info->ats_background_info_present_flag,
0);
}
TEST_F(AtlasTest, MultistreamAlphaNoAlpha) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = MULTISTREAM_ALPHA_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_atlas_width = 1920;
basic.ats_atlas_height = 1080;
basic.ats_num_atlas_segments_minus_1 = 0;
basic.ats_alpha_segments_present_flag = 0;
basic.ats_input_stream_id[0] = 0;
basic.ats_segment_width[0] = 1920;
basic.ats_segment_height[0] = 1080;
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
EXPECT_EQ(
pbi_->atlas_list[0][0].ats_basic_info->ats_alpha_segments_present_flag,
0);
}
TEST_F(AtlasTest, MultistreamAlphaWithBackground) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = MULTISTREAM_ALPHA_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_atlas_width = 1920;
basic.ats_atlas_height = 1080;
basic.ats_num_atlas_segments_minus_1 = 0;
basic.ats_alpha_segments_present_flag = 0;
basic.ats_background_info_present_flag = 1;
basic.ats_background_red_value = 255;
basic.ats_background_green_value = 128;
basic.ats_background_blue_value = 0;
basic.ats_input_stream_id[0] = 0;
basic.ats_segment_width[0] = 1920;
basic.ats_segment_height[0] = 1080;
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
const AtlasBasicInfo *db = pbi_->atlas_list[0][0].ats_basic_info;
EXPECT_EQ(db->ats_background_info_present_flag, 1);
EXPECT_EQ(db->ats_background_red_value, 255);
EXPECT_EQ(db->ats_background_green_value, 128);
EXPECT_EQ(db->ats_background_blue_value, 0);
}
// Covers num_region_rows >= 3 branch.
TEST_F(AtlasTest, EnhancedAtlasThreeRows) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = ENHANCED_ATLAS;
// 1 column × 3 rows, uniform
src.ats_reg_params.ats_num_region_columns_minus_1 = 0;
src.ats_reg_params.ats_num_region_rows_minus_1 = 2;
src.ats_reg_params.ats_uniform_spacing_flag = 1;
src.ats_reg_params.ats_region_width_minus_1 = 1919;
src.ats_reg_params.ats_region_height_minus_1 = 359;
src.ats_reg_params.NumRegionsInAtlas = 3;
src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 1;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
const AtlasSegmentInfo *dst = &pbi_->atlas_list[0][0];
EXPECT_EQ(dst->ats_reg_params.ats_num_region_rows_minus_1, 2);
EXPECT_EQ(dst->ats_reg_params.NumRegionsInAtlas, 3);
EXPECT_EQ(dst->ats_reg_seg_map.ats_num_atlas_segments_minus_1, 2);
}
TEST_F(AtlasTest, BasicAtlasSegmentCountSweep) {
const int seg_counts[] = { 2, 4, 8 };
for (int si = 0; si < 3; si++) {
int n = seg_counts[si];
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = BASIC_ATLAS;
AtlasBasicInfo basic;
memset(&basic, 0, sizeof(basic));
basic.ats_stream_id_present = 1;
basic.ats_atlas_width = 480 * n;
basic.ats_atlas_height = 270;
basic.ats_num_atlas_segments_minus_1 = n - 1;
for (int i = 0; i < n; i++) {
basic.ats_input_stream_id[i] = i;
basic.ats_segment_top_left_pos_x[i] = 480 * i;
basic.ats_segment_width[i] = 480;
basic.ats_segment_height[i] = 270;
}
src.ats_basic_info = &basic;
src.ats_basic_info_s = basic;
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u) << "segments=" << n;
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written) << "segments=" << n;
EXPECT_EQ(
pbi_->atlas_list[0][0].ats_basic_info->ats_num_atlas_segments_minus_1,
n - 1);
}
}
TEST_F(AtlasTest, DimensionExtremes) {
const int dims[] = { 0, 1, 65535 };
for (int di = 0; di < 3; di++) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = SINGLE_ATLAS;
src.ats_nominal_width_minus1 = dims[di];
src.ats_nominal_height_minus1 = dims[di];
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u) << "dim=" << dims[di];
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written) << "dim=" << dims[di];
EXPECT_EQ(pbi_->atlas_list[0][0].ats_nominal_width_minus1, dims[di]);
EXPECT_EQ(pbi_->atlas_list[0][0].ats_nominal_height_minus1, dims[di]);
}
}
TEST_F(AtlasTest, LabelSegmentIdRange) {
const int ids[] = { 0, 127, 255 };
for (int ii = 0; ii < 3; ii++) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = SINGLE_ATLAS;
src.ats_nominal_width_minus1 = 255;
src.ats_nominal_height_minus1 = 255;
src.ats_label_seg.ats_signalled_atlas_segment_ids_flag = 1;
src.ats_label_seg.ats_atlas_segment_id[0] = ids[ii];
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u) << "label_id=" << ids[ii];
memset(pbi_, 0, sizeof(*pbi_));
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written) << "label_id=" << ids[ii];
EXPECT_EQ(pbi_->atlas_list[0][0].ats_label_seg.ats_atlas_segment_id[0],
ids[ii]);
}
}
TEST_F(AtlasTest, EnhancedAtlas4x4) {
AtlasSegmentInfo src;
memset(&src, 0, sizeof(src));
src.valid = 1;
src.atlas_segment_id = 1;
src.atlas_segment_mode_idc = ENHANCED_ATLAS;
src.ats_reg_params.ats_num_region_columns_minus_1 = 3;
src.ats_reg_params.ats_num_region_rows_minus_1 = 3;
src.ats_reg_params.ats_uniform_spacing_flag = 1;
src.ats_reg_params.ats_region_width_minus_1 = 479;
src.ats_reg_params.ats_region_height_minus_1 = 269;
src.ats_reg_params.NumRegionsInAtlas = 16;
src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 1;
uint32_t written = write_atlas_obu(&src, buf_);
ASSERT_GT(written, 0u);
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
ASSERT_EQ(read, written);
EXPECT_EQ(pbi_->atlas_list[0][0].ats_reg_params.NumRegionsInAtlas, 16);
}
} // namespace