Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert VideoCodecParameters.extra_data to vector #323

Open
wants to merge 5 commits into
base: dev-0.6
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions symphonia-common/src/mpeg/video/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,37 @@ impl HEVCDecoderConfigurationRecord {
})
}
}

#[derive(Debug, Default)]
pub struct DOVIDecoderConfigurationRecord {
pub dv_version_major: u8,
pub dv_version_minor: u8,
pub dv_profile: u8,
pub dv_level: u8,
pub rpu_present_flag: bool,
pub el_present_flag: bool,
pub bl_present_flag: bool,
pub dv_bl_signal_compatibility_id: u8,
}

impl DOVIDecoderConfigurationRecord {
pub fn read(buf: &[u8]) -> Result<Self> {
let mut br = BitReaderLtr::new(buf);

// Parse the DOVIDecoderConfigurationRecord, point 3.2 from
// https://professional.dolby.com/siteassets/content-creation/dolby-vision-for-content-creators/dolby_vision_bitstreams_within_the_iso_base_media_file_format_dec2017.pdf

let config = DOVIDecoderConfigurationRecord {
dv_version_major: br.read_bits_leq32(8)? as u8,
dv_version_minor: br.read_bits_leq32(8)? as u8,
dv_profile: br.read_bits_leq32(7)? as u8,
dv_level: br.read_bits_leq32(6)? as u8,
rpu_present_flag: br.read_bit()? != 0,
el_present_flag: br.read_bit()? != 0,
bl_present_flag: br.read_bit()? != 0,
dv_bl_signal_compatibility_id: br.read_bits_leq32(4)? as u8,
};

Ok(config)
}
}
64 changes: 49 additions & 15 deletions symphonia-core/src/codecs/video.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,29 @@ impl fmt::Display for VideoCodecId {
}
}

/// An `VideoExtraDataId` is a unique identifier used to identify a specific video extra data.
#[repr(transparent)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct VideoExtraDataId(u32);

/// Null video extra data ID.
pub const VIDEO_EXTRA_DATA_ID_NULL: VideoExtraDataId = VideoExtraDataId(0x0);

impl Default for VideoExtraDataId {
fn default() -> Self {
VIDEO_EXTRA_DATA_ID_NULL
}
}

/// Extra data for a video codec.
#[derive(Clone, Debug, Default)]
pub struct VideoExtraData {
/// The extra data ID.
pub id: VideoExtraDataId,
/// Extra data (defined by codec)
pub data: Box<[u8]>,
}

/// Codec parameters for video codecs.
#[derive(Clone, Debug, Default)]
pub struct VideoCodecParameters {
Expand All @@ -67,21 +90,10 @@ pub struct VideoCodecParameters {
/// Video height.
pub height: Option<u16>,
/// Extra data (defined by the codec).
pub extra_data: Option<Box<[u8]>>,
pub extra_data: Vec<VideoExtraData>,
}

impl VideoCodecParameters {
pub fn new() -> VideoCodecParameters {
VideoCodecParameters {
codec: CODEC_ID_NULL_VIDEO,
profile: None,
level: None,
width: None,
height: None,
extra_data: None,
}
}

/// Provide the `VideoCodecId`.
pub fn for_codec(&mut self, codec: VideoCodecId) -> &mut Self {
self.codec = codec;
Expand Down Expand Up @@ -112,9 +124,9 @@ impl VideoCodecParameters {
self
}

/// Provide codec extra data.
pub fn with_extra_data(&mut self, data: Box<[u8]>) -> &mut Self {
self.extra_data = Some(data);
/// Adds codec's extra data.
pub fn add_extra_data(&mut self, data: VideoExtraData) -> &mut Self {
self.extra_data.push(data);
self
}
}
Expand Down Expand Up @@ -379,4 +391,26 @@ pub mod well_known {
/// VC-1 Advanced Profile
pub const CODEC_PROFILE_VC1_ADVANCED: CodecProfile = CodecProfile(2);
}

pub mod extra_data {
use super::super::VideoExtraDataId;

/// AVCDecoderConfigurationRecord
pub const VIDEO_EXTRA_DATA_ID_AVC_DECODER_CONFIG: VideoExtraDataId = VideoExtraDataId(1);

/// HEVCDecoderConfigurationRecord
pub const VIDEO_EXTRA_DATA_ID_HEVC_DECODER_CONFIG: VideoExtraDataId = VideoExtraDataId(2);

/// VP9DecoderConfiguration
pub const VIDEO_EXTRA_DATA_ID_VP9_DECODER_CONFIG: VideoExtraDataId = VideoExtraDataId(3);

/// AV1DecoderConfiguration
pub const VIDEO_EXTRA_DATA_ID_AV1_DECODER_CONFIG: VideoExtraDataId = VideoExtraDataId(4);

/// DolbyVisionConfiguration
pub const VIDEO_EXTRA_DATA_ID_DOLBY_VISION_CONFIG: VideoExtraDataId = VideoExtraDataId(5);

/// DolbyVision EL HEVC
pub const VIDEO_EXTRA_DATA_ID_DOLBY_VISION_EL_HEVC: VideoExtraDataId = VideoExtraDataId(6);
}
}
8 changes: 5 additions & 3 deletions symphonia-format-isomp4/src/atoms/alac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_core::codecs::audio::well_known::CODEC_ID_ALAC;
use symphonia_core::codecs::audio::AudioCodecParameters;
use symphonia_core::errors::{decode_error, unsupported_error, Result};
use symphonia_core::io::ReadBytes;

use crate::atoms::{Atom, AtomHeader};

use super::stsd::AudioSampleEntry;

#[allow(dead_code)]
#[derive(Debug)]
pub struct AlacAtom {
Expand Down Expand Up @@ -46,7 +47,8 @@ impl Atom for AlacAtom {
}

impl AlacAtom {
pub fn fill_codec_params(&self, codec_params: &mut AudioCodecParameters) {
codec_params.for_codec(CODEC_ID_ALAC).with_extra_data(self.extra_data.clone());
pub fn fill_audio_sample_entry(&self, entry: &mut AudioSampleEntry) {
entry.codec_id = CODEC_ID_ALAC;
entry.extra_data = Some(self.extra_data.clone());
}
}
25 changes: 15 additions & 10 deletions symphonia-format-isomp4/src/atoms/avcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_common::mpeg::video::AVCDecoderConfigurationRecord;
use symphonia_core::codecs::video::well_known::extra_data::VIDEO_EXTRA_DATA_ID_AVC_DECODER_CONFIG;
use symphonia_core::codecs::video::well_known::CODEC_ID_H264;
use symphonia_core::codecs::video::VideoCodecParameters;
use symphonia_core::codecs::video::VideoExtraData;
use symphonia_core::codecs::CodecProfile;
use symphonia_core::errors::{Error, Result};
use symphonia_core::io::ReadBytes;

use crate::atoms::{Atom, AtomHeader};

use super::stsd::VisualSampleEntry;

#[allow(dead_code)]
#[derive(Debug)]
pub struct AvcCAtom {
/// AVC extra data (AVCDecoderConfigurationRecord).
extra_data: Box<[u8]>,
extra_data: VideoExtraData,
profile: CodecProfile,
level: u32,
}
Expand All @@ -31,20 +34,22 @@ impl Atom for AvcCAtom {
.data_len()
.ok_or_else(|| Error::DecodeError("isomp4 (avcC): expected atom size to be known"))?;

let extra_data = reader.read_boxed_slice_exact(len as usize)?;
let extra_data = VideoExtraData {
id: VIDEO_EXTRA_DATA_ID_AVC_DECODER_CONFIG,
data: reader.read_boxed_slice_exact(len as usize)?,
};

let avc_config = AVCDecoderConfigurationRecord::read(&extra_data)?;
let avc_config = AVCDecoderConfigurationRecord::read(&extra_data.data)?;

Ok(Self { extra_data, profile: avc_config.profile, level: avc_config.level })
}
}

impl AvcCAtom {
pub fn fill_codec_params(&self, codec_params: &mut VideoCodecParameters) {
codec_params
.for_codec(CODEC_ID_H264)
.with_profile(self.profile)
.with_level(self.level)
.with_extra_data(self.extra_data.clone());
pub fn fill_video_sample_entry(&self, entry: &mut VisualSampleEntry) {
entry.codec_id = CODEC_ID_H264;
entry.profile = Some(self.profile);
entry.level = Some(self.level);
entry.extra_data.push(self.extra_data.clone());
}
}
8 changes: 5 additions & 3 deletions symphonia-format-isomp4/src/atoms/dac3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_core::codecs::audio::well_known::CODEC_ID_AC3;
use symphonia_core::codecs::audio::AudioCodecParameters;
use symphonia_core::errors::{Error, Result};
use symphonia_core::io::ReadBytes;

use crate::atoms::{Atom, AtomHeader};

use super::stsd::AudioSampleEntry;

#[allow(dead_code)]
#[derive(Debug)]
pub struct Dac3Atom {
Expand All @@ -33,7 +34,8 @@ impl Atom for Dac3Atom {
}

impl Dac3Atom {
pub fn fill_codec_params(&self, codec_params: &mut AudioCodecParameters) {
codec_params.for_codec(CODEC_ID_AC3).with_extra_data(self.extra_data.clone());
pub fn fill_audio_sample_entry(&self, entry: &mut AudioSampleEntry) {
entry.codec_id = CODEC_ID_AC3;
entry.extra_data = Some(self.extra_data.clone());
}
}
8 changes: 5 additions & 3 deletions symphonia-format-isomp4/src/atoms/dec3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_core::codecs::audio::well_known::CODEC_ID_EAC3;
use symphonia_core::codecs::audio::AudioCodecParameters;
use symphonia_core::errors::{Error, Result};
use symphonia_core::io::ReadBytes;

use crate::atoms::{Atom, AtomHeader};

use super::stsd::AudioSampleEntry;

#[allow(dead_code)]
#[derive(Debug)]
pub struct Dec3Atom {
Expand All @@ -33,7 +34,8 @@ impl Atom for Dec3Atom {
}

impl Dec3Atom {
pub fn fill_codec_params(&self, codec_params: &mut AudioCodecParameters) {
codec_params.for_codec(CODEC_ID_EAC3).with_extra_data(self.extra_data.clone());
pub fn fill_audio_sample_entry(&self, entry: &mut AudioSampleEntry) {
entry.codec_id = CODEC_ID_EAC3;
entry.extra_data = Some(self.extra_data.clone());
}
}
43 changes: 43 additions & 0 deletions symphonia-format-isomp4/src/atoms/dovi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Symphonia
// Copyright (c) 2019-2022 The Project Symphonia Developers.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_core::codecs::video::well_known::extra_data::VIDEO_EXTRA_DATA_ID_DOLBY_VISION_CONFIG;
use symphonia_core::codecs::video::VideoExtraData;
use symphonia_core::errors::{Error, Result};
use symphonia_core::io::ReadBytes;

use crate::atoms::{Atom, AtomHeader};

use super::stsd::VisualSampleEntry;

#[allow(dead_code)]
#[derive(Debug)]
pub struct DoviAtom {
extra_data: VideoExtraData,
}

impl Atom for DoviAtom {
fn read<B: ReadBytes>(reader: &mut B, header: AtomHeader) -> Result<Self> {
// The Dolby Vision Configuration atom payload (dvvC and dvcC)
let len = header
.data_len()
.ok_or_else(|| Error::DecodeError("isomp4 (dovi): expected atom size to be known"))?;

let dovi_data = VideoExtraData {
id: VIDEO_EXTRA_DATA_ID_DOLBY_VISION_CONFIG,
data: reader.read_boxed_slice_exact(len as usize)?,
};

Ok(Self { extra_data: dovi_data })
}
}

impl DoviAtom {
pub fn fill_video_sample_entry(&self, entry: &mut VisualSampleEntry) {
entry.extra_data.push(self.extra_data.clone());
}
}
38 changes: 16 additions & 22 deletions symphonia-format-isomp4/src/atoms/esds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use symphonia_core::codecs::audio::AudioCodecParameters;
use symphonia_core::codecs::video::VideoCodecParameters;
use symphonia_core::codecs::video::{VideoExtraData, VIDEO_EXTRA_DATA_ID_NULL};
use symphonia_core::codecs::CodecId;
use symphonia_core::errors::{decode_error, unsupported_error, Error, Result};
use symphonia_core::io::{FiniteStream, ReadBytes, ScopedStream};
Expand All @@ -15,6 +14,8 @@ use crate::atoms::{Atom, AtomHeader};

use log::{debug, warn};

use super::stsd::{AudioSampleEntry, VisualSampleEntry};

const ES_DESCRIPTOR: u8 = 0x03;
const DECODER_CONFIG_DESCRIPTOR: u8 = 0x04;
const DECODER_SPECIFIC_DESCRIPTOR: u8 = 0x05;
Expand Down Expand Up @@ -82,54 +83,47 @@ impl Atom for EsdsAtom {

impl EsdsAtom {
/// If the elementary stream descriptor describes an audio stream, populate the provided
/// audio codec parameters.
pub fn fill_audio_codec_params(&self, codec_params: &mut AudioCodecParameters) -> Result<()> {
use symphonia_core::codecs::audio::CODEC_ID_NULL_AUDIO;

/// audio sample entry.
pub fn fill_audio_sample_entry(&self, entry: &mut AudioSampleEntry) -> Result<()> {
match get_codec_id_from_object_type(self.descriptor.dec_config.object_type_indication) {
Some(CodecId::Audio(id)) => {
// Object type indication identified an audio codec.
codec_params.for_codec(id);
entry.codec_id = id;
}
Some(_) => {
// Object type indication identified a non-audio codec. This is unexpected.
return decode_error("isomp4 (esds): expected an audio codec type");
}
None => {
// Unknown object type indication.
codec_params.for_codec(CODEC_ID_NULL_AUDIO);
}
None => {}
}

if let Some(ds_config) = &self.descriptor.dec_config.dec_specific_info {
codec_params.with_extra_data(ds_config.extra_data.clone());
entry.extra_data = Some(ds_config.extra_data.clone());
}

Ok(())
}

/// If the elementary stream descriptor describes an video stream, populate the provided
/// video codec parameters.
pub fn fill_video_codec_params(&self, codec_params: &mut VideoCodecParameters) -> Result<()> {
use symphonia_core::codecs::video::CODEC_ID_NULL_VIDEO;

/// video sample entry.
pub fn fill_video_sample_entry(&self, entry: &mut VisualSampleEntry) -> Result<()> {
match get_codec_id_from_object_type(self.descriptor.dec_config.object_type_indication) {
Some(CodecId::Video(id)) => {
// Object type indication identified an video codec.
codec_params.for_codec(id);
entry.codec_id = id;
}
Some(_) => {
// Object type indication identified a non-video codec. This is unexpected.
return decode_error("isomp4 (esds): expected a video codec type");
}
None => {
// Unknown object type indication.
codec_params.for_codec(CODEC_ID_NULL_VIDEO);
}
None => {}
}

if let Some(ds_config) = &self.descriptor.dec_config.dec_specific_info {
codec_params.with_extra_data(ds_config.extra_data.clone());
entry.extra_data.push(VideoExtraData {
id: VIDEO_EXTRA_DATA_ID_NULL,
data: ds_config.extra_data.clone(),
});
}

Ok(())
Expand Down
Loading