blob: d604b2a8111258663313a2f40bf02473c5dbc273 [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/brt_syntax.h"
#include "av2/decoder/decoder.h"
#include "av2/decoder/decodeframe.h"
extern "C" {
#include "av2/decoder/obu.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;
}
static uint32_t write_brt_obu(const BufferRemovalTimingInfo *brt,
uint8_t *dst) {
struct avm_write_bit_buffer wb = { dst, 0 };
av2_write_brt_info(brt, &wb);
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 BrtTest : 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(BrtTest, NonOpsDependent) {
BufferRemovalTimingInfo src;
memset(&src, 0, sizeof(src));
src.br_ops_dependent_flag = 0;
src.br_time = 42;
uint32_t written = write_brt_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_buffer_removal_timing_obu(pbi_, &rb, 0);
ASSERT_EQ(read, written);
EXPECT_EQ(pbi_->common.brt_info.br_ops_dependent_flag, 0);
EXPECT_EQ(pbi_->common.brt_info.br_time, 42);
}
TEST_F(BrtTest, OpsDependentWithModel) {
BufferRemovalTimingInfo src;
memset(&src, 0, sizeof(src));
src.br_ops_dependent_flag = 1;
src.br_ops_id = 2;
src.br_ops_cnt[2] = 3;
src.br_decoder_model_present_op_flag[2][0] = 1;
src.br_time_op[2][0] = 100;
src.br_decoder_model_present_op_flag[2][1] = 0;
src.br_decoder_model_present_op_flag[2][2] = 1;
src.br_time_op[2][2] = 200;
// Pre-populate matching OPS in decoder state for conformance check.
pbi_->ops_list[0][2].valid = 1;
pbi_->ops_list[0][2].ops_id = 2;
pbi_->ops_list[0][2].ops_cnt = 3;
uint32_t written = write_brt_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_buffer_removal_timing_obu(pbi_, &rb, 0);
ASSERT_EQ(read, written);
const BufferRemovalTimingInfo *dst = &pbi_->common.brt_info;
EXPECT_EQ(dst->br_ops_dependent_flag, 1);
EXPECT_EQ(dst->br_ops_id, 2);
EXPECT_EQ(dst->br_ops_cnt[2], 3);
EXPECT_EQ(dst->br_decoder_model_present_op_flag[2][0], 1);
EXPECT_EQ(dst->br_time_op[2][0], 100);
EXPECT_EQ(dst->br_decoder_model_present_op_flag[2][1], 0);
EXPECT_EQ(dst->br_decoder_model_present_op_flag[2][2], 1);
EXPECT_EQ(dst->br_time_op[2][2], 200);
}
TEST_F(BrtTest, OpsDependentNoModel) {
BufferRemovalTimingInfo src;
memset(&src, 0, sizeof(src));
src.br_ops_dependent_flag = 1;
src.br_ops_id = 0;
src.br_ops_cnt[0] = 2;
// All decoder_model_present flags = 0
pbi_->ops_list[0][0].valid = 1;
pbi_->ops_list[0][0].ops_id = 0;
pbi_->ops_list[0][0].ops_cnt = 2;
uint32_t written = write_brt_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_buffer_removal_timing_obu(pbi_, &rb, 0);
ASSERT_EQ(read, written);
EXPECT_EQ(pbi_->common.brt_info.br_ops_dependent_flag, 1);
EXPECT_EQ(pbi_->common.brt_info.br_ops_cnt[0], 2);
EXPECT_EQ(pbi_->common.brt_info.br_decoder_model_present_op_flag[0][0], 0);
EXPECT_EQ(pbi_->common.brt_info.br_decoder_model_present_op_flag[0][1], 0);
}
TEST_F(BrtTest, BrTimeRiceGolombSweep) {
const int values[] = { 0, 1, 5, 16, 100 };
for (int vi = 0; vi < 5; vi++) {
BufferRemovalTimingInfo src;
memset(&src, 0, sizeof(src));
src.br_ops_dependent_flag = 0;
src.br_time = values[vi];
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_brt_obu(&src, buf_);
ASSERT_GT(written, 0u) << "val=" << values[vi];
memset(&pbi_->common.brt_info, 0, sizeof(pbi_->common.brt_info));
pbi_->common.error.error_code = AVM_CODEC_OK;
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_buffer_removal_timing_obu(pbi_, &rb, 0);
ASSERT_EQ(read, written) << "val=" << values[vi];
EXPECT_EQ(pbi_->common.brt_info.br_time, values[vi]);
}
}
TEST_F(BrtTest, OpsIdBoundarySweep) {
const int ids[] = { 0, 7, 15 };
for (int ii = 0; ii < 3; ii++) {
BufferRemovalTimingInfo src;
memset(&src, 0, sizeof(src));
src.br_ops_dependent_flag = 1;
src.br_ops_id = ids[ii];
src.br_ops_cnt[ids[ii]] = 1;
memset(pbi_, 0, sizeof(*pbi_));
pbi_->ops_list[0][ids[ii]].valid = 1;
pbi_->ops_list[0][ids[ii]].ops_id = ids[ii];
pbi_->ops_list[0][ids[ii]].ops_cnt = 1;
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_brt_obu(&src, buf_);
ASSERT_GT(written, 0u) << "id=" << ids[ii];
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_buffer_removal_timing_obu(pbi_, &rb, 0);
ASSERT_EQ(read, written) << "id=" << ids[ii];
EXPECT_EQ(pbi_->common.brt_info.br_ops_id, ids[ii]);
}
}
TEST_F(BrtTest, OpsCntSweep) {
const int counts[] = { 1, 3, 7 };
for (int ci = 0; ci < 3; ci++) {
BufferRemovalTimingInfo src;
memset(&src, 0, sizeof(src));
src.br_ops_dependent_flag = 1;
src.br_ops_id = 0;
src.br_ops_cnt[0] = counts[ci];
memset(pbi_, 0, sizeof(*pbi_));
pbi_->ops_list[0][0].valid = 1;
pbi_->ops_list[0][0].ops_id = 0;
pbi_->ops_list[0][0].ops_cnt = counts[ci];
memset(buf_, 0, sizeof(buf_));
uint32_t written = write_brt_obu(&src, buf_);
ASSERT_GT(written, 0u) << "cnt=" << counts[ci];
struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
rb_error_handler };
uint32_t read = av2_read_buffer_removal_timing_obu(pbi_, &rb, 0);
ASSERT_EQ(read, written) << "cnt=" << counts[ci];
EXPECT_EQ(pbi_->common.brt_info.br_ops_cnt[0], counts[ci]);
}
}
} // namespace