blob: 955f14c4dd0c2085738513e9d80b664ed62136c7 [file] [log] [blame]
/*
* Copyright (c) 2023, Alliance for Open Media. All rights reserved
*
* This source code is subject to the terms of the BSD 3-Clause Clear License
* and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
* License was not distributed with this source code in the LICENSE file, you
* can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
* Alliance for Open Media Patent License 1.0 was not distributed with this
* source code in the PATENTS file, you can obtain it at
* www.aomedia.org/license/patent.
*/
#ifndef CLI_OBU_SEQUENCER_BASE_H_
#define CLI_OBU_SEQUENCER_BASE_H_
#include <cstdint>
#include <list>
#include <optional>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/status/status.h"
#include "absl/types/span.h"
#include "iamf/cli/audio_element_with_data.h"
#include "iamf/cli/audio_frame_with_data.h"
#include "iamf/cli/parameter_block_with_data.h"
#include "iamf/cli/temporal_unit_view.h"
#include "iamf/common/leb_generator.h"
#include "iamf/common/write_bit_buffer.h"
#include "iamf/obu/arbitrary_obu.h"
#include "iamf/obu/codec_config.h"
#include "iamf/obu/ia_sequence_header.h"
#include "iamf/obu/mix_presentation.h"
namespace iamf_tools {
/*!\brief Abstract base class for serializing and writing out OBUs.
*
* This class contains functions to serialize and write an IA Sequence. The
* concrete classes are responsible for packing and writing the output to some
* output stream.
*
* Usage pattern:
* // Create a concrete sequencer. Interface is dependent on the conreate
* // sequencer.
* std::unique_ptr<ObuSequencerBase> sequencer = ...;
*
* // Call the `PushDescriptorObus` method.
* RETURN_IF_NOT_OK(sequencer->PushDescriptorObus(...));
*
* while (more data is available) {
* // Call the `PushTemporalUnit` method.
* RETURN_IF_NOT_OK(sequencer->PushTemporalUnit(...));
* }
* // Signal that no more data is coming.
* // Depending on the context, choose one of the closing functions. Either
* // `UpdateDescriptorObusAndClose` (preferred) or `Close`.
* RETURN_IF_NOT_OK(sequencer->UpdateDescriptorObusAndClose(...));
* // Or:
* RETURN_IF_NOT_OK(sequencer->Close());
*
* // Optionally. `Abort` may be called to clean up output. E.g. file-based
* // sequencers could delete their output file. `Abort` is most useful when
* // some component outside the class failes; failures in `PushDescriptorObus`,
* `PushTemporalUnit`, or `UpdateDescriptorObusAndClose` automatically call
* `Abort`.
*/
class ObuSequencerBase {
public:
/*!\brief Serializes and writes out a temporal unit.
*
* Write out the OBUs contained within the input arguments to the output write
* buffer.
*
* \param include_temporal_delimiters Whether the serialized data should
* include a temporal delimiter.
* \param temporal_unit Temporal unit to write out.
* \param wb Write buffer to write to.
* \param num_samples Number of samples written out.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
[[deprecated("Use this class as per the class documentation instead.")]]
static absl::Status WriteTemporalUnit(bool include_temporal_delimiters,
const TemporalUnitView& temporal_unit,
WriteBitBuffer& wb, int& num_samples);
/*!\brief Writes the input descriptor OBUs.
*
* Write out the OBUs contained within the input arguments to the output write
* buffer.
*
* \param ia_sequence_header_obu IA Sequence Header OBU to write.
* \param codec_config_obus Codec Config OBUs to write.
* \param audio_elements Audio Element OBUs with data to write.
* \param mix_presentation_obus Mix Presentation OBUs to write.
* \param arbitrary_obus Arbitrary OBUs to write.
* \param wb Write buffer to write to.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
[[deprecated("Use this class as per the class documentation instead.")]]
static absl::Status WriteDescriptorObus(
const IASequenceHeaderObu& ia_sequence_header_obu,
const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
const std::list<MixPresentationObu>& mix_presentation_obus,
const std::list<ArbitraryObu>& arbitrary_obus, WriteBitBuffer& wb);
/*!\brief Constructor.
*
* \param leb_generator Leb generator to use when writing OBUs.
* \param include_temporal_delimiters Whether the serialized data should
* include a temporal delimiter.
* \param delay_descriptors_until_first_untrimmed_sample When `true`,
* `PushSerializedDescriptorObus` will be delayed until the first
* untrimmed sample is pushed.
*/
ObuSequencerBase(const LebGenerator& leb_generator,
bool include_temporal_delimiters,
bool delay_descriptors_until_first_untrimmed_sample);
/*!\brief Destructor.*/
virtual ~ObuSequencerBase() = 0;
/*!\brief Gathers statistics on and pushes the OBUs to some output.
*
* \param ia_sequence_header_obu IA Sequence Header OBU to write.
* \param codec_config_obus Codec Config OBUs to write.
* \param audio_elements Audio Element OBUs with data to write.
* \param mix_presentation_obus Mix Presentation OBUs to write.
* \param arbitrary_obus Arbitrary OBUs to write.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
absl::Status PushDescriptorObus(
const IASequenceHeaderObu& ia_sequence_header_obu,
const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
const std::list<MixPresentationObu>& mix_presentation_obus,
const std::list<ArbitraryObu>& arbitrary_obus);
/*!\brief Gathers statistics on and pushes the temporal unit to some output.
*
* \param temporal_unit Temporal unit to push.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
absl::Status PushTemporalUnit(const TemporalUnitView& temporal_unit);
/*!\brief Finalizes the descriptor OBUs and closes the output.
*
* \param ia_sequence_header_obu IA Sequence Header OBU to write.
* \param codec_config_obus Codec Config OBUs to write.
* \param audio_elements Audio Element OBUs with data to write.
* \param mix_presentation_obus Mix Presentation OBUs to write.
* \param arbitrary_obus Arbitrary OBUs to write.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
absl::Status UpdateDescriptorObusAndClose(
const IASequenceHeaderObu& ia_sequence_header_obu,
const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
const std::list<MixPresentationObu>& mix_presentation_obus,
const std::list<ArbitraryObu>& arbitrary_obus);
/*!\brief Signals that no more data is coming, and closes the output.
*
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
absl::Status Close();
/*!\brief Aborts writing the output.
*
* Useful for sequencers which want to clean up their output. Such as to avoid
* leaving a stray file when encoding fails.
*/
void Abort();
/*!\brief Pick and places OBUs and write to some output.
*
* \param ia_sequence_header_obu IA Sequence Header OBU to write.
* \param codec_config_obus Codec Config OBUs to write.
* \param audio_elements Audio Element OBUs with data to write.
* \param mix_presentation_obus Mix Presentation OBUs to write.
* \param audio_frames Data about Audio Frame OBUs to write.
* \param parameter_blocks Data about Parameter Block OBUs to write.
* \param arbitrary_obus Arbitrary OBUs to write.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
[[deprecated("Use this class as per the class documentation instead.")]]
absl::Status PickAndPlace(
const IASequenceHeaderObu& ia_sequence_header_obu,
const absl::flat_hash_map<uint32_t, CodecConfigObu>& codec_config_obus,
const absl::flat_hash_map<uint32_t, AudioElementWithData>& audio_elements,
const std::list<MixPresentationObu>& mix_presentation_obus,
const std::list<AudioFrameWithData>& audio_frames,
const std::list<ParameterBlockWithData>& parameter_blocks,
const std::list<ArbitraryObu>& arbitrary_obus);
protected:
/*!\brief Pushes the descriptor OBUs and to some output.
*
* Various statistics are also signalled to the concrete class. For example,
* an MP4 sequencer may need the timing information to control the timebase in
* the output file. Concrete classes may ignore these statistics as they see
* fit.
*
* \param common_samples_per_frame Common number of samples per frame for the
* IA Sequence.
* \param common_sample_rate Common sample rate for the IA Sequence.
* \param common_bit_depth Common bit depth for the IA Sequence.
* \param first_untrimmed_timestamp Timestamp for the first untrimmed sample
* in the IA Sequence, or
* `delay_descriptors_until_first_untrimmed_sample` is `false`. In some
* contexts, this is known as the first Presentation Time Stamp (PTS).
* \param descriptor_obus Serialized descriptor OBUs to push.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
virtual absl::Status PushSerializedDescriptorObus(
uint32_t common_samples_per_frame, uint32_t common_sample_rate,
uint8_t common_bit_depth,
std::optional<int64_t> first_untrimmed_timestamp, int num_channels,
absl::Span<const uint8_t> descriptor_obus) = 0;
/*!\brief Pushes a single temporal unit to some output.
*
* \param timestamp Start timestamp of the temporal unit.
* \param num_samples Number of samples in the temporal unit.
* \param temporal_unit Temporal unit to push.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
virtual absl::Status PushSerializedTemporalUnit(
int64_t timestamp, int num_samples,
absl::Span<const uint8_t> temporal_unit) = 0;
/*!\brief Pushes the finalized descriptor OBUs to some output.
*
* \param descriptor_obus Serialized finalized descriptor OBUs to push.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
virtual absl::Status PushFinalizedDescriptorObus(
absl::Span<const uint8_t> descriptor_obus) = 0;
/*!\brief Signals that no more data is coming, and closes the output. */
virtual void CloseDerived() = 0;
/*!\brief Aborts writing the output.
*
* Useful for sequencers which want to clean up their output. Such as to avoid
* leaving a stray file when encoding fails.
*/
virtual void AbortDerived() = 0;
// The `LebGenerator` to use when writing OBUs.
const LebGenerator leb_generator_;
private:
/*!\brief Handles the initial temporal units.
*
* This function manages state to help process the initial temporal units up
* to and including the first one that has a real sample. In a typical IA
* Sequence, this would rarely be more few frames.
*
* \param temporal_unit Temporal unit to push.
* \param serialized_temporal_unit Serialized temporla unit.
* \return `absl::OkStatus()` on success. A specific status on failure.
*/
absl::Status HandleInitialTemporalUnits(
const TemporalUnitView& temporal_unit,
absl::Span<const uint8_t> serialized_temporal_unit);
enum State {
// Initial state.
kInitialized,
// `PushDescriptorObus` has been called, but it may have been delayed when
// `delay_descriptors_until_first_untrimmed_sample_` is `true`.
kPushDescriptorObusCalled,
// Descriptors have been pushed, in this state temporal units are no longer
// delayed.
kPushSerializedDescriptorsCalled,
// `Close` or `Abort` has been called.
kClosed
};
State state_ = kInitialized;
const bool delay_descriptors_until_first_untrimmed_sample_;
const bool include_temporal_delimiters_;
// Statistics for the current IA Sequence. Convenient to hold, in order to
// validate that the finalized OBUs are consistent with the initial ones.
struct DescriptorStatistics {
uint32_t common_samples_per_frame = 0;
uint32_t common_sample_rate = 0;
uint8_t common_bit_depth = 0;
int num_channels = 0;
std::optional<int64_t> first_untrimmed_timestamp;
std::vector<uint8_t> descriptor_obus;
};
std::optional<DescriptorStatistics> descriptor_statistics_;
// Reusable scratch buffer.
WriteBitBuffer wb_;
int64_t num_temporal_units_for_logging_ = 0;
int64_t cumulative_num_samples_for_logging_ = 0;
// State for delayed OBUs. `delay_descriptors_until_first_untrimmed_sample_ ==
// true` implies we must cache and delayed OBUs until the first untrimmed
// sample is seen. In practical IA Sequences, this is rarely more than a few
// temporal units.
struct SerializedTemporalUnit {
int64_t start_timestamp;
uint32_t num_untrimmed_samples;
std::vector<uint8_t> data;
};
std::list<SerializedTemporalUnit> delayed_temporal_units_;
};
} // namespace iamf_tools
#endif // CLI_OBU_SEQUENCER_H_