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