blob: 19b81f8fd818f4c43e99039eab3f254148f77733 [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 OBU_MIX_PRESENTATION_H_
#define OBU_MIX_PRESENTATION_H_
#include <cstdint>
#include <optional>
#include <string>
#include <utility>
#include <variant>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "iamf/common/read_bit_buffer.h"
#include "iamf/common/write_bit_buffer.h"
#include "iamf/obu/obu_base.h"
#include "iamf/obu/obu_header.h"
#include "iamf/obu/param_definitions.h"
#include "iamf/obu/types.h"
namespace iamf_tools {
struct RenderingConfig {
/*!\brief A 2-bit enum describing how to render the content to headphones. */
enum HeadphonesRenderingMode : uint8_t {
kHeadphonesRenderingModeStereo = 0,
kHeadphonesRenderingModeBinaural = 1,
kHeadphonesRenderingModeReserved2 = 2,
kHeadphonesRenderingModeReserved3 = 3,
};
friend bool operator==(const RenderingConfig& lhs,
const RenderingConfig& rhs) = default;
HeadphonesRenderingMode headphones_rendering_mode; // 2 bits.
uint8_t reserved; // 6 bits.
DecodedUleb128 rendering_config_extension_size;
// Length `rendering_config_extension_size`.
std::vector<uint8_t> rendering_config_extension_bytes;
};
/*!\brief One of the audio elements within a sub-mix. */
struct SubMixAudioElement {
friend bool operator==(const SubMixAudioElement& lhs,
const SubMixAudioElement& rhs) = default;
/*!\brief Reads and validates the SubMixAudioElement from the buffer.
*
* \param rb Buffer to read from.
* \return `absl::OkStatus()` if the layout is valid. A specific status if the
* write fails.
*/
absl::Status ReadAndValidate(const int32_t& count_label, ReadBitBuffer& rb);
// The ID of the associated Audio Element OBU.
DecodedUleb128 audio_element_id;
// Length `count_labels`.
std::vector<std::string> localized_element_annotations;
RenderingConfig rendering_config;
// The gain value to be applied to the rendered audio element signal.
MixGainParamDefinition element_mix_gain;
};
struct AnchoredLoudnessElement {
/*!\brief A 8-bit enum for the associated loudness measurement.
*
* As defined in ISO-CICP.
*/
enum AnchorElement : uint8_t {
kAnchorElementUnknown = 0,
kAnchorElementDialogue = 1,
kAnchorElementAlbum = 2,
};
friend bool operator==(const AnchoredLoudnessElement& lhs,
const AnchoredLoudnessElement& rhs) = default;
AnchorElement anchor_element; // 8 bits.
int16_t anchored_loudness; // Q7.8 format.
};
struct AnchoredLoudness {
friend bool operator==(const AnchoredLoudness& lhs,
const AnchoredLoudness& rhs) = default;
// `num_anchored_loudness` is implicit based on the size of
// `anchor_elements`.
std::vector<AnchoredLoudnessElement> anchor_elements = {};
};
struct LayoutExtension {
friend bool operator==(const LayoutExtension& lhs,
const LayoutExtension& rhs) = default;
DecodedUleb128 info_type_size = 0;
// Length `info_type_size`.
std::vector<uint8_t> info_type_bytes;
};
/*!\brief The loudness information for a given audio signal. */
struct LoudnessInfo {
/*!\brief A 8-bit bitmask to determine the included optional loudness types.
*/
enum InfoTypeBitmask : uint8_t {
kTruePeak = 0x01,
kAnchoredLoudness = 0x02,
kInfoTypeBitMask4 = 0x04,
kInfoTypeBitMask8 = 0x08,
kInfoTypeBitMask16 = 0x10,
kInfoTypeBitMask32 = 0x20,
kInfoTypeBitMask64 = 0x40,
kInfoTypeBitMask128 = 0x80,
// For backwards compatibility several info types signal the need
// for a `layout_extension`.
kAnyLayoutExtension = 0xfc,
};
friend bool operator==(const LoudnessInfo& lhs,
const LoudnessInfo& rhs) = default;
uint8_t info_type; // Apply `LoudnessInfoTypeBitmask` to identify what types
// of loudness information are included.
int16_t integrated_loudness = 0; // Q7.8 format.
int16_t digital_peak = 0; // Q7.8 format.
// Present if `(info_type & kTruePeak) != 0`.
int16_t true_peak = 0; // Q7.8 format.
// Present if `(info_type & kAnchoredLoudness) != 0`.
AnchoredLoudness anchored_loudness;
// Present if `(info_type & kAnyLayoutExtension) != 0`.
LayoutExtension layout_extension;
};
/*!\brief Layout is defined using the sound system convention of ITU2051-3.
*
* Implements syntax and utility functions when the `Layout` defined in
* https://aomediacodec.github.io/iamf/v1.1.0.html#syntax-layout is
* `LOUDSPEAKERS_SS_CONVENTION`.
*/
struct LoudspeakersSsConventionLayout {
/*!\brief A 4-bit enum for loudspeaker layout.
*
* Sound systems A through J refer to ITU2051-3.
*/
enum SoundSystem : uint8_t {
kSoundSystemA_0_2_0 = 0,
kSoundSystemB_0_5_0 = 1,
kSoundSystemC_2_5_0 = 2,
kSoundSystemD_4_5_0 = 3,
kSoundSystemE_4_5_1 = 4,
kSoundSystemF_3_7_0 = 5,
kSoundSystemG_4_9_0 = 6,
kSoundSystemH_9_10_3 = 7,
kSoundSystemI_0_7_0 = 8,
kSoundSystemJ_4_7_0 = 9,
kSoundSystem10_2_7_0 = 10,
kSoundSystem11_2_3_0 = 11,
kSoundSystem12_0_1_0 = 12,
kSoundSystem13_6_9_0 = 13,
kSoundSystemBeginReserved = 14,
kSoundSystemEndReserved = 15,
};
friend bool operator==(const LoudspeakersSsConventionLayout& lhs,
const LoudspeakersSsConventionLayout& rhs) = default;
/*!\brief Writes the layout to the buffer.
*
* \param wb Buffer to write to.
* \return `absl::OkStatus()` if the layout is valid. A specific status if the
* write fails.
*/
absl::Status Write(bool& found_stereo_layout, WriteBitBuffer& wb) const;
/*!\brief Reads the layout from the buffer.
*
* \param rb Buffer to read from.
* \return `absl::OkStatus()` if the layout is valid. A specific status if the
* read fails.
*/
absl::Status Read(ReadBitBuffer& rb);
/*!\brief Prints logging information about the layout. */
void Print() const;
SoundSystem sound_system;
uint8_t reserved; // 2 bits.
};
/*!\brief Layout is binaural or reserved.
*
* Implements syntax and utility functions when the `Layout` defined in
* https://aomediacodec.github.io/iamf/v1.1.0.html#syntax-layout is
* `BINAURAL` or `RESERVED`.
*/
struct LoudspeakersReservedOrBinauralLayout {
friend bool operator==(const LoudspeakersReservedOrBinauralLayout& lhs,
const LoudspeakersReservedOrBinauralLayout& rhs) =
default;
/*!\brief Writes the layout to the buffer.
*
* \param wb Buffer to write to.
* \return `absl::OkStatus()` if the layout is valid. A specific status if the
* write fails.
*/
absl::Status Write(WriteBitBuffer& wb) const;
/*!\brief Reads the layout from the buffer.
*
* \param rb Buffer to read from.
* \return `absl::OkStatus()` if the layout is valid. A specific status if the
* read fails.
*/
absl::Status Read(ReadBitBuffer& rb);
/*!\brief Prints logging information about the layout. */
void Print() const;
uint8_t reserved; // 6 bits.
};
/*!\brief Specifies either a binaural system or physical loudspeaker positions.
*
* Implements syntax and utility functions related to the `Layout` defined in
* https://aomediacodec.github.io/iamf/v1.1.0.html#syntax-layout.
*/
struct Layout {
/*!\brief A 2-bit enum for the type of layout. */
enum LayoutType : uint8_t {
kLayoutTypeReserved0 = 0,
kLayoutTypeReserved1 = 1,
kLayoutTypeLoudspeakersSsConvention = 2, // Using convention of ITU2051-3.
kLayoutTypeBinaural = 3, // Layout is binaural.
};
friend bool operator==(const Layout& lhs, const Layout& rhs) = default;
/*!\brief Reads and validates the Layout from the buffer.
*
* \param rb Buffer to read from.
* \return `absl::OkStatus()` if the layout is valid. A specific status if the
* read fails.
*/
absl::Status ReadAndValidate(ReadBitBuffer& rb);
LayoutType layout_type; // 2 bits.
// The active field depends on `layout_type`.
std::variant<LoudspeakersSsConventionLayout,
LoudspeakersReservedOrBinauralLayout>
specific_layout;
};
/*!\brief Identifies measured loudness information according to layout. */
struct MixPresentationLayout {
friend bool operator==(const MixPresentationLayout& lhs,
const MixPresentationLayout& rhs) = default;
/*!\brief Reads and validates the MixPresentationLayout from the buffer.
*
* \param rb Buffer to read from.
* \return `absl::OkStatus()` if the layout is valid. A specific status if the
* read fails.
*/
absl::Status ReadAndValidate(ReadBitBuffer& rb);
Layout loudness_layout;
LoudnessInfo loudness;
};
/*!\brief One of the sub-mixes within a Mix Presentation Obu. */
struct MixPresentationSubMix {
friend bool operator==(const MixPresentationSubMix& lhs,
const MixPresentationSubMix& rhs) = default;
/*!\brief Reads and validates the MixPresentationSubMix from the buffer.
*
* \param rb Buffer to read from.
* \return `absl::OkStatus()` if the sub-mix is valid. A specific status if
* the read fails.
*/
absl::Status ReadAndValidate(const int32_t& count_label, ReadBitBuffer& rb);
// `num_audio_elements` is implicit based on the size of `audio_elements`.
std::vector<SubMixAudioElement> audio_elements;
// The gain value to be applied in post-processing the mixed audio signal to
// generate the audio signal for playback.
MixGainParamDefinition output_mix_gain;
// `num_layouts` is implicit based on the size of `layouts`.
std::vector<MixPresentationLayout> layouts;
};
struct MixPresentationTags {
struct Tag {
friend bool operator==(const Tag& lhs, const Tag& rhs) = default;
std::string tag_name;
std::string tag_value;
};
friend bool operator==(const MixPresentationTags& lhs,
const MixPresentationTags& rhs) = default;
/*!\brief Writes the MixPresentationTags to the buffer.
*
* \param wb Buffer to write to.
* \return `absl::OkStatus()` if the MixPresentationTags is valid. A specific
* status if the write fails.
*/
absl::Status ValidateAndWrite(WriteBitBuffer& wb) const;
// `num_tags` is implicit based on the size of `tags`.
std::vector<Tag> tags;
};
/*!\brief Metadata required for post-processing the mixed audio signal.
*
* The metadata specifies how to render, process and mix one or more audio
* elements.
*
* A Mix Presentation MAY contain one or more sub-mixes. Common use cases MAY
* specify only one sub-mix, which includes all rendered and processed Audio
* Elements used in the Mix Presentation. The use-case for specifying more than
* one sub-mix arises if an IA multiplexer is merging two or more IA Sequences.
* In this case, it MAY choose to capture the loudness information from the
* original IA Sequences in multiple sub-mixes, instead of recomputing the
* loudness information for the final mix.
*/
class MixPresentationObu : public ObuBase {
public:
/*!\brief Writes the number of channels for a `Layout` to the output argument.
*
* \param loudness_layout `Layout` to process.
* \param num_channels Number of channels for this layout if successful.
* \return `absl::OkStatus()` if successful. `absl::InvalidArgumentError()`
* if the `layout_type` enum is a reserved or unknown value.
*/
static absl::Status GetNumChannelsFromLayout(const Layout& loudness_layout,
int32_t& num_channels);
/*!\brief Constructor.
*
* This class takes ownership of any allocated memory nested within
* `MixGainParamDefinition`s.
*
* \param header `ObuHeader` of the OBU.
* \param mix_presentation_id `mix_presentation_id` in the OBU.
* \param count_label `count_label` in the OBU.
* \param annotations_language Vector representing all of the
* `annotations_language`s in the OBU.
* \param localized_presentation_annotations Vector representing all of the
* `localized_presentation_annotations`s in the OBU.
* \param sub_mixes Vector representing all of the sub mixes in the OBU.
*/
MixPresentationObu(
const ObuHeader& header, DecodedUleb128 mix_presentation_id,
DecodedUleb128 count_label,
const std::vector<std::string>& annotations_language,
const std::vector<std::string>& localized_presentation_annotations,
std::vector<MixPresentationSubMix>& sub_mixes)
: ObuBase(header, kObuIaMixPresentation),
sub_mixes_(std::move(sub_mixes)),
mix_presentation_id_(mix_presentation_id),
count_label_(count_label),
annotations_language_(annotations_language),
localized_presentation_annotations_(
localized_presentation_annotations) {}
/*!\brief Creates a `MixPresentationObu` from a `ReadBitBuffer`.
*
* This function is designed to be used from the perspective of the decoder.
* It will call `ReadAndValidatePayload` in order to read from the buffer;
* therefore it can fail.
*
* \param header `ObuHeader` of the OBU.
* \param payload_size Size of the obu payload in bytes.
* \param rb `ReadBitBuffer` where the `MixPresentationObu` data is stored.
* Data read from the buffer is consumed.
* \return A `MixPresentationObu` on success. A specific status on failure.
*/
static absl::StatusOr<MixPresentationObu> CreateFromBuffer(
const ObuHeader& header, int64_t payload_size, ReadBitBuffer& rb);
/*!\brief Destructor. */
~MixPresentationObu() override = default;
friend bool operator==(const MixPresentationObu& lhs,
const MixPresentationObu& rhs) = default;
/*!\brief Prints logging information about the OBU. */
void PrintObu() const override;
DecodedUleb128 GetMixPresentationId() const { return mix_presentation_id_; }
/*!\brief Gets a copy of the `annotations_language`.
*
* \return A copy of the `annotations_language` member variable.
*/
std::vector<std::string> GetAnnotationsLanguage() const {
return annotations_language_;
}
/*!\brief Gets a copy of the `localized_presentation_annotations`.
*
* \return A copy of the `localized_presentation_annotations` member variable.
*/
std::vector<std::string> GetLocalizedPresentationAnnotations() const {
return localized_presentation_annotations_;
}
DecodedUleb128 GetNumSubMixes() const { return sub_mixes_.size(); }
std::vector<MixPresentationSubMix> sub_mixes_;
// Implicitly included based on `obu_size` after writing the IAMF v1.1.0
// payload.
std::optional<MixPresentationTags> mix_presentation_tags_;
private:
DecodedUleb128 mix_presentation_id_;
DecodedUleb128 count_label_;
// Length `count_label`.
std::vector<std::string> annotations_language_;
// Length `count_label`.
std::vector<std::string> localized_presentation_annotations_;
// `num_sub_mixes_` is implicit based on the size of `sub_mixes_`.
// Used only by the factory create function.
explicit MixPresentationObu(const ObuHeader& header)
: ObuBase(header, kObuIaMixPresentation),
sub_mixes_({}),
mix_presentation_id_(DecodedUleb128()),
count_label_(DecodedUleb128()),
annotations_language_({}),
localized_presentation_annotations_({}) {}
/*!\brief Writes the OBU payload to the buffer.
*
* \param wb Buffer to write to.
* \return `absl::OkStatus()` if OBU is valid. A specific status on failure.
*/
absl::Status ValidateAndWritePayload(WriteBitBuffer& wb) const override;
/*!\brief Reads the OBU payload from the buffer.
*
* \param payload_size Size of the obu payload in bytes.
* \param rb Buffer to read from.
* \return `absl::OkStatus()` if the payload is valid. A specific status on
* failure.
*/
absl::Status ReadAndValidatePayloadDerived(int64_t payload_size,
ReadBitBuffer& rb) override;
};
} // namespace iamf_tools
#endif // OBU_MIX_PRESENTATION_H_