Initial commit
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Andrey Tkachenko 2023-02-03 23:15:20 +04:00
parent 3cd01850c1
commit 230addb924
12 changed files with 708 additions and 0 deletions

14
.drone.yml Normal file
View File

@ -0,0 +1,14 @@
kind: pipeline
name: default
steps:
- name: build
image: rust
commands:
- cargo build --verbose --all
- name: fmt-check
image: rust
commands:
- rustup component add rustfmt
- cargo fmt --all -- --check

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "h265parser"
authors = ["Andrey Tkachenko <andrey@aidev.ru>"]
version = "0.0.1"
edition = "2021"
[dependencies]
anyhow = "1.0.66"
bitstream-io = "1.5.0"
bytes = "1.2.1"
log = "0.4.17"
thiserror = "1.0.37"

View File

@ -1,3 +1,5 @@
[![Build Status](https://ci.aidev.ru/api/badges/andrey/h265parser/status.svg)](https://ci.aidev.ru/andrey/h265parser)
# h265parser # h265parser
h265 NAL parser h265 NAL parser

5
examples/parser_demo.rs Normal file
View File

@ -0,0 +1,5 @@
use h265parser::slice;
fn main() {
println!("todo!")
}

35
src/h265parser/consts.rs Normal file
View File

@ -0,0 +1,35 @@
pub(crate) static DEFAULT_SCALING_LIST0: [u8; 16] = [
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
];
pub(crate) static DEFAULT_SCALING_LIST1: [u8; 64] = [
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 16, 17, 16, 17, 18, 17, 18, 18, 17, 18, 21, 19, 20,
21, 20, 19, 21, 24, 22, 22, 24, 24, 22, 22, 24, 25, 25, 27, 30, 27, 25, 25, 29, 31, 35, 35, 31,
29, 36, 41, 44, 41, 36, 47, 54, 54, 47, 65, 70, 65, 88, 88, 115,
];
pub(crate) static DEFAULT_SCALING_LIST2: [u8; 64] = [
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 20, 20, 20,
20, 20, 20, 20, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 28, 28, 28, 28, 28,
28, 33, 33, 33, 33, 33, 41, 41, 41, 41, 54, 54, 54, 71, 71, 91,
];
pub(crate) static ASPECT_RATIOS: [(u32, u32); 17] = [
(0, 0),
(1, 1),
(12, 11),
(10, 11),
(16, 11),
(40, 33),
(24, 11),
(20, 11),
(32, 11),
(80, 33),
(18, 11),
(15, 11),
(64, 33),
(160, 99),
(4, 3),
(3, 2),
(2, 1),
];

6
src/h265parser/mod.rs Normal file
View File

@ -0,0 +1,6 @@
pub mod consts;
pub mod pps;
pub mod slice;
pub mod sps;
pub mod vps;
pub mod vui;

65
src/h265parser/pps.rs Normal file
View File

@ -0,0 +1,65 @@
use crate::sps::H265SPS;
#[derive(Debug, Copy, Clone)]
pub struct H265ScalingList {
pub scaling_list_dc_coef_minus8_16x16: [i16; 6],
pub scaling_list_dc_coef_minus8_32x32: [i16; 2],
pub scaling_lists_4x4: [[u8; 16]; 6],
pub scaling_lists_8x8: [[u8; 64]; 6],
pub scaling_lists_16x16: [[u8; 64]; 6],
pub scaling_lists_32x32: [[u8; 64]; 2],
}
impl Default for H265ScalingList {
fn default() -> Self {
todo!()
}
}
#[derive(Debug, Copy, Clone, Default)]
pub struct H265PPS {
pub id: u32,
pub sps: H265SPS,
pub dependent_slice_segments_enabled_flag: bool,
pub output_flag_present_flag: bool,
pub num_extra_slice_header_bits: u8,
pub sign_data_hiding_enabled_flag: bool,
pub cabac_init_present_flag: bool,
pub num_ref_idx_l0_default_active_minus1: u8,
pub num_ref_idx_l1_default_active_minus1: u8,
pub init_qp_minus26: i8,
pub constrained_intra_pred_flag: bool,
pub transform_skip_enabled_flag: bool,
pub cu_qp_delta_enabled_flag: bool,
pub diff_cu_qp_delta_depth: u8,
pub cb_qp_offset: i8,
pub cr_qp_offset: i8,
pub slice_chroma_qp_offsets_present_flag: bool,
pub weighted_pred_flag: bool,
pub weighted_bipred_flag: bool,
pub transquant_bypass_enabled_flag: bool,
pub tiles_enabled_flag: bool,
pub entropy_coding_sync_enabled_flag: bool,
pub num_tile_columns_minus1: u8,
pub num_tile_rows_minus1: u8,
pub uniform_spacing_flag: bool,
pub column_width_minus1: [u32; 19],
pub row_height_minus1: [u32; 21],
pub loop_filter_across_tiles_enabled_flag: bool,
pub loop_filter_across_slices_enabled_flag: bool,
pub deblocking_filter_control_present_flag: bool,
pub deblocking_filter_override_enabled_flag: bool,
pub deblocking_filter_disabled_flag: bool,
pub beta_offset_div2: i8,
pub tc_offset_div2: i8,
pub scaling_list_data_present_flag: bool,
pub scaling_list: H265ScalingList,
pub lists_modification_present_flag: bool,
pub log2_parallel_merge_level_minus2: u8,
pub slice_segment_header_extension_present_flag: bool,
pub pps_extension_flag: bool,
}
impl H265PPS {
pub fn parse() {}
}

95
src/h265parser/slice.rs Normal file
View File

@ -0,0 +1,95 @@
use crate::pps::H265PPS;
#[derive(Debug, Copy, Clone, Default)]
pub struct H265ShortTermRefPicSet {
pub inter_ref_pic_set_prediction_flag: bool,
pub delta_idx_minus1: u8,
pub delta_rps_sign: u8,
pub abs_delta_rps_minus1: u16,
pub num_delta_pocs: u8,
pub num_negative_pics: u8,
pub num_positive_pics: u8,
pub used_by_curr_pic_s0: [u8; 16],
pub used_by_curr_pic_s1: [u8; 16],
pub delta_poc_s0: [i32; 16],
pub delta_poc_s1: [i32; 16],
}
#[derive(Debug, Copy, Clone, Default)]
pub struct H265RefPicListModification {
pub ref_pic_list_modification_flag_l0: bool,
pub list_entry_l0: [u32; 15],
pub ref_pic_list_modification_flag_l1: bool,
pub list_entry_l1: [u32; 15],
}
#[derive(Debug, Copy, Clone, Default)]
pub struct H265PredWeightTable {
pub luma_log2_weight_denom: u8,
pub delta_chroma_log2_weight_denom: i8,
pub luma_weight_l0_flag: [bool; 15],
pub chroma_weight_l0_flag: [bool; 15],
pub delta_luma_weight_l0: [i8; 15],
pub luma_offset_l0: [i8; 15],
pub delta_chroma_weight_l0: [[i8; 2]; 15],
pub delta_chroma_offset_l0: [[i16; 2]; 15],
pub luma_weight_l1_flag: [bool; 15],
pub chroma_weight_l1_flag: [bool; 15],
pub delta_luma_weight_l1: [i8; 15],
pub luma_offset_l1: [i8; 15],
pub delta_chroma_weight_l1: [[i8; 2]; 15],
pub delta_chroma_offset_l1: [[i16; 2]; 15],
}
#[derive(Debug, Clone)]
pub struct H265SliceHdr {
pub first_slice_segment_in_pic_flag: bool,
pub no_output_of_prior_pics_flag: bool,
pub pps: H265PPS,
pub dependent_slice_segment_flag: bool,
pub segment_address: u32,
pub type_0: u8,
pub pic_output_flag: bool,
pub colour_plane_id: u8,
pub pic_order_cnt_lsb: u16,
pub short_term_ref_pic_set_sps_flag: bool,
pub short_term_ref_pic_sets: H265ShortTermRefPicSet,
pub short_term_ref_pic_set_idx: u8,
pub num_long_term_sps: u8,
pub num_long_term_pics: u8,
pub lt_idx_sps: [u8; 16],
pub poc_lsb_lt: [u32; 16],
pub used_by_curr_pic_lt_flag: [bool; 16],
pub delta_poc_msb_present_flag: [bool; 16],
pub delta_poc_msb_cycle_lt: [u32; 16],
pub temporal_mvp_enabled_flag: bool,
pub sao_luma_flag: bool,
pub sao_chroma_flag: bool,
pub num_ref_idx_active_override_flag: bool,
pub num_ref_idx_l0_active_minus1: u8,
pub num_ref_idx_l1_active_minus1: u8,
pub ref_pic_list_modification: H265RefPicListModification,
pub mvd_l1_zero_flag: bool,
pub cabac_init_flag: bool,
pub collocated_from_l0_flag: bool,
pub collocated_ref_idx: u8,
pub pred_weight_table: H265PredWeightTable,
pub five_minus_max_num_merge_cand: u8,
pub qp_delta: i8,
pub cb_qp_offset: i8,
pub cr_qp_offset: i8,
pub deblocking_filter_override_flag: bool,
pub deblocking_filter_disabled_flag: bool,
pub beta_offset_div2: i8,
pub tc_offset_div2: i8,
pub loop_filter_across_slices_enabled_flag: bool,
pub num_entry_point_offsets: u32,
pub offset_len_minus1: u8,
pub entry_point_offset_minus1: *mut u32,
pub num_poc_total_curr: i32,
pub header_size: u32,
pub n_emulation_prevention_bytes: u32,
pub num_short_term_picture_slice_header_bits: u32,
pub num_long_term_picture_slice_header_bits: u32,
}

69
src/h265parser/sps.rs Normal file
View File

@ -0,0 +1,69 @@
use crate::{slice::H265ShortTermRefPicSet, vui::H265VUIParams};
use super::{
pps::H265ScalingList,
vps::{H265ProfileTierLevel, H265VPS},
};
#[derive(Debug, Copy, Clone)]
pub struct H265SPS {
pub id: u8,
pub vps: H265VPS,
pub max_sub_layers_minus1: u8,
pub temporal_id_nesting_flag: bool,
pub profile_tier_level: H265ProfileTierLevel,
pub chroma_format_idc: u8,
pub separate_colour_plane_flag: bool,
pub pic_width_in_luma_samples: u16,
pub pic_height_in_luma_samples: u16,
pub conformance_window_flag: bool,
pub conf_win_left_offset: u32,
pub conf_win_right_offset: u32,
pub conf_win_top_offset: u32,
pub conf_win_bottom_offset: u32,
pub bit_depth_luma_minus8: u8,
pub bit_depth_chroma_minus8: u8,
pub log2_max_pic_order_cnt_lsb_minus4: u8,
pub sub_layer_ordering_info_present_flag: bool,
pub max_dec_pic_buffering_minus1: [u8; 8],
pub max_num_reorder_pics: [u8; 8],
pub max_latency_increase_plus1: [u8; 8],
pub log2_min_luma_coding_block_size_minus3: u8,
pub log2_diff_max_min_luma_coding_block_size: u8,
pub log2_min_transform_block_size_minus2: u8,
pub log2_diff_max_min_transform_block_size: u8,
pub max_transform_hierarchy_depth_inter: u8,
pub max_transform_hierarchy_depth_intra: u8,
pub scaling_list_enabled_flag: bool,
pub scaling_list_data_present_flag: bool,
pub scaling_list: H265ScalingList,
pub amp_enabled_flag: bool,
pub sample_adaptive_offset_enabled_flag: bool,
pub pcm_enabled_flag: bool,
pub pcm_sample_bit_depth_luma_minus1: u8,
pub pcm_sample_bit_depth_chroma_minus1: u8,
pub log2_min_pcm_luma_coding_block_size_minus3: u8,
pub log2_diff_max_min_pcm_luma_coding_block_size: u8,
pub pcm_loop_filter_disabled_flag: bool,
pub num_short_term_ref_pic_sets: u8,
pub short_term_ref_pic_set: [H265ShortTermRefPicSet; 65],
pub long_term_ref_pics_present_flag: bool,
pub num_long_term_ref_pics_sps: u8,
pub lt_ref_pic_poc_lsb_sps: [u16; 32],
pub used_by_curr_pic_lt_sps_flag: [u8; 32],
pub temporal_mvp_enabled_flag: bool,
pub strong_intra_smoothing_enabled_flag: bool,
pub vui_parameters_present_flag: bool,
pub vui_params: Option<H265VUIParams>,
pub sps_extension_flag: bool,
pub chroma_array_type: u8,
pub width: i32,
pub height: i32,
pub fps: (i32, i32),
}
impl Default for H265SPS {
fn default() -> Self {
todo!()
}
}

324
src/h265parser/vps.rs Normal file
View File

@ -0,0 +1,324 @@
use std::io;
use anyhow::Error;
use bitstream_io::{BigEndian, BitRead, BitReader};
use crate::GolombCode;
#[derive(Debug, Default, Copy, Clone)]
pub struct H265ProfileTierLevel {
pub profile_space: u8,
pub tier_flag: bool,
pub profile_idc: u8,
pub profile_compatibility_flag: [bool; 32],
pub progressive_source_flag: bool,
pub interlaced_source_flag: bool,
pub non_packed_constraint_flag: bool,
pub frame_only_constraint_flag: bool,
pub level_idc: u8,
pub sub_layer_profile_present_flag: [bool; 6],
pub sub_layer_level_present_flag: [bool; 6],
pub sub_layer_profile_space: [u8; 6],
pub sub_layer_tier_flag: [bool; 6],
pub sub_layer_profile_idc: [u8; 6],
pub sub_layer_profile_compatibility_flag: [[bool; 32]; 6],
pub sub_layer_progressive_source_flag: [bool; 6],
pub sub_layer_interlaced_source_flag: [bool; 6],
pub sub_layer_non_packed_constraint_flag: [bool; 6],
pub sub_layer_frame_only_constraint_flag: [bool; 6],
pub sub_layer_level_idc: [u8; 6],
}
impl H265ProfileTierLevel {
pub fn parse<R: io::Read>(
bs: &mut BitReader<R, BigEndian>,
max_num_sub_layers_minus1: u8,
) -> Result<H265ProfileTierLevel, Error> {
let mut ptl = H265ProfileTierLevel::default();
ptl.profile_space = bs.read(2)?;
ptl.tier_flag = bs.read_bit()?;
ptl.profile_idc = bs.read(5)?;
for j in 0..32 {
ptl.profile_compatibility_flag[j] = bs.read_bit()?;
}
ptl.progressive_source_flag = bs.read_bit()?;
ptl.interlaced_source_flag = bs.read_bit()?;
ptl.non_packed_constraint_flag = bs.read_bit()?;
ptl.frame_only_constraint_flag = bs.read_bit()?;
let _ = bs.read::<u64>(44)?;
ptl.level_idc = bs.read(8)?;
for j in 0..max_num_sub_layers_minus1 as usize {
ptl.sub_layer_profile_present_flag[j] = bs.read_bit()?;
ptl.sub_layer_level_present_flag[j] = bs.read_bit()?;
}
if max_num_sub_layers_minus1 > 0 {
for _ in max_num_sub_layers_minus1..8 {
let _ = bs.read::<u32>(2)?;
}
}
for i in 0..max_num_sub_layers_minus1 as usize {
if ptl.sub_layer_profile_present_flag[i] {
ptl.sub_layer_profile_space[i] = bs.read(2)?;
ptl.sub_layer_tier_flag[i] = bs.read_bit()?;
ptl.sub_layer_profile_idc[i] = bs.read(5)?;
for j in 0..32 {
ptl.sub_layer_profile_compatibility_flag[i][j] = bs.read_bit()?;
}
ptl.sub_layer_progressive_source_flag[i] = bs.read_bit()?;
ptl.sub_layer_interlaced_source_flag[i] = bs.read_bit()?;
ptl.sub_layer_non_packed_constraint_flag[i] = bs.read_bit()?;
ptl.sub_layer_frame_only_constraint_flag[i] = bs.read_bit()?;
let _ = bs.read::<u64>(44)?;
}
if ptl.sub_layer_level_present_flag[i] {
ptl.sub_layer_level_idc[i] = bs.read(8)?;
}
}
Ok(ptl)
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct H265HRDParams {
pub nal_hrd_parameters_present_flag: bool,
pub vcl_hrd_parameters_present_flag: bool,
pub sub_pic_hrd_params_present_flag: bool,
pub tick_divisor_minus2: u8,
pub du_cpb_removal_delay_increment_length_minus1: u8,
pub sub_pic_cpb_params_in_pic_timing_sei_flag: bool,
pub dpb_output_delay_du_length_minus1: u8,
pub bit_rate_scale: u8,
pub cpb_size_scale: u8,
pub cpb_size_du_scale: u8,
pub initial_cpb_removal_delay_length_minus1: u8,
pub au_cpb_removal_delay_length_minus1: u8,
pub dpb_output_delay_length_minus1: u8,
pub fixed_pic_rate_general_flag: [bool; 7],
pub fixed_pic_rate_within_cvs_flag: [bool; 7],
pub elemental_duration_in_tc_minus1: [u16; 7],
pub low_delay_hrd_flag: [bool; 7],
pub cpb_cnt_minus1: [u8; 7],
pub sublayer_hrd_params: [Option<H265SubLayerHRDParams>; 7],
}
impl H265HRDParams {
pub fn parse<R: io::Read>(
bs: &mut BitReader<R, BigEndian>,
common_inf_present_flag: bool,
max_num_sub_layers_minus1: u8,
) -> Result<Self, Error> {
let mut hrd = Self::default();
hrd.initial_cpb_removal_delay_length_minus1 = 23u8;
hrd.au_cpb_removal_delay_length_minus1 = 23u8;
hrd.dpb_output_delay_length_minus1 = 23u8;
if common_inf_present_flag {
hrd.nal_hrd_parameters_present_flag = bs.read_bit()?;
hrd.vcl_hrd_parameters_present_flag = bs.read_bit()?;
if hrd.nal_hrd_parameters_present_flag || hrd.vcl_hrd_parameters_present_flag {
hrd.sub_pic_hrd_params_present_flag = bs.read_bit()?;
if hrd.sub_pic_hrd_params_present_flag {
hrd.tick_divisor_minus2 = bs.read(8)?;
hrd.du_cpb_removal_delay_increment_length_minus1 = bs.read(5)?;
hrd.sub_pic_cpb_params_in_pic_timing_sei_flag = bs.read_bit()?;
hrd.dpb_output_delay_du_length_minus1 = bs.read(5)?;
}
hrd.bit_rate_scale = bs.read(4)?;
hrd.cpb_size_scale = bs.read(4)?;
if hrd.sub_pic_hrd_params_present_flag {
hrd.cpb_size_du_scale = bs.read(4)?;
}
hrd.initial_cpb_removal_delay_length_minus1 = bs.read(5)?;
hrd.au_cpb_removal_delay_length_minus1 = bs.read(5)?;
hrd.dpb_output_delay_length_minus1 = bs.read(5)?;
}
}
for i in 0..=max_num_sub_layers_minus1 as usize {
hrd.fixed_pic_rate_general_flag[i] = bs.read_bit()?;
if !hrd.fixed_pic_rate_general_flag[i] {
hrd.fixed_pic_rate_within_cvs_flag[i] = bs.read_bit()?;
} else {
hrd.fixed_pic_rate_within_cvs_flag[i] = true;
}
if hrd.fixed_pic_rate_within_cvs_flag[i] {
hrd.elemental_duration_in_tc_minus1[i] = bs.read_ue()? as _; // <= 2047
} else {
hrd.low_delay_hrd_flag[i] = bs.read_bit()?;
}
if !hrd.low_delay_hrd_flag[i] {
hrd.cpb_cnt_minus1[i] = bs.read_ue()? as _; // <= 31
}
if hrd.vcl_hrd_parameters_present_flag || hrd.nal_hrd_parameters_present_flag {
hrd.sublayer_hrd_params[i] = Some(H265SubLayerHRDParams::parse(
bs,
hrd.cpb_cnt_minus1[i],
hrd.sub_pic_hrd_params_present_flag,
)?);
}
}
Ok(hrd)
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct H265SubLayerHRDParams {
pub bit_rate_value_minus1: [u32; 32],
pub cpb_size_value_minus1: [u32; 32],
pub cpb_size_du_value_minus1: [u32; 32],
pub bit_rate_du_value_minus1: [u32; 32],
pub cbr_flag: [bool; 32],
}
impl H265SubLayerHRDParams {
pub fn parse<R: io::Read>(
bs: &mut BitReader<R, BigEndian>,
cpb_cnt: u8,
sub_pic_hrd_params_present_flag: bool,
) -> Result<Self, Error> {
let mut sub_hrd = H265SubLayerHRDParams::default();
for i in 0..=cpb_cnt as usize {
sub_hrd.bit_rate_value_minus1[i] = bs.read_ue()?;
sub_hrd.cpb_size_value_minus1[i] = bs.read_ue()?;
if sub_pic_hrd_params_present_flag {
sub_hrd.cpb_size_du_value_minus1[i] = bs.read_ue()? as _;
sub_hrd.bit_rate_du_value_minus1[i] = bs.read_ue()? as _;
}
sub_hrd.cbr_flag[i] = bs.read_bit()?;
}
Ok(sub_hrd)
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct H265VPS {
pub id: u8,
pub max_layers_minus1: u8,
pub max_sub_layers_minus1: u8,
pub temporal_id_nesting_flag: bool,
pub profile_tier_level: H265ProfileTierLevel,
pub sub_layer_ordering_info_present_flag: bool,
pub max_dec_pic_buffering_minus1: [u8; 8],
pub max_num_reorder_pics: [u8; 8],
pub max_latency_increase_plus1: [u32; 8],
pub max_layer_id: u8,
pub num_layer_sets_minus1: u16,
pub timing_info_present_flag: bool,
pub num_units_in_tick: u32,
pub time_scale: u32,
pub poc_proportional_to_timing_flag: bool,
pub num_ticks_poc_diff_one_minus1: u32,
pub num_hrd_parameters: u16,
pub hrd_layer_set_idx: u16,
pub cprms_present_flag: bool,
pub hrd_params: H265HRDParams,
pub vps_extension: bool,
pub valid: bool,
}
impl H265VPS {
pub fn parse<R: io::Read>(bs: &mut BitReader<R, BigEndian>) -> Result<Self, Error> {
let mut vps = H265VPS::default();
vps.cprms_present_flag = true;
vps.id = bs.read(4)?;
let _: u8 = bs.read(2)?;
vps.max_layers_minus1 = bs.read(6)?;
vps.max_sub_layers_minus1 = bs.read(3)?;
vps.temporal_id_nesting_flag = bs.read_bit()?;
let _: u16 = bs.read(16)?;
vps.profile_tier_level = H265ProfileTierLevel::parse(bs, vps.max_sub_layers_minus1)?;
vps.sub_layer_ordering_info_present_flag = bs.read_bit()?;
let from = if vps.sub_layer_ordering_info_present_flag {
0
} else {
vps.max_sub_layers_minus1 as usize
};
for i in from..=vps.max_sub_layers_minus1 as usize {
vps.max_dec_pic_buffering_minus1[i] = bs.read_ue()? as _;
vps.max_num_reorder_pics[i] = bs.read_ue()? as _;
vps.max_dec_pic_buffering_minus1[i] = bs.read_ue()? as _;
vps.max_latency_increase_plus1[i] = bs.read_ue()? as _;
}
/* setting default values if `vps.sub_layer_ordering_info_present_flag` is zero */
if !vps.sub_layer_ordering_info_present_flag && vps.max_sub_layers_minus1 > 0 {
for i in 0..=(vps.max_sub_layers_minus1 - 1) as usize {
vps.max_dec_pic_buffering_minus1[i] =
vps.max_dec_pic_buffering_minus1[vps.max_sub_layers_minus1 as usize];
vps.max_num_reorder_pics[i] =
vps.max_num_reorder_pics[vps.max_sub_layers_minus1 as usize];
vps.max_latency_increase_plus1[i] =
vps.max_latency_increase_plus1[vps.max_sub_layers_minus1 as usize];
}
}
vps.max_layer_id = bs.read(6)?;
vps.num_layer_sets_minus1 = bs.read_ue()? as _; // <= 1023
// CHECK_ALLOWED_MAX (vps.max_layer_id, 0)?;
// CHECK_ALLOWED_MAX (vps.num_layer_sets_minus1, 0)?;
for _ in 1..=vps.num_layer_sets_minus1 {
for _ in 0..=vps.max_layer_id {
let _ = bs.read_bit()?;
}
}
vps.timing_info_present_flag = bs.read_bit()?;
if vps.timing_info_present_flag {
vps.num_units_in_tick = bs.read(32)?;
vps.time_scale = bs.read(32)?;
vps.poc_proportional_to_timing_flag = bs.read_bit()?;
if vps.poc_proportional_to_timing_flag {
vps.num_ticks_poc_diff_one_minus1 = bs.read_ue()? as _;
}
vps.num_hrd_parameters = bs.read_ue()? as _;
// CHECK_ALLOWED_MAX (vps.num_hrd_parameters, 1)?;
if vps.num_hrd_parameters > 0 {
vps.hrd_layer_set_idx = bs.read_ue()? as _; // <= 1023
// CHECK_ALLOWED_MAX (vps.hrd_layer_set_idx, 0);
vps.hrd_params =
H265HRDParams::parse(bs, vps.cprms_present_flag, vps.max_sub_layers_minus1)?
}
}
vps.vps_extension = bs.read_bit()?;
Ok(vps)
}
}

48
src/h265parser/vui.rs Normal file
View File

@ -0,0 +1,48 @@
use super::vps::H265HRDParams;
#[derive(Debug, Copy, Clone, Default)]
pub struct H265VUIParams {
pub aspect_ratio_info_present_flag: bool,
pub aspect_ratio_idc: u8,
pub sar_width: u16,
pub sar_height: u16,
pub overscan_info_present_flag: bool,
pub overscan_appropriate_flag: bool,
pub video_signal_type_present_flag: bool,
pub video_format: u8,
pub video_full_range_flag: bool,
pub colour_description_present_flag: bool,
pub colour_primaries: u8,
pub transfer_characteristics: u8,
pub matrix_coefficients: u8,
pub chroma_loc_info_present_flag: bool,
pub chroma_sample_loc_type_top_field: u8,
pub chroma_sample_loc_type_bottom_field: u8,
pub neutral_chroma_indication_flag: bool,
pub field_seq_flag: bool,
pub frame_field_info_present_flag: bool,
pub default_display_window_flag: bool,
pub def_disp_win_left_offset: u32,
pub def_disp_win_right_offset: u32,
pub def_disp_win_top_offset: u32,
pub def_disp_win_bottom_offset: u32,
pub timing_info_present_flag: bool,
pub num_units_in_tick: u32,
pub time_scale: u32,
pub poc_proportional_to_timing_flag: bool,
pub num_ticks_poc_diff_one_minus1: u32,
pub hrd_parameters_present_flag: bool,
pub hrd_params: Option<H265HRDParams>,
pub bitstream_restriction_flag: bool,
pub tiles_fixed_structure_flag: bool,
pub motion_vectors_over_pic_boundaries_flag: bool,
pub restricted_ref_pic_lists_flag: bool,
pub min_spatial_segmentation_idc: u16,
pub max_bytes_per_pic_denom: u8,
pub max_bits_per_min_cu_denom: u8,
pub log2_max_mv_length_horizontal: u8,
pub log2_max_mv_length_vertical: u8,
pub aspect_ratio: (u32, u32),
}
impl H265VUIParams {}

33
src/lib.rs Normal file
View File

@ -0,0 +1,33 @@
use std::io;
use anyhow::Error;
use bitstream_io::{BitRead, BitReader, Endianness};
mod h265parser;
pub use h265parser::*;
trait GolombCode {
fn read_ue(&mut self) -> Result<u32, Error>;
fn read_se(&mut self) -> Result<i32, Error> {
let val = self.read_ue()?;
let sign = (((val & 0x1) as i32) << 1) - 1;
Ok(((val >> 1) as i32 + (val & 0x1) as i32) * sign)
}
}
impl<R: io::Read, E: Endianness> GolombCode for BitReader<R, E> {
fn read_ue(&mut self) -> Result<u32, Error> {
let count = self.read_unary1()?;
if count > 31 {
anyhow::bail!("exp golomb too large")
} else if count > 0 {
let val = self.read::<u32>(count)?;
Ok((1 << count) - 1 + val)
} else {
Ok(0)
}
}
}