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/renderer_factory.h"
13
14 #include <cstddef>
15 #include <memory>
16 #include <variant>
17 #include <vector>
18
19 #include "absl/log/log.h"
20 #include "iamf/cli/audio_element_with_data.h"
21 #include "iamf/cli/renderer/audio_element_renderer_ambisonics_to_channel.h"
22 #include "iamf/cli/renderer/audio_element_renderer_base.h"
23 #include "iamf/cli/renderer/audio_element_renderer_channel_to_channel.h"
24 #include "iamf/cli/renderer/audio_element_renderer_passthrough.h"
25 #include "iamf/obu/audio_element.h"
26 #include "iamf/obu/mix_presentation.h"
27 #include "iamf/obu/types.h"
28
29 namespace iamf_tools {
30
31 namespace {
32
IsAudioElementRenderedBinaural(RenderingConfig::HeadphonesRenderingMode headphones_rendering_mode,Layout::LayoutType layout_type)33 bool IsAudioElementRenderedBinaural(
34 RenderingConfig::HeadphonesRenderingMode headphones_rendering_mode,
35 Layout::LayoutType layout_type) {
36 {
37 return headphones_rendering_mode ==
38 RenderingConfig::kHeadphonesRenderingModeBinaural &&
39 layout_type == Layout::kLayoutTypeBinaural;
40 }
41 }
42
MaybeCreateAmbisonicsRenderer(bool use_binaural,const std::vector<DecodedUleb128> & audio_substream_ids,const SubstreamIdLabelsMap & substream_id_to_labels,const AudioElementObu::AudioElementConfig & config,const Layout & loudness_layout,size_t num_samples_per_frame)43 std::unique_ptr<AudioElementRendererBase> MaybeCreateAmbisonicsRenderer(
44 bool use_binaural, const std::vector<DecodedUleb128>& audio_substream_ids,
45 const SubstreamIdLabelsMap& substream_id_to_labels,
46 const AudioElementObu::AudioElementConfig& config,
47 const Layout& loudness_layout, size_t num_samples_per_frame) {
48 const auto* ambisonics_config = std::get_if<AmbisonicsConfig>(&config);
49 if (ambisonics_config == nullptr) {
50 LOG(ERROR) << "Ambisonics config is inconsistent with audio element type.";
51 return nullptr;
52 }
53
54 if (use_binaural) {
55 LOG(WARNING) << "Skipping creating an Ambisonics to binaural-based "
56 "renderer. Binaural rendering is not yet supported for "
57 "ambisonics.";
58 return nullptr;
59 }
60
61 return AudioElementRendererAmbisonicsToChannel::CreateFromAmbisonicsConfig(
62 *ambisonics_config, audio_substream_ids, substream_id_to_labels,
63 loudness_layout, num_samples_per_frame);
64 }
65
MaybeCreateChannelRenderer(bool use_binaural,const AudioElementObu::AudioElementConfig & config,const Layout & loudness_layout,size_t num_samples_per_frame)66 std::unique_ptr<AudioElementRendererBase> MaybeCreateChannelRenderer(
67 bool use_binaural, const AudioElementObu::AudioElementConfig& config,
68 const Layout& loudness_layout, size_t num_samples_per_frame) {
69 const auto* channel_config =
70 std::get_if<ScalableChannelLayoutConfig>(&config);
71 if (channel_config == nullptr) {
72 LOG(ERROR) << "Channel config is inconsistent with audio element type.";
73 return nullptr;
74 }
75 // Lazily try to make a pass-through renderer.
76 auto pass_through_renderer =
77 AudioElementRendererPassThrough::CreateFromScalableChannelLayoutConfig(
78 *channel_config, loudness_layout, num_samples_per_frame);
79 if (pass_through_renderer != nullptr) {
80 return pass_through_renderer;
81 }
82
83 if (use_binaural) {
84 LOG(WARNING) << "Skipping creating a channel to binaural-based renderer.";
85 return nullptr;
86 }
87 return AudioElementRendererChannelToChannel::
88 CreateFromScalableChannelLayoutConfig(*channel_config, loudness_layout,
89 num_samples_per_frame);
90 }
91
92 } // namespace
93
~RendererFactoryBase()94 RendererFactoryBase::~RendererFactoryBase() {}
95
96 std::unique_ptr<AudioElementRendererBase>
CreateRendererForLayout(const std::vector<DecodedUleb128> & audio_substream_ids,const SubstreamIdLabelsMap & substream_id_to_labels,AudioElementObu::AudioElementType audio_element_type,const AudioElementObu::AudioElementConfig & audio_element_config,const RenderingConfig & rendering_config,const Layout & loudness_layout,size_t num_samples_per_frame) const97 RendererFactory::CreateRendererForLayout(
98 const std::vector<DecodedUleb128>& audio_substream_ids,
99 const SubstreamIdLabelsMap& substream_id_to_labels,
100 AudioElementObu::AudioElementType audio_element_type,
101 const AudioElementObu::AudioElementConfig& audio_element_config,
102 const RenderingConfig& rendering_config, const Layout& loudness_layout,
103 size_t num_samples_per_frame) const {
104 const bool use_binaural = IsAudioElementRenderedBinaural(
105 rendering_config.headphones_rendering_mode, loudness_layout.layout_type);
106
107 switch (audio_element_type) {
108 case AudioElementObu::kAudioElementSceneBased:
109 return MaybeCreateAmbisonicsRenderer(
110 use_binaural, audio_substream_ids, substream_id_to_labels,
111 audio_element_config, loudness_layout, num_samples_per_frame);
112 case AudioElementObu::kAudioElementChannelBased:
113 return MaybeCreateChannelRenderer(use_binaural, audio_element_config,
114 loudness_layout, num_samples_per_frame);
115 case AudioElementObu::kAudioElementBeginReserved:
116 case AudioElementObu::kAudioElementEndReserved:
117 LOG(WARNING) << "Unsupported audio_element_type_= " << audio_element_type;
118 return nullptr;
119 }
120 // The above switch is exhaustive.
121 LOG(FATAL) << "Unsupported audio_element_type_= " << audio_element_type;
122 }
123
124 } // namespace iamf_tools
125