• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/global_timing_module.h"
13 
14 #include <cstdint>
15 #include <memory>
16 #include <optional>
17 #include <utility>
18 #include <variant>
19 
20 #include "absl/container/flat_hash_map.h"
21 #include "absl/container/flat_hash_set.h"
22 #include "absl/log/log.h"
23 #include "absl/memory/memory.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/str_cat.h"
26 #include "iamf/cli/audio_element_with_data.h"
27 #include "iamf/cli/cli_util.h"
28 #include "iamf/common/utils/macros.h"
29 #include "iamf/common/utils/validation_utils.h"
30 #include "iamf/obu/audio_element.h"
31 #include "iamf/obu/codec_config.h"
32 #include "iamf/obu/param_definition_variant.h"
33 #include "iamf/obu/types.h"
34 
35 namespace iamf_tools {
36 
37 namespace {
38 
InitializeInternal(const absl::flat_hash_map<DecodedUleb128,AudioElementWithData> & audio_elements,const absl::flat_hash_map<DecodedUleb128,ParamDefinitionVariant> & param_definition_variants,auto & audio_frame_timing_data,auto & parameter_block_timing_data)39 absl::Status InitializeInternal(
40     const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>&
41         audio_elements,
42     const absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant>&
43         param_definition_variants,
44     auto& audio_frame_timing_data, auto& parameter_block_timing_data) {
45   // TODO(b/283281856): Handle cases where `parameter_rate` and `sample_rate`
46   //                    differ.
47   for (const auto& [unused_id, audio_element] : audio_elements) {
48     // Initialize all substream IDs to start at 0 even if the substreams do not
49     // actually appear in the bitstream.
50     for (const auto& audio_substream_id :
51          audio_element.obu.audio_substream_ids_) {
52       const uint32_t sample_rate =
53           audio_element.codec_config->GetOutputSampleRate();
54       RETURN_IF_NOT_OK(
55           ValidateNotEqual(sample_rate, uint32_t{0}, "sample rate"));
56 
57       const auto [unused_iter, inserted] = audio_frame_timing_data.insert(
58           {audio_substream_id, {.rate = sample_rate, .timestamp = 0}});
59 
60       if (!inserted) {
61         return absl::InvalidArgumentError(
62             absl::StrCat("Audio substream ID: ", audio_substream_id,
63                          " already exists in the Global Timing Module"));
64       }
65     }
66   }
67 
68   // Initialize all parameter IDs to start with a timestamp 0.
69   for (const auto& [parameter_id, param_definition_variant] :
70        param_definition_variants) {
71     const DecodedUleb128 parameter_rate = std::visit(
72         [](const auto& param_definition) {
73           return param_definition.parameter_rate_;
74         },
75         param_definition_variant);
76     RETURN_IF_NOT_OK(
77         ValidateNotEqual(parameter_rate, DecodedUleb128(0), "parameter rate"));
78 
79     const auto [unused_iter, inserted] = parameter_block_timing_data.insert(
80         {parameter_id, {.rate = parameter_rate, .timestamp = 0}});
81     if (!inserted) {
82       return absl::InvalidArgumentError(
83           absl::StrCat("Parameter ID: ", parameter_id,
84                        " already exists in the Global Timing Module"));
85     }
86   }
87 
88   return absl::OkStatus();
89 }
90 
91 }  // namespace
92 
Create(const absl::flat_hash_map<DecodedUleb128,AudioElementWithData> & audio_elements,const absl::flat_hash_map<DecodedUleb128,ParamDefinitionVariant> & param_definition_variants)93 std::unique_ptr<GlobalTimingModule> GlobalTimingModule::Create(
94     const absl::flat_hash_map<DecodedUleb128, AudioElementWithData>&
95         audio_elements,
96     const absl::flat_hash_map<DecodedUleb128, ParamDefinitionVariant>&
97         param_definition_variants) {
98   absl::flat_hash_map<DecodedUleb128, TimingData> audio_frame_timing_data;
99   absl::flat_hash_map<DecodedUleb128, TimingData> parameter_block_timing_data;
100   const auto status =
101       InitializeInternal(audio_elements, param_definition_variants,
102                          audio_frame_timing_data, parameter_block_timing_data);
103   if (!status.ok()) {
104     LOG(ERROR) << status;
105     return nullptr;
106   }
107 
108   return absl::WrapUnique(
109       new GlobalTimingModule(std::move(audio_frame_timing_data),
110                              std::move(parameter_block_timing_data)));
111 }
112 
GetNextAudioFrameTimestamps(const DecodedUleb128 audio_substream_id,const uint32_t duration,InternalTimestamp & start_timestamp,InternalTimestamp & end_timestamp)113 absl::Status GlobalTimingModule::GetNextAudioFrameTimestamps(
114     const DecodedUleb128 audio_substream_id, const uint32_t duration,
115     InternalTimestamp& start_timestamp, InternalTimestamp& end_timestamp) {
116   return GetTimestampsForId(audio_substream_id, duration,
117                             audio_frame_timing_data_, start_timestamp,
118                             end_timestamp);
119 }
120 
GetNextParameterBlockTimestamps(const uint32_t parameter_id,const InternalTimestamp input_start_timestamp,const uint32_t duration,InternalTimestamp & start_timestamp,InternalTimestamp & end_timestamp)121 absl::Status GlobalTimingModule::GetNextParameterBlockTimestamps(
122     const uint32_t parameter_id, const InternalTimestamp input_start_timestamp,
123     const uint32_t duration, InternalTimestamp& start_timestamp,
124     InternalTimestamp& end_timestamp) {
125   RETURN_IF_NOT_OK(GetTimestampsForId(parameter_id, duration,
126                                       parameter_block_timing_data_,
127                                       start_timestamp, end_timestamp));
128   return CompareTimestamps(
129       input_start_timestamp, start_timestamp,
130       absl::StrCat("In GetNextParameterBlockTimestamps() for param ID= ",
131                    parameter_id, ": "));
132 }
133 
GetGlobalAudioFrameTimestamp(std::optional<InternalTimestamp> & global_timestamp) const134 absl::Status GlobalTimingModule::GetGlobalAudioFrameTimestamp(
135     std::optional<InternalTimestamp>& global_timestamp) const {
136   if (audio_frame_timing_data_.empty()) {
137     return absl::InvalidArgumentError("No audio frames to get timestamps for");
138   }
139 
140   const InternalTimestamp common_timestamp =
141       audio_frame_timing_data_.begin()->second.timestamp;
142   for (const auto& [unused_id, timing_data] : audio_frame_timing_data_) {
143     if (common_timestamp != timing_data.timestamp) {
144       // Some audio frames have not advance their timestamps yet, return OK
145       // but let `global_timestamp` hold no value.
146       global_timestamp = std::nullopt;
147       return absl::OkStatus();
148     }
149   }
150 
151   global_timestamp = common_timestamp;
152   return absl::OkStatus();
153 }
154 
GetTimestampsForId(const DecodedUleb128 id,const uint32_t duration,absl::flat_hash_map<DecodedUleb128,TimingData> & id_to_timing_data,InternalTimestamp & start_timestamp,InternalTimestamp & end_timestamp)155 absl::Status GlobalTimingModule::GetTimestampsForId(
156     const DecodedUleb128 id, const uint32_t duration,
157     absl::flat_hash_map<DecodedUleb128, TimingData>& id_to_timing_data,
158     InternalTimestamp& start_timestamp, InternalTimestamp& end_timestamp) {
159   auto timing_data_iter = id_to_timing_data.find(id);
160   if (timing_data_iter == id_to_timing_data.end()) {
161     // This allows generating timing information when
162     // `IGNORE_ERRORS_USE_ONLY_FOR_IAMF_TEST_SUITE` is defined.
163     // TODO(b/278865608): Find better solutions to generate negative test
164     //                    vectors.
165     start_timestamp = 0;
166     end_timestamp = duration;
167     return absl::InvalidArgumentError(
168         absl::StrCat("Timestamps for ID: ", id, " not found"));
169   }
170 
171   auto& timing_data = timing_data_iter->second;
172   start_timestamp = timing_data.timestamp;
173   end_timestamp = start_timestamp + duration;
174   timing_data.timestamp += duration;
175   return absl::OkStatus();
176 }
177 
178 }  // namespace iamf_tools
179