• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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