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 #ifndef CLI_OBU_SEQUENCER_BASE_H_ 13 #define CLI_OBU_SEQUENCER_BASE_H_ 14 15 #include <cstdint> 16 #include <list> 17 #include <optional> 18 #include <vector> 19 20 #include "absl/container/flat_hash_map.h" 21 #include "absl/status/status.h" 22 #include "absl/types/span.h" 23 #include "iamf/cli/audio_element_with_data.h" 24 #include "iamf/cli/audio_frame_with_data.h" 25 #include "iamf/cli/parameter_block_with_data.h" 26 #include "iamf/cli/temporal_unit_view.h" 27 #include "iamf/common/leb_generator.h" 28 #include "iamf/common/write_bit_buffer.h" 29 #include "iamf/obu/arbitrary_obu.h" 30 #include "iamf/obu/codec_config.h" 31 #include "iamf/obu/ia_sequence_header.h" 32 #include "iamf/obu/mix_presentation.h" 33 34 namespace iamf_tools { 35 36 /*!\brief Abstract base class for serializing and writing out OBUs. 37 * 38 * This class contains functions to serialize and write an IA Sequence. The 39 * concrete classes are responsible for packing and writing the output to some 40 * output stream. 41 * 42 * Usage pattern: 43 * // Create a concrete sequencer. Interface is dependent on the conreate 44 * // sequencer. 45 * std::unique_ptr<ObuSequencerBase> sequencer = ...; 46 * 47 * // Call the `PushDescriptorObus` method. 48 * RETURN_IF_NOT_OK(sequencer->PushDescriptorObus(...)); 49 * 50 * while (more data is available) { 51 * // Call the `PushTemporalUnit` method. 52 * RETURN_IF_NOT_OK(sequencer->PushTemporalUnit(...)); 53 * } 54 * // Signal that no more data is coming. 55 * // Depending on the context, choose one of the closing functions. Either 56 * // `UpdateDescriptorObusAndClose` (preferred) or `Close`. 57 * RETURN_IF_NOT_OK(sequencer->UpdateDescriptorObusAndClose(...)); 58 * // Or: 59 * RETURN_IF_NOT_OK(sequencer->Close()); 60 * 61 * // Optionally. `Abort` may be called to clean up output. E.g. file-based 62 * // sequencers could delete their output file. `Abort` is most useful when 63 * // some component outside the class failes; failures in `PushDescriptorObus`, 64 * `PushTemporalUnit`, or `UpdateDescriptorObusAndClose` automatically call 65 * `Abort`. 66 */ 67 class ObuSequencerBase { 68 public: 69 /*!\brief Serializes and writes out a temporal unit. 70 * 71 * Write out the OBUs contained within the input arguments to the output write 72 * buffer. 73 * 74 * \param include_temporal_delimiters Whether the serialized data should 75 * include a temporal delimiter. 76 * \param temporal_unit Temporal unit to write out. 77 * \param wb Write buffer to write to. 78 * \param num_samples Number of samples written out. 79 * \return `absl::OkStatus()` on success. A specific status on failure. 80 */ 81 [[deprecated("Use this class as per the class documentation instead.")]] 82 static absl::Status WriteTemporalUnit(bool include_temporal_delimiters, 83 const TemporalUnitView& temporal_unit, 84 WriteBitBuffer& wb, int& num_samples); 85 86 /*!\brief Writes the input descriptor OBUs. 87 * 88 * Write out the OBUs contained within the input arguments to the output write 89 * buffer. 90 * 91 * \param ia_sequence_header_obu IA Sequence Header OBU to write. 92 * \param codec_config_obus Codec Config OBUs to write. 93 * \param audio_elements Audio Element OBUs with data to write. 94 * \param mix_presentation_obus Mix Presentation OBUs to write. 95 * \param arbitrary_obus Arbitrary OBUs to write. 96 * \param wb Write buffer to write to. 97 * \return `absl::OkStatus()` on success. A specific status on failure. 98 */ 99 [[deprecated("Use this class as per the class documentation instead.")]] 100 static absl::Status WriteDescriptorObus( 101 const IASequenceHeaderObu& ia_sequence_header_obu, 102 const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus, 103 const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements, 104 const std::list<MixPresentationObu>& mix_presentation_obus, 105 const std::list<ArbitraryObu>& arbitrary_obus, WriteBitBuffer& wb); 106 107 /*!\brief Constructor. 108 * 109 * \param leb_generator Leb generator to use when writing OBUs. 110 * \param include_temporal_delimiters Whether the serialized data should 111 * include a temporal delimiter. 112 * \param delay_descriptors_until_first_untrimmed_sample When `true`, 113 * `PushSerializedDescriptorObus` will be delayed until the first 114 * untrimmed sample is pushed. 115 */ 116 ObuSequencerBase(const LebGenerator& leb_generator, 117 bool include_temporal_delimiters, 118 bool delay_descriptors_until_first_untrimmed_sample); 119 120 /*!\brief Destructor.*/ 121 virtual ~ObuSequencerBase() = 0; 122 123 /*!\brief Gathers statistics on and pushes the OBUs to some output. 124 * 125 * \param ia_sequence_header_obu IA Sequence Header OBU to write. 126 * \param codec_config_obus Codec Config OBUs to write. 127 * \param audio_elements Audio Element OBUs with data to write. 128 * \param mix_presentation_obus Mix Presentation OBUs to write. 129 * \param arbitrary_obus Arbitrary OBUs to write. 130 * \return `absl::OkStatus()` on success. A specific status on failure. 131 */ 132 absl::Status PushDescriptorObus( 133 const IASequenceHeaderObu& ia_sequence_header_obu, 134 const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus, 135 const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements, 136 const std::list<MixPresentationObu>& mix_presentation_obus, 137 const std::list<ArbitraryObu>& arbitrary_obus); 138 139 /*!\brief Gathers statistics on and pushes the temporal unit to some output. 140 * 141 * \param temporal_unit Temporal unit to push. 142 * \return `absl::OkStatus()` on success. A specific status on failure. 143 */ 144 absl::Status PushTemporalUnit(const TemporalUnitView& temporal_unit); 145 146 /*!\brief Finalizes the descriptor OBUs and closes the output. 147 * 148 * \param ia_sequence_header_obu IA Sequence Header OBU to write. 149 * \param codec_config_obus Codec Config OBUs to write. 150 * \param audio_elements Audio Element OBUs with data to write. 151 * \param mix_presentation_obus Mix Presentation OBUs to write. 152 * \param arbitrary_obus Arbitrary OBUs to write. 153 * \return `absl::OkStatus()` on success. A specific status on failure. 154 */ 155 absl::Status UpdateDescriptorObusAndClose( 156 const IASequenceHeaderObu& ia_sequence_header_obu, 157 const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus, 158 const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements, 159 const std::list<MixPresentationObu>& mix_presentation_obus, 160 const std::list<ArbitraryObu>& arbitrary_obus); 161 162 /*!\brief Signals that no more data is coming, and closes the output. 163 * 164 * \return `absl::OkStatus()` on success. A specific status on failure. 165 */ 166 absl::Status Close(); 167 168 /*!\brief Aborts writing the output. 169 * 170 * Useful for sequencers which want to clean up their output. Such as to avoid 171 * leaving a stray file when encoding fails. 172 */ 173 void Abort(); 174 175 /*!\brief Pick and places OBUs and write to some output. 176 * 177 * \param ia_sequence_header_obu IA Sequence Header OBU to write. 178 * \param codec_config_obus Codec Config OBUs to write. 179 * \param audio_elements Audio Element OBUs with data to write. 180 * \param mix_presentation_obus Mix Presentation OBUs to write. 181 * \param audio_frames Data about Audio Frame OBUs to write. 182 * \param parameter_blocks Data about Parameter Block OBUs to write. 183 * \param arbitrary_obus Arbitrary OBUs to write. 184 * \return `absl::OkStatus()` on success. A specific status on failure. 185 */ 186 [[deprecated("Use this class as per the class documentation instead.")]] 187 absl::Status PickAndPlace( 188 const IASequenceHeaderObu& ia_sequence_header_obu, 189 const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus, 190 const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements, 191 const std::list<MixPresentationObu>& mix_presentation_obus, 192 const std::list<AudioFrameWithData>& audio_frames, 193 const std::list<ParameterBlockWithData>& parameter_blocks, 194 const std::list<ArbitraryObu>& arbitrary_obus); 195 196 protected: 197 /*!\brief Pushes the descriptor OBUs and to some output. 198 * 199 * Various statistics are also signalled to the concrete class. For example, 200 * an MP4 sequencer may need the timing information to control the timebase in 201 * the output file. Concrete classes may ignore these statistics as they see 202 * fit. 203 * 204 * \param common_samples_per_frame Common number of samples per frame for the 205 * IA Sequence. 206 * \param common_sample_rate Common sample rate for the IA Sequence. 207 * \param common_bit_depth Common bit depth for the IA Sequence. 208 * \param first_untrimmed_timestamp Timestamp for the first untrimmed sample 209 * in the IA Sequence, or 210 * `delay_descriptors_until_first_untrimmed_sample` is `false`. In some 211 * contexts, this is known as the first Presentation Time Stamp (PTS). 212 * \param descriptor_obus Serialized descriptor OBUs to push. 213 * \return `absl::OkStatus()` on success. A specific status on failure. 214 */ 215 virtual absl::Status PushSerializedDescriptorObus( 216 uint32_t common_samples_per_frame, uint32_t common_sample_rate, 217 uint8_t common_bit_depth, 218 std::optional<int64_t> first_untrimmed_timestamp, int num_channels, 219 absl::Span<const uint8_t> descriptor_obus) = 0; 220 221 /*!\brief Pushes a single temporal unit to some output. 222 * 223 * \param timestamp Start timestamp of the temporal unit. 224 * \param num_samples Number of samples in the temporal unit. 225 * \param temporal_unit Temporal unit to push. 226 * \return `absl::OkStatus()` on success. A specific status on failure. 227 */ 228 virtual absl::Status PushSerializedTemporalUnit( 229 int64_t timestamp, int num_samples, 230 absl::Span<const uint8_t> temporal_unit) = 0; 231 232 /*!\brief Pushes the finalized descriptor OBUs to some output. 233 * 234 * \param descriptor_obus Serialized finalized descriptor OBUs to push. 235 * \return `absl::OkStatus()` on success. A specific status on failure. 236 */ 237 virtual absl::Status PushFinalizedDescriptorObus( 238 absl::Span<const uint8_t> descriptor_obus) = 0; 239 240 /*!\brief Signals that no more data is coming, and closes the output. */ 241 virtual void CloseDerived() = 0; 242 243 /*!\brief Aborts writing the output. 244 * 245 * Useful for sequencers which want to clean up their output. Such as to avoid 246 * leaving a stray file when encoding fails. 247 */ 248 virtual void AbortDerived() = 0; 249 250 // The `LebGenerator` to use when writing OBUs. 251 const LebGenerator leb_generator_; 252 253 private: 254 /*!\brief Handles the initial temporal units. 255 * 256 * This function manages state to help process the initial temporal units up 257 * to and including the first one that has a real sample. In a typical IA 258 * Sequence, this would rarely be more few frames. 259 * 260 * \param temporal_unit Temporal unit to push. 261 * \param serialized_temporal_unit Serialized temporla unit. 262 * \return `absl::OkStatus()` on success. A specific status on failure. 263 */ 264 absl::Status HandleInitialTemporalUnits( 265 const TemporalUnitView& temporal_unit, 266 absl::Span<const uint8_t> serialized_temporal_unit); 267 268 enum State { 269 // Initial state. 270 kInitialized, 271 // `PushDescriptorObus` has been called, but it may have been delayed when 272 // `delay_descriptors_until_first_untrimmed_sample_` is `true`. 273 kPushDescriptorObusCalled, 274 // Descriptors have been pushed, in this state temporal units are no longer 275 // delayed. 276 kPushSerializedDescriptorsCalled, 277 // `Close` or `Abort` has been called. 278 kClosed 279 }; 280 State state_ = kInitialized; 281 282 const bool delay_descriptors_until_first_untrimmed_sample_; 283 const bool include_temporal_delimiters_; 284 285 // Statistics for the current IA Sequence. Convenient to hold, in order to 286 // validate that the finalized OBUs are consistent with the initial ones. 287 struct DescriptorStatistics { 288 uint32_t common_samples_per_frame = 0; 289 uint32_t common_sample_rate = 0; 290 uint8_t common_bit_depth = 0; 291 int num_channels = 0; 292 std::optional<int64_t> first_untrimmed_timestamp; 293 std::vector<uint8_t> descriptor_obus; 294 }; 295 std::optional<DescriptorStatistics> descriptor_statistics_; 296 297 // Reusable scratch buffer. 298 WriteBitBuffer wb_; 299 300 int64_t num_temporal_units_for_logging_ = 0; 301 int64_t cumulative_num_samples_for_logging_ = 0; 302 303 // State for delayed OBUs. `delay_descriptors_until_first_untrimmed_sample_ == 304 // true` implies we must cache and delayed OBUs until the first untrimmed 305 // sample is seen. In practical IA Sequences, this is rarely more than a few 306 // temporal units. 307 struct SerializedTemporalUnit { 308 int64_t start_timestamp; 309 uint32_t num_untrimmed_samples; 310 std::vector<uint8_t> data; 311 }; 312 std::list<SerializedTemporalUnit> delayed_temporal_units_; 313 }; 314 315 } // namespace iamf_tools 316 317 #endif // CLI_OBU_SEQUENCER_H_ 318