chromium/chromecast/public/media/decoder_config.h

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROMECAST_PUBLIC_MEDIA_DECODER_CONFIG_H_
#define CHROMECAST_PUBLIC_MEDIA_DECODER_CONFIG_H_

#include <stdint.h>

#include <vector>

#include "cast_decrypt_config.h"
#include "stream_id.h"

namespace chromecast::media {

// Maximum audio bytes per sample.
static const int kMaxBytesPerSample = 4;

// Maximum audio sampling rate.
static const int kMaxSampleRate = 192000;

// TODO(guohuideng): change at least AudioCodec and SampleFormat to enum class.
enum AudioCodec : int {
  kAudioCodecUnknown = 0,
  kCodecAAC,
  kCodecMP3,
  kCodecPCM,
  kCodecPCM_S16BE,
  kCodecVorbis,
  kCodecOpus,
  kCodecEAC3,
  kCodecAC3,
  kCodecDTS,
  kCodecFLAC,
  kCodecMpegHAudio,
  kCodecDTSXP2,
  kCodecDTSE,

  kAudioCodecMin = kAudioCodecUnknown,
  kAudioCodecMax = kCodecDTSE,
};

enum class ChannelLayout {
  UNSUPPORTED,

  // Front C
  MONO,

  // Front L, Front R
  STEREO,

  // Front L, Front R, Front C, LFE, Side L, Side R
  SURROUND_5_1,

  // Actual channel layout is specified in the bitstream and the actual channel
  // count is unknown at Chromium media pipeline level (useful for audio
  // pass-through mode).
  BITSTREAM,

  // Channels are not explicitly mapped to speakers.
  DISCRETE,

  // Max value, must always equal the largest entry ever logged.
  MAX_LAST = DISCRETE,
};

// Internal chromecast apps use this to decide on channel_layout.
inline ChannelLayout ChannelLayoutFromChannelNumber(int channel_number) {
  switch (channel_number) {
    case 1:
      return ChannelLayout::MONO;
    case 2:
      return ChannelLayout::STEREO;
    case 6:
      return ChannelLayout::SURROUND_5_1;
    default:
      return ChannelLayout::UNSUPPORTED;
  }
}

enum SampleFormat : int {
  kUnknownSampleFormat = 0,
  kSampleFormatU8,         // Unsigned 8-bit w/ bias of 128.
  kSampleFormatS16,        // Signed 16-bit.
  kSampleFormatS32,        // Signed 32-bit.
  kSampleFormatF32,        // Float 32-bit.
  kSampleFormatPlanarS16,  // Signed 16-bit planar.
  kSampleFormatPlanarF32,  // Float 32-bit planar.
  kSampleFormatPlanarS32,  // Signed 32-bit planar.
  kSampleFormatS24,        // Signed 24-bit.
  kSampleFormatPlanarU8,   // Unsigned 8-bit w/ bias of 128 planar.

  kSampleFormatMin = kUnknownSampleFormat,
  kSampleFormatMax = kSampleFormatPlanarU8,
};

enum VideoCodec : int {
  kVideoCodecUnknown = 0,
  kCodecH264,
  kCodecVC1,
  kCodecMPEG2,
  kCodecMPEG4,
  kCodecTheora,
  kCodecVP8,
  kCodecVP9,
  kCodecHEVC,
  kCodecDolbyVisionH264,
  kCodecDolbyVisionHEVC,
  kCodecAV1,

  kVideoCodecMin = kVideoCodecUnknown,
  kVideoCodecMax = kCodecAV1,
};

// Profile for Video codec.
enum VideoProfile : int {
  kVideoProfileUnknown = 0,
  kH264Baseline,
  kH264Main,
  kH264Extended,
  kH264High,
  kH264High10,
  kH264High422,
  kH264High444Predictive,
  kH264ScalableBaseline,
  kH264ScalableHigh,
  kH264StereoHigh,
  kH264MultiviewHigh,
  kVP8ProfileAny,
  kVP9Profile0,
  kVP9Profile1,
  kVP9Profile2,
  kVP9Profile3,
  kDolbyVisionProfile0,
  kDolbyVisionProfile5,
  kDolbyVisionProfile7,
  kHEVCMain,
  kHEVCMain10,
  kHEVCMainStillPicture,
  kAV1ProfileMain,
  kAV1ProfileHigh,
  kAV1ProfilePro,
  kDolbyVisionProfile8,
  kDolbyVisionProfile9,
  kHEVCRext,
  kHEVCHighThroughput,
  kHEVCMultiviewMain,
  kHEVCScalableMain,
  kHEVC3dMain,
  kHEVCScreenExtended,
  kHEVCScalableRext,
  kHEVCHighThroughputScreenExtended,
  kVVCProfileMain10,
  kVVCProfileMain12,
  kVVCProfileMain12Intra,
  kVVCProfileMultilayerMain10,
  kVVCProfileMain10444,
  kVVCProfileMain12444,
  kVVCProfileMain16444,
  kVVCProfileMain12444Intra,
  kVVCProfileMain16444Intra,
  kVVCProfileMultilayerMain10444,
  kVVCProfileMain10Still,
  kVVCProfileMain12Still,
  kVVCProfileMain10444Still,
  kVVCProfileMain12444Still,
  kVVCProfileMain16444Still,

  kVideoProfileMin = kVideoProfileUnknown,
  kVideoProfileMax = kVVCProfileMain16444Still,
};

struct CodecProfileLevel {
  VideoCodec codec;
  VideoProfile profile;
  int level;
};

// ---- Begin copy/paste from //media/base/video_color_space.h ----
// Described in ISO 23001-8:2016

// Table 2
enum class PrimaryID : uint8_t {
  INVALID = 0,
  BT709 = 1,
  UNSPECIFIED = 2,
  BT470M = 4,
  BT470BG = 5,
  SMPTE170M = 6,
  SMPTE240M = 7,
  FILM = 8,
  BT2020 = 9,
  SMPTEST428_1 = 10,
  SMPTEST431_2 = 11,
  SMPTEST432_1 = 12,
  EBU_3213_E = 22
};

// Table 3
enum class TransferID : uint8_t {
  INVALID = 0,
  BT709 = 1,
  UNSPECIFIED = 2,
  GAMMA22 = 4,
  GAMMA28 = 5,
  SMPTE170M = 6,
  SMPTE240M = 7,
  LINEAR = 8,
  LOG = 9,
  LOG_SQRT = 10,
  IEC61966_2_4 = 11,
  BT1361_ECG = 12,
  IEC61966_2_1 = 13,
  BT2020_10 = 14,
  BT2020_12 = 15,
  SMPTEST2084 = 16,
  SMPTEST428_1 = 17,

  // Not yet standardized
  ARIB_STD_B67 = 18,  // AKA hybrid-log gamma, HLG.
};

// Table 4
enum class MatrixID : uint8_t {
  RGB = 0,
  BT709 = 1,
  UNSPECIFIED = 2,
  FCC = 4,
  BT470BG = 5,
  SMPTE170M = 6,
  SMPTE240M = 7,
  YCOCG = 8,
  BT2020_NCL = 9,
  BT2020_CL = 10,
  YDZDX = 11,
  INVALID = 255,
};
// ---- End copy/pasted from media/base/video_color_space.h ----

// This corresponds to the WebM Range enum which is part of WebM color data
// (see http://www.webmproject.org/docs/container/#Range).
// H.264 only uses a bool, which corresponds to the LIMITED/FULL values.
// ---- Begin copy/paste from //ui/gfx/color_space.h ----
enum class RangeID : int8_t {
  INVALID = 0,
  // Limited Rec. 709 color range with RGB values ranging from 16 to 235.
  LIMITED = 1,
  // Full RGB color range with RGB values from 0 to 255.
  FULL = 2,
  // Range is defined by TransferID/MatrixID.
  DERIVED = 3,
  LAST = DERIVED
};
// ---- Begin copy/paste from //ui/gfx/color_space.h ----

// ---- Begin copy/paste from //ui/gfx/hdr_metadata.h ----
// SMPTE ST 2086 color volume metadata.
struct ColorVolumeMetadata {
  float primary_r_chromaticity_x = 0;
  float primary_r_chromaticity_y = 0;
  float primary_g_chromaticity_x = 0;
  float primary_g_chromaticity_y = 0;
  float primary_b_chromaticity_x = 0;
  float primary_b_chromaticity_y = 0;
  float white_point_chromaticity_x = 0;
  float white_point_chromaticity_y = 0;
  float luminance_max = 0;
  float luminance_min = 0;

  ColorVolumeMetadata();
  ColorVolumeMetadata(const ColorVolumeMetadata& rhs);
  ColorVolumeMetadata& operator=(const ColorVolumeMetadata& rhs);
};

// HDR metadata common for HDR10 and WebM/VP9-based HDR formats.
struct HDRMetadata {
  ColorVolumeMetadata color_volume_metadata;
  unsigned max_content_light_level = 0;
  unsigned max_frame_average_light_level = 0;

  HDRMetadata();
  HDRMetadata(const HDRMetadata& rhs);
  HDRMetadata& operator=(const HDRMetadata& rhs);
};

inline ColorVolumeMetadata::ColorVolumeMetadata() = default;
inline ColorVolumeMetadata::ColorVolumeMetadata(const ColorVolumeMetadata&) =
    default;
inline ColorVolumeMetadata& ColorVolumeMetadata::operator=(
    const ColorVolumeMetadata&) = default;

inline HDRMetadata::HDRMetadata() = default;
inline HDRMetadata::HDRMetadata(const HDRMetadata&) = default;
inline HDRMetadata& HDRMetadata::operator=(const HDRMetadata&) = default;
// ---- End copy/paste from //ui/gfx/hdr_metadata.h ----

constexpr int kChannelAll = -1;

// TODO(erickung): Remove constructor once CMA backend implementation doesn't
// create a new object to reset the configuration and use IsValidConfig() to
// determine if the configuration is still valid or not.
struct AudioConfig {
  AudioConfig();
  AudioConfig(const AudioConfig& other);
  ~AudioConfig();

  bool is_encrypted() const {
    return encryption_scheme != EncryptionScheme::kUnencrypted;
  }

  // Stream id.
  StreamId id = StreamId::kPrimary;
  // Audio codec.
  AudioCodec codec = AudioCodec::kAudioCodecUnknown;
  // Audio channel layout.
  ChannelLayout channel_layout = ChannelLayout::UNSUPPORTED;
  // The format of each audio sample.
  SampleFormat sample_format = SampleFormat::kUnknownSampleFormat;
  // Number of bytes in each channel.
  int bytes_per_channel = 0;
  // Number of channels in this audio stream.
  int channel_number = 0;
  // Number of audio samples per second.
  int samples_per_second = 0;
  // Extra data buffer for certain codec initialization.
  std::vector<uint8_t> extra_data;
  // Encryption scheme (if any) used for the content.
  EncryptionScheme encryption_scheme = EncryptionScheme::kUnencrypted;
  // Hardware AV sync flag.
  bool use_hw_av_sync = false;
  // The session id which the Android AudioTrack will be attached to. If not
  // valid, a new one will be atomically generated by the Android system.
  // For Cast Connect Multizone use case, if the app uses hardware av sync,
  // mediashell will get the id of the media session opened by the app.
  int audio_track_session_id = 0;
};

inline AudioConfig::AudioConfig() = default;
inline AudioConfig::AudioConfig(const AudioConfig& other) = default;
inline AudioConfig::~AudioConfig() = default;

// TODO(erickung): Remove constructor once CMA backend implementation does't
// create a new object to reset the configuration and use IsValidConfig() to
// determine if the configuration is still valid or not.
struct VideoConfig {
  VideoConfig();
  VideoConfig(const VideoConfig& other);
  ~VideoConfig();

  bool is_encrypted() const {
    return encryption_scheme != EncryptionScheme::kUnencrypted;
  }

  // Stream Id.
  StreamId id = StreamId::kPrimary;
  // Video codec.
  VideoCodec codec = VideoCodec::kVideoCodecUnknown;
  // Video codec profile.
  VideoProfile profile = VideoProfile::kVideoProfileUnknown;
  // Video codec level.
  uint32_t codec_profile_level = 0;
  // Additional video config for the video stream if available. Consumers of
  // this structure should make an explicit copy of |additional_config| if it
  // will be used after SetConfig() finishes.
  VideoConfig* additional_config = nullptr;
  // Extra data buffer for certain codec initialization.
  std::vector<uint8_t> extra_data;
  // Encryption scheme (if any) used for the content.
  EncryptionScheme encryption_scheme = EncryptionScheme::kUnencrypted;

  // ColorSpace info
  PrimaryID primaries = PrimaryID::UNSPECIFIED;
  TransferID transfer = TransferID::UNSPECIFIED;
  MatrixID matrix = MatrixID::UNSPECIFIED;
  RangeID range = RangeID::INVALID;

  bool have_hdr_metadata = false;
  HDRMetadata hdr_metadata;

  // Info about the width and height, in pixels.
  int width = 0;
  int height = 0;
};

inline VideoConfig::VideoConfig() = default;
inline VideoConfig::VideoConfig(const VideoConfig& other) = default;
inline VideoConfig::~VideoConfig() = default;

inline bool IsValidConfig(const AudioConfig& config) {
  return config.codec >= kAudioCodecMin && config.codec <= kAudioCodecMax &&
         config.codec != kAudioCodecUnknown &&
         config.channel_layout != ChannelLayout::UNSUPPORTED &&
         config.sample_format >= kSampleFormatMin &&
         config.sample_format <= kSampleFormatMax &&
         ((config.sample_format != kUnknownSampleFormat &&
           config.channel_number > 0 && config.bytes_per_channel > 0 &&
           config.bytes_per_channel <= kMaxBytesPerSample) ||
          config.channel_layout == ChannelLayout::BITSTREAM) &&
         config.samples_per_second > 0 &&
         config.samples_per_second <= kMaxSampleRate;
}

inline bool IsValidConfig(const VideoConfig& config) {
  return config.codec >= kVideoCodecMin && config.codec <= kVideoCodecMax &&
         config.codec != kVideoCodecUnknown;
}

}  // namespace chromecast::media

#endif  // CHROMECAST_PUBLIC_MEDIA_DECODER_CONFIG_H_