-
-
Notifications
You must be signed in to change notification settings - Fork 30
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
h265 add docs and tests #371
base: main
Are you sure you want to change the base?
Changes from all commits
000ad3d
b205dc8
2c9c675
9f24119
54d0a47
1c3fd49
3a8ddc8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,42 +10,115 @@ use scuffle_bytes_util::{BitReader, BitWriter}; | |
/// HEVC Decoder Configuration Record | ||
/// ISO/IEC 14496-15:2022(E) - 8.3.2.1 | ||
pub struct HEVCDecoderConfigurationRecord { | ||
/// The `configuration_version` as a u8. Matches the field as defined in ISO/IEC 23008-2. | ||
pub configuration_version: u8, | ||
|
||
/// The `general_profile_space` as a u8. Matches the field as defined in ISO/IEC 23008-2. | ||
pub general_profile_space: u8, | ||
|
||
/// The `general_tier_flag` as a bool. Matches the field as defined in ISO/IEC 23008-2. | ||
pub general_tier_flag: bool, | ||
|
||
/// The `general_profile_idc` as a u8. Matches the field as defined in ISO/IEC 23008-2. | ||
pub general_profile_idc: u8, | ||
|
||
/// The `general_profile_compatibility_flags` as a u32. Matches the field as defined in ISO/IEC 23008-2. | ||
pub general_profile_compatibility_flags: u32, | ||
|
||
/// The `general_constraint_indicator_flags` as a u64. Matches the field as defined in ISO/IEC 23008-2. | ||
pub general_constraint_indicator_flags: u64, | ||
|
||
/// The `general_level_idc` as a u32. Matches the field as defined in ISO/IEC 23008-2. | ||
pub general_level_idc: u8, | ||
|
||
/// The `min_spatial_segmentation_idc` as a u16. Matches the field as defined in ISO/IEC 23008-2. | ||
pub min_spatial_segmentation_idc: u16, | ||
pub parallelism_type: u8, | ||
|
||
/// The `chroma_format_idc` as a u8. Matches the field as defined in ISO/IEC 23008-2. | ||
pub chroma_format_idc: u8, | ||
|
||
/// The `bit_depth_luma_minus8` as a u8. Matches the field as defined in ISO/IEC 23008-2. | ||
pub bit_depth_luma_minus8: u8, | ||
|
||
/// The `bit_depth_chroma_minus8` as a u8. Matches the field as defined in ISO/IEC 23008-2. | ||
pub bit_depth_chroma_minus8: u8, | ||
|
||
// TODO: nutype enum | ||
/// The `parallelism_type` as a u8. | ||
/// | ||
/// 0 means the stream supports mixed types of parallel decoding or otherwise. | ||
/// | ||
/// 1 means the stream supports slice based parallel decoding. | ||
/// | ||
/// 2 means the stream supports tile based parallel decoding. | ||
/// | ||
/// 3 means the stream supports entropy coding sync based parallel decoding. | ||
pub parallelism_type: u8, | ||
|
||
// definitely shouldn't be a u16. prolly f64 | ||
/// The `avg_frame_rate` as a u16. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how does this field work for non-integer framerates |
||
pub avg_frame_rate: u16, | ||
|
||
/// The `constant_frame_rate` as a u8. | ||
/// | ||
/// 0 means the stream might have a constant frame rate. | ||
/// | ||
/// 1 means the stream has a constant framerate. | ||
/// | ||
/// 2 means the representation of each temporal layer in the stream has a constant framerate. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Likewise with the nutype-enum |
||
pub constant_frame_rate: u8, | ||
|
||
// make this a nutype enum | ||
/// The `num_temporal_layers` as a u8. This is the count of tepmoral layers or `sub-layer`s as defined in ISO/IEC 23008-2. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should make nutype enums |
||
/// | ||
/// 0 means the stream might be temporally scalable. | ||
/// | ||
/// 1 means the stream is NOT temporally scalable. | ||
/// | ||
/// 2 or more means the stream is temporally scalable, and the count of temporal layers is equal to this value. | ||
pub num_temporal_layers: u8, | ||
|
||
/// The `temporal_id_nested` as a bool. | ||
/// | ||
/// 0 means means the opposite might not be true (refer to what 1 means for this flag). | ||
/// | ||
/// 1 means all the activated SPS have `sps_temporal_id_nesting_flag` (as defined in ISC/IEC 23008-2) set to 1 and that temporal sub-layer up-switching to a higehr temporal layer can be done at any sample. | ||
pub temporal_id_nested: bool, | ||
|
||
/// The `length_size_minus_one` is the u8 length of the NALUnitLength minus one. | ||
pub length_size_minus_one: u8, | ||
|
||
/// The `arrays` is a vec of NaluArray. | ||
/// Refer to the NaluArray struct in the NaluArray docs for more info. | ||
pub arrays: Vec<NaluArray>, | ||
} | ||
|
||
// turn into nutype enum | ||
#[derive(Debug, Clone, PartialEq)] | ||
/// Nalu Array Structure | ||
/// ISO/IEC 14496-15:2022(E) - 8.3.2.1 | ||
pub struct NaluArray { | ||
/// The `array_completeness` is a flag set to 1 when all NAL units are in the array and none are in the stream. It is set to 0 if otherwise. | ||
pub array_completeness: bool, | ||
/// The `nal_unit_type` is the type of the NAL units in the `nalus` vec, as defined in ISO/IEC 23008-2. | ||
/// Refer to the `NaluType` enum for more info. | ||
pub nal_unit_type: NaluType, | ||
/// `nalus` is a vec of NAL units. Each of these will contain either a VPS, PPS, SPS, or an unknown u8 as specified in ISO/IEC 23008-2. | ||
/// Refer to the `NaluType` enum for more info. | ||
pub nalus: Vec<Bytes>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Copy)] | ||
/// Nalu Type | ||
/// The Nalu Type. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be a nutype enum |
||
/// ISO/IEC 23008-2:2020(E) - 7.4.2.2 (Table 7-1) | ||
pub enum NaluType { | ||
/// The Video Parameter Set. | ||
Vps, | ||
/// The Picture Parameter Set. | ||
Pps, | ||
/// The Sequence Parameter Set. | ||
Sps, | ||
/// An unknown u8. This is the default value if the NaluType is set to something other than VPS, PPS, or SPS. | ||
Unknown(u8), | ||
} | ||
|
||
|
@@ -72,6 +145,8 @@ impl From<NaluType> for u8 { | |
} | ||
|
||
impl HEVCDecoderConfigurationRecord { | ||
/// Demuxes an HEVCDecoderConfigurationRecord from a byte stream. | ||
/// Returns a demuxed HEVCDecoderConfigurationRecord. | ||
pub fn demux(data: &mut io::Cursor<Bytes>) -> io::Result<Self> { | ||
let mut bit_reader = BitReader::new(data); | ||
|
||
|
@@ -154,6 +229,7 @@ impl HEVCDecoderConfigurationRecord { | |
}) | ||
} | ||
|
||
/// Returns the total byte size of the HEVCDecoderConfigurationRecord. | ||
pub fn size(&self) -> u64 { | ||
1 // configuration_version | ||
+ 1 // general_profile_space, general_tier_flag, general_profile_idc | ||
|
@@ -178,6 +254,8 @@ impl HEVCDecoderConfigurationRecord { | |
}).sum::<u64>() | ||
} | ||
|
||
/// Muxes the HEVCDecoderConfigurationRecord into a byte stream. | ||
/// Returns a muxed byte stream. | ||
pub fn mux<T: io::Write>(&self, writer: &mut T) -> io::Result<()> { | ||
let mut bit_writer = BitWriter::new(writer); | ||
|
||
|
@@ -230,3 +308,84 @@ impl HEVCDecoderConfigurationRecord { | |
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
#[cfg_attr(all(test, coverage_nightly), coverage(off))] | ||
mod tests { | ||
use std::io; | ||
|
||
use bytes::Bytes; | ||
|
||
use crate::{ColorConfig, HEVCDecoderConfigurationRecord, NaluType, Sps}; | ||
|
||
#[test] | ||
fn test_config_demux() { | ||
// h265 config | ||
let data = Bytes::from(b"\x01\x01@\0\0\0\x90\0\0\0\0\0\x99\xf0\0\xfc\xfd\xf8\xf8\0\0\x0f\x03 \0\x01\0\x18@\x01\x0c\x01\xff\xff\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\x95@\x90!\0\x01\0=B\x01\x01\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\xa0\x01@ \x05\xa1e\x95R\x90\x84d_\xf8\xc0Z\x80\x80\x80\x82\0\0\x03\0\x02\0\0\x03\x01 \xc0\x0b\xbc\xa2\0\x02bX\0\x011-\x08\"\0\x01\0\x07D\x01\xc0\x93|\x0c\xc9".to_vec()); | ||
|
||
let config = HEVCDecoderConfigurationRecord::demux(&mut io::Cursor::new(data)).unwrap(); | ||
|
||
assert_eq!(config.configuration_version, 1); | ||
assert_eq!(config.general_profile_space, 0); | ||
assert!(!config.general_tier_flag); | ||
assert_eq!(config.general_profile_idc, 1); | ||
assert_eq!(config.general_profile_compatibility_flags, 64); | ||
assert_eq!(config.general_constraint_indicator_flags, 144); | ||
assert_eq!(config.general_level_idc, 153); | ||
assert_eq!(config.min_spatial_segmentation_idc, 0); | ||
assert_eq!(config.parallelism_type, 0); | ||
assert_eq!(config.chroma_format_idc, 1); | ||
assert_eq!(config.bit_depth_luma_minus8, 0); | ||
assert_eq!(config.bit_depth_chroma_minus8, 0); | ||
assert_eq!(config.avg_frame_rate, 0); | ||
assert_eq!(config.constant_frame_rate, 0); | ||
assert_eq!(config.num_temporal_layers, 1); | ||
assert!(config.temporal_id_nested); | ||
assert_eq!(config.length_size_minus_one, 3); | ||
assert_eq!(config.arrays.len(), 3); | ||
|
||
let vps = &config.arrays[0]; | ||
assert!(!vps.array_completeness); | ||
assert_eq!(vps.nal_unit_type, NaluType::Vps); | ||
assert_eq!(vps.nalus.len(), 1); | ||
|
||
let sps = &config.arrays[1]; | ||
assert!(!sps.array_completeness); | ||
assert_eq!(sps.nal_unit_type, NaluType::Sps); | ||
assert_eq!(sps.nalus.len(), 1); | ||
let sps = Sps::parse(sps.nalus[0].clone()).unwrap(); | ||
assert_eq!( | ||
sps, | ||
Sps { | ||
color_config: Some(ColorConfig { | ||
full_range: false, | ||
color_primaries: 1, | ||
matrix_coefficients: 1, | ||
transfer_characteristics: 1, | ||
}), | ||
frame_rate: 144.0, | ||
width: 2560, | ||
height: 1440, | ||
} | ||
); | ||
|
||
let pps = &config.arrays[2]; | ||
assert!(!pps.array_completeness); | ||
assert_eq!(pps.nal_unit_type, NaluType::Pps); | ||
assert_eq!(pps.nalus.len(), 1); | ||
} | ||
|
||
#[test] | ||
fn test_config_mux() { | ||
let data = Bytes::from(b"\x01\x01@\0\0\0\x90\0\0\0\0\0\x99\xf0\0\xfc\xfd\xf8\xf8\0\0\x0f\x03 \0\x01\0\x18@\x01\x0c\x01\xff\xff\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\x95@\x90!\0\x01\0=B\x01\x01\x01@\0\0\x03\0\x90\0\0\x03\0\0\x03\0\x99\xa0\x01@ \x05\xa1e\x95R\x90\x84d_\xf8\xc0Z\x80\x80\x80\x82\0\0\x03\0\x02\0\0\x03\x01 \xc0\x0b\xbc\xa2\0\x02bX\0\x011-\x08\"\0\x01\0\x07D\x01\xc0\x93|\x0c\xc9".to_vec()); | ||
|
||
let config = HEVCDecoderConfigurationRecord::demux(&mut io::Cursor::new(data.clone())).unwrap(); | ||
|
||
assert_eq!(config.size(), data.len() as u64); | ||
|
||
let mut buf = Vec::new(); | ||
config.mux(&mut buf).unwrap(); | ||
|
||
assert_eq!(buf, data.to_vec()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,42 @@ | ||
//! A pure Rust implementation of the H.265 encoder and decoder. | ||
//! | ||
//! This crate is designed to provide a simple and safe interface to encode and decode H.265 headers. | ||
//! | ||
//! ## Why do we need this? | ||
//! | ||
//! This crate aims to provides a simple and safe interface for h265. | ||
//! | ||
//! ## How is this different from other h265 crates? | ||
//! | ||
//! The other main h265 crate is TODO. | ||
//! | ||
//! ## Notable features | ||
//! | ||
//! This crate is a completely safe implementation of H265 encoding and decoding, which means there is no unsafe code! | ||
//! | ||
//! ## Examples | ||
//! | ||
//! TODO | ||
//! | ||
//! ## Status | ||
//! | ||
//! This crate is currently under development and is not yet stable. | ||
//! | ||
//! Unit tests are not yet fully implemented. Use at your own risk. | ||
//! | ||
//! ## License | ||
//! | ||
//! This project is licensed under the [MIT](./LICENSE.MIT) or [Apache-2.0](./LICENSE.Apache-2.0) license. | ||
//! You can choose between one of them if you use this work. | ||
//! | ||
//! `SPDX-License-Identifier: MIT OR Apache-2.0` | ||
#![cfg_attr(all(coverage_nightly, test), feature(coverage_attribute))] | ||
#![cfg_attr(docsrs, feature(doc_cfg))] | ||
#![deny(missing_docs)] | ||
#![deny(unsafe_code)] | ||
|
||
mod config; | ||
mod sps; | ||
|
||
pub use self::config::{HEVCDecoderConfigurationRecord, NaluArray, NaluType}; | ||
pub use self::sps::{ColorConfig, Sps}; | ||
|
||
#[cfg(test)] | ||
mod tests; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps we should create a nutype-enum for this field which has the fields u are talking about but also supports unknowns.