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/demixing_module.h"
13
14 #include <algorithm>
15 #include <climits>
16 #include <cmath>
17 #include <cstddef>
18 #include <cstdint>
19 #include <list>
20 #include <utility>
21 #include <variant>
22 #include <vector>
23
24 #include "absl/container/flat_hash_map.h"
25 #include "absl/container/flat_hash_set.h"
26 #include "absl/log/check.h"
27 #include "absl/log/log.h"
28 #include "absl/status/status.h"
29 #include "absl/status/statusor.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/string_view.h"
32 #include "iamf/cli/audio_element_with_data.h"
33 #include "iamf/cli/audio_frame_decoder.h"
34 #include "iamf/cli/audio_frame_with_data.h"
35 #include "iamf/cli/channel_label.h"
36 #include "iamf/cli/cli_util.h"
37 #include "iamf/common/utils/macros.h"
38 #include "iamf/common/utils/numeric_utils.h"
39 #include "iamf/obu/audio_element.h"
40 #include "iamf/obu/audio_frame.h"
41 #include "iamf/obu/demixing_info_parameter_data.h"
42 #include "iamf/obu/types.h"
43
44 namespace iamf_tools {
45
46 namespace {
47
48 using enum ChannelLabel::Label;
49
50 using DemixingMetadataForAudioElementId =
51 DemixingModule::DemixingMetadataForAudioElementId;
52
S7ToS5DownMixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)53 absl::Status S7ToS5DownMixer(const DownMixingParams& down_mixing_params,
54 LabelSamplesMap& label_to_samples) {
55 LOG_FIRST_N(INFO, 1) << "S7 to S5";
56
57 // Check input to perform this down-mixing exist.
58 if (label_to_samples.find(kL7) == label_to_samples.end() ||
59 label_to_samples.find(kR7) == label_to_samples.end() ||
60 label_to_samples.find(kLss7) == label_to_samples.end() ||
61 label_to_samples.find(kLrs7) == label_to_samples.end() ||
62 label_to_samples.find(kRss7) == label_to_samples.end() ||
63 label_to_samples.find(kRrs7) == label_to_samples.end()) {
64 return absl::InvalidArgumentError("Missing some input channels");
65 }
66
67 const auto& l7_samples = label_to_samples[kL7];
68 const auto& lss7_samples = label_to_samples[kLss7];
69 const auto& lrs7_samples = label_to_samples[kLrs7];
70 const auto& r7_samples = label_to_samples[kR7];
71 const auto& rss7_samples = label_to_samples[kRss7];
72 const auto& rrs7_samples = label_to_samples[kRrs7];
73
74 auto& l5_samples = label_to_samples[kL5];
75 auto& r5_samples = label_to_samples[kR5];
76 auto& ls5_samples = label_to_samples[kLs5];
77 auto& rs5_samples = label_to_samples[kRs5];
78
79 // Directly copy L7/R7 to L5/R5, because they are the same.
80 l5_samples = l7_samples;
81 r5_samples = r7_samples;
82
83 // Handle Ls5 and Rs5.
84 ls5_samples.resize(lss7_samples.size());
85 rs5_samples.resize(rss7_samples.size());
86 for (int i = 0; i < ls5_samples.size(); i++) {
87 ls5_samples[i] = down_mixing_params.alpha * lss7_samples[i] +
88 down_mixing_params.beta * lrs7_samples[i];
89 rs5_samples[i] = down_mixing_params.alpha * rss7_samples[i] +
90 down_mixing_params.beta * rrs7_samples[i];
91 }
92
93 return absl::OkStatus();
94 }
95
S5ToS7Demixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)96 absl::Status S5ToS7Demixer(const DownMixingParams& down_mixing_params,
97 LabelSamplesMap& label_to_samples) {
98 LOG_FIRST_N(INFO, 1) << "S5 to S7";
99
100 const std::vector<InternalSampleType>* l5_samples;
101 const std::vector<InternalSampleType>* ls5_samples;
102 const std::vector<InternalSampleType>* lss7_samples;
103 const std::vector<InternalSampleType>* r5_samples;
104 const std::vector<InternalSampleType>* rs5_samples;
105 const std::vector<InternalSampleType>* rss7_samples;
106 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
107 kL5, label_to_samples, &l5_samples));
108 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
109 kLs5, label_to_samples, &ls5_samples));
110 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
111 kLss7, label_to_samples, &lss7_samples));
112 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
113 kR5, label_to_samples, &r5_samples));
114 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
115 kRs5, label_to_samples, &rs5_samples));
116 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
117 kRss7, label_to_samples, &rss7_samples));
118
119 auto& l7_samples = label_to_samples[kDemixedL7];
120 auto& r7_samples = label_to_samples[kDemixedR7];
121 auto& lrs7_samples = label_to_samples[kDemixedLrs7];
122 auto& rrs7_samples = label_to_samples[kDemixedRrs7];
123
124 // Directly copy L5/R5 to L7/R7, because they are the same.
125 l7_samples = *l5_samples;
126 r7_samples = *r5_samples;
127
128 // Handle Lrs7 and Rrs7.
129 const size_t num_ticks = l5_samples->size();
130 lrs7_samples.resize(num_ticks, 0.0);
131 rrs7_samples.resize(num_ticks, 0.0);
132 for (int i = 0; i < num_ticks; i++) {
133 lrs7_samples[i] =
134 ((*ls5_samples)[i] - down_mixing_params.alpha * (*lss7_samples)[i]) /
135 down_mixing_params.beta;
136 rrs7_samples[i] =
137 ((*rs5_samples)[i] - down_mixing_params.alpha * (*rss7_samples)[i]) /
138 down_mixing_params.beta;
139 }
140
141 return absl::OkStatus();
142 }
143
S5ToS3DownMixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)144 absl::Status S5ToS3DownMixer(const DownMixingParams& down_mixing_params,
145 LabelSamplesMap& label_to_samples) {
146 LOG_FIRST_N(INFO, 1) << "S5 to S3";
147
148 // Check input to perform this down-mixing exist.
149 if (label_to_samples.find(kL5) == label_to_samples.end() ||
150 label_to_samples.find(kLs5) == label_to_samples.end() ||
151 label_to_samples.find(kR5) == label_to_samples.end() ||
152 label_to_samples.find(kRs5) == label_to_samples.end()) {
153 return absl::InvalidArgumentError("Missing some input channels");
154 }
155
156 const auto& l5_samples = label_to_samples[kL5];
157 const auto& ls5_samples = label_to_samples[kLs5];
158 const auto& r5_samples = label_to_samples[kR5];
159 const auto& rs5_samples = label_to_samples[kRs5];
160
161 auto& l3_samples = label_to_samples[kL3];
162 auto& r3_samples = label_to_samples[kR3];
163 l3_samples.resize(l5_samples.size());
164 r3_samples.resize(r5_samples.size());
165 for (int i = 0; i < l3_samples.size(); i++) {
166 l3_samples[i] = l5_samples[i] + down_mixing_params.delta * ls5_samples[i];
167 r3_samples[i] = r5_samples[i] + down_mixing_params.delta * rs5_samples[i];
168 }
169
170 return absl::OkStatus();
171 }
172
S3ToS5Demixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)173 absl::Status S3ToS5Demixer(const DownMixingParams& down_mixing_params,
174 LabelSamplesMap& label_to_samples) {
175 LOG_FIRST_N(INFO, 1) << "S3 to S5";
176
177 const std::vector<InternalSampleType>* l3_samples;
178 const std::vector<InternalSampleType>* l5_samples;
179 const std::vector<InternalSampleType>* r3_samples;
180 const std::vector<InternalSampleType>* r5_samples;
181 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
182 kL3, label_to_samples, &l3_samples));
183 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
184 kL5, label_to_samples, &l5_samples));
185 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
186 kR3, label_to_samples, &r3_samples));
187 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
188 kR5, label_to_samples, &r5_samples));
189
190 auto& ls5_samples = label_to_samples[kDemixedLs5];
191 auto& rs5_samples = label_to_samples[kDemixedRs5];
192
193 const size_t num_ticks = l3_samples->size();
194 ls5_samples.resize(num_ticks, 0.0);
195 rs5_samples.resize(num_ticks, 0.0);
196 for (int i = 0; i < num_ticks; i++) {
197 ls5_samples[i] =
198 ((*l3_samples)[i] - (*l5_samples)[i]) / down_mixing_params.delta;
199 rs5_samples[i] =
200 ((*r3_samples)[i] - (*r5_samples)[i]) / down_mixing_params.delta;
201 }
202
203 return absl::OkStatus();
204 }
205
S3ToS2DownMixer(const DownMixingParams &,LabelSamplesMap & label_to_samples)206 absl::Status S3ToS2DownMixer(const DownMixingParams& /*down_mixing_params*/,
207 LabelSamplesMap& label_to_samples) {
208 LOG_FIRST_N(INFO, 1) << "S3 to S2";
209
210 // Check input to perform this down-mixing exist.
211 if (label_to_samples.find(kL3) == label_to_samples.end() ||
212 label_to_samples.find(kR3) == label_to_samples.end() ||
213 label_to_samples.find(kCentre) == label_to_samples.end()) {
214 return absl::InvalidArgumentError("Missing some input channels");
215 }
216
217 const auto& l3_samples = label_to_samples[kL3];
218 const auto& r3_samples = label_to_samples[kR3];
219 const auto& c_samples = label_to_samples[kCentre];
220
221 auto& l2_samples = label_to_samples[kL2];
222 auto& r2_samples = label_to_samples[kR2];
223 l2_samples.resize(l3_samples.size());
224 r2_samples.resize(r3_samples.size());
225 for (int i = 0; i < l2_samples.size(); i++) {
226 l2_samples[i] = l3_samples[i] + 0.707 * c_samples[i];
227 r2_samples[i] = r3_samples[i] + 0.707 * c_samples[i];
228 }
229
230 return absl::OkStatus();
231 }
232
S2ToS3Demixer(const DownMixingParams &,LabelSamplesMap & label_to_samples)233 absl::Status S2ToS3Demixer(const DownMixingParams& /*down_mixing_params*/,
234 LabelSamplesMap& label_to_samples) {
235 LOG_FIRST_N(INFO, 1) << "S2 to S3";
236
237 const std::vector<InternalSampleType>* l2_samples;
238 const std::vector<InternalSampleType>* r2_samples;
239 const std::vector<InternalSampleType>* c_samples;
240 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
241 kL2, label_to_samples, &l2_samples));
242 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
243 kR2, label_to_samples, &r2_samples));
244 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
245 kCentre, label_to_samples, &c_samples));
246
247 auto& l3_samples = label_to_samples[kDemixedL3];
248 auto& r3_samples = label_to_samples[kDemixedR3];
249
250 const size_t num_ticks = c_samples->size();
251 l3_samples.resize(num_ticks, 0.0);
252 r3_samples.resize(num_ticks, 0.0);
253 for (int i = 0; i < num_ticks; i++) {
254 l3_samples[i] = ((*l2_samples)[i] - 0.707 * (*c_samples)[i]);
255 r3_samples[i] = ((*r2_samples)[i] - 0.707 * (*c_samples)[i]);
256 }
257
258 return absl::OkStatus();
259 }
260
S2ToS1DownMixer(const DownMixingParams &,LabelSamplesMap & label_to_samples)261 absl::Status S2ToS1DownMixer(const DownMixingParams& /*down_mixing_params*/,
262 LabelSamplesMap& label_to_samples) {
263 LOG_FIRST_N(INFO, 1) << "S2 to S1";
264
265 // Check input to perform this down-mixing exist.
266 if (label_to_samples.find(kL2) == label_to_samples.end() ||
267 label_to_samples.find(kR2) == label_to_samples.end()) {
268 return absl::UnknownError("Missing some input channels");
269 }
270
271 const auto& l2_samples = label_to_samples[kL2];
272 const auto& r2_samples = label_to_samples[kR2];
273
274 auto& mono_samples = label_to_samples[kMono];
275 mono_samples.resize(l2_samples.size());
276 for (int i = 0; i < mono_samples.size(); i++) {
277 mono_samples[i] = 0.5 * (l2_samples[i] + r2_samples[i]);
278 }
279
280 return absl::OkStatus();
281 }
282
S1ToS2Demixer(const DownMixingParams &,LabelSamplesMap & label_to_samples)283 absl::Status S1ToS2Demixer(const DownMixingParams& /*down_mixing_params*/,
284 LabelSamplesMap& label_to_samples) {
285 LOG_FIRST_N(INFO, 1) << "S1 to S2";
286
287 const std::vector<InternalSampleType>* l2_samples;
288 const std::vector<InternalSampleType>* mono_samples;
289 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
290 kL2, label_to_samples, &l2_samples));
291 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
292 kMono, label_to_samples, &mono_samples));
293
294 auto& r2_samples = label_to_samples[kDemixedR2];
295 const size_t num_ticks = mono_samples->size();
296 r2_samples.resize(num_ticks, 0.0);
297 for (int i = 0; i < num_ticks; i++) {
298 r2_samples[i] = 2.0 * (*mono_samples)[i] - (*l2_samples)[i];
299 }
300
301 return absl::OkStatus();
302 }
303
T4ToT2DownMixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)304 absl::Status T4ToT2DownMixer(const DownMixingParams& down_mixing_params,
305 LabelSamplesMap& label_to_samples) {
306 LOG_FIRST_N(INFO, 1) << "T4 to T2";
307
308 // Check input to perform this down-mixing exist.
309 if (label_to_samples.find(kLtf4) == label_to_samples.end() ||
310 label_to_samples.find(kLtb4) == label_to_samples.end() ||
311 label_to_samples.find(kRtf4) == label_to_samples.end() ||
312 label_to_samples.find(kRtb4) == label_to_samples.end()) {
313 return absl::UnknownError("Missing some input channels");
314 }
315
316 const auto& ltf4_samples = label_to_samples[kLtf4];
317 const auto& ltb4_samples = label_to_samples[kLtb4];
318 const auto& rtf4_samples = label_to_samples[kRtf4];
319 const auto& rtb4_samples = label_to_samples[kRtb4];
320
321 auto& ltf2_samples = label_to_samples[kLtf2];
322 auto& rtf2_samples = label_to_samples[kRtf2];
323 ltf2_samples.resize(ltf4_samples.size());
324 rtf2_samples.resize(rtf4_samples.size());
325 for (int i = 0; i < ltf2_samples.size(); i++) {
326 ltf2_samples[i] =
327 ltf4_samples[i] + down_mixing_params.gamma * ltb4_samples[i];
328 rtf2_samples[i] =
329 rtf4_samples[i] + down_mixing_params.gamma * rtb4_samples[i];
330 }
331
332 return absl::OkStatus();
333 }
334
T2ToT4Demixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)335 absl::Status T2ToT4Demixer(const DownMixingParams& down_mixing_params,
336 LabelSamplesMap& label_to_samples) {
337 LOG_FIRST_N(INFO, 1) << "T2 to T4";
338
339 const std::vector<InternalSampleType>* ltf2_samples;
340 const std::vector<InternalSampleType>* ltf4_samples;
341 const std::vector<InternalSampleType>* rtf2_samples;
342 const std::vector<InternalSampleType>* rtf4_samples;
343 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
344 kLtf2, label_to_samples, <f2_samples));
345 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
346 kLtf4, label_to_samples, <f4_samples));
347 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
348 kRtf2, label_to_samples, &rtf2_samples));
349 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
350 kRtf4, label_to_samples, &rtf4_samples));
351
352 auto& ltb4_samples = label_to_samples[kDemixedLtb4];
353 auto& rtb4_samples = label_to_samples[kDemixedRtb4];
354 const size_t num_ticks = ltf2_samples->size();
355 ltb4_samples.resize(num_ticks, 0.0);
356 rtb4_samples.resize(num_ticks, 0.0);
357 for (int i = 0; i < num_ticks; i++) {
358 ltb4_samples[i] =
359 ((*ltf2_samples)[i] - (*ltf4_samples)[i]) / down_mixing_params.gamma;
360 rtb4_samples[i] =
361 ((*rtf2_samples)[i] - (*rtf4_samples)[i]) / down_mixing_params.gamma;
362 }
363
364 return absl::OkStatus();
365 }
366
T2ToTf2DownMixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)367 absl::Status T2ToTf2DownMixer(const DownMixingParams& down_mixing_params,
368 LabelSamplesMap& label_to_samples) {
369 LOG_FIRST_N(INFO, 1) << "T2 to TF2";
370
371 // Check input to perform this down-mixing exist.
372 if (label_to_samples.find(kLtf2) == label_to_samples.end() ||
373 label_to_samples.find(kLs5) == label_to_samples.end() ||
374 label_to_samples.find(kRtf2) == label_to_samples.end() ||
375 label_to_samples.find(kRs5) == label_to_samples.end()) {
376 return absl::UnknownError("Missing some input channels");
377 }
378
379 const auto& ltf2_samples = label_to_samples[kLtf2];
380 const auto& ls5_samples = label_to_samples[kLs5];
381 const auto& rtf2_samples = label_to_samples[kRtf2];
382 const auto& rs5_samples = label_to_samples[kRs5];
383
384 auto& ltf3_samples = label_to_samples[kLtf3];
385 auto& rtf3_samples = label_to_samples[kRtf3];
386 ltf3_samples.resize(ltf2_samples.size());
387 rtf3_samples.resize(rtf2_samples.size());
388 for (int i = 0; i < ltf2_samples.size(); i++) {
389 ltf3_samples[i] = ltf2_samples[i] + down_mixing_params.w *
390 down_mixing_params.delta *
391 ls5_samples[i];
392 rtf3_samples[i] = rtf2_samples[i] + down_mixing_params.w *
393 down_mixing_params.delta *
394 rs5_samples[i];
395 }
396
397 return absl::OkStatus();
398 }
399
Tf2ToT2Demixer(const DownMixingParams & down_mixing_params,LabelSamplesMap & label_to_samples)400 absl::Status Tf2ToT2Demixer(const DownMixingParams& down_mixing_params,
401 LabelSamplesMap& label_to_samples) {
402 LOG_FIRST_N(INFO, 1) << "TF2 to T2";
403
404 const std::vector<InternalSampleType>* ltf3_samples;
405 const std::vector<InternalSampleType>* l3_samples;
406 const std::vector<InternalSampleType>* l5_samples;
407 const std::vector<InternalSampleType>* rtf3_samples;
408 const std::vector<InternalSampleType>* r3_samples;
409 const std::vector<InternalSampleType>* r5_samples;
410 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
411 kLtf3, label_to_samples, <f3_samples));
412 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
413 kL3, label_to_samples, &l3_samples));
414 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
415 kL5, label_to_samples, &l5_samples));
416 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
417 kRtf3, label_to_samples, &rtf3_samples));
418 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
419 kR3, label_to_samples, &r3_samples));
420 RETURN_IF_NOT_OK(DemixingModule::FindSamplesOrDemixedSamples(
421 kR5, label_to_samples, &r5_samples));
422
423 auto& ltf2_samples = label_to_samples[kDemixedLtf2];
424 auto& rtf2_samples = label_to_samples[kDemixedRtf2];
425 const size_t num_ticks = ltf3_samples->size();
426 ltf2_samples.resize(num_ticks, 0.0);
427 rtf2_samples.resize(num_ticks, 0.0);
428 for (int i = 0; i < num_ticks; i++) {
429 ltf2_samples[i] =
430 (*ltf3_samples)[i] -
431 down_mixing_params.w * ((*l3_samples)[i] - (*l5_samples)[i]);
432 rtf2_samples[i] =
433 (*rtf3_samples)[i] -
434 down_mixing_params.w * ((*r3_samples)[i] - (*r5_samples)[i]);
435 }
436
437 return absl::OkStatus();
438 }
439
440 // Helper to fill in the fields of `DemixingMetadataForAudioElementId`.
FillRequiredDemixingMetadata(const absl::flat_hash_set<ChannelLabel::Label> & labels_to_demix,const SubstreamIdLabelsMap & substream_id_to_labels,const LabelGainMap & label_to_output_gain,DemixingMetadataForAudioElementId & demixing_metadata)441 absl::Status FillRequiredDemixingMetadata(
442 const absl::flat_hash_set<ChannelLabel::Label>& labels_to_demix,
443 const SubstreamIdLabelsMap& substream_id_to_labels,
444 const LabelGainMap& label_to_output_gain,
445 DemixingMetadataForAudioElementId& demixing_metadata) {
446 auto& down_mixers = demixing_metadata.down_mixers;
447 auto& demixers = demixing_metadata.demixers;
448
449 if (!down_mixers.empty() || !demixers.empty()) {
450 return absl::UnknownError(
451 "`FillRequiredDemixingMetadata()` should only be called once per Audio "
452 "Element ID");
453 }
454 demixing_metadata.substream_id_to_labels = substream_id_to_labels;
455 demixing_metadata.label_to_output_gain = label_to_output_gain;
456
457 // Find the input surround number.
458 int input_surround_number = 0;
459 if (labels_to_demix.contains(kL7)) {
460 input_surround_number = 7;
461 } else if (labels_to_demix.contains(kL5)) {
462 input_surround_number = 5;
463 } else if (labels_to_demix.contains(kL3)) {
464 input_surround_number = 3;
465 } else if (labels_to_demix.contains(kL2)) {
466 input_surround_number = 2;
467 } else if (labels_to_demix.contains(kMono)) {
468 input_surround_number = 1;
469 }
470
471 // Find the lowest output surround number.
472 int output_lowest_surround_number = INT_MAX;
473 for (const auto& [substream_id, labels] :
474 demixing_metadata.substream_id_to_labels) {
475 if (std::find(labels.begin(), labels.end(), kL7) != labels.end() &&
476 output_lowest_surround_number > 7) {
477 output_lowest_surround_number = 7;
478 } else if (std::find(labels.begin(), labels.end(), kL5) != labels.end() &&
479 output_lowest_surround_number > 5) {
480 output_lowest_surround_number = 5;
481 } else if (std::find(labels.begin(), labels.end(), kL3) != labels.end() &&
482 output_lowest_surround_number > 3) {
483 output_lowest_surround_number = 3;
484 } else if (std::find(labels.begin(), labels.end(), kL2) != labels.end() &&
485 output_lowest_surround_number > 2) {
486 output_lowest_surround_number = 2;
487 } else if (std::find(labels.begin(), labels.end(), kMono) != labels.end() &&
488 output_lowest_surround_number > 1) {
489 output_lowest_surround_number = 1;
490 // This is the lowest possible value, abort.
491 break;
492 }
493 }
494 LOG(INFO) << "Surround down-mixers from S" << input_surround_number << " to S"
495 << output_lowest_surround_number << " needed:";
496 for (int surround_number = input_surround_number;
497 surround_number > output_lowest_surround_number; surround_number--) {
498 if (surround_number == 7) {
499 down_mixers.push_back(S7ToS5DownMixer);
500 LOG(INFO) << " S7ToS5DownMixer added";
501 demixers.push_front(S5ToS7Demixer);
502 LOG(INFO) << " S5ToS7Demixer added";
503 } else if (surround_number == 5) {
504 down_mixers.push_back(S5ToS3DownMixer);
505 LOG(INFO) << " S5ToS3DownMixer added";
506 demixers.push_front(S3ToS5Demixer);
507 LOG(INFO) << " S3ToS5Demixer added";
508 } else if (surround_number == 3) {
509 down_mixers.push_back(S3ToS2DownMixer);
510 LOG(INFO) << " S3ToS2DownMixer added";
511 demixers.push_front(S2ToS3Demixer);
512 LOG(INFO) << " S2ToS3Demixer added";
513 } else if (surround_number == 2) {
514 down_mixers.push_back(S2ToS1DownMixer);
515 LOG(INFO) << " S2ToS1DownMixer added";
516 demixers.push_front(S1ToS2Demixer);
517 LOG(INFO) << " S1ToS2Demixer added";
518 }
519 }
520
521 // Find the input height number. Artificially defining the height number of
522 // "TF2" as 1.
523 int input_height_number = 0;
524 if (labels_to_demix.contains(kLtf4)) {
525 input_height_number = 4;
526 } else if (labels_to_demix.contains(kLtf2)) {
527 input_height_number = 2;
528 } else if (labels_to_demix.contains(kLtf3)) {
529 input_height_number = 1;
530 }
531
532 // Find the lowest output height number.
533 int output_lowest_height_number = INT_MAX;
534 for (const auto& [substream_id, labels] :
535 demixing_metadata.substream_id_to_labels) {
536 if (std::find(labels.begin(), labels.end(), kLtf4) != labels.end() &&
537 output_lowest_height_number > 4) {
538 output_lowest_height_number = 4;
539 } else if (std::find(labels.begin(), labels.end(), kLtf2) != labels.end() &&
540 output_lowest_height_number > 2) {
541 output_lowest_height_number = 2;
542 } else if (std::find(labels.begin(), labels.end(), kLtf3) != labels.end() &&
543 output_lowest_height_number > 1) {
544 output_lowest_height_number = 1;
545 // This is the lowest possible value, abort.
546 break;
547 }
548 }
549
550 // Collect demixers in a separate list first and append the list to the
551 // output later. Height demixers need to be in reverse order as height
552 // down-mixers but should go after the surround demixers.
553 LOG(INFO) << "Height down-mixers from T" << input_height_number << " to "
554 << (output_lowest_height_number == 2 ? "T2" : "TF3") << " needed:";
555 std::list<Demixer> height_demixers;
556 for (int height_number = input_height_number;
557 height_number > output_lowest_height_number; height_number--) {
558 if (height_number == 4) {
559 down_mixers.push_back(T4ToT2DownMixer);
560 LOG(INFO) << " T4ToT2DownMixer added";
561 height_demixers.push_front(T2ToT4Demixer);
562 LOG(INFO) << " T2ToT4Demixer added";
563 } else if (height_number == 2) {
564 down_mixers.push_back(T2ToTf2DownMixer);
565 LOG(INFO) << " T2ToTf2DownMixer added";
566 height_demixers.push_front(Tf2ToT2Demixer);
567 LOG(INFO) << " Tf2ToT2Demixer added";
568 }
569 }
570 demixers.splice(demixers.end(), height_demixers);
571
572 return absl::OkStatus();
573 }
574
ConfigureLabeledFrame(const AudioFrameWithData & audio_frame,LabeledFrame & labeled_frame)575 void ConfigureLabeledFrame(const AudioFrameWithData& audio_frame,
576 LabeledFrame& labeled_frame) {
577 labeled_frame.end_timestamp = audio_frame.end_timestamp;
578 labeled_frame.samples_to_trim_at_end =
579 audio_frame.obu.header_.num_samples_to_trim_at_end;
580 labeled_frame.samples_to_trim_at_start =
581 audio_frame.obu.header_.num_samples_to_trim_at_start;
582 labeled_frame.demixing_params = audio_frame.down_mixing_params;
583 }
584
ConfigureLabeledFrame(const DecodedAudioFrame & decoded_audio_frame,LabeledFrame & labeled_decoded_frame)585 void ConfigureLabeledFrame(const DecodedAudioFrame& decoded_audio_frame,
586 LabeledFrame& labeled_decoded_frame) {
587 labeled_decoded_frame.end_timestamp = decoded_audio_frame.end_timestamp;
588 labeled_decoded_frame.samples_to_trim_at_end =
589 decoded_audio_frame.samples_to_trim_at_end;
590 labeled_decoded_frame.samples_to_trim_at_start =
591 decoded_audio_frame.samples_to_trim_at_start;
592 labeled_decoded_frame.demixing_params =
593 decoded_audio_frame.down_mixing_params;
594 }
595
GetSubstreamId(const AudioFrameWithData & audio_frame_with_data)596 uint32_t GetSubstreamId(const AudioFrameWithData& audio_frame_with_data) {
597 return audio_frame_with_data.obu.GetSubstreamId();
598 }
599
GetSubstreamId(const DecodedAudioFrame & audio_frame_with_data)600 uint32_t GetSubstreamId(const DecodedAudioFrame& audio_frame_with_data) {
601 return audio_frame_with_data.substream_id;
602 }
603
GetSamples(const AudioFrameWithData & audio_frame_with_data)604 const std::vector<std::vector<int32_t>>* GetSamples(
605 const AudioFrameWithData& audio_frame_with_data) {
606 if (!audio_frame_with_data.pcm_samples.has_value()) {
607 return nullptr;
608 }
609 return &audio_frame_with_data.pcm_samples.value();
610 }
611
GetSamples(const DecodedAudioFrame & audio_frame_with_data)612 const std::vector<std::vector<int32_t>>* GetSamples(
613 const DecodedAudioFrame& audio_frame_with_data) {
614 return &audio_frame_with_data.decoded_samples;
615 }
616
617 // NOOP function if the frame is not a DecodedAudioFrame.
PassThroughReconGainData(const AudioFrameWithData &,LabeledFrame &)618 absl::Status PassThroughReconGainData(const AudioFrameWithData& /*audio_frame*/,
619 LabeledFrame& /*labeled_frame*/) {
620 return absl::OkStatus();
621 }
622
PassThroughReconGainData(const DecodedAudioFrame & decoded_audio_frame,LabeledFrame & labeled_decoded_frame)623 absl::Status PassThroughReconGainData(
624 const DecodedAudioFrame& decoded_audio_frame,
625 LabeledFrame& labeled_decoded_frame) {
626 if (decoded_audio_frame.audio_element_with_data == nullptr) {
627 LOG(INFO)
628 << "No audio element with data found, thus layer info is inaccessible.";
629 return absl::OkStatus();
630 }
631 auto layout_config = std::get_if<ScalableChannelLayoutConfig>(
632 &decoded_audio_frame.audio_element_with_data->obu.config_);
633 if (layout_config == nullptr) {
634 LOG_IF(INFO, decoded_audio_frame.start_timestamp == 0)
635 << "No scalable channel layout config found, thus recon gain "
636 "info is not necessary.";
637 return absl::OkStatus();
638 }
639 auto& loudspeaker_layout_per_layer =
640 labeled_decoded_frame.loudspeaker_layout_per_layer;
641 loudspeaker_layout_per_layer.clear();
642 loudspeaker_layout_per_layer.reserve(
643 layout_config->channel_audio_layer_configs.size());
644 for (const auto& channel_audio_layer_config :
645 layout_config->channel_audio_layer_configs) {
646 loudspeaker_layout_per_layer.push_back(
647 channel_audio_layer_config.loudspeaker_layout);
648 }
649 labeled_decoded_frame.recon_gain_info_parameter_data =
650 decoded_audio_frame.recon_gain_info_parameter_data;
651 return absl::OkStatus();
652 }
653
654 // TODO(b/377553811): Unify `AudioFrameWithData` and `DecodedAudioFrame`.
655 template <typename T>
StoreSamplesForAudioElementId(const std::list<T> & audio_frames_or_decoded_audio_frames,const SubstreamIdLabelsMap & substream_id_to_labels,LabeledFrame & labeled_frame)656 absl::Status StoreSamplesForAudioElementId(
657 const std::list<T>& audio_frames_or_decoded_audio_frames,
658 const SubstreamIdLabelsMap& substream_id_to_labels,
659 LabeledFrame& labeled_frame) {
660 if (audio_frames_or_decoded_audio_frames.empty()) {
661 return absl::OkStatus();
662 }
663 const int32_t common_start_timestamp =
664 audio_frames_or_decoded_audio_frames.begin()->start_timestamp;
665
666 for (auto& audio_frame : audio_frames_or_decoded_audio_frames) {
667 const auto substream_id = GetSubstreamId(audio_frame);
668 auto substream_id_labels_iter = substream_id_to_labels.find(substream_id);
669 if (substream_id_labels_iter == substream_id_to_labels.end()) {
670 // This audio frame might belong to a different audio element; skip it.
671 continue;
672 }
673
674 // Validate that the frames are all aligned in time.
675 RETURN_IF_NOT_OK(CompareTimestamps(common_start_timestamp,
676 audio_frame.start_timestamp,
677 "In StoreSamplesForAudioElementId(): "));
678
679 const auto& labels = substream_id_labels_iter->second;
680 int channel_index = 0;
681 for (const auto& label : labels) {
682 const auto* input_samples = GetSamples(audio_frame);
683 if (input_samples == nullptr) {
684 return absl::InvalidArgumentError(
685 "Input samples are not available for down-mixing.");
686 }
687 const size_t num_ticks = input_samples->size();
688
689 ConfigureLabeledFrame(audio_frame, labeled_frame);
690
691 auto& samples = labeled_frame.label_to_samples[label];
692 samples.resize(num_ticks, 0);
693 for (int t = 0; t < samples.size(); t++) {
694 samples[t] = Int32ToNormalizedFloatingPoint<InternalSampleType>(
695 (*input_samples)[t][channel_index]);
696 }
697 channel_index++;
698 }
699 RETURN_IF_NOT_OK(PassThroughReconGainData(audio_frame, labeled_frame));
700 }
701
702 return absl::OkStatus();
703 }
704
ApplyDemixers(const std::list<Demixer> & demixers,LabeledFrame & labeled_frame)705 absl::Status ApplyDemixers(const std::list<Demixer>& demixers,
706 LabeledFrame& labeled_frame) {
707 for (const auto& demixer : demixers) {
708 RETURN_IF_NOT_OK(
709 demixer(labeled_frame.demixing_params, labeled_frame.label_to_samples));
710 }
711 return absl::OkStatus();
712 }
713
GetDemixerMetadata(const DecodedUleb128 audio_element_id,const absl::flat_hash_map<DecodedUleb128,DemixingMetadataForAudioElementId> & audio_element_id_to_demixing_metadata,const DemixingMetadataForAudioElementId * & demixing_metadata)714 absl::Status GetDemixerMetadata(
715 const DecodedUleb128 audio_element_id,
716 const absl::flat_hash_map<DecodedUleb128,
717 DemixingMetadataForAudioElementId>&
718 audio_element_id_to_demixing_metadata,
719 const DemixingMetadataForAudioElementId*& demixing_metadata) {
720 const auto iter =
721 audio_element_id_to_demixing_metadata.find(audio_element_id);
722 if (iter == audio_element_id_to_demixing_metadata.end()) {
723 return absl::InvalidArgumentError(absl::StrCat(
724 "Demxiing metadata for Audio Element ID= ", audio_element_id,
725 " not found"));
726 }
727 demixing_metadata = &iter->second;
728 return absl::OkStatus();
729 }
730
731 absl::StatusOr<absl::flat_hash_set<ChannelLabel::Label>>
LookupLabelsToReconstruct(const AudioElementObu & obu)732 LookupLabelsToReconstruct(const AudioElementObu& obu) {
733 switch (obu.GetAudioElementType()) {
734 using enum AudioElementObu::AudioElementType;
735 case kAudioElementChannelBased: {
736 const auto& channel_audio_layer_configs =
737 std::get<ScalableChannelLayoutConfig>(obu.config_)
738 .channel_audio_layer_configs;
739 if (channel_audio_layer_configs.empty()) {
740 return absl::InvalidArgumentError(absl::StrCat(
741 "Expected non-empty channel audio layer configs for Audio "
742 "Element ID= ",
743 obu.GetAudioElementId()));
744 }
745
746 // Reconstruct the highest layer.
747 return ChannelLabel::
748 LookupLabelsToReconstructFromScalableLoudspeakerLayout(
749 channel_audio_layer_configs.back().loudspeaker_layout,
750 channel_audio_layer_configs.back().expanded_loudspeaker_layout);
751 }
752 case kAudioElementSceneBased:
753 // OK. Ambisonics does not have any channels to be reconstructed.
754 return absl::flat_hash_set<ChannelLabel::Label>{};
755 break;
756 default:
757 return absl::UnimplementedError(absl::StrCat(
758 "Unsupported audio element type= ", obu.GetAudioElementType()));
759 }
760 }
LogForAudioElementId(absl::string_view log_prefix,DecodedUleb128 audio_element_id,const IdLabeledFrameMap & id_to_labeled_frame)761 void LogForAudioElementId(absl::string_view log_prefix,
762 DecodedUleb128 audio_element_id,
763 const IdLabeledFrameMap& id_to_labeled_frame) {
764 if (!id_to_labeled_frame.contains(audio_element_id)) {
765 return;
766 }
767 for (const auto& [label, samples] :
768 id_to_labeled_frame.at(audio_element_id).label_to_samples) {
769 LOG_FIRST_N(INFO, 1) << " Channel " << label << ":\t" << log_prefix
770 << " frame size= " << samples.size() << ".";
771 }
772 }
773
774 } // namespace
775
FindSamplesOrDemixedSamples(ChannelLabel::Label label,const LabelSamplesMap & label_to_samples,const std::vector<InternalSampleType> ** samples)776 absl::Status DemixingModule::FindSamplesOrDemixedSamples(
777 ChannelLabel::Label label, const LabelSamplesMap& label_to_samples,
778 const std::vector<InternalSampleType>** samples) {
779 if (label_to_samples.find(label) != label_to_samples.end()) {
780 *samples = &label_to_samples.at(label);
781 return absl::OkStatus();
782 }
783
784 auto demixed_label = ChannelLabel::GetDemixedLabel(label);
785 if (!demixed_label.ok()) {
786 return demixed_label.status();
787 }
788 if (label_to_samples.find(*demixed_label) != label_to_samples.end()) {
789 *samples = &label_to_samples.at(*demixed_label);
790 return absl::OkStatus();
791 } else {
792 *samples = nullptr;
793 return absl::UnknownError(
794 absl::StrCat("Channel ", label, " or ", *demixed_label, " not found"));
795 }
796 }
797
798 absl::StatusOr<DemixingModule>
CreateForDownMixingAndReconstruction(const absl::flat_hash_map<DecodedUleb128,DownmixingAndReconstructionConfig> && id_to_config_map)799 DemixingModule::CreateForDownMixingAndReconstruction(
800 const absl::flat_hash_map<
801 DecodedUleb128, DownmixingAndReconstructionConfig>&& id_to_config_map) {
802 absl::flat_hash_map<DecodedUleb128, DemixingMetadataForAudioElementId>
803 audio_element_id_to_demixing_metadata;
804
805 for (const auto& [audio_element_id, config] : id_to_config_map) {
806 RETURN_IF_NOT_OK(FillRequiredDemixingMetadata(
807 config.user_labels, config.substream_id_to_labels,
808 config.label_to_output_gain,
809 audio_element_id_to_demixing_metadata[audio_element_id]));
810 }
811
812 return DemixingModule(DemixingMode::kDownMixingAndReconstruction,
813 std::move(audio_element_id_to_demixing_metadata));
814 }
815
CreateForReconstruction(const absl::flat_hash_map<DecodedUleb128,AudioElementWithData> & audio_elements)816 absl::StatusOr<DemixingModule> DemixingModule::CreateForReconstruction(
817 const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>&
818 audio_elements) {
819 absl::flat_hash_map<DecodedUleb128, DemixingMetadataForAudioElementId>
820 audio_element_id_to_demixing_metadata;
821 for (const auto& [audio_element_id, audio_element_with_data] :
822 audio_elements) {
823 const auto labels_to_reconstruct =
824 LookupLabelsToReconstruct(audio_element_with_data.obu);
825 if (!labels_to_reconstruct.ok()) {
826 return labels_to_reconstruct.status();
827 }
828
829 auto [iter, inserted] = audio_element_id_to_demixing_metadata.insert(
830 {audio_element_id, DemixingMetadataForAudioElementId()});
831 CHECK(inserted) << "The target map was initially empty, iterating over "
832 "`audio_elements` cannot produce a duplicate key.";
833 RETURN_IF_NOT_OK(FillRequiredDemixingMetadata(
834 *labels_to_reconstruct, audio_element_with_data.substream_id_to_labels,
835 audio_element_with_data.label_to_output_gain, iter->second));
836 iter->second.down_mixers.clear();
837 }
838
839 return DemixingModule(DemixingMode::kReconstruction,
840 std::move(audio_element_id_to_demixing_metadata));
841 }
842
DownMixSamplesToSubstreams(DecodedUleb128 audio_element_id,const DownMixingParams & down_mixing_params,LabelSamplesMap & input_label_to_samples,absl::flat_hash_map<uint32_t,SubstreamData> & substream_id_to_substream_data) const843 absl::Status DemixingModule::DownMixSamplesToSubstreams(
844 DecodedUleb128 audio_element_id, const DownMixingParams& down_mixing_params,
845 LabelSamplesMap& input_label_to_samples,
846 absl::flat_hash_map<uint32_t, SubstreamData>&
847 substream_id_to_substream_data) const {
848 const DemixingMetadataForAudioElementId* demixing_metadata = nullptr;
849 RETURN_IF_NOT_OK(GetDemixerMetadata(audio_element_id,
850 audio_element_id_to_demixing_metadata_,
851 demixing_metadata));
852
853 // First perform all the down mixing.
854 for (const auto& down_mixer : demixing_metadata->down_mixers) {
855 RETURN_IF_NOT_OK(down_mixer(down_mixing_params, input_label_to_samples));
856 }
857
858 const size_t num_time_ticks = input_label_to_samples.begin()->second.size();
859
860 for (const auto& [substream_id, output_channel_labels] :
861 demixing_metadata->substream_id_to_labels) {
862 std::vector<std::vector<int32_t>> substream_samples(
863 num_time_ticks,
864 // One or two channels.
865 std::vector<int32_t>(output_channel_labels.size(), 0));
866 // Output gains to be applied to the (one or two) channels.
867 std::vector<double> output_gains_linear(output_channel_labels.size());
868 int channel_index = 0;
869 for (const auto& output_channel_label : output_channel_labels) {
870 auto iter = input_label_to_samples.find(output_channel_label);
871 if (iter == input_label_to_samples.end()) {
872 return absl::UnknownError(absl::StrCat(
873 "Samples do not exist for channel: ", output_channel_label));
874 }
875 for (int t = 0; t < num_time_ticks; t++) {
876 RETURN_IF_NOT_OK(NormalizedFloatingPointToInt32(
877 iter->second[t], substream_samples[t][channel_index]));
878 }
879
880 // Compute and store the linear output gains.
881 auto gain_iter =
882 demixing_metadata->label_to_output_gain.find(output_channel_label);
883 output_gains_linear[channel_index] = 1.0;
884 if (gain_iter != demixing_metadata->label_to_output_gain.end()) {
885 output_gains_linear[channel_index] =
886 std::pow(10.0, gain_iter->second / 20.0);
887 }
888
889 channel_index++;
890 }
891
892 // Find the `SubstreamData` with this `substream_id`.
893 auto substream_data_iter =
894 substream_id_to_substream_data.find(substream_id);
895 if (substream_data_iter == substream_id_to_substream_data.end()) {
896 return absl::UnknownError(absl::StrCat(
897 "Failed to find substream data for substream ID= ", substream_id));
898 }
899 auto& substream_data = substream_data_iter->second;
900
901 // Add all down mixed samples to both queues.
902
903 for (const auto& channel_samples : substream_samples) {
904 substream_data.samples_obu.push_back(channel_samples);
905
906 // Apply output gains to the samples going to the encoder.
907 std::vector<int32_t> attenuated_channel_samples(channel_samples.size());
908 for (int i = 0; i < channel_samples.size(); ++i) {
909 // Intermediate computation is a `double`. But both `channel_samples`
910 // and `attenuated_channel_samples` are `int32_t`.
911 const double attenuated_sample =
912 static_cast<double>(channel_samples[i]) / output_gains_linear[i];
913 RETURN_IF_NOT_OK(ClipDoubleToInt32(attenuated_sample,
914 attenuated_channel_samples[i]));
915 }
916 substream_data.samples_encode.push_back(attenuated_channel_samples);
917 }
918 }
919
920 return absl::OkStatus();
921 }
922
923 // TODO(b/288240600): Down-mix audio samples in a standalone function too.
DemixOriginalAudioSamples(const std::list<AudioFrameWithData> & audio_frames) const924 absl::StatusOr<IdLabeledFrameMap> DemixingModule::DemixOriginalAudioSamples(
925 const std::list<AudioFrameWithData>& audio_frames) const {
926 if (demixing_mode_ == DemixingMode::kReconstruction) {
927 return absl::FailedPreconditionError(
928 "Demixing original audio samples is not available in reconstruction "
929 "mode.");
930 }
931 IdLabeledFrameMap id_to_labeled_frame;
932 for (const auto& [audio_element_id, demixing_metadata] :
933 audio_element_id_to_demixing_metadata_) {
934 // Process the original audio frames.
935 LabeledFrame labeled_frame;
936 RETURN_IF_NOT_OK(StoreSamplesForAudioElementId(
937 audio_frames, demixing_metadata.substream_id_to_labels, labeled_frame));
938 if (!labeled_frame.label_to_samples.empty()) {
939 RETURN_IF_NOT_OK(
940 ApplyDemixers(demixing_metadata.demixers, labeled_frame));
941 id_to_labeled_frame[audio_element_id] = std::move(labeled_frame);
942 }
943
944 LogForAudioElementId("Original", audio_element_id, id_to_labeled_frame);
945 }
946
947 return id_to_labeled_frame;
948 }
949
DemixDecodedAudioSamples(const std::list<DecodedAudioFrame> & decoded_audio_frames) const950 absl::StatusOr<IdLabeledFrameMap> DemixingModule::DemixDecodedAudioSamples(
951 const std::list<DecodedAudioFrame>& decoded_audio_frames) const {
952 IdLabeledFrameMap id_to_labeled_decoded_frame;
953 for (const auto& [audio_element_id, demixing_metadata] :
954 audio_element_id_to_demixing_metadata_) {
955 // Process the decoded audio frames.
956 LabeledFrame labeled_decoded_frame;
957 RETURN_IF_NOT_OK(StoreSamplesForAudioElementId(
958 decoded_audio_frames, demixing_metadata.substream_id_to_labels,
959 labeled_decoded_frame));
960 if (!labeled_decoded_frame.label_to_samples.empty()) {
961 RETURN_IF_NOT_OK(
962 ApplyDemixers(demixing_metadata.demixers, labeled_decoded_frame));
963 id_to_labeled_decoded_frame[audio_element_id] =
964 std::move(labeled_decoded_frame);
965 }
966
967 LogForAudioElementId("Decoded", audio_element_id,
968 id_to_labeled_decoded_frame);
969 }
970
971 return id_to_labeled_decoded_frame;
972 }
973
GetDownMixers(DecodedUleb128 audio_element_id,const std::list<Demixer> * & down_mixers) const974 absl::Status DemixingModule::GetDownMixers(
975 DecodedUleb128 audio_element_id,
976 const std::list<Demixer>*& down_mixers) const {
977 const DemixingMetadataForAudioElementId* demixing_metadata = nullptr;
978 RETURN_IF_NOT_OK(GetDemixerMetadata(audio_element_id,
979 audio_element_id_to_demixing_metadata_,
980 demixing_metadata));
981 down_mixers = &demixing_metadata->down_mixers;
982 return absl::OkStatus();
983 }
984
GetDemixers(DecodedUleb128 audio_element_id,const std::list<Demixer> * & demixers) const985 absl::Status DemixingModule::GetDemixers(
986 DecodedUleb128 audio_element_id,
987 const std::list<Demixer>*& demixers) const {
988 const DemixingMetadataForAudioElementId* demixing_metadata = nullptr;
989 RETURN_IF_NOT_OK(GetDemixerMetadata(audio_element_id,
990 audio_element_id_to_demixing_metadata_,
991 demixing_metadata));
992 demixers = &demixing_metadata->demixers;
993 return absl::OkStatus();
994 }
995
996 } // namespace iamf_tools
997