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/cli/proto_conversion/proto_to_obu/arbitrary_obu_generator.h"
13
14 #include <cstdint>
15 #include <list>
16 #include <optional>
17 #include <vector>
18
19 #include "absl/status/status.h"
20 #include "absl/status/status_matchers.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include "iamf/cli/proto/arbitrary_obu.pb.h"
24 #include "iamf/obu/arbitrary_obu.h"
25 #include "iamf/obu/obu_header.h"
26 #include "src/google/protobuf/repeated_ptr_field.h"
27 #include "src/google/protobuf/text_format.h"
28
29 namespace iamf_tools {
30 namespace {
31
32 using ::absl_testing::IsOk;
33
34 typedef ::google::protobuf::RepeatedPtrField<
35 iamf_tools_cli_proto::ArbitraryObuMetadata>
36 ArbitraryObuMetadatas;
37
38 constexpr int64_t kInsertionTick = 123;
39
FillArbitraryObu(iamf_tools_cli_proto::ArbitraryObuMetadata * arbitrary_obu_metadata)40 void FillArbitraryObu(
41 iamf_tools_cli_proto::ArbitraryObuMetadata* arbitrary_obu_metadata) {
42 ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
43 R"pb(
44 insertion_hook: INSERTION_HOOK_BEFORE_DESCRIPTORS
45 obu_type: OBU_IA_RESERVED_24
46 obu_header {
47 obu_redundant_copy: false
48 obu_trimming_status_flag: false
49 obu_extension_flag: false
50 }
51 payload: ""
52 )pb",
53 arbitrary_obu_metadata));
54 }
55
TEST(Generate,CopiesInsertionHookBeforeDescriptors)56 TEST(Generate, CopiesInsertionHookBeforeDescriptors) {
57 ArbitraryObuMetadatas arbitrary_obu_metadatas;
58 FillArbitraryObu(arbitrary_obu_metadatas.Add());
59 arbitrary_obu_metadatas.at(0).set_insertion_hook(
60 iamf_tools_cli_proto::INSERTION_HOOK_BEFORE_DESCRIPTORS);
61
62 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
63 std::list<ArbitraryObu> arbitrary_obus;
64 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
65
66 EXPECT_EQ(arbitrary_obus.front().insertion_hook_,
67 ArbitraryObu::kInsertionHookBeforeDescriptors);
68 EXPECT_EQ(arbitrary_obus.front().insertion_tick_, std::nullopt);
69 }
70
TEST(Generate,CopiesInsertionHookAfterDescriptors)71 TEST(Generate, CopiesInsertionHookAfterDescriptors) {
72 ArbitraryObuMetadatas arbitrary_obu_metadatas;
73 FillArbitraryObu(arbitrary_obu_metadatas.Add());
74 arbitrary_obu_metadatas.at(0).set_insertion_hook(
75 iamf_tools_cli_proto::INSERTION_HOOK_AFTER_DESCRIPTORS);
76
77 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
78 std::list<ArbitraryObu> arbitrary_obus;
79 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
80
81 EXPECT_EQ(arbitrary_obus.front().insertion_hook_,
82 ArbitraryObu::kInsertionHookAfterDescriptors);
83 EXPECT_EQ(arbitrary_obus.front().insertion_tick_, std::nullopt);
84 }
85
TEST(Generate,CopiesInsertionHookAfterCodecConfigs)86 TEST(Generate, CopiesInsertionHookAfterCodecConfigs) {
87 ArbitraryObuMetadatas arbitrary_obu_metadatas;
88 FillArbitraryObu(arbitrary_obu_metadatas.Add());
89 arbitrary_obu_metadatas.at(0).set_insertion_hook(
90 iamf_tools_cli_proto::INSERTION_HOOK_AFTER_CODEC_CONFIGS);
91
92 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
93 std::list<ArbitraryObu> arbitrary_obus;
94 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
95
96 EXPECT_EQ(arbitrary_obus.front().insertion_hook_,
97 ArbitraryObu::kInsertionHookAfterCodecConfigs);
98 EXPECT_EQ(arbitrary_obus.front().insertion_tick_, std::nullopt);
99 }
100
TEST(Generate,InsertionTickDefaultsToZeroForTimeBasedInsertionHooks)101 TEST(Generate, InsertionTickDefaultsToZeroForTimeBasedInsertionHooks) {
102 ArbitraryObuMetadatas arbitrary_obu_metadatas;
103 FillArbitraryObu(arbitrary_obu_metadatas.Add());
104 arbitrary_obu_metadatas.at(0).set_insertion_hook(
105 iamf_tools_cli_proto::INSERTION_HOOK_BEFORE_PARAMETER_BLOCKS_AT_TICK);
106
107 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
108 std::list<ArbitraryObu> arbitrary_obus;
109 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
110
111 EXPECT_EQ(arbitrary_obus.front().insertion_hook_,
112 ArbitraryObu::kInsertionHookBeforeParameterBlocksAtTick);
113 ASSERT_TRUE(arbitrary_obus.front().insertion_tick_.has_value());
114 EXPECT_EQ(arbitrary_obus.front().insertion_tick_, 0);
115 }
116
TEST(Generate,CopiesInsertionTickForTimeBasedInsertionHooks)117 TEST(Generate, CopiesInsertionTickForTimeBasedInsertionHooks) {
118 ArbitraryObuMetadatas arbitrary_obu_metadatas;
119 FillArbitraryObu(arbitrary_obu_metadatas.Add());
120 arbitrary_obu_metadatas.at(0).set_insertion_hook(
121 iamf_tools_cli_proto::INSERTION_HOOK_BEFORE_PARAMETER_BLOCKS_AT_TICK);
122 arbitrary_obu_metadatas.at(0).set_insertion_tick(kInsertionTick);
123
124 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
125 std::list<ArbitraryObu> arbitrary_obus;
126 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
127
128 EXPECT_EQ(arbitrary_obus.front().insertion_hook_,
129 ArbitraryObu::kInsertionHookBeforeParameterBlocksAtTick);
130 ASSERT_TRUE(arbitrary_obus.front().insertion_tick_.has_value());
131 EXPECT_EQ(arbitrary_obus.front().insertion_tick_, kInsertionTick);
132 }
133
TEST(Generate,CopiesInsertionHookAfterParameterBlocksAtTime)134 TEST(Generate, CopiesInsertionHookAfterParameterBlocksAtTime) {
135 ArbitraryObuMetadatas arbitrary_obu_metadatas;
136 FillArbitraryObu(arbitrary_obu_metadatas.Add());
137 arbitrary_obu_metadatas.at(0).set_insertion_hook(
138 iamf_tools_cli_proto::INSERTION_HOOK_AFTER_PARAMETER_BLOCKS_AT_TICK);
139 arbitrary_obu_metadatas.at(0).set_insertion_tick(kInsertionTick);
140
141 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
142 std::list<ArbitraryObu> arbitrary_obus;
143 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
144
145 EXPECT_EQ(arbitrary_obus.front().insertion_hook_,
146 ArbitraryObu::kInsertionHookAfterParameterBlocksAtTick);
147 ASSERT_TRUE(arbitrary_obus.front().insertion_tick_.has_value());
148 EXPECT_EQ(arbitrary_obus.front().insertion_tick_, kInsertionTick);
149 }
150
TEST(Generate,CopiesInsertionHookAfterAudioFramesAtTime)151 TEST(Generate, CopiesInsertionHookAfterAudioFramesAtTime) {
152 ArbitraryObuMetadatas arbitrary_obu_metadatas;
153 FillArbitraryObu(arbitrary_obu_metadatas.Add());
154 arbitrary_obu_metadatas.at(0).set_insertion_hook(
155 iamf_tools_cli_proto::INSERTION_HOOK_AFTER_AUDIO_FRAMES_AT_TICK);
156 arbitrary_obu_metadatas.at(0).set_insertion_tick(kInsertionTick);
157
158 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
159 std::list<ArbitraryObu> arbitrary_obus;
160 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
161
162 EXPECT_EQ(arbitrary_obus.front().insertion_hook_,
163 ArbitraryObu::kInsertionHookAfterAudioFramesAtTick);
164 ASSERT_TRUE(arbitrary_obus.front().insertion_tick_.has_value());
165 EXPECT_EQ(arbitrary_obus.front().insertion_tick_, kInsertionTick);
166 }
167
TEST(Generate,FailsOnInvalidInsertionHook)168 TEST(Generate, FailsOnInvalidInsertionHook) {
169 ArbitraryObuMetadatas arbitrary_obu_metadatas;
170 FillArbitraryObu(arbitrary_obu_metadatas.Add());
171 arbitrary_obu_metadatas.at(0).set_insertion_hook(
172 iamf_tools_cli_proto::INSERTION_HOOK_INVALID);
173
174 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
175 std::list<ArbitraryObu> arbitrary_obus;
176
177 EXPECT_FALSE(generator.Generate(arbitrary_obus).ok());
178 EXPECT_TRUE(arbitrary_obus.empty());
179 }
180
TEST(Generate,CopiesInvalidatesBitstreamFalse)181 TEST(Generate, CopiesInvalidatesBitstreamFalse) {
182 ArbitraryObuMetadatas arbitrary_obu_metadatas;
183 FillArbitraryObu(arbitrary_obu_metadatas.Add());
184 arbitrary_obu_metadatas.at(0).set_invalidates_bitstream(false);
185
186 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
187 std::list<ArbitraryObu> arbitrary_obus;
188 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
189
190 EXPECT_EQ(arbitrary_obus.front().invalidates_bitstream_, false);
191 }
192
TEST(Generate,CopiesInvalidatesBitstreamTrue)193 TEST(Generate, CopiesInvalidatesBitstreamTrue) {
194 ArbitraryObuMetadatas arbitrary_obu_metadatas;
195 FillArbitraryObu(arbitrary_obu_metadatas.Add());
196 arbitrary_obu_metadatas.at(0).set_invalidates_bitstream(true);
197
198 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
199 std::list<ArbitraryObu> arbitrary_obus;
200 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
201
202 EXPECT_EQ(arbitrary_obus.front().invalidates_bitstream_, true);
203 }
204
TEST(Generate,GeneratesEmptyListForEmptyInput)205 TEST(Generate, GeneratesEmptyListForEmptyInput) {
206 ArbitraryObuMetadatas arbitrary_obu_metadatas = {};
207
208 ArbitraryObuGenerator generator(arbitrary_obu_metadatas);
209 std::list<ArbitraryObu> arbitrary_obus;
210 EXPECT_THAT(generator.Generate(arbitrary_obus), IsOk());
211
212 EXPECT_TRUE(arbitrary_obus.empty());
213 }
214
215 class ArbitraryObuGeneratorTest : public testing::Test {
216 public:
ArbitraryObuGeneratorTest()217 ArbitraryObuGeneratorTest() {}
218
InitAndTestGenerateExpectOk()219 void InitAndTestGenerateExpectOk() {
220 // Generate the OBUs.
221 std::list<ArbitraryObu> output_obus;
222 ArbitraryObuGenerator generator(arbitrary_obu_metadata_);
223 EXPECT_THAT(generator.Generate(output_obus), IsOk());
224
225 EXPECT_EQ(output_obus, expected_obus_);
226 }
227
228 protected:
229 ArbitraryObuMetadatas arbitrary_obu_metadata_;
230
231 std::list<ArbitraryObu> expected_obus_;
232 };
233
TEST_F(ArbitraryObuGeneratorTest,ReservedObu)234 TEST_F(ArbitraryObuGeneratorTest, ReservedObu) {
235 ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
236 R"pb(
237 insertion_hook: INSERTION_HOOK_BEFORE_DESCRIPTORS
238 obu_type: OBU_IA_RESERVED_24
239 obu_header {
240 obu_redundant_copy: false
241 obu_trimming_status_flag: false
242 obu_extension_flag: false
243 }
244 payload: "abc"
245 )pb",
246 arbitrary_obu_metadata_.Add()));
247
248 expected_obus_.emplace_back(kObuIaReserved24, ObuHeader(),
249 std::vector<uint8_t>({'a', 'b', 'c'}),
250 ArbitraryObu::kInsertionHookBeforeDescriptors);
251 InitAndTestGenerateExpectOk();
252 }
253
TEST_F(ArbitraryObuGeneratorTest,ObuWithExtensionHeader)254 TEST_F(ArbitraryObuGeneratorTest, ObuWithExtensionHeader) {
255 ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
256 R"pb(
257 insertion_hook: INSERTION_HOOK_AFTER_DESCRIPTORS
258 obu_type: OBU_IA_SEQUENCE_HEADER
259 obu_header {
260 obu_redundant_copy: false
261 obu_trimming_status_flag: false
262 obu_extension_flag: true
263 extension_header_size: 5
264 extension_header_bytes: "extra"
265 }
266 payload: "iamf\x00\x00"
267 )pb",
268 arbitrary_obu_metadata_.Add()));
269
270 expected_obus_.emplace_back(
271 kObuIaSequenceHeader,
272 ObuHeader{.obu_extension_flag = true,
273 .extension_header_size = 5,
274 .extension_header_bytes = {'e', 'x', 't', 'r', 'a'}},
275 std::vector<uint8_t>({'i', 'a', 'm', 'f', '\0', '\0'}),
276 ArbitraryObu::kInsertionHookAfterDescriptors);
277 InitAndTestGenerateExpectOk();
278 }
279
TEST_F(ArbitraryObuGeneratorTest,InvalidObuType)280 TEST_F(ArbitraryObuGeneratorTest, InvalidObuType) {
281 ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
282 R"pb(
283 insertion_hook: INSERTION_HOOK_AFTER_DESCRIPTORS
284 obu_type: OBU_IA_INVALID
285 obu_header {
286 obu_redundant_copy: false
287 obu_trimming_status_flag: false
288 obu_extension_flag: false
289 }
290 payload: ""
291 )pb",
292 arbitrary_obu_metadata_.Add()));
293 std::list<ArbitraryObu> output_obus;
294 ArbitraryObuGenerator generator(arbitrary_obu_metadata_);
295
296 EXPECT_FALSE(generator.Generate(output_obus).ok());
297 }
298
299 } // namespace
300 } // namespace iamf_tools
301