1use std::fmt;
5use std::io::Write;
6
7use crate::codec::h264::nalu_writer::NaluWriter;
8use crate::codec::h264::nalu_writer::NaluWriterError;
9use crate::codec::h264::parser::HrdParams;
10use crate::codec::h264::parser::NaluType;
11use crate::codec::h264::parser::Pps;
12use crate::codec::h264::parser::Sps;
13use crate::codec::h264::parser::DEFAULT_4X4_INTER;
14use crate::codec::h264::parser::DEFAULT_4X4_INTRA;
15use crate::codec::h264::parser::DEFAULT_8X8_INTER;
16use crate::codec::h264::parser::DEFAULT_8X8_INTRA;
17
18mod private {
19 pub trait NaluStruct {}
20}
21
22impl private::NaluStruct for Sps {}
23
24impl private::NaluStruct for Pps {}
25
26#[derive(Debug)]
27pub enum SynthesizerError {
28 Unsupported,
29 NaluWriter(NaluWriterError),
30}
31
32impl fmt::Display for SynthesizerError {
33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34 match self {
35 SynthesizerError::Unsupported => write!(f, "tried to synthesize unsupported settings"),
36 SynthesizerError::NaluWriter(x) => write!(f, "{}", x.to_string()),
37 }
38 }
39}
40
41impl From<NaluWriterError> for SynthesizerError {
42 fn from(err: NaluWriterError) -> Self {
43 SynthesizerError::NaluWriter(err)
44 }
45}
46
47pub type SynthesizerResult<T> = Result<T, SynthesizerError>;
48
49pub struct Synthesizer<'n, N: private::NaluStruct, W: Write> {
51 writer: NaluWriter<W>,
52 nalu: &'n N,
53}
54
55const EXTENDED_SAR: u8 = 255;
57
58impl<N: private::NaluStruct, W: Write> Synthesizer<'_, N, W> {
59 fn u<T: Into<u32>>(&mut self, bits: usize, value: T) -> SynthesizerResult<()> {
60 self.writer.write_u(bits, value)?;
61 Ok(())
62 }
63
64 fn f<T: Into<u32>>(&mut self, bits: usize, value: T) -> SynthesizerResult<()> {
65 self.writer.write_f(bits, value)?;
66 Ok(())
67 }
68
69 fn ue<T: Into<u32>>(&mut self, value: T) -> SynthesizerResult<()> {
70 self.writer.write_ue(value)?;
71 Ok(())
72 }
73
74 fn se<T: Into<i32>>(&mut self, value: T) -> SynthesizerResult<()> {
75 self.writer.write_se(value)?;
76 Ok(())
77 }
78
79 fn scaling_list(&mut self, list: &[u8], default: &[u8]) -> SynthesizerResult<()> {
80 if list == default {
82 self.se(-8)?;
83 return Ok(());
84 }
85
86 let mut run = list.len();
88
89 for j in (1..list.len()).rev() {
92 if list[j - 1] != list[j] {
93 break;
94 }
95 run -= 1;
96 }
97
98 let mut last_scale = 8;
100 for scale in &list[0..run] {
101 let delta_scale = *scale as i32 - last_scale;
102 self.se(delta_scale)?;
103 last_scale = *scale as i32;
104 }
105
106 if run < list.len() {
110 self.se(-last_scale)?;
111 }
112
113 Ok(())
114 }
115
116 fn default_scaling_list(i: usize) -> &'static [u8] {
117 match i {
119 0 => &DEFAULT_4X4_INTRA[..],
120 1 => &DEFAULT_4X4_INTRA[..],
121 2 => &DEFAULT_4X4_INTRA[..],
122 3 => &DEFAULT_4X4_INTER[..],
123 4 => &DEFAULT_4X4_INTER[..],
124 5 => &DEFAULT_4X4_INTER[..],
125 6 => &DEFAULT_8X8_INTRA[..],
126 7 => &DEFAULT_8X8_INTER[..],
127 8 => &DEFAULT_8X8_INTRA[..],
128 9 => &DEFAULT_8X8_INTER[..],
129 10 => &DEFAULT_8X8_INTRA[..],
130 11 => &DEFAULT_8X8_INTER[..],
131 _ => unreachable!(),
132 }
133 }
134
135 fn rbsp_trailing_bits(&mut self) -> SynthesizerResult<()> {
136 self.f(1, 1u32)?;
137
138 while !self.writer.aligned() {
139 self.f(1, 0u32)?;
140 }
141
142 Ok(())
143 }
144}
145
146impl<'n, W: Write> Synthesizer<'n, Sps, W> {
147 pub fn synthesize(
148 ref_idc: u8,
149 sps: &'n Sps,
150 writer: W,
151 ep_enabled: bool,
152 ) -> SynthesizerResult<()> {
153 let mut s = Self { writer: NaluWriter::<W>::new(writer, ep_enabled), nalu: sps };
154
155 s.writer.write_header(ref_idc, NaluType::Sps as u8)?;
156 s.seq_parameter_set_data()?;
157 s.rbsp_trailing_bits()
158 }
159
160 fn hrd_parameters(&mut self, hrd_params: &HrdParams) -> SynthesizerResult<()> {
161 self.ue(hrd_params.cpb_cnt_minus1)?;
162 self.u(4, hrd_params.bit_rate_scale)?;
163 self.u(4, hrd_params.cpb_size_scale)?;
164
165 for i in 0..=(hrd_params.cpb_cnt_minus1 as usize) {
166 self.ue(hrd_params.bit_rate_value_minus1[i])?;
167 self.ue(hrd_params.cpb_size_value_minus1[i])?;
168 self.u(1, hrd_params.cbr_flag[i])?;
169 }
170
171 self.u(5, hrd_params.initial_cpb_removal_delay_length_minus1)?;
172 self.u(5, hrd_params.cpb_removal_delay_length_minus1)?;
173 self.u(5, hrd_params.dpb_output_delay_length_minus1)?;
174 self.u(5, hrd_params.time_offset_length)?;
175
176 Ok(())
177 }
178
179 fn vui_parameters(&mut self) -> SynthesizerResult<()> {
180 let vui_params = &self.nalu.vui_parameters;
182
183 self.u(1, vui_params.aspect_ratio_info_present_flag)?;
184 if vui_params.aspect_ratio_info_present_flag {
185 self.u(8, vui_params.aspect_ratio_idc)?;
186 if vui_params.aspect_ratio_idc == EXTENDED_SAR {
187 self.u(16, vui_params.sar_width)?;
188 self.u(16, vui_params.sar_height)?;
189 }
190 }
191
192 self.u(1, vui_params.overscan_info_present_flag)?;
193 if vui_params.overscan_info_present_flag {
194 self.u(1, vui_params.overscan_appropriate_flag)?;
195 }
196
197 self.u(1, vui_params.video_signal_type_present_flag)?;
198 if vui_params.video_signal_type_present_flag {
199 self.u(3, vui_params.video_format)?;
200 self.u(1, vui_params.video_full_range_flag)?;
201
202 self.u(1, vui_params.colour_description_present_flag)?;
203 if vui_params.colour_description_present_flag {
204 self.u(8, vui_params.colour_primaries)?;
205 self.u(8, vui_params.transfer_characteristics)?;
206 self.u(8, vui_params.matrix_coefficients)?;
207 }
208 }
209
210 self.u(1, vui_params.chroma_loc_info_present_flag)?;
211 if vui_params.chroma_loc_info_present_flag {
212 self.ue(vui_params.chroma_sample_loc_type_top_field)?;
213 self.ue(self.nalu.vui_parameters.chroma_sample_loc_type_bottom_field)?;
214 }
215
216 self.u(1, vui_params.timing_info_present_flag)?;
217 if vui_params.timing_info_present_flag {
218 self.u(32, vui_params.num_units_in_tick)?;
219 self.u(32, vui_params.time_scale)?;
220 self.u(1, vui_params.fixed_frame_rate_flag)?;
221 }
222
223 self.u(1, vui_params.nal_hrd_parameters_present_flag)?;
224 if vui_params.nal_hrd_parameters_present_flag {
225 self.hrd_parameters(&vui_params.nal_hrd_parameters)?;
226 }
227 self.u(1, vui_params.vcl_hrd_parameters_present_flag)?;
228 if vui_params.vcl_hrd_parameters_present_flag {
229 self.hrd_parameters(&vui_params.vcl_hrd_parameters)?;
230 }
231
232 if vui_params.nal_hrd_parameters_present_flag || vui_params.vcl_hrd_parameters_present_flag
233 {
234 self.u(1, vui_params.low_delay_hrd_flag)?;
235 }
236
237 self.u(1, vui_params.pic_struct_present_flag)?;
238
239 self.u(1, vui_params.bitstream_restriction_flag)?;
240 if vui_params.bitstream_restriction_flag {
241 self.u(1, vui_params.motion_vectors_over_pic_boundaries_flag)?;
242 self.ue(vui_params.max_bytes_per_pic_denom)?;
243 self.ue(vui_params.max_bits_per_mb_denom)?;
244 self.ue(vui_params.log2_max_mv_length_horizontal)?;
245 self.ue(vui_params.log2_max_mv_length_vertical)?;
246 self.ue(vui_params.max_num_reorder_frames)?;
247 self.ue(vui_params.max_dec_frame_buffering)?;
248 }
249
250 Ok(())
251 }
252
253 fn seq_parameter_set_data(&mut self) -> SynthesizerResult<()> {
254 self.u(8, self.nalu.profile_idc)?;
256 self.u(1, self.nalu.constraint_set0_flag)?;
257 self.u(1, self.nalu.constraint_set1_flag)?;
258 self.u(1, self.nalu.constraint_set2_flag)?;
259 self.u(1, self.nalu.constraint_set3_flag)?;
260 self.u(1, self.nalu.constraint_set4_flag)?;
261 self.u(1, self.nalu.constraint_set5_flag)?;
262 self.u(2, 0u32)?;
263 self.u(8, self.nalu.level_idc as u32)?;
264 self.ue(self.nalu.seq_parameter_set_id)?;
265
266 if self.nalu.profile_idc == 100
267 || self.nalu.profile_idc == 110
268 || self.nalu.profile_idc == 122
269 || self.nalu.profile_idc == 244
270 || self.nalu.profile_idc == 44
271 || self.nalu.profile_idc == 83
272 || self.nalu.profile_idc == 86
273 || self.nalu.profile_idc == 118
274 || self.nalu.profile_idc == 128
275 || self.nalu.profile_idc == 138
276 || self.nalu.profile_idc == 139
277 || self.nalu.profile_idc == 134
278 || self.nalu.profile_idc == 135
279 {
280 self.ue(self.nalu.chroma_format_idc)?;
281
282 if self.nalu.chroma_format_idc == 3 {
283 self.u(1, self.nalu.separate_colour_plane_flag)?;
284 }
285
286 self.ue(self.nalu.bit_depth_luma_minus8)?;
287 self.ue(self.nalu.bit_depth_chroma_minus8)?;
288 self.u(1, self.nalu.qpprime_y_zero_transform_bypass_flag)?;
289 self.u(1, self.nalu.seq_scaling_matrix_present_flag)?;
290
291 if self.nalu.seq_scaling_matrix_present_flag {
292 let scaling_list_count = if self.nalu.chroma_format_idc != 3 { 8 } else { 12 };
293
294 for i in 0..scaling_list_count {
295 if i < 6 {
297 if self.nalu.scaling_lists_4x4[i] == [0; 16] {
298 self.u(1, false)?;
299 } else {
300 self.u(1, true)?;
301 self.scaling_list(
302 &self.nalu.scaling_lists_4x4[i],
303 Self::default_scaling_list(i),
304 )?;
305 }
306 } else if self.nalu.scaling_lists_8x8[i - 6] == [0; 64] {
307 self.u(1, false)?;
308 } else {
309 self.u(1, true)?;
310 self.scaling_list(
311 &self.nalu.scaling_lists_8x8[i - 6],
312 Self::default_scaling_list(i),
313 )?;
314 }
315 }
316 }
317 }
318
319 self.ue(self.nalu.log2_max_frame_num_minus4)?;
320 self.ue(self.nalu.pic_order_cnt_type)?;
321
322 if self.nalu.pic_order_cnt_type == 0 {
323 self.ue(self.nalu.log2_max_pic_order_cnt_lsb_minus4)?;
324 } else if self.nalu.pic_order_cnt_type == 1 {
325 self.u(1, self.nalu.delta_pic_order_always_zero_flag)?;
326 self.se(self.nalu.offset_for_non_ref_pic)?;
327 self.se(self.nalu.offset_for_top_to_bottom_field)?;
328 self.ue(self.nalu.num_ref_frames_in_pic_order_cnt_cycle)?;
329
330 for offset_for_ref_frame in &self.nalu.offset_for_ref_frame {
331 self.se(*offset_for_ref_frame)?;
332 }
333 }
334
335 self.ue(self.nalu.max_num_ref_frames)?;
336 self.u(1, self.nalu.gaps_in_frame_num_value_allowed_flag)?;
337 self.ue(self.nalu.pic_width_in_mbs_minus1)?;
338 self.ue(self.nalu.pic_height_in_map_units_minus1)?;
339 self.u(1, self.nalu.frame_mbs_only_flag)?;
340 if !self.nalu.frame_mbs_only_flag {
341 self.u(1, self.nalu.mb_adaptive_frame_field_flag)?;
342 }
343 self.u(1, self.nalu.direct_8x8_inference_flag)?;
344
345 self.u(1, self.nalu.frame_cropping_flag)?;
346 if self.nalu.frame_cropping_flag {
347 self.ue(self.nalu.frame_crop_left_offset)?;
348 self.ue(self.nalu.frame_crop_right_offset)?;
349 self.ue(self.nalu.frame_crop_top_offset)?;
350 self.ue(self.nalu.frame_crop_bottom_offset)?;
351 }
352
353 self.u(1, self.nalu.vui_parameters_present_flag)?;
354 if self.nalu.vui_parameters_present_flag {
355 self.vui_parameters()?;
356 }
357
358 Ok(())
359 }
360}
361
362impl<'n, W: Write> Synthesizer<'n, Pps, W> {
363 pub fn synthesize(
364 ref_idc: u8,
365 pps: &'n Pps,
366 writer: W,
367 ep_enabled: bool,
368 ) -> SynthesizerResult<()> {
369 let mut s = Self { writer: NaluWriter::<W>::new(writer, ep_enabled), nalu: pps };
370
371 s.writer.write_header(ref_idc, NaluType::Pps as u8)?;
372 s.pic_parameter_set_rbsp()?;
373 s.rbsp_trailing_bits()
374 }
375
376 fn pic_parameter_set_rbsp(&mut self) -> SynthesizerResult<()> {
377 self.ue(self.nalu.pic_parameter_set_id)?;
378 self.ue(self.nalu.seq_parameter_set_id)?;
379 self.u(1, self.nalu.entropy_coding_mode_flag)?;
380 self.u(1, self.nalu.bottom_field_pic_order_in_frame_present_flag)?;
381
382 self.ue(self.nalu.num_slice_groups_minus1)?;
383 if self.nalu.num_slice_groups_minus1 > 0 {
384 return Err(SynthesizerError::Unsupported);
385 }
386
387 self.ue(self.nalu.num_ref_idx_l0_default_active_minus1)?;
388 self.ue(self.nalu.num_ref_idx_l1_default_active_minus1)?;
389 self.u(1, self.nalu.weighted_pred_flag)?;
390 self.u(2, self.nalu.weighted_bipred_idc)?;
391 self.se(self.nalu.pic_init_qp_minus26)?;
392 self.se(self.nalu.pic_init_qs_minus26)?;
393 self.se(self.nalu.chroma_qp_index_offset)?;
394 self.u(1, self.nalu.deblocking_filter_control_present_flag)?;
395 self.u(1, self.nalu.constrained_intra_pred_flag)?;
396 self.u(1, self.nalu.redundant_pic_cnt_present_flag)?;
397
398 if !(self.nalu.transform_8x8_mode_flag
399 || self.nalu.pic_scaling_matrix_present_flag
400 || self.nalu.second_chroma_qp_index_offset != 0)
401 {
402 return Ok(());
403 }
404
405 self.u(1, self.nalu.transform_8x8_mode_flag)?;
406 self.u(1, self.nalu.pic_scaling_matrix_present_flag)?;
407
408 if self.nalu.pic_scaling_matrix_present_flag {
409 let mut scaling_list_count = 6;
410 if self.nalu.transform_8x8_mode_flag {
411 if self.nalu.sps.chroma_format_idc != 3 {
412 scaling_list_count += 2;
413 } else {
414 scaling_list_count += 6;
415 }
416 }
417
418 for i in 0..scaling_list_count {
419 if i < 6 {
421 if self.nalu.scaling_lists_4x4[i] == [0; 16] {
422 self.u(1, false)?;
423 } else {
424 self.u(1, true)?;
425 self.scaling_list(
426 &self.nalu.scaling_lists_4x4[i],
427 Self::default_scaling_list(i),
428 )?;
429 }
430 } else if self.nalu.scaling_lists_8x8[i - 6] == [0; 64] {
431 self.u(1, false)?;
432 } else {
433 self.u(1, true)?;
434 self.scaling_list(
435 &self.nalu.scaling_lists_8x8[i - 6],
436 Self::default_scaling_list(i),
437 )?;
438 }
439 }
440 }
441
442 self.se(self.nalu.second_chroma_qp_index_offset)?;
443
444 Ok(())
445 }
446}
447
448#[cfg(test)]
449mod tests {
450 use std::io::Cursor;
451
452 use super::*;
453 use crate::codec::h264::parser::Nalu;
454 use crate::codec::h264::parser::NaluType;
455 use crate::codec::h264::parser::Parser;
456 use crate::codec::h264::parser::Profile;
457
458 #[test]
459 fn synthesize_sps() {
460 let raw_sps_buf = [0x00, 0x00, 0x00, 0x01, 0x07, 0x00, 0x00, 0x0a, 0xfb, 0x88];
461 let mut raw_sps = Cursor::new(&raw_sps_buf[..]);
462
463 let nalu = Nalu::next(&mut raw_sps).unwrap();
464 assert_eq!(nalu.header.type_, NaluType::Sps);
465
466 let mut parser = Parser::default();
467 let sps = parser.parse_sps(&nalu).unwrap();
468
469 let mut buf = Vec::<u8>::new();
470 Synthesizer::<'_, Sps, _>::synthesize(0, sps, &mut buf, false).unwrap();
471
472 assert_eq!(buf, raw_sps_buf);
473
474 let write_to_file = std::option_env!("CROS_CODECS_TEST_WRITE_TO_FILE") == Some("true");
475 if write_to_file {
476 let mut out = std::fs::File::create("sps.h264").unwrap();
477 out.write_all(&buf).unwrap();
478 out.flush().unwrap();
479 }
480
481 let mut cursor = Cursor::new(&buf[..]);
482 let nalu = Nalu::next(&mut cursor).unwrap();
483
484 let mut parser = Parser::default();
485
486 let sps2 = parser.parse_sps(&nalu).unwrap();
487
488 assert_eq!(sps, sps2);
489 }
490
491 #[test]
492 fn synthesize_sps_scaling_lists() {
493 let sps = Sps {
494 profile_idc: Profile::High as u8,
495 seq_scaling_matrix_present_flag: true,
496 scaling_lists_4x4: [[11, 20, 10, 20, 10, 22, 10, 20, 10, 20, 13, 20, 10, 20, 10, 24];
497 6],
498 scaling_lists_8x8: [
499 [
500 33, 20, 10, 21, 33, 20, 12, 20, 33, 23, 10, 20, 33, 20, 10, 20, 33, 24, 10, 20,
501 33, 20, 15, 20, 33, 20, 10, 26, 33, 20, 17, 20, 33, 28, 10, 20, 33, 20, 10, 20,
502 33, 29, 10, 20, 33, 20, 11, 20, 33, 20, 10, 20, 33, 20, 10, 20, 33, 20, 10, 20,
503 33, 20, 10, 20,
504 ],
505 [
506 10, 77, 11, 20, 10, 77, 12, 20, 10, 77, 13, 20, 10, 77, 14, 20, 10, 77, 15, 20,
507 10, 77, 16, 20, 10, 77, 17, 20, 10, 77, 18, 20, 10, 77, 19, 20, 10, 77, 10, 20,
508 10, 77, 10, 21, 10, 77, 10, 22, 10, 77, 10, 23, 10, 77, 10, 24, 10, 77, 10, 26,
509 10, 77, 10, 28,
510 ],
511 [0; 64],
512 [0; 64],
513 [0; 64],
514 [0; 64],
515 ],
516 frame_mbs_only_flag: true,
517 ..Default::default()
518 };
519
520 let mut buf = Vec::<u8>::new();
521 Synthesizer::<'_, Sps, _>::synthesize(0, &sps, &mut buf, false).unwrap();
522
523 let write_to_file = std::option_env!("CROS_CODECS_TEST_WRITE_TO_FILE") == Some("true");
524 if write_to_file {
525 let mut out = std::fs::File::create("sps.h264").unwrap();
526 out.write_all(&buf).unwrap();
527 out.flush().unwrap();
528 }
529
530 let mut cursor = Cursor::new(&buf[..]);
531 let nalu = Nalu::next(&mut cursor).unwrap();
532
533 let mut parser = Parser::default();
534
535 let sps2 = parser.parse_sps(&nalu).unwrap();
536
537 assert_eq!(sps.scaling_lists_4x4, sps2.scaling_lists_4x4);
538 assert_eq!(sps.scaling_lists_8x8, sps2.scaling_lists_8x8);
539 }
540
541 #[test]
542 fn synthesize_pps() {
543 let raw_sps_pps = [
544 0x00, 0x00, 0x00, 0x01, 0x07, 0x4d, 0x40, 0x0d, 0xa9, 0x18, 0x28, 0x3e, 0x60, 0x0d,
545 0x41, 0x80, 0x41, 0xad, 0xb0, 0xad, 0x7b, 0xdf, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08,
546 0xde, 0x09, 0x88,
547 ];
548
549 let mut buf = Vec::<u8>::new();
550 let mut out = Cursor::new(&mut buf);
551
552 let mut cursor = Cursor::new(&raw_sps_pps[..]);
553 let mut parser: Parser = Default::default();
554
555 while let Ok(nalu) = Nalu::next(&mut cursor) {
556 match nalu.header.type_ {
557 NaluType::Sps => {
558 let sps = parser.parse_sps(&nalu).unwrap();
559 Synthesizer::<'_, Sps, _>::synthesize(0, sps, &mut out, false).unwrap();
560 }
561 NaluType::Pps => {
562 let pps = parser.parse_pps(&nalu).unwrap();
563 Synthesizer::<'_, Pps, _>::synthesize(0, pps, &mut out, false).unwrap();
564 }
565 _ => panic!(),
566 }
567 }
568
569 let write_to_file = std::option_env!("CROS_CODECS_TEST_WRITE_TO_FILE") == Some("true");
570 if write_to_file {
571 let mut out = std::fs::File::create("sps_pps.h264").unwrap();
572 out.write_all(&buf).unwrap();
573 out.flush().unwrap();
574
575 let mut out = std::fs::File::create("sps_pps_ref.h264").unwrap();
576 out.write_all(&raw_sps_pps).unwrap();
577 out.flush().unwrap();
578 }
579
580 assert_eq!(buf, raw_sps_pps);
581 }
582}