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
13 #include "iamf/cli/renderer/renderer_utils.h"
14
15 #include <cstddef>
16 #include <vector>
17
18 #include "absl/status/status_matchers.h"
19 #include "absl/types/span.h"
20 #include "gmock/gmock.h"
21 #include "gtest/gtest.h"
22 #include "iamf/cli/channel_label.h"
23 #include "iamf/cli/demixing_module.h"
24 #include "iamf/obu/mix_presentation.h"
25 #include "iamf/obu/types.h"
26
27 namespace iamf_tools {
28 namespace renderer_utils {
29 namespace {
30
31 using ::absl_testing::IsOk;
32 using enum ChannelLabel::Label;
33 using testing::DoubleEq;
34 using testing::Pointwise;
35
36 constexpr size_t kNumSamplesPerFrame = 8;
37
TEST(ArrangeSamplesToRender,SucceedsOnEmptyFrame)38 TEST(ArrangeSamplesToRender, SucceedsOnEmptyFrame) {
39 std::vector<std::vector<InternalSampleType>> samples(
40 kNumSamplesPerFrame, std::vector<InternalSampleType>(0));
41 size_t num_valid_samples = 0;
42 EXPECT_THAT(ArrangeSamplesToRender({}, {}, samples, num_valid_samples),
43 IsOk());
44
45 // `samples` remains the same size, but `num_valid_samples` is zero.
46 EXPECT_EQ(samples.size(), kNumSamplesPerFrame);
47 EXPECT_EQ(num_valid_samples, 0);
48 }
49
TEST(ArrangeSamplesToRender,ArrangesSamplesInTimeChannelAxes)50 TEST(ArrangeSamplesToRender, ArrangesSamplesInTimeChannelAxes) {
51 const LabeledFrame kStereoLabeledFrame = {
52 .label_to_samples = {{kL2, {0, 1, 2}}, {kR2, {10, 11, 12}}}};
53 const std::vector<ChannelLabel::Label> kStereoArrangement = {kL2, kR2};
54
55 std::vector<std::vector<InternalSampleType>> samples(
56 kNumSamplesPerFrame,
57 std::vector<InternalSampleType>(kStereoArrangement.size()));
58 size_t num_valid_samples = 0;
59 EXPECT_THAT(ArrangeSamplesToRender(kStereoLabeledFrame, kStereoArrangement,
60 samples, num_valid_samples),
61 IsOk());
62 EXPECT_THAT(absl::MakeConstSpan(samples).first(num_valid_samples),
63 testing::ElementsAreArray({Pointwise(DoubleEq(), {0.0, 10.0}),
64 Pointwise(DoubleEq(), {1.0, 11.0}),
65 Pointwise(DoubleEq(), {2.0, 12.0})}));
66 }
67
TEST(ArrangeSamplesToRender,FindsDemixedLabels)68 TEST(ArrangeSamplesToRender, FindsDemixedLabels) {
69 const LabeledFrame kDemixedTwoLayerStereoFrame = {
70 .label_to_samples = {{kMono, {75}}, {kL2, {50}}, {kDemixedR2, {100}}}};
71 const std::vector<ChannelLabel::Label> kStereoArrangement = {kL2, kR2};
72
73 std::vector<std::vector<InternalSampleType>> samples(
74 kNumSamplesPerFrame,
75 std::vector<InternalSampleType>(kStereoArrangement.size()));
76 size_t num_valid_samples = 0;
77 EXPECT_THAT(
78 ArrangeSamplesToRender(kDemixedTwoLayerStereoFrame, kStereoArrangement,
79 samples, num_valid_samples),
80 IsOk());
81 EXPECT_THAT(
82 absl::MakeConstSpan(samples).first(num_valid_samples),
83 testing::ElementsAreArray({Pointwise(DoubleEq(), {50.0, 100.0})}));
84 }
85
TEST(ArrangeSamplesToRender,IgnoresExtraLabels)86 TEST(ArrangeSamplesToRender, IgnoresExtraLabels) {
87 const LabeledFrame kStereoLabeledFrameWithExtraLabel = {
88 .label_to_samples = {{kL2, {0}}, {kR2, {10}}, {kLFE, {999}}}};
89 const std::vector<ChannelLabel::Label> kStereoArrangement = {kL2, kR2};
90
91 std::vector<std::vector<InternalSampleType>> samples(
92 kNumSamplesPerFrame,
93 std::vector<InternalSampleType>(kStereoArrangement.size()));
94 size_t num_valid_samples = 0;
95 EXPECT_THAT(
96 ArrangeSamplesToRender(kStereoLabeledFrameWithExtraLabel,
97 kStereoArrangement, samples, num_valid_samples),
98 IsOk());
99 EXPECT_THAT(absl::MakeConstSpan(samples).first(num_valid_samples),
100 testing::ElementsAreArray({Pointwise(DoubleEq(), {0.0, 10.0})}));
101 }
102
TEST(ArrangeSamplesToRender,LeavesOmittedLabelsZeroForMixedOrderAmbisonics)103 TEST(ArrangeSamplesToRender, LeavesOmittedLabelsZeroForMixedOrderAmbisonics) {
104 const LabeledFrame kMixedFirstOrderAmbisonicsFrame = {
105 .label_to_samples = {
106 {kA0, {1, 2}}, {kA2, {201, 202}}, {kA3, {301, 302}}}};
107 const std::vector<ChannelLabel::Label> kMixedFirstOrderAmbisonicsArrangement =
108 {kA0, kOmitted, kA2, kA3};
109
110 std::vector<std::vector<InternalSampleType>> samples(
111 kNumSamplesPerFrame, std::vector<InternalSampleType>(
112 kMixedFirstOrderAmbisonicsArrangement.size()));
113 size_t num_valid_samples = 0;
114 EXPECT_THAT(ArrangeSamplesToRender(kMixedFirstOrderAmbisonicsFrame,
115 kMixedFirstOrderAmbisonicsArrangement,
116 samples, num_valid_samples),
117 IsOk());
118 EXPECT_THAT(absl::MakeConstSpan(samples).first(num_valid_samples),
119 testing::ElementsAreArray(
120 {Pointwise(DoubleEq(), {1.0, 0.0, 201.0, 301.0}),
121 Pointwise(DoubleEq(), {2.0, 0.0, 202.0, 302.0})}));
122 }
123
TEST(ArrangeSamplesToRender,LeavesOmittedLabelsZeroForChannelBasedLayout)124 TEST(ArrangeSamplesToRender, LeavesOmittedLabelsZeroForChannelBasedLayout) {
125 const LabeledFrame kLFEOnlyFrame = {.label_to_samples = {{kLFE, {1, 2}}}};
126 const std::vector<ChannelLabel::Label> kLFEAsSecondChannelArrangement = {
127 kOmitted, kOmitted, kLFE, kOmitted};
128
129 std::vector<std::vector<InternalSampleType>> samples(
130 kNumSamplesPerFrame,
131 std::vector<InternalSampleType>(kLFEAsSecondChannelArrangement.size()));
132 size_t num_valid_samples = 0;
133 EXPECT_THAT(
134 ArrangeSamplesToRender(kLFEOnlyFrame, kLFEAsSecondChannelArrangement,
135 samples, num_valid_samples),
136 IsOk());
137 EXPECT_THAT(
138 absl::MakeConstSpan(samples).first(num_valid_samples),
139 testing::ElementsAreArray({Pointwise(DoubleEq(), {0.0, 0.0, 1.0, 0.0}),
140 Pointwise(DoubleEq(), {0.0, 0.0, 2.0, 0.0})}));
141 }
142
TEST(ArrangeSamplesToRender,ExcludesSamplesToBeTrimmed)143 TEST(ArrangeSamplesToRender, ExcludesSamplesToBeTrimmed) {
144 const LabeledFrame kMonoLabeledFrameWithSamplesToTrim = {
145 .samples_to_trim_at_end = 2,
146 .samples_to_trim_at_start = 1,
147 .label_to_samples = {{kMono, {999, 100, 999, 999}}}};
148 const std::vector<ChannelLabel::Label> kMonoArrangement = {kMono};
149
150 std::vector<std::vector<InternalSampleType>> samples(
151 kNumSamplesPerFrame,
152 std::vector<InternalSampleType>(kMonoArrangement.size()));
153 size_t num_valid_samples = 0;
154 EXPECT_THAT(
155 ArrangeSamplesToRender(kMonoLabeledFrameWithSamplesToTrim,
156 kMonoArrangement, samples, num_valid_samples),
157 IsOk());
158 EXPECT_THAT(absl::MakeConstSpan(samples).first(num_valid_samples),
159 testing::ElementsAreArray({Pointwise(DoubleEq(), {100.0})}));
160 }
161
TEST(ArrangeSamplesToRender,OverwritesInputVector)162 TEST(ArrangeSamplesToRender, OverwritesInputVector) {
163 const LabeledFrame kMonoLabeledFrame = {
164 .label_to_samples = {{kMono, {1, 2}}}};
165 const std::vector<ChannelLabel::Label> kMonoArrangement = {kMono};
166
167 std::vector<std::vector<InternalSampleType>> samples = {{999}, {999}};
168 size_t num_valid_samples = 0;
169 EXPECT_THAT(ArrangeSamplesToRender(kMonoLabeledFrame, kMonoArrangement,
170 samples, num_valid_samples),
171 IsOk());
172 EXPECT_THAT(absl::MakeConstSpan(samples).first(num_valid_samples),
173 testing::ElementsAreArray({Pointwise(DoubleEq(), {1.0}),
174 Pointwise(DoubleEq(), {2.0})}));
175 }
176
TEST(ArrangeSamplesToRender,TrimmingAllFramesFromStartIsResultsInEmptyOutput)177 TEST(ArrangeSamplesToRender, TrimmingAllFramesFromStartIsResultsInEmptyOutput) {
178 const LabeledFrame kMonoLabeledFrameWithSamplesToTrim = {
179 .samples_to_trim_at_end = 0,
180 .samples_to_trim_at_start = 4,
181 .label_to_samples = {{kMono, {999, 999, 999, 999}}}};
182 const std::vector<ChannelLabel::Label> kMonoArrangement = {kMono};
183
184 std::vector<std::vector<InternalSampleType>> samples(
185 kNumSamplesPerFrame,
186 std::vector<InternalSampleType>(kMonoArrangement.size()));
187 size_t num_valid_samples = 0;
188 EXPECT_THAT(
189 ArrangeSamplesToRender(kMonoLabeledFrameWithSamplesToTrim,
190 kMonoArrangement, samples, num_valid_samples),
191 IsOk());
192 EXPECT_TRUE(absl::MakeConstSpan(samples).first(num_valid_samples).empty());
193 }
194
TEST(ArrangeSamplesToRender,InvalidWhenRequestedLabelsHaveDifferentNumberOfSamples)195 TEST(ArrangeSamplesToRender,
196 InvalidWhenRequestedLabelsHaveDifferentNumberOfSamples) {
197 const LabeledFrame kStereoLabeledFrameWithMissingSample = {
198 .label_to_samples = {{kL2, {0, 1}}, {kR2, {10}}}};
199 const std::vector<ChannelLabel::Label> kStereoArrangement = {kL2, kR2};
200
201 std::vector<std::vector<InternalSampleType>> samples(
202 kNumSamplesPerFrame,
203 std::vector<InternalSampleType>(kStereoArrangement.size()));
204 size_t num_valid_samples = 0;
205 EXPECT_FALSE(ArrangeSamplesToRender(kStereoLabeledFrameWithMissingSample,
206 kStereoArrangement, samples,
207 num_valid_samples)
208 .ok());
209 }
210
TEST(ArrangeSamplesToRender,InvalidWhenTrimIsImplausible)211 TEST(ArrangeSamplesToRender, InvalidWhenTrimIsImplausible) {
212 const LabeledFrame kFrameWithExcessSamplesTrimmed = {
213 .samples_to_trim_at_end = 1,
214 .samples_to_trim_at_start = 2,
215 .label_to_samples = {{kL2, {0, 1}}, {kR2, {10, 11}}}};
216 const std::vector<ChannelLabel::Label> kStereoArrangement = {kL2, kR2};
217
218 std::vector<std::vector<InternalSampleType>> samples(
219 kNumSamplesPerFrame,
220 std::vector<InternalSampleType>(kStereoArrangement.size()));
221 size_t num_valid_samples = 0;
222 EXPECT_FALSE(ArrangeSamplesToRender(kFrameWithExcessSamplesTrimmed,
223 kStereoArrangement, samples,
224 num_valid_samples)
225 .ok());
226 }
227
TEST(ArrangeSamplesToRender,InvalidMissingLabel)228 TEST(ArrangeSamplesToRender, InvalidMissingLabel) {
229 const LabeledFrame kStereoLabeledFrame = {
230 .label_to_samples = {{kL2, {0}}, {kR2, {10}}}};
231 const std::vector<ChannelLabel::Label> kMonoArrangement = {kMono};
232
233 std::vector<std::vector<InternalSampleType>> unused_samples(
234 kNumSamplesPerFrame,
235 std::vector<InternalSampleType>(kMonoArrangement.size()));
236 size_t num_valid_samples = 0;
237 EXPECT_FALSE(ArrangeSamplesToRender(kStereoLabeledFrame, kMonoArrangement,
238 unused_samples, num_valid_samples)
239 .ok());
240 }
241
TEST(LookupOutputKeyFromPlaybackLayout,SucceedsForChannelBasedLayout)242 TEST(LookupOutputKeyFromPlaybackLayout, SucceedsForChannelBasedLayout) {
243 EXPECT_THAT(
244 LookupOutputKeyFromPlaybackLayout(
245 {.layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
246 .specific_layout =
247 LoudspeakersSsConventionLayout{
248 .sound_system =
249 LoudspeakersSsConventionLayout::kSoundSystemA_0_2_0}}),
250 IsOk());
251 }
252
TEST(LookupOutputKeyFromPlaybackLayout,SucceedsFor9_1_6)253 TEST(LookupOutputKeyFromPlaybackLayout, SucceedsFor9_1_6) {
254 EXPECT_THAT(
255 LookupOutputKeyFromPlaybackLayout(
256 {.layout_type = Layout::kLayoutTypeLoudspeakersSsConvention,
257 .specific_layout =
258 LoudspeakersSsConventionLayout{
259 .sound_system =
260 LoudspeakersSsConventionLayout::kSoundSystem13_6_9_0}}),
261 IsOk());
262 }
TEST(LookupOutputKeyFromPlaybackLayout,FailsOnBinauralBasedLayout)263 TEST(LookupOutputKeyFromPlaybackLayout, FailsOnBinauralBasedLayout) {
264 EXPECT_FALSE(LookupOutputKeyFromPlaybackLayout(
265 {.layout_type = Layout::kLayoutTypeBinaural,
266 .specific_layout = LoudspeakersReservedOrBinauralLayout{}})
267 .ok());
268 }
269
TEST(LookupOutputKeyFromPlaybackLayout,FailsOnReservedLayout)270 TEST(LookupOutputKeyFromPlaybackLayout, FailsOnReservedLayout) {
271 EXPECT_FALSE(LookupOutputKeyFromPlaybackLayout(
272 {.layout_type = Layout::kLayoutTypeReserved0,
273 .specific_layout = LoudspeakersReservedOrBinauralLayout{}})
274 .ok());
275 }
276
277 } // namespace
278 } // namespace renderer_utils
279 } // namespace iamf_tools
280