rusty_h264_encoder/
params.rs1use crate::config::EncoderConfig;
8use rusty_h264_common::{BitWriter, NalUnit, NalUnitType};
9
10#[derive(Debug, Clone)]
12pub struct Sps {
13 pub profile_idc: u8,
14 pub constraint_set1_flag: bool,
15 pub level_idc: u8,
16 pub seq_parameter_set_id: u32,
17 pub log2_max_frame_num_minus4: u32,
18 pub pic_order_cnt_type: u32,
19 pub log2_max_pic_order_cnt_lsb_minus4: u32,
20 pub max_num_ref_frames: u32,
21 pub pic_width_in_mbs_minus1: u32,
22 pub pic_height_in_map_units_minus1: u32,
23 pub frame_crop_right: u32,
26 pub frame_crop_bottom: u32,
27}
28
29impl Sps {
30 pub fn from_config(cfg: &EncoderConfig) -> Self {
32 let mb_w = cfg.mb_width();
33 let mb_h = cfg.mb_height();
34 let crop_right = (mb_w * 16 - cfg.width) / 2;
37 let crop_bottom = (mb_h * 16 - cfg.height) / 2;
38 Self {
39 profile_idc: cfg.profile.profile_idc(),
40 constraint_set1_flag: true, level_idc: cfg.level_idc,
42 seq_parameter_set_id: 0,
43 log2_max_frame_num_minus4: 0, pic_order_cnt_type: 0,
45 log2_max_pic_order_cnt_lsb_minus4: 0, max_num_ref_frames: cfg.num_ref_frames.max(1),
47 pic_width_in_mbs_minus1: (mb_w - 1) as u32,
48 pic_height_in_map_units_minus1: (mb_h - 1) as u32,
49 frame_crop_right: crop_right as u32,
50 frame_crop_bottom: crop_bottom as u32,
51 }
52 }
53
54 pub fn write_rbsp(&self, w: &mut BitWriter) {
56 w.write_bits(self.profile_idc as u32, 8);
57 let mut constraints = 0u32;
59 if self.constraint_set1_flag {
60 constraints |= 1 << 6; }
62 w.write_bits(constraints, 8);
63 w.write_bits(self.level_idc as u32, 8);
64 w.write_ue(self.seq_parameter_set_id);
65 w.write_ue(self.log2_max_frame_num_minus4);
67 w.write_ue(self.pic_order_cnt_type);
68 if self.pic_order_cnt_type == 0 {
69 w.write_ue(self.log2_max_pic_order_cnt_lsb_minus4);
70 }
71 w.write_ue(self.max_num_ref_frames);
72 w.write_bit(false); w.write_ue(self.pic_width_in_mbs_minus1);
74 w.write_ue(self.pic_height_in_map_units_minus1);
75 w.write_bit(true); w.write_bit(false); let cropping = self.frame_crop_right != 0 || self.frame_crop_bottom != 0;
78 w.write_bit(cropping); if cropping {
80 w.write_ue(0); w.write_ue(self.frame_crop_right);
82 w.write_ue(0); w.write_ue(self.frame_crop_bottom);
84 }
85 w.write_bit(false); w.rbsp_trailing_bits();
87 }
88
89 pub fn to_nal(&self) -> NalUnit {
91 let mut w = BitWriter::new();
92 self.write_rbsp(&mut w);
93 NalUnit::new(3, NalUnitType::Sps, w.into_bytes())
94 }
95}
96
97#[derive(Debug, Clone)]
99pub struct Pps {
100 pub pic_parameter_set_id: u32,
101 pub seq_parameter_set_id: u32,
102 pub num_ref_idx_l0_default_active_minus1: u32,
103 pub pic_init_qp_minus26: i32,
104 pub deblocking_filter_control_present_flag: bool,
105}
106
107impl Pps {
108 pub fn from_config(cfg: &EncoderConfig) -> Self {
110 Self {
111 pic_parameter_set_id: 0,
112 seq_parameter_set_id: 0,
113 num_ref_idx_l0_default_active_minus1: cfg.num_ref_frames.max(1) - 1,
114 pic_init_qp_minus26: cfg.qp as i32 - 26,
115 deblocking_filter_control_present_flag: true,
119 }
120 }
121
122 pub fn write_rbsp(&self, w: &mut BitWriter) {
124 w.write_ue(self.pic_parameter_set_id);
125 w.write_ue(self.seq_parameter_set_id);
126 w.write_bit(false); w.write_bit(false); w.write_ue(0); w.write_ue(self.num_ref_idx_l0_default_active_minus1);
130 w.write_ue(0); w.write_bit(false); w.write_bits(0, 2); w.write_se(self.pic_init_qp_minus26);
134 w.write_se(0); w.write_se(0); w.write_bit(self.deblocking_filter_control_present_flag);
137 w.write_bit(false); w.write_bit(false); w.rbsp_trailing_bits();
140 }
141
142 pub fn to_nal(&self) -> NalUnit {
144 let mut w = BitWriter::new();
145 self.write_rbsp(&mut w);
146 NalUnit::new(3, NalUnitType::Pps, w.into_bytes())
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use rusty_h264_common::{nal::emulation_unprevent, BitReader};
154
155 #[test]
156 fn sps_roundtrips_through_reader() {
157 let cfg = EncoderConfig::new(1920, 1080); let sps = Sps::from_config(&cfg);
159 let nal = sps.to_nal();
160
161 let rbsp = emulation_unprevent(&nal.rbsp);
162 let mut r = BitReader::new(&rbsp);
163 assert_eq!(r.read_bits(8).unwrap(), 66); let constraints = r.read_bits(8).unwrap();
165 assert_eq!((constraints >> 6) & 1, 1); assert_eq!(r.read_bits(8).unwrap(), 30); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 1); assert!(!r.read_bit().unwrap()); assert_eq!(r.read_ue().unwrap(), 119); assert_eq!(r.read_ue().unwrap(), 67); assert!(r.read_bit().unwrap()); assert!(!r.read_bit().unwrap()); assert!(r.read_bit().unwrap()); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 4); }
183
184 #[test]
185 fn pps_roundtrips_through_reader() {
186 let cfg = EncoderConfig::new(640, 480);
187 let pps = Pps::from_config(&cfg);
188 let nal = pps.to_nal();
189
190 let rbsp = emulation_unprevent(&nal.rbsp);
191 let mut r = BitReader::new(&rbsp);
192 assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert!(!r.read_bit().unwrap()); assert!(!r.read_bit().unwrap()); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert_eq!(r.read_ue().unwrap(), 0); assert!(!r.read_bit().unwrap()); assert_eq!(r.read_bits(2).unwrap(), 0); assert_eq!(r.read_se().unwrap(), 0); }
203}