1 /*
2 * Copyright (c) 2023, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12 #include "iamf/obu/audio_frame.h"
13
14 #include <cstdint>
15 #include <limits>
16 #include <memory>
17 #include <numeric>
18 #include <vector>
19
20 #include "absl/status/status.h"
21 #include "absl/status/status_matchers.h"
22 #include "absl/types/span.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "iamf/common/leb_generator.h"
26 #include "iamf/common/read_bit_buffer.h"
27 #include "iamf/common/write_bit_buffer.h"
28 #include "iamf/obu/obu_header.h"
29 #include "iamf/obu/tests/obu_test_base.h"
30 #include "iamf/obu/types.h"
31
32 namespace iamf_tools {
33 namespace {
34
35 using ::absl_testing::IsOk;
36
TEST(AudioFrameConstructor,SetsImplicitObuType0)37 TEST(AudioFrameConstructor, SetsImplicitObuType0) {
38 AudioFrameObu obu({}, /*audio_substream_id=*/0, {});
39 EXPECT_EQ(obu.header_.obu_type, kObuIaAudioFrameId0);
40 }
41
TEST(AudioFrameConstructor,SetsImplicitObuType17)42 TEST(AudioFrameConstructor, SetsImplicitObuType17) {
43 AudioFrameObu obu({}, /*audio_substream_id=*/17, {});
44 EXPECT_EQ(obu.header_.obu_type, kObuIaAudioFrameId17);
45 }
46
TEST(AudioFrameConstructor,SetsExplicitObuType)47 TEST(AudioFrameConstructor, SetsExplicitObuType) {
48 AudioFrameObu obu({}, /*audio_substream_id=*/18, {});
49 EXPECT_EQ(obu.header_.obu_type, kObuIaAudioFrame);
50 }
51
52 class AudioFrameObuTest : public ObuTestBase, public testing::Test {
53 public:
AudioFrameObuTest()54 AudioFrameObuTest()
55 : ObuTestBase(
56 /*expected_header=*/{kObuIaAudioFrameId0 << 3, 1},
57 /*expected_payload=*/{42}),
58 audio_substream_id_(0),
59 audio_frame_({42}) {}
60
61 ~AudioFrameObuTest() override = default;
62
63 protected:
InitExpectOk()64 void InitExpectOk() override {
65 obu_ = std::make_unique<AudioFrameObu>(header_, audio_substream_id_,
66 audio_frame_);
67 }
68
WriteObuExpectOk(WriteBitBuffer & wb)69 void WriteObuExpectOk(WriteBitBuffer& wb) override {
70 EXPECT_THAT(obu_->ValidateAndWriteObu(wb), IsOk());
71 }
72
73 DecodedUleb128 audio_substream_id_;
74 std::vector<uint8_t> audio_frame_;
75
76 std::unique_ptr<AudioFrameObu> obu_;
77 };
78
TEST_F(AudioFrameObuTest,DefaultImplicitMinSubstreamId)79 TEST_F(AudioFrameObuTest, DefaultImplicitMinSubstreamId) {
80 InitAndTestWrite();
81 EXPECT_EQ(obu_->GetSubstreamId(), 0);
82 }
83
TEST_F(AudioFrameObuTest,ImplicitSubstreamIdEdge)84 TEST_F(AudioFrameObuTest, ImplicitSubstreamIdEdge) {
85 audio_substream_id_ = 17;
86
87 expected_header_ = {kObuIaAudioFrameId17 << 3, 1};
88 InitAndTestWrite();
89 EXPECT_EQ(obu_->GetSubstreamId(), 17);
90 }
91
TEST_F(AudioFrameObuTest,ExplicitSubstreamIdEdge)92 TEST_F(AudioFrameObuTest, ExplicitSubstreamIdEdge) {
93 audio_substream_id_ = 18;
94
95 expected_header_ = {kObuIaAudioFrame << 3, 2},
96 expected_payload_ = {// `explicit_audio_substream_id`
97 18,
98 // `audio_frame`.
99 42};
100 InitAndTestWrite();
101 EXPECT_EQ(obu_->GetSubstreamId(), 18);
102 }
103
TEST_F(AudioFrameObuTest,MaximumSubstreamId)104 TEST_F(AudioFrameObuTest, MaximumSubstreamId) {
105 audio_substream_id_ = std::numeric_limits<DecodedUleb128>::max();
106
107 expected_header_ = {kObuIaAudioFrame << 3, 6},
108 expected_payload_ = {// `explicit_audio_substream_id`
109 0xff, 0xff, 0xff, 0xff, 0x0f,
110 // `audio_frame`.
111 42};
112 InitAndTestWrite();
113 EXPECT_EQ(obu_->GetSubstreamId(), std::numeric_limits<uint32_t>::max());
114 }
115
TEST_F(AudioFrameObuTest,NonMinimalLebGeneratorAffectsAllLeb128s)116 TEST_F(AudioFrameObuTest, NonMinimalLebGeneratorAffectsAllLeb128s) {
117 leb_generator_ =
118 LebGenerator::Create(LebGenerator::GenerationMode::kFixedSize, 8);
119 audio_substream_id_ = 128;
120
121 expected_header_ = {kObuIaAudioFrame << 3,
122 0x80 | 9,
123 0x80,
124 0x80,
125 0x80,
126 0x80,
127 0x80,
128 0x80,
129 0x00},
130 expected_payload_ = {// `explicit_audio_substream_id`
131 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
132 // `audio_frame`.
133 42};
134 InitAndTestWrite();
135 EXPECT_EQ(obu_->GetSubstreamId(), 128);
136 }
137
TEST_F(AudioFrameObuTest,AudioFrameEmpty)138 TEST_F(AudioFrameObuTest, AudioFrameEmpty) {
139 audio_frame_ = {};
140
141 expected_header_ = {kObuIaAudioFrameId0 << 3, 0};
142 expected_payload_ = {};
143 InitAndTestWrite();
144 }
145
TEST_F(AudioFrameObuTest,VaryMostLegalFields)146 TEST_F(AudioFrameObuTest, VaryMostLegalFields) {
147 header_ = ObuHeader{.obu_redundant_copy = false,
148 .obu_trimming_status_flag = true,
149 .obu_extension_flag = true,
150 .num_samples_to_trim_at_end = 128,
151 .num_samples_to_trim_at_start = 256,
152 .extension_header_size = 3,
153 .extension_header_bytes = {'a', 'b', 'c'}};
154 leb_generator_ =
155 LebGenerator::Create(LebGenerator::GenerationMode::kFixedSize, 5);
156 audio_substream_id_ = 512;
157 audio_frame_ = {255, 254, 253, 252, 251, 250};
158
159 expected_header_ = {kObuIaAudioFrame << 3 | kObuTrimmingStatusFlagBitMask |
160 kObuExtensionFlagBitMask,
161 // `obu_size`.
162 0x80 | 29, 0x80, 0x80, 0x80, 0x00,
163 // `num_samples_to_trim_at_end`.
164 0x80, 0x81, 0x80, 0x80, 0x00,
165 // `num_samples_to_trim_at_start`.
166 0x80, 0x82, 0x80, 0x80, 0x00,
167 // `extension_header_size`.
168 0x80 | 3, 0x80, 0x80, 0x80, 0x00,
169 // `extension_header_bytes`.
170 'a', 'b', 'c'};
171 expected_payload_ = {// `explicit_audio_substream_id`
172 0x80, 0x84, 0x80, 0x80, 0x00,
173 // `audio_frame`.
174 255, 254, 253, 252, 251, 250};
175
176 InitAndTestWrite();
177
178 EXPECT_EQ(obu_->GetSubstreamId(), 512);
179 }
180
TEST_F(AudioFrameObuTest,AudioFrameMultipleBytes)181 TEST_F(AudioFrameObuTest, AudioFrameMultipleBytes) {
182 audio_frame_ = {1, 2, 3, 4, 5};
183
184 expected_header_ = {kObuIaAudioFrameId0 << 3, 5},
185 expected_payload_ = {// `audio_frame`.
186 1, 2, 3, 4, 5};
187 InitAndTestWrite();
188 }
189
TEST_F(AudioFrameObuTest,AudioFrameLarge)190 TEST_F(AudioFrameObuTest, AudioFrameLarge) {
191 audio_frame_.resize(16385);
192 std::iota(audio_frame_.begin(), audio_frame_.end(), 1);
193
194 expected_header_ = {kObuIaAudioFrameId0 << 3, 0x81, 0x80, 0x01},
195 expected_payload_ = audio_frame_;
196 InitAndTestWrite();
197 }
198
TEST_F(AudioFrameObuTest,ObuTrimmingStatusFlagAtEnd)199 TEST_F(AudioFrameObuTest, ObuTrimmingStatusFlagAtEnd) {
200 header_.obu_trimming_status_flag = 1;
201 header_.num_samples_to_trim_at_end = 1;
202 header_.num_samples_to_trim_at_start = 0;
203
204 expected_header_ =
205 {// `obu_type` (5), `obu_redundant_copy` (1), `obu_trimming_status_flag`
206 // (1), `obu_extension_flag` (1)
207 (kObuIaAudioFrameId0 << 3) | kObuTrimmingStatusFlagBitMask,
208 // `obu_size`
209 3,
210 // `num_samples_to_trim_at_end`.
211 1,
212 // `num_samples_to_trim_at_start`.
213 0},
214 InitAndTestWrite();
215 }
216
TEST_F(AudioFrameObuTest,ObuTrimmingStatusFlagNumSamplesMaximum)217 TEST_F(AudioFrameObuTest, ObuTrimmingStatusFlagNumSamplesMaximum) {
218 header_.obu_trimming_status_flag = 1;
219 header_.num_samples_to_trim_at_end = std::numeric_limits<uint32_t>::max();
220 header_.num_samples_to_trim_at_start = std::numeric_limits<uint32_t>::max();
221
222 expected_header_ =
223 {// `obu_type` (5), `obu_redundant_copy` (1), `obu_trimming_status_flag`
224 // (1), `obu_extension_flag` (1)
225 (kObuIaAudioFrameId0 << 3) | kObuTrimmingStatusFlagBitMask,
226 // `obu_size`
227 11,
228 // `num_samples_to_trim_at_end`.
229 0xff, 0xff, 0xff, 0xff, 0x0f,
230 // `num_samples_to_trim_at_start`.
231 0xff, 0xff, 0xff, 0xff, 0x0f},
232 InitAndTestWrite();
233 }
234
TEST_F(AudioFrameObuTest,ObuTrimmingStatusFlagAtStart)235 TEST_F(AudioFrameObuTest, ObuTrimmingStatusFlagAtStart) {
236 header_.obu_trimming_status_flag = 1;
237 header_.num_samples_to_trim_at_end = 0;
238 header_.num_samples_to_trim_at_start = 1;
239
240 expected_header_ =
241 {// `obu_type` (5), `obu_redundant_copy` (1), `obu_trimming_status_flag`
242 // (1), `obu_extension_flag` (1)
243 (kObuIaAudioFrameId0 << 3) | kObuTrimmingStatusFlagBitMask,
244 // `obu_size`
245 3,
246 // `num_samples_to_trim_at_end`.
247 0,
248 // `num_samples_to_trim_at_start`.
249 1},
250 InitAndTestWrite();
251 }
252
TEST_F(AudioFrameObuTest,ObuTrimmingStatusFlagBothStartAndEnd)253 TEST_F(AudioFrameObuTest, ObuTrimmingStatusFlagBothStartAndEnd) {
254 header_.obu_trimming_status_flag = 1;
255 header_.num_samples_to_trim_at_end = 1;
256 header_.num_samples_to_trim_at_start = 1;
257
258 expected_header_ =
259 {// `obu_type` (5), `obu_redundant_copy` (1), `obu_trimming_status_flag`
260 // (1), `obu_extension_flag` (1)
261 (kObuIaAudioFrameId0 << 3) | kObuTrimmingStatusFlagBitMask,
262 // `obu_size`
263 3,
264 // `num_samples_to_trim_at_end`.
265 1,
266 // `num_samples_to_trim_at_start`.
267 1},
268 InitAndTestWrite();
269 }
270
TEST_F(AudioFrameObuTest,ExtensionHeader)271 TEST_F(AudioFrameObuTest, ExtensionHeader) {
272 header_.obu_extension_flag = 1;
273 header_.extension_header_size = 5;
274 header_.extension_header_bytes = {'e', 'x', 't', 'r', 'a'};
275
276 expected_header_ = {kObuIaAudioFrameId0 << 3 | kObuExtensionFlagBitMask,
277 // `obu_size`.
278 7,
279 // `extension_header_size`.
280 5,
281 // `extension_header_bytes`.
282 'e', 'x', 't', 'r', 'a'};
283 InitAndTestWrite();
284 }
285
TEST_F(AudioFrameObuTest,ValidateAndWriteObuFailsWithIllegalRedundantCopy)286 TEST_F(AudioFrameObuTest, ValidateAndWriteObuFailsWithIllegalRedundantCopy) {
287 header_.obu_redundant_copy = 1;
288
289 InitExpectOk();
290 WriteBitBuffer unused_wb(0);
291 EXPECT_FALSE(obu_->ValidateAndWriteObu(unused_wb).ok());
292 }
293
294 // --- Begin CreateFromBuffer tests ---
TEST(CreateFromBuffer,ValidAudioFrameWithExplicitId)295 TEST(CreateFromBuffer, ValidAudioFrameWithExplicitId) {
296 std::vector<uint8_t> source = {// `explicit_audio_substream_id`, arbitrary.
297 18,
298 // `audio_frame`, arbitrary values.
299 8, 6, 24, 55, 11};
300 auto buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
301 1024, absl::MakeConstSpan(source));
302 ObuHeader header = {.obu_type = kObuIaAudioFrame}; // Requires explicit ID.
303 const int64_t obu_payload_size = 6;
304 auto obu = AudioFrameObu::CreateFromBuffer(header, obu_payload_size, *buffer);
305 EXPECT_THAT(obu, IsOk());
306 EXPECT_EQ(obu->GetSubstreamId(), 18);
307 EXPECT_EQ(obu->audio_frame_, std::vector<uint8_t>({8, 6, 24, 55, 11}));
308 }
309
TEST(CreateFromBuffer,ValidAudioFrameWithImplicitId)310 TEST(CreateFromBuffer, ValidAudioFrameWithImplicitId) {
311 std::vector<uint8_t> source = {// `audio_frame`, arbitrary values.
312 8, 6, 24, 55, 11};
313 auto buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
314 1024, absl::MakeConstSpan(source));
315 ObuHeader header = {.obu_type = kObuIaAudioFrameId0}; // ID from OBU type.
316 int64_t obu_payload_size = 5;
317 auto obu = AudioFrameObu::CreateFromBuffer(header, obu_payload_size, *buffer);
318 EXPECT_THAT(obu, IsOk());
319 // audio_substream_id is set implicitly to the value of `obu_type`
320 AudioFrameObu expected_obu =
321 AudioFrameObu(header, /*audio_substream_id=*/0,
322 /*audio_frame=*/{8, 6, 24, 55, 11});
323 EXPECT_EQ(obu->GetSubstreamId(), 0);
324 EXPECT_EQ(obu->audio_frame_, std::vector<uint8_t>({8, 6, 24, 55, 11}));
325 }
326
TEST(CreateFromBuffer,FailsWithPayloadSizeTooLarge)327 TEST(CreateFromBuffer, FailsWithPayloadSizeTooLarge) {
328 std::vector<uint8_t> source = {// `explicit_audio_substream_id`, arbitrary.
329 18,
330 // `audio_frame`, arbitrary values.
331 8, 6, 24, 55, 11};
332 auto buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
333 1024, absl::MakeConstSpan(source));
334 ObuHeader header = {.obu_type = kObuIaAudioFrame}; // Requires explicit ID.
335 int64_t obu_payload_size = 7;
336 auto obu = AudioFrameObu::CreateFromBuffer(header, obu_payload_size, *buffer);
337 EXPECT_FALSE(obu.ok());
338 }
339
TEST(CreateFromBuffer,FailsWithPayloadSizeZero)340 TEST(CreateFromBuffer, FailsWithPayloadSizeZero) {
341 // With one byte used by the substream ID, a payload size of 0 is not valid.
342 std::vector<uint8_t> source = {// `explicit_audio_substream_id`, arbitrary.
343 18,
344 // `audio_frame`, arbitrary values.
345 8, 6, 24, 55, 11};
346 auto buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
347 1024, absl::MakeConstSpan(source));
348 ObuHeader header = {.obu_type = kObuIaAudioFrame}; // Requires explicit ID.
349 int64_t obu_payload_size = 0;
350 auto obu = AudioFrameObu::CreateFromBuffer(header, obu_payload_size, *buffer);
351 EXPECT_FALSE(obu.ok());
352 }
353
TEST(CreateFromBuffer,FailsWithPayloadSizeLessThanSizeUsedById)354 TEST(CreateFromBuffer, FailsWithPayloadSizeLessThanSizeUsedById) {
355 // With three bytes used by the ID, a payload size of 2 is not valid.
356 std::vector<uint8_t> source = {
357 0x80, 0x80, 0x1, // `explicit_audio_substream_id`, 3 byte ULEB.
358 8, 6, 24, 55, 11}; // `audio_frame`, arbitrary values.
359 auto buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
360 1024, absl::MakeConstSpan(source));
361 ObuHeader header = {.obu_type = kObuIaAudioFrame}; // Requires explicit ID.
362 int64_t obu_payload_size = 2; // Less than the 3 used for the ID.
363 auto obu = AudioFrameObu::CreateFromBuffer(header, obu_payload_size, *buffer);
364 EXPECT_FALSE(obu.ok());
365 }
366
TEST(CreateFromBuffer,FailsWithNegativePayloadSize)367 TEST(CreateFromBuffer, FailsWithNegativePayloadSize) {
368 std::vector<uint8_t> source = {// `audio_frame`, arbitrary values.
369 8, 6, 24, 55, 11};
370 auto buffer = MemoryBasedReadBitBuffer::CreateFromSpan(
371 1024, absl::MakeConstSpan(source));
372 ObuHeader header = {.obu_type = kObuIaAudioFrameId0}; // ID from OBU type.
373 int64_t obu_payload_size = -1;
374 auto obu = AudioFrameObu::CreateFromBuffer(header, obu_payload_size, *buffer);
375 EXPECT_FALSE(obu.ok());
376 }
377
378 } // namespace
379 } // namespace iamf_tools
380