• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 use std::fmt;
5 use std::io::Write;
6 
7 use crate::codec::h264::nalu_writer::NaluWriter;
8 use crate::codec::h264::nalu_writer::NaluWriterError;
9 use crate::codec::h264::parser::HrdParams;
10 use crate::codec::h264::parser::NaluType;
11 use crate::codec::h264::parser::Pps;
12 use crate::codec::h264::parser::Sps;
13 use crate::codec::h264::parser::DEFAULT_4X4_INTER;
14 use crate::codec::h264::parser::DEFAULT_4X4_INTRA;
15 use crate::codec::h264::parser::DEFAULT_8X8_INTER;
16 use crate::codec::h264::parser::DEFAULT_8X8_INTRA;
17 
18 mod private {
19     pub trait NaluStruct {}
20 }
21 
22 impl private::NaluStruct for Sps {}
23 
24 impl private::NaluStruct for Pps {}
25 
26 #[derive(Debug)]
27 pub enum SynthesizerError {
28     Unsupported,
29     NaluWriter(NaluWriterError),
30 }
31 
32 impl fmt::Display for SynthesizerError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result33     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 
41 impl From<NaluWriterError> for SynthesizerError {
from(err: NaluWriterError) -> Self42     fn from(err: NaluWriterError) -> Self {
43         SynthesizerError::NaluWriter(err)
44     }
45 }
46 
47 pub type SynthesizerResult<T> = Result<T, SynthesizerError>;
48 
49 /// A helper to output typed NALUs to [`std::io::Write`] using [`NaluWriter`].
50 pub struct Synthesizer<'n, N: private::NaluStruct, W: Write> {
51     writer: NaluWriter<W>,
52     nalu: &'n N,
53 }
54 
55 /// Extended Sample Aspect Ratio - H.264 Table E-1
56 const EXTENDED_SAR: u8 = 255;
57 
58 impl<N: private::NaluStruct, W: Write> Synthesizer<'_, N, W> {
u<T: Into<u32>>(&mut self, bits: usize, value: T) -> SynthesizerResult<()>59     fn u<T: Into<u32>>(&mut self, bits: usize, value: T) -> SynthesizerResult<()> {
60         self.writer.write_u(bits, value)?;
61         Ok(())
62     }
63 
f<T: Into<u32>>(&mut self, bits: usize, value: T) -> SynthesizerResult<()>64     fn f<T: Into<u32>>(&mut self, bits: usize, value: T) -> SynthesizerResult<()> {
65         self.writer.write_f(bits, value)?;
66         Ok(())
67     }
68 
ue<T: Into<u32>>(&mut self, value: T) -> SynthesizerResult<()>69     fn ue<T: Into<u32>>(&mut self, value: T) -> SynthesizerResult<()> {
70         self.writer.write_ue(value)?;
71         Ok(())
72     }
73 
se<T: Into<i32>>(&mut self, value: T) -> SynthesizerResult<()>74     fn se<T: Into<i32>>(&mut self, value: T) -> SynthesizerResult<()> {
75         self.writer.write_se(value)?;
76         Ok(())
77     }
78 
scaling_list(&mut self, list: &[u8], default: &[u8]) -> SynthesizerResult<()>79     fn scaling_list(&mut self, list: &[u8], default: &[u8]) -> SynthesizerResult<()> {
80         // H.264 7.3.2.1.1.1
81         if list == default {
82             self.se(-8)?;
83             return Ok(());
84         }
85 
86         // The number of list values we want to encode.
87         let mut run = list.len();
88 
89         // Check how many values at the end of the matrix are the same,
90         // so we can save on encoding those.
91         for j in (1..list.len()).rev() {
92             if list[j - 1] != list[j] {
93                 break;
94             }
95             run -= 1;
96         }
97 
98         // Encode deltas.
99         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         // Didn't encode all values, encode -|last_scale| to set decoder's
107         // |next_scale| (H.264 7.3.2.1.1.1) to zero, i.e. decoder should repeat
108         // last values in matrix.
109         if run < list.len() {
110             self.se(-last_scale)?;
111         }
112 
113         Ok(())
114     }
115 
default_scaling_list(i: usize) -> &'static [u8]116     fn default_scaling_list(i: usize) -> &'static [u8] {
117         // H.264 Table 7-2
118         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 
rbsp_trailing_bits(&mut self) -> SynthesizerResult<()>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 
146 impl<'n, W: Write> Synthesizer<'n, Sps, W> {
synthesize( ref_idc: u8, sps: &'n Sps, writer: W, ep_enabled: bool, ) -> SynthesizerResult<()>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 
hrd_parameters(&mut self, hrd_params: &HrdParams) -> SynthesizerResult<()>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 
vui_parameters(&mut self) -> SynthesizerResult<()>179     fn vui_parameters(&mut self) -> SynthesizerResult<()> {
180         // H.264 E.1.1
181         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 
seq_parameter_set_data(&mut self) -> SynthesizerResult<()>253     fn seq_parameter_set_data(&mut self) -> SynthesizerResult<()> {
254         // H.264 7.3.2.1.1
255         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, /* reserved_zero_2bits */ 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                     // Assume if scaling lists are zeroed that they are not present.
296                     if i < 6 {
297                         if self.nalu.scaling_lists_4x4[i] == [0; 16] {
298                             self.u(1, /* seq_scaling_list_present_flag */ false)?;
299                         } else {
300                             self.u(1, /* seq_scaling_list_present_flag */ 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, /* seq_scaling_list_present_flag */ false)?;
308                     } else {
309                         self.u(1, /* seq_scaling_list_present_flag */ 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 
362 impl<'n, W: Write> Synthesizer<'n, Pps, W> {
synthesize( ref_idc: u8, pps: &'n Pps, writer: W, ep_enabled: bool, ) -> SynthesizerResult<()>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 
pic_parameter_set_rbsp(&mut self) -> SynthesizerResult<()>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                 // Assume if scaling lists are zeroed that they are not present.
420                 if i < 6 {
421                     if self.nalu.scaling_lists_4x4[i] == [0; 16] {
422                         self.u(1, /* seq_scaling_list_present_flag */ false)?;
423                     } else {
424                         self.u(1, /* seq_scaling_list_present_flag */ 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, /* seq_scaling_list_present_flag */ false)?;
432                 } else {
433                     self.u(1, /* seq_scaling_list_present_flag */ 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)]
449 mod 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]
synthesize_sps()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]
synthesize_sps_scaling_lists()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]
synthesize_pps()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 }
583