From 3840b3c863b331c04fd14f594d8064c53b3c29d2 Mon Sep 17 00:00:00 2001 From: sscobici Date: Sun, 6 Oct 2024 09:16:02 +0300 Subject: [PATCH] chore: create utils-format to reuse code between formats --- Cargo.toml | 1 + symphonia-format-isomp4/Cargo.toml | 3 +- symphonia-format-isomp4/src/atoms/avcc.rs | 31 ++------- symphonia-format-mkv/Cargo.toml | 3 +- symphonia-format-mkv/src/codecs.rs | 71 ++------------------- symphonia-utils-format/Cargo.toml | 17 +++++ symphonia-utils-format/README.md | 15 +++++ symphonia-utils-format/src/lib.rs | 15 +++++ symphonia-utils-format/src/video/mod.rs | 78 +++++++++++++++++++++++ 9 files changed, 140 insertions(+), 94 deletions(-) create mode 100644 symphonia-utils-format/Cargo.toml create mode 100644 symphonia-utils-format/README.md create mode 100644 symphonia-utils-format/src/lib.rs create mode 100644 symphonia-utils-format/src/video/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 317412ef..c4c7cf41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "symphonia-format-riff", "symphonia-metadata", "symphonia-play", + "symphonia-utils-format", "symphonia-utils-xiph", "symphonia-check", ] diff --git a/symphonia-format-isomp4/Cargo.toml b/symphonia-format-isomp4/Cargo.toml index 38dc82f2..b78ac4d2 100644 --- a/symphonia-format-isomp4/Cargo.toml +++ b/symphonia-format-isomp4/Cargo.toml @@ -17,4 +17,5 @@ encoding_rs = "0.8.17" log = "0.4" symphonia-core = { version = "0.5.4", path = "../symphonia-core" } symphonia-metadata = { version = "0.5.4", path = "../symphonia-metadata" } -symphonia-utils-xiph = { version = "0.5.4", path = "../symphonia-utils-xiph" } \ No newline at end of file +symphonia-utils-xiph = { version = "0.5.4", path = "../symphonia-utils-xiph" } +symphonia-utils-format = { version = "0.5.4", path = "../symphonia-utils-format" } \ No newline at end of file diff --git a/symphonia-format-isomp4/src/atoms/avcc.rs b/symphonia-format-isomp4/src/atoms/avcc.rs index 303eb79b..127fa03a 100644 --- a/symphonia-format-isomp4/src/atoms/avcc.rs +++ b/symphonia-format-isomp4/src/atoms/avcc.rs @@ -8,8 +8,9 @@ use symphonia_core::codecs::video::well_known::CODEC_ID_H264; use symphonia_core::codecs::video::VideoCodecParameters; use symphonia_core::codecs::CodecProfile; -use symphonia_core::errors::{decode_error, Error, Result}; -use symphonia_core::io::{BitReaderLtr, ReadBitsLtr, ReadBytes}; +use symphonia_core::errors::{Error, Result}; +use symphonia_core::io::ReadBytes; +use symphonia_utils_format::video::AVCDecoderConfigurationRecord; use crate::atoms::{Atom, AtomHeader}; @@ -32,31 +33,9 @@ impl Atom for AvcCAtom { let extra_data = reader.read_boxed_slice_exact(len as usize)?; - dbg!(extra_data.len()); + let avc_config = AVCDecoderConfigurationRecord::read(&extra_data)?; - // Parse the AVCDecoderConfigurationRecord to get the profile and level. Defined in - // ISO/IEC 14496-15 section 5.3.3.1. - let mut br = BitReaderLtr::new(&extra_data); - - // Configuration version is always 1. - let configuration_version = br.read_bits_leq32(8)?; - - if configuration_version != 1 { - return decode_error( - "isomp4 (avc): unexpected avc decoder configuration record version", - ); - } - - // AVC profile as defined in ISO/IEC 14496-10. - let avc_profile_indication = br.read_bits_leq32(8)?; - let _profile_compatibility = br.read_bits_leq32(8)?; - let avc_level_indication = br.read_bits_leq32(8)?; - - Ok(Self { - extra_data, - profile: CodecProfile::new(avc_profile_indication), - level: avc_level_indication, - }) + Ok(Self { extra_data, profile: avc_config.profile, level: avc_config.level }) } } diff --git a/symphonia-format-mkv/Cargo.toml b/symphonia-format-mkv/Cargo.toml index 79f4ae9e..fbc57ab5 100644 --- a/symphonia-format-mkv/Cargo.toml +++ b/symphonia-format-mkv/Cargo.toml @@ -17,4 +17,5 @@ log = "0.4" lazy_static = "1.4.0" symphonia-core = { version = "0.5.4", path = "../symphonia-core" } symphonia-metadata = { version = "0.5.4", path = "../symphonia-metadata" } -symphonia-utils-xiph = { version = "0.5.4", path = "../symphonia-utils-xiph" } \ No newline at end of file +symphonia-utils-xiph = { version = "0.5.4", path = "../symphonia-utils-xiph" } +symphonia-utils-format = { version = "0.5.4", path = "../symphonia-utils-format" } \ No newline at end of file diff --git a/symphonia-format-mkv/src/codecs.rs b/symphonia-format-mkv/src/codecs.rs index 8a8d631b..4de5bdf0 100644 --- a/symphonia-format-mkv/src/codecs.rs +++ b/symphonia-format-mkv/src/codecs.rs @@ -16,7 +16,10 @@ use symphonia_core::codecs::video::{well_known::*, VideoCodecId, VideoCodecParam use symphonia_core::codecs::{CodecId, CodecParameters, CodecProfile}; use symphonia_core::errors::{decode_error, Error, Result}; -use symphonia_core::io::{BitReaderLtr, BufReader, ReadBitsLtr, ReadBytes}; +use symphonia_core::io::{BufReader, ReadBytes}; +use symphonia_utils_format::video::{ + AVCDecoderConfigurationRecord, HEVCDecoderConfigurationRecord, +}; use symphonia_utils_xiph::flac::metadata::{MetadataBlockHeader, MetadataBlockType}; use crate::lacing::read_xiph_sizes; @@ -342,7 +345,7 @@ fn get_codec_profile_and_level(track: &TrackElement) -> (Option, O track .codec_private .as_ref() - .and_then(|buf| HevcDecoderConfigurationRecord::read(buf).ok()) + .and_then(|buf| HEVCDecoderConfigurationRecord::read(buf).ok()) .map(|cfg| (Some(cfg.profile), Some(cfg.level))) .unwrap_or_else(|| (None, None)) } @@ -351,67 +354,3 @@ fn get_codec_profile_and_level(track: &TrackElement) -> (Option, O _ => (None, None), } } - -struct AVCDecoderConfigurationRecord { - profile: CodecProfile, - level: u32, -} - -impl AVCDecoderConfigurationRecord { - fn read(buf: &[u8]) -> Result { - let mut br = BitReaderLtr::new(buf); - - // Parse the AVCDecoderConfigurationRecord to get the profile and level. Defined in - // ISO/IEC 14496-15 section 5.3.3.1. - - // Configuration version is always 1. - let configuration_version = br.read_bits_leq32(8)?; - - if configuration_version != 1 { - return decode_error("mkv (avc): unexpected avc decoder configuration record version"); - } - - // AVC profile as defined in ISO/IEC 14496-10. - let avc_profile_indication = br.read_bits_leq32(8)?; - let _profile_compatibility = br.read_bits_leq32(8)?; - let avc_level_indication = br.read_bits_leq32(8)?; - - Ok(AVCDecoderConfigurationRecord { - profile: CodecProfile::new(avc_profile_indication), - level: avc_level_indication, - }) - } -} - -struct HevcDecoderConfigurationRecord { - profile: CodecProfile, - level: u32, -} - -impl HevcDecoderConfigurationRecord { - fn read(buf: &[u8]) -> Result { - let mut br = BitReaderLtr::new(buf); - - // Parse the HevcDecoderConfigurationRecord to get the profile and level. Defined in - // ISO/IEC 14496-15 section 8.3.3.1. - - // Configuration version is always 1. - let configuration_version = br.read_bits_leq32(8)?; - - if configuration_version != 1 { - return decode_error("mkv (hevc): unexpected avc decoder configuration record version"); - } - - let _general_profile_space = br.read_bits_leq32(2)?; - let _general_tier_flag = br.read_bit()?; - let general_profile_idc = br.read_bits_leq32(5)?; - let _general_profile_compatibility_flags = br.read_bits_leq32(32)?; - let _general_constraint_indicator_flags = br.read_bits_leq64(48)?; - let general_level_idc = br.read_bits_leq32(8)?; - - Ok(HevcDecoderConfigurationRecord { - profile: CodecProfile::new(general_profile_idc), - level: general_level_idc, - }) - } -} diff --git a/symphonia-utils-format/Cargo.toml b/symphonia-utils-format/Cargo.toml new file mode 100644 index 00000000..c10458fa --- /dev/null +++ b/symphonia-utils-format/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "symphonia-utils-format" +version = "0.5.4" +description = "Project Symphonia utilities for formats." +homepage = "https://github.com/pdeljanov/Symphonia" +repository = "https://github.com/pdeljanov/Symphonia" +authors = ["Philip Deljanov "] +license = "MPL-2.0" +readme = "README.md" +categories = ["multimedia", "multimedia::audio", "multimedia::encoding"] +keywords = ["audio", "multimedia", "media", "mpeg"] +edition = "2021" +rust-version = "1.56" + +[dependencies] +symphonia-core = { version = "0.5.4", path = "../symphonia-core" } +symphonia-metadata = { version = "0.5.4", path = "../symphonia-metadata" } \ No newline at end of file diff --git a/symphonia-utils-format/README.md b/symphonia-utils-format/README.md new file mode 100644 index 00000000..813e018f --- /dev/null +++ b/symphonia-utils-format/README.md @@ -0,0 +1,15 @@ +# Symphonia Format Utilities + +[![Docs](https://docs.rs/symphonia-utils-format/badge.svg)](https://docs.rs/symphonia-utils-format) + +Common utilities for formats for Project Symphonia. + +**Note:** This crate is part of Symphonia. Please use the [`symphonia`](https://crates.io/crates/symphonia) crate instead of this one directly. + +## License + +Symphonia is provided under the MPL v2.0 license. Please refer to the LICENSE file for more details. + +## Contributing + +Symphonia is a free and open-source project that welcomes contributions! To get started, please read our [Contribution Guidelines](https://github.com/pdeljanov/Symphonia/tree/master/CONTRIBUTING.md). diff --git a/symphonia-utils-format/src/lib.rs b/symphonia-utils-format/src/lib.rs new file mode 100644 index 00000000..06381e88 --- /dev/null +++ b/symphonia-utils-format/src/lib.rs @@ -0,0 +1,15 @@ +// 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/. + +// The following lints are allowed in all Symphonia crates. Please see clippy.toml for their +// justification. +#![allow(clippy::comparison_chain)] +#![allow(clippy::excessive_precision)] +#![allow(clippy::identity_op)] +#![allow(clippy::manual_range_contains)] + +pub mod video; diff --git a/symphonia-utils-format/src/video/mod.rs b/symphonia-utils-format/src/video/mod.rs new file mode 100644 index 00000000..ae873500 --- /dev/null +++ b/symphonia-utils-format/src/video/mod.rs @@ -0,0 +1,78 @@ +// 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::CodecProfile; +use symphonia_core::errors::{decode_error, Result}; +use symphonia_core::io::{BitReaderLtr, ReadBitsLtr}; + +pub struct AVCDecoderConfigurationRecord { + pub profile: CodecProfile, + pub level: u32, +} + +impl AVCDecoderConfigurationRecord { + pub fn read(buf: &[u8]) -> Result { + let mut br = BitReaderLtr::new(buf); + + // Parse the AVCDecoderConfigurationRecord to get the profile and level. Defined in + // ISO/IEC 14496-15 section 5.3.3.1. + + // Configuration version is always 1. + let configuration_version = br.read_bits_leq32(8)?; + + if configuration_version != 1 { + return decode_error( + "utils (avc): unexpected avc decoder configuration record version", + ); + } + + // AVC profile as defined in ISO/IEC 14496-10. + let avc_profile_indication = br.read_bits_leq32(8)?; + let _profile_compatibility = br.read_bits_leq32(8)?; + let avc_level_indication = br.read_bits_leq32(8)?; + + Ok(AVCDecoderConfigurationRecord { + profile: CodecProfile::new(avc_profile_indication), + level: avc_level_indication, + }) + } +} + +pub struct HEVCDecoderConfigurationRecord { + pub profile: CodecProfile, + pub level: u32, +} + +impl HEVCDecoderConfigurationRecord { + pub fn read(buf: &[u8]) -> Result { + let mut br = BitReaderLtr::new(buf); + + // Parse the HEVCDecoderConfigurationRecord to get the profile and level. Defined in + // ISO/IEC 14496-15 section 8.3.3.1. + + // Configuration version is always 1. + let configuration_version = br.read_bits_leq32(8)?; + + if configuration_version != 1 { + return decode_error( + "utils (hevc): unexpected hevc decoder configuration record version", + ); + } + + let _general_profile_space = br.read_bits_leq32(2)?; + let _general_tier_flag = br.read_bit()?; + let general_profile_idc = br.read_bits_leq32(5)?; + let _general_profile_compatibility_flags = br.read_bits_leq32(32)?; + let _general_constraint_indicator_flags = br.read_bits_leq64(48)?; + let general_level_idc = br.read_bits_leq32(8)?; + + Ok(HEVCDecoderConfigurationRecord { + profile: CodecProfile::new(general_profile_idc), + level: general_level_idc, + }) + } +}