• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024, 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/wav_sample_provider.h"
13 
14 #include <array>
15 #include <cstdint>
16 #include <filesystem>
17 #include <string>
18 
19 // [internal] Placeholder for get runfiles header.
20 #include "absl/container/flat_hash_map.h"
21 #include "absl/status/status_matchers.h"
22 #include "absl/strings/string_view.h"
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "iamf/cli/audio_element_with_data.h"
26 #include "iamf/cli/channel_label.h"
27 #include "iamf/cli/demixing_module.h"
28 #include "iamf/cli/proto/audio_element.pb.h"
29 #include "iamf/cli/proto/audio_frame.pb.h"
30 #include "iamf/cli/proto/user_metadata.pb.h"
31 #include "iamf/cli/tests/cli_test_utils.h"
32 #include "iamf/cli/user_metadata_builder/iamf_input_layout.h"
33 #include "iamf/obu/codec_config.h"
34 #include "iamf/obu/types.h"
35 #include "src/google/protobuf/text_format.h"
36 
37 namespace iamf_tools {
38 namespace {
39 
40 using ::absl_testing::IsOk;
41 using enum ChannelLabel::Label;
42 using testing::Pointwise;
43 
44 constexpr DecodedUleb128 kAudioElementId = 300;
45 constexpr DecodedUleb128 kSubstreamId = 0;
46 constexpr DecodedUleb128 kCodecConfigId = 200;
47 constexpr uint32_t kSampleRate = 48000;
48 
49 constexpr bool kUseChannelMetadatas = true;
50 constexpr bool kUseDeprecatedChannelLabels = false;
51 
52 constexpr auto kExpectedSamplesL2 = std::to_array<InternalSampleType>(
53     {1 << 16, 2 << 16, 3 << 16, 4 << 16, 5 << 16, 6 << 16, 7 << 16, 8 << 16});
54 constexpr auto kExpectedSamplesR2 =
55     std::to_array({65535 << 16, 65534 << 16, 65533 << 16, 65532 << 16,
56                    65531 << 16, 65530 << 16, 65529 << 16, 65528 << 16});
57 
58 using iamf_tools_cli_proto::AudioFrameObuMetadata;
59 
FillChannelMetadata(AudioFrameObuMetadata & audio_frame_metadata)60 void FillChannelMetadata(AudioFrameObuMetadata& audio_frame_metadata) {
61   using enum iamf_tools_cli_proto::ChannelLabel;
62   auto* channel_metadata = audio_frame_metadata.add_channel_metadatas();
63   channel_metadata->set_channel_id(0);
64   channel_metadata->set_channel_label(CHANNEL_LABEL_L_2);
65   channel_metadata = audio_frame_metadata.add_channel_metadatas();
66   channel_metadata->set_channel_id(1);
67   channel_metadata->set_channel_label(CHANNEL_LABEL_R_2);
68 }
69 
FillDeprecatedChannelLabels(AudioFrameObuMetadata & audio_frame_metadata)70 void FillDeprecatedChannelLabels(AudioFrameObuMetadata& audio_frame_metadata) {
71   audio_frame_metadata.add_channel_ids(0);
72   audio_frame_metadata.add_channel_labels("L2");
73   audio_frame_metadata.add_channel_ids(1);
74   audio_frame_metadata.add_channel_labels("R2");
75 }
76 
FillStereoDataForAudioElementId(bool use_channel_metadatas,uint32_t audio_element_id,AudioFrameObuMetadata & audio_frame_metadata)77 void FillStereoDataForAudioElementId(
78     bool use_channel_metadatas, uint32_t audio_element_id,
79     AudioFrameObuMetadata& audio_frame_metadata) {
80   ASSERT_TRUE(google::protobuf::TextFormat::ParseFromString(
81       R"pb(
82         wav_filename: "stereo_8_samples_48khz_s16le.wav"
83         samples_to_trim_at_end: 0
84         samples_to_trim_at_start: 0
85       )pb",
86       &audio_frame_metadata));
87   audio_frame_metadata.set_audio_element_id(audio_element_id);
88   if (use_channel_metadatas) {
89     FillChannelMetadata(audio_frame_metadata);
90   } else {
91     FillDeprecatedChannelLabels(audio_frame_metadata);
92   }
93 }
94 
InitializeTestData(bool use_channel_metadatas,const uint32_t sample_rate,iamf_tools_cli_proto::UserMetadata & user_metadata,absl::flat_hash_map<DecodedUleb128,AudioElementWithData> & audio_elements)95 void InitializeTestData(
96     bool use_channel_metadatas, const uint32_t sample_rate,
97     iamf_tools_cli_proto::UserMetadata& user_metadata,
98     absl::flat_hash_map<DecodedUleb128, AudioElementWithData>& audio_elements) {
99   FillStereoDataForAudioElementId(use_channel_metadatas, kAudioElementId,
100                                   *user_metadata.add_audio_frame_metadata());
101   static absl::flat_hash_map<uint32_t, CodecConfigObu> codec_config_obus;
102   codec_config_obus.clear();
103   AddLpcmCodecConfigWithIdAndSampleRate(kCodecConfigId, sample_rate,
104                                         codec_config_obus);
105   AddScalableAudioElementWithSubstreamIds(
106       IamfInputLayout::kStereo, kAudioElementId, kCodecConfigId, {kSubstreamId},
107       codec_config_obus, audio_elements);
108 }
109 
GetInputWavDir()110 std::string GetInputWavDir() {
111   static const auto input_wav_dir =
112       (std::filesystem::current_path() / std::string("iamf/cli/testdata"))
113           .string();
114   return input_wav_dir;
115 }
116 
TEST(Create,SucceedsForStereoInputWithChannelMetadatas)117 TEST(Create, SucceedsForStereoInputWithChannelMetadatas) {
118   iamf_tools_cli_proto::UserMetadata user_metadata;
119   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
120   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
121                      audio_elements);
122 
123   EXPECT_THAT(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
124                                         GetInputWavDir(), audio_elements),
125               IsOk());
126 }
127 
TEST(Create,SucceedsForStereoInputWithDeprecatedChannelLabels)128 TEST(Create, SucceedsForStereoInputWithDeprecatedChannelLabels) {
129   iamf_tools_cli_proto::UserMetadata user_metadata;
130   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
131   InitializeTestData(kUseDeprecatedChannelLabels, kSampleRate, user_metadata,
132                      audio_elements);
133 
134   EXPECT_THAT(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
135                                         GetInputWavDir(), audio_elements),
136               IsOk());
137 }
138 
TEST(Create,FailsWhenMixingChannelIdsAndChannelMetadatas)139 TEST(Create, FailsWhenMixingChannelIdsAndChannelMetadatas) {
140   iamf_tools_cli_proto::UserMetadata user_metadata;
141   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
142   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
143                      audio_elements);
144   // Forbid any state where the new and old styles are mixed.
145   FillDeprecatedChannelLabels(*user_metadata.mutable_audio_frame_metadata(0));
146 
147   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
148                                          GetInputWavDir(), audio_elements)
149                    .ok());
150 }
151 
TEST(Create,FailsWhenUserMetadataContainsDuplicateAudioElementIds)152 TEST(Create, FailsWhenUserMetadataContainsDuplicateAudioElementIds) {
153   iamf_tools_cli_proto::UserMetadata user_metadata;
154   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
155   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
156                      audio_elements);
157   FillStereoDataForAudioElementId(kUseChannelMetadatas, kAudioElementId,
158                                   *user_metadata.add_audio_frame_metadata());
159 
160   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
161                                          GetInputWavDir(), audio_elements)
162                    .ok());
163 }
164 
TEST(Create,FailsWhenMatchingAudioElementObuIsMissing)165 TEST(Create, FailsWhenMatchingAudioElementObuIsMissing) {
166   iamf_tools_cli_proto::UserMetadata user_metadata;
167   const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>
168       kNoAudioElements = {};
169   FillStereoDataForAudioElementId(kUseChannelMetadatas, kAudioElementId,
170                                   *user_metadata.add_audio_frame_metadata());
171 
172   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
173                                          GetInputWavDir(), kNoAudioElements)
174                    .ok());
175 }
176 
TEST(Create,FailsWhenCodecConfigIsMissing)177 TEST(Create, FailsWhenCodecConfigIsMissing) {
178   iamf_tools_cli_proto::UserMetadata user_metadata;
179   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
180   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
181                      audio_elements);
182 
183   // Corrupt the audio element by clearing the codec config pointer.
184   ASSERT_TRUE(audio_elements.contains(kAudioElementId));
185   audio_elements.at(kAudioElementId).codec_config = nullptr;
186 
187   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
188                                          GetInputWavDir(), audio_elements)
189                    .ok());
190 }
191 
TEST(Create,FailsForUnknownLabels)192 TEST(Create, FailsForUnknownLabels) {
193   constexpr absl::string_view kUnknownLabel = "unknown_label";
194   iamf_tools_cli_proto::UserMetadata user_metadata;
195   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
196   InitializeTestData(kUseDeprecatedChannelLabels, kSampleRate, user_metadata,
197                      audio_elements);
198   user_metadata.mutable_audio_frame_metadata(0)->set_channel_labels(
199       0, kUnknownLabel);
200 
201   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
202                                          GetInputWavDir(), audio_elements)
203                    .ok());
204 }
205 
TEST(Create,SucceedsForDuplicateDeprecatedChannelIds)206 TEST(Create, SucceedsForDuplicateDeprecatedChannelIds) {
207   constexpr uint32_t kDuplicateChannelId = 0;
208   iamf_tools_cli_proto::UserMetadata user_metadata;
209   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
210   InitializeTestData(kUseDeprecatedChannelLabels, kSampleRate, user_metadata,
211                      audio_elements);
212   user_metadata.mutable_audio_frame_metadata(0)->set_channel_ids(
213       0, kDuplicateChannelId);
214   user_metadata.mutable_audio_frame_metadata(0)->set_channel_ids(
215       1, kDuplicateChannelId);
216 
217   EXPECT_THAT(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
218                                         GetInputWavDir(), audio_elements),
219               IsOk());
220 }
221 
TEST(Create,SucceedsForDuplicateChannelMetadatasChannelIds)222 TEST(Create, SucceedsForDuplicateChannelMetadatasChannelIds) {
223   constexpr uint32_t kDuplicateChannelId = 0;
224   iamf_tools_cli_proto::UserMetadata user_metadata;
225   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
226   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
227                      audio_elements);
228   user_metadata.mutable_audio_frame_metadata(0)
229       ->mutable_channel_metadatas(0)
230       ->set_channel_id(kDuplicateChannelId);
231   user_metadata.mutable_audio_frame_metadata(0)
232       ->mutable_channel_metadatas(1)
233       ->set_channel_id(kDuplicateChannelId);
234 
235   EXPECT_THAT(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
236                                         GetInputWavDir(), audio_elements),
237               IsOk());
238 }
239 
TEST(Create,FailsForDuplicateDeprecatedChannelLabels)240 TEST(Create, FailsForDuplicateDeprecatedChannelLabels) {
241   constexpr absl::string_view kDuplicateLabel = "L2";
242   iamf_tools_cli_proto::UserMetadata user_metadata;
243   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
244   InitializeTestData(kUseDeprecatedChannelLabels, kSampleRate, user_metadata,
245                      audio_elements);
246   user_metadata.mutable_audio_frame_metadata(0)->set_channel_labels(
247       0, kDuplicateLabel);
248   user_metadata.mutable_audio_frame_metadata(0)->set_channel_labels(
249       1, kDuplicateLabel);
250 
251   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
252                                          GetInputWavDir(), audio_elements)
253                    .ok());
254 }
255 
TEST(Create,FailsForDuplicateChannelMetadatasChannelLabels)256 TEST(Create, FailsForDuplicateChannelMetadatasChannelLabels) {
257   constexpr auto kDuplicateLabel = iamf_tools_cli_proto::CHANNEL_LABEL_L_2;
258   iamf_tools_cli_proto::UserMetadata user_metadata;
259   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
260   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
261                      audio_elements);
262   user_metadata.mutable_audio_frame_metadata(0)
263       ->mutable_channel_metadatas(0)
264       ->set_channel_label(kDuplicateLabel);
265   user_metadata.mutable_audio_frame_metadata(0)
266       ->mutable_channel_metadatas(1)
267       ->set_channel_label(kDuplicateLabel);
268 
269   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
270                                          GetInputWavDir(), audio_elements)
271                    .ok());
272 }
273 
TEST(Create,FailsForDeprecatedChannelIdTooLarge)274 TEST(Create, FailsForDeprecatedChannelIdTooLarge) {
275   iamf_tools_cli_proto::UserMetadata user_metadata;
276   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
277   InitializeTestData(kUseDeprecatedChannelLabels, kSampleRate, user_metadata,
278                      audio_elements);
279   // Channel IDs are indexed from zero; a stereo wav file must not have a
280   // channel ID greater than 1.
281   constexpr auto kFirstChannelIndex = 0;
282   constexpr uint32_t kChannelIdTooLargeForStereoWavFile = 2;
283   user_metadata.mutable_audio_frame_metadata(0)->mutable_channel_ids()->Set(
284       kFirstChannelIndex, kChannelIdTooLargeForStereoWavFile);
285 
286   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
287                                          GetInputWavDir(), audio_elements)
288                    .ok());
289 }
290 
TEST(Create,FailsForChannelMetadataChannelIdTooLarge)291 TEST(Create, FailsForChannelMetadataChannelIdTooLarge) {
292   iamf_tools_cli_proto::UserMetadata user_metadata;
293   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
294   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
295                      audio_elements);
296   // Channel IDs are indexed from zero; a stereo wav file must not have a
297   // channel ID greater than 1.
298   constexpr auto kFirstChannelIndex = 0;
299   constexpr uint32_t kChannelIdTooLargeForStereoWavFile = 2;
300   user_metadata.mutable_audio_frame_metadata(0)
301       ->mutable_channel_metadatas(kFirstChannelIndex)
302       ->set_channel_id(kChannelIdTooLargeForStereoWavFile);
303 
304   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
305                                          GetInputWavDir(), audio_elements)
306                    .ok());
307 }
308 
TEST(Create,FailsForDifferentSizedDeprecatedChannelIdsAndChannelLabels)309 TEST(Create, FailsForDifferentSizedDeprecatedChannelIdsAndChannelLabels) {
310   iamf_tools_cli_proto::UserMetadata user_metadata;
311   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
312   InitializeTestData(kUseDeprecatedChannelLabels, kSampleRate, user_metadata,
313                      audio_elements);
314 
315   // Add one extra channel label, which does not have a corresponding
316   // channel ID, causing the `Create()` to fail.
317   user_metadata.mutable_audio_frame_metadata(0)->add_channel_labels("C");
318 
319   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
320                                          GetInputWavDir(), audio_elements)
321                    .ok());
322 }
323 
TEST(Create,FailsForBitDepthLowerThanFile)324 TEST(Create, FailsForBitDepthLowerThanFile) {
325   iamf_tools_cli_proto::UserMetadata user_metadata;
326   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
327   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
328                      audio_elements);
329 
330   // Try to load a 24-bit WAV file with a codec config whose bit depth is 16.
331   // The `Initialize()` would refuse to lower the bit depth and fail.
332   user_metadata.mutable_audio_frame_metadata(0)->set_wav_filename(
333       "stereo_8_samples_48khz_s24le.wav");
334   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
335                                          GetInputWavDir(), audio_elements)
336                    .ok());
337 }
338 
TEST(Create,FailsForMismatchingSampleRates)339 TEST(Create, FailsForMismatchingSampleRates) {
340   iamf_tools_cli_proto::UserMetadata user_metadata;
341   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
342 
343   // Set the sample rate of the codec config to a different one than the WAV
344   // file, causing the `Initialize()` to fail.
345   const uint32_t kWrongSampleRate = 16000;
346   InitializeTestData(kUseChannelMetadatas, kWrongSampleRate, user_metadata,
347                      audio_elements);
348 
349   EXPECT_FALSE(WavSampleProvider::Create(user_metadata.audio_frame_metadata(),
350                                          GetInputWavDir(), audio_elements)
351                    .ok());
352 }
353 
ReadOneFrameExpectFinished(WavSampleProvider & wav_sample_provider,LabelSamplesMap & labeled_samples)354 void ReadOneFrameExpectFinished(WavSampleProvider& wav_sample_provider,
355                                 LabelSamplesMap& labeled_samples) {
356   bool finished_reading = false;
357   EXPECT_THAT(wav_sample_provider.ReadFrames(kAudioElementId, labeled_samples,
358                                              finished_reading),
359               IsOk());
360   EXPECT_TRUE(finished_reading);
361 }
362 
TEST(WavSampleProviderTest,ReadFrameSucceedsWithDeprecatedChannelLabels)363 TEST(WavSampleProviderTest, ReadFrameSucceedsWithDeprecatedChannelLabels) {
364   iamf_tools_cli_proto::UserMetadata user_metadata;
365   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
366   InitializeTestData(kUseDeprecatedChannelLabels, kSampleRate, user_metadata,
367                      audio_elements);
368   auto wav_sample_provider = WavSampleProvider::Create(
369       user_metadata.audio_frame_metadata(), GetInputWavDir(), audio_elements);
370   ASSERT_THAT(wav_sample_provider, IsOk());
371 
372   LabelSamplesMap labeled_samples;
373   ReadOneFrameExpectFinished(*wav_sample_provider, labeled_samples);
374 
375   // Validate samples read from the WAV file.
376   EXPECT_THAT(
377       labeled_samples[kL2],
378       Pointwise(InternalSampleMatchesIntegralSample(), kExpectedSamplesL2));
379   EXPECT_THAT(
380       labeled_samples[kR2],
381       Pointwise(InternalSampleMatchesIntegralSample(), kExpectedSamplesR2));
382 }
383 
TEST(WavSampleProviderTest,ReadFrameSucceedsWithChannelMetadatas)384 TEST(WavSampleProviderTest, ReadFrameSucceedsWithChannelMetadatas) {
385   iamf_tools_cli_proto::UserMetadata user_metadata;
386   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
387   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
388                      audio_elements);
389 
390   auto wav_sample_provider = WavSampleProvider::Create(
391       user_metadata.audio_frame_metadata(), GetInputWavDir(), audio_elements);
392   ASSERT_THAT(wav_sample_provider, IsOk());
393 
394   LabelSamplesMap labeled_samples;
395   ReadOneFrameExpectFinished(*wav_sample_provider, labeled_samples);
396 
397   // Validate samples read from the WAV file.
398   EXPECT_THAT(
399       labeled_samples[kL2],
400       Pointwise(InternalSampleMatchesIntegralSample(), kExpectedSamplesL2));
401   EXPECT_THAT(
402       labeled_samples[kR2],
403       Pointwise(InternalSampleMatchesIntegralSample(), kExpectedSamplesR2));
404 }
405 
TEST(WavSampleProviderTest,ReadFrameFailsWithWrongAudioElementId)406 TEST(WavSampleProviderTest, ReadFrameFailsWithWrongAudioElementId) {
407   iamf_tools_cli_proto::UserMetadata user_metadata;
408   absl::flat_hash_map<DecodedUleb128, AudioElementWithData> audio_elements;
409   InitializeTestData(kUseChannelMetadatas, kSampleRate, user_metadata,
410                      audio_elements);
411 
412   auto wav_sample_provider = WavSampleProvider::Create(
413       user_metadata.audio_frame_metadata(), GetInputWavDir(), audio_elements);
414   ASSERT_THAT(wav_sample_provider, IsOk());
415 
416   // Try to read frames using a wrong Audio Element ID.
417   const auto kWrongAudioElementId = kAudioElementId + 99;
418   LabelSamplesMap labeled_samples;
419   bool finished_reading = false;
420   EXPECT_FALSE(
421       wav_sample_provider
422           ->ReadFrames(kWrongAudioElementId, labeled_samples, finished_reading)
423           .ok());
424 }
425 
426 }  // namespace
427 }  // namespace iamf_tools
428