• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright (c) 2024, Alliance for Open Media. All rights reserved
4  *
5  * This source code is subject to the terms of the BSD 3-Clause Clear License
6  * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
7  * License was not distributed with this source code in the LICENSE file, you
8  * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
9  * Alliance for Open Media Patent License 1.0 was not distributed with this
10  * source code in the PATENTS file, you can obtain it at
11  * www.aomedia.org/license/patent.
12  */
13 
14 #include "iamf/cli/renderer/audio_element_renderer_channel_to_channel.h"
15 
16 #include <cstddef>
17 #include <cstdint>
18 #include <memory>
19 #include <optional>
20 #include <vector>
21 
22 #include "absl/base/no_destructor.h"
23 #include "absl/container/flat_hash_map.h"
24 #include "absl/log/log.h"
25 #include "absl/memory/memory.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/str_cat.h"
28 #include "absl/strings/string_view.h"
29 #include "absl/types/span.h"
30 #include "iamf/cli/channel_label.h"
31 #include "iamf/cli/renderer/loudspeakers_renderer.h"
32 #include "iamf/cli/renderer/renderer_utils.h"
33 #include "iamf/common/utils/macros.h"
34 #include "iamf/common/utils/map_utils.h"
35 #include "iamf/common/utils/validation_utils.h"
36 #include "iamf/obu/audio_element.h"
37 #include "iamf/obu/mix_presentation.h"
38 #include "iamf/obu/types.h"
39 
40 namespace iamf_tools {
41 namespace {
42 
43 constexpr absl::string_view kMonoInputKey = "0+1+0";
44 constexpr absl::string_view kStereoInputKey = "0+2+0";
45 constexpr absl::string_view k5_1_chInputKey = "0+5+0";
46 constexpr absl::string_view k5_1_2_chInputKey = "2+5+0";
47 constexpr absl::string_view k5_1_4InputKey = "4+5+0";
48 constexpr absl::string_view k7_1_0InputKey = "0+7+0";
49 constexpr absl::string_view k7_1_4InputKey = "4+7+0";
50 constexpr absl::string_view k7_1_2InputKey = "7.1.2";
51 constexpr absl::string_view k3_1_2InputKey = "3.1.2";
52 constexpr absl::string_view k9_1_6InputKey = "9.1.6";
53 
54 // TODO(b/359180486): Unify with `IsExpandedLayoutEquivalentToSoundSystem` in
55 //                    `audio_element_passthrough.cc`.
LookupInputKeyFromLoudspeakerLayout(ChannelAudioLayerConfig::ExpandedLoudspeakerLayout expanded_layout)56 absl::StatusOr<absl::string_view> LookupInputKeyFromLoudspeakerLayout(
57     ChannelAudioLayerConfig::ExpandedLoudspeakerLayout expanded_layout) {
58   switch (expanded_layout) {
59     using enum ChannelAudioLayerConfig::ExpandedLoudspeakerLayout;
60     using enum ChannelAudioLayerConfig::LoudspeakerLayout;
61     case kExpandedLayoutStereoS:
62       return k5_1_4InputKey;
63     case kExpandedLayoutLFE:
64     case kExpandedLayoutStereoSS:
65     case kExpandedLayoutStereoRS:
66     case kExpandedLayoutStereoTF:
67     case kExpandedLayoutStereoTB:
68     case kExpandedLayoutTop4Ch:
69     case kExpandedLayout3_0_ch:
70       return k7_1_4InputKey;
71     case kExpandedLayout9_1_6_ch:
72     case kExpandedLayoutStereoF:
73     case kExpandedLayoutStereoSi:
74     case kExpandedLayoutStereoTpSi:
75     case kExpandedLayoutTop6Ch:
76       return k9_1_6InputKey;
77     default:
78       return absl::InvalidArgumentError(absl::StrCat(
79           "Channel order not found for layout= ", expanded_layout));
80   }
81 }
82 
LookupInputKeyFromLoudspeakerLayout(ChannelAudioLayerConfig::LoudspeakerLayout loudspeaker_layout,std::optional<ChannelAudioLayerConfig::ExpandedLoudspeakerLayout> expanded_loudspeaker_layout)83 absl::StatusOr<absl::string_view> LookupInputKeyFromLoudspeakerLayout(
84     ChannelAudioLayerConfig::LoudspeakerLayout loudspeaker_layout,
85     std::optional<ChannelAudioLayerConfig::ExpandedLoudspeakerLayout>
86         expanded_loudspeaker_layout) {
87   if (loudspeaker_layout == ChannelAudioLayerConfig::kLayoutExpanded) {
88     RETURN_IF_NOT_OK(ValidateHasValue(expanded_loudspeaker_layout,
89                                       "expanded_loudspeaker_layout"));
90     return LookupInputKeyFromLoudspeakerLayout(*expanded_loudspeaker_layout);
91   }
92 
93   using enum LoudspeakersSsConventionLayout::SoundSystem;
94   using enum ChannelAudioLayerConfig::LoudspeakerLayout;
95 
96   static const absl::NoDestructor<absl::flat_hash_map<
97       ChannelAudioLayerConfig::LoudspeakerLayout, absl::string_view>>
98       kLoudspeakerLayoutToInputKey({
99           {kLayoutMono, kMonoInputKey},
100           {kLayoutStereo, kStereoInputKey},
101           {kLayout5_1_ch, k5_1_chInputKey},
102           {kLayout5_1_2_ch, k5_1_2_chInputKey},
103           {kLayout5_1_4_ch, k5_1_4InputKey},
104           {kLayout7_1_ch, k7_1_0InputKey},
105           {kLayout7_1_4_ch, k7_1_4InputKey},
106           {kLayout7_1_2_ch, k7_1_2InputKey},
107           {kLayout3_1_2_ch, k3_1_2InputKey},
108       });
109 
110   return LookupInMap(*kLoudspeakerLayoutToInputKey, loudspeaker_layout,
111                      "Input key for `LoudspeakerLayout`");
112 }
113 
114 }  // namespace
115 
116 std::unique_ptr<AudioElementRendererChannelToChannel>
CreateFromScalableChannelLayoutConfig(const ScalableChannelLayoutConfig & scalable_channel_layout_config,const Layout & playback_layout,size_t num_samples_per_frame)117 AudioElementRendererChannelToChannel::CreateFromScalableChannelLayoutConfig(
118     const ScalableChannelLayoutConfig& scalable_channel_layout_config,
119     const Layout& playback_layout, size_t num_samples_per_frame) {
120   if (scalable_channel_layout_config.channel_audio_layer_configs.empty()) {
121     LOG(ERROR) << "No channel audio layer configs provided.";
122     return nullptr;
123   }
124   const auto& highest_channel_audio_layer_config =
125       scalable_channel_layout_config.channel_audio_layer_configs.back();
126   const auto& ordered_labels =
127       ChannelLabel::LookupEarChannelOrderFromScalableLoudspeakerLayout(
128           highest_channel_audio_layer_config.loudspeaker_layout,
129           highest_channel_audio_layer_config.expanded_loudspeaker_layout);
130   if (!ordered_labels.ok()) {
131     LOG(ERROR) << ordered_labels.status();
132     return nullptr;
133   }
134 
135   const auto& input_key = LookupInputKeyFromLoudspeakerLayout(
136       highest_channel_audio_layer_config.loudspeaker_layout,
137       highest_channel_audio_layer_config.expanded_loudspeaker_layout);
138   if (!input_key.ok()) {
139     LOG(ERROR) << input_key.status();
140     return nullptr;
141   }
142   const auto& output_key =
143       renderer_utils::LookupOutputKeyFromPlaybackLayout(playback_layout);
144   if (!output_key.ok()) {
145     LOG(ERROR) << output_key.status();
146     return nullptr;
147   }
148 
149   const auto& gains = LookupPrecomputedGains(*input_key, *output_key);
150   if (!gains.ok()) {
151     LOG(ERROR) << gains.status();
152     return nullptr;
153   }
154 
155   int32_t num_output_channels = 0;
156   if (!MixPresentationObu::GetNumChannelsFromLayout(playback_layout,
157                                                     num_output_channels)
158            .ok()) {
159     return nullptr;
160   }
161 
162   return absl::WrapUnique(new AudioElementRendererChannelToChannel(
163       *input_key, *output_key, static_cast<size_t>(num_output_channels),
164       num_samples_per_frame, *ordered_labels, *gains));
165 }
166 
RenderSamples(absl::Span<const std::vector<InternalSampleType>> samples_to_render,std::vector<InternalSampleType> & rendered_samples)167 absl::Status AudioElementRendererChannelToChannel::RenderSamples(
168     absl::Span<const std::vector<InternalSampleType>> samples_to_render,
169     std::vector<InternalSampleType>& rendered_samples) {
170   // Render the samples.
171   RETURN_IF_NOT_OK(RenderChannelLayoutToLoudspeakers(
172       samples_to_render, current_labeled_frame_->demixing_params,
173       ordered_labels_, input_key_, output_key_, gains_, rendered_samples));
174 
175   return absl::OkStatus();
176 }
177 
178 }  // namespace iamf_tools
179