sps_vui_rewriter.cc (23674B)
1 /* 2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 * 10 */ 11 12 #include "common_video/h264/sps_vui_rewriter.h" 13 14 #include <algorithm> 15 #include <cstdint> 16 #include <cstring> 17 #include <optional> 18 #include <vector> 19 20 #include "api/array_view.h" 21 #include "api/video/color_space.h" 22 #include "common_video/h264/h264_common.h" 23 #include "common_video/h264/sps_parser.h" 24 #include "rtc_base/bit_buffer.h" 25 #include "rtc_base/bitstream_reader.h" 26 #include "rtc_base/buffer.h" 27 #include "rtc_base/checks.h" 28 #include "rtc_base/logging.h" 29 #include "system_wrappers/include/metrics.h" 30 31 namespace webrtc { 32 33 namespace { 34 35 // The maximum expected growth from adding a VUI to the SPS. It's actually 36 // closer to 24 or so, but better safe than sorry. 37 const size_t kMaxVuiSpsIncrease = 64; 38 39 const char* kSpsValidHistogramName = "WebRTC.Video.H264.SpsValid"; 40 enum SpsValidEvent { 41 kReceivedSpsVuiOk = 1, 42 kReceivedSpsRewritten = 2, 43 kReceivedSpsParseFailure = 3, 44 kSentSpsPocOk = 4, 45 kSentSpsVuiOk = 5, 46 kSentSpsRewritten = 6, 47 kSentSpsParseFailure = 7, 48 kSpsRewrittenMax = 8 49 }; 50 51 #define RETURN_FALSE_ON_FAIL(x) \ 52 do { \ 53 if (!(x)) { \ 54 RTC_LOG_F(LS_ERROR) << " (line:" << __LINE__ << ") FAILED: " #x; \ 55 return false; \ 56 } \ 57 } while (0) 58 59 uint8_t CopyUInt8(BitstreamReader& source, BitBufferWriter& destination) { 60 uint8_t tmp = source.Read<uint8_t>(); 61 if (!destination.WriteUInt8(tmp)) { 62 source.Invalidate(); 63 } 64 return tmp; 65 } 66 67 uint32_t CopyExpGolomb(BitstreamReader& source, BitBufferWriter& destination) { 68 uint32_t tmp = source.ReadExponentialGolomb(); 69 if (!destination.WriteExponentialGolomb(tmp)) { 70 source.Invalidate(); 71 } 72 return tmp; 73 } 74 75 uint32_t CopyBits(int bits, 76 BitstreamReader& source, 77 BitBufferWriter& destination) { 78 RTC_DCHECK_GT(bits, 0); 79 RTC_DCHECK_LE(bits, 32); 80 uint64_t tmp = source.ReadBits(bits); 81 if (!destination.WriteBits(tmp, bits)) { 82 source.Invalidate(); 83 } 84 return tmp; 85 } 86 87 bool CopyAndRewriteVui(const SpsParser::SpsState& sps, 88 BitstreamReader& source, 89 BitBufferWriter& destination, 90 const ColorSpace* color_space, 91 SpsVuiRewriter::ParseResult& out_vui_rewritten); 92 93 void CopyHrdParameters(BitstreamReader& source, BitBufferWriter& destination); 94 bool AddBitstreamRestriction(BitBufferWriter* destination, 95 uint32_t max_num_ref_frames); 96 bool IsDefaultColorSpace(const ColorSpace& color_space); 97 bool AddVideoSignalTypeInfo(BitBufferWriter& destination, 98 const ColorSpace& color_space); 99 bool CopyOrRewriteVideoSignalTypeInfo( 100 BitstreamReader& source, 101 BitBufferWriter& destination, 102 const ColorSpace* color_space, 103 SpsVuiRewriter::ParseResult& out_vui_rewritten); 104 bool CopyRemainingBits(BitstreamReader& source, BitBufferWriter& destination); 105 } // namespace 106 107 void SpsVuiRewriter::UpdateStats(ParseResult result, Direction direction) { 108 switch (result) { 109 case SpsVuiRewriter::ParseResult::kVuiRewritten: 110 RTC_HISTOGRAM_ENUMERATION( 111 kSpsValidHistogramName, 112 direction == SpsVuiRewriter::Direction::kIncoming 113 ? SpsValidEvent::kReceivedSpsRewritten 114 : SpsValidEvent::kSentSpsRewritten, 115 SpsValidEvent::kSpsRewrittenMax); 116 break; 117 case SpsVuiRewriter::ParseResult::kVuiOk: 118 RTC_HISTOGRAM_ENUMERATION( 119 kSpsValidHistogramName, 120 direction == SpsVuiRewriter::Direction::kIncoming 121 ? SpsValidEvent::kReceivedSpsVuiOk 122 : SpsValidEvent::kSentSpsVuiOk, 123 SpsValidEvent::kSpsRewrittenMax); 124 break; 125 case SpsVuiRewriter::ParseResult::kFailure: 126 RTC_HISTOGRAM_ENUMERATION( 127 kSpsValidHistogramName, 128 direction == SpsVuiRewriter::Direction::kIncoming 129 ? SpsValidEvent::kReceivedSpsParseFailure 130 : SpsValidEvent::kSentSpsParseFailure, 131 SpsValidEvent::kSpsRewrittenMax); 132 break; 133 } 134 } 135 136 SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps( 137 ArrayView<const uint8_t> buffer, 138 std::optional<SpsParser::SpsState>* sps, 139 const ColorSpace* color_space, 140 Buffer* destination) { 141 // Create temporary RBSP decoded buffer of the payload (exlcuding the 142 // leading nalu type header byte (the SpsParser uses only the payload). 143 std::vector<uint8_t> rbsp_buffer = H264::ParseRbsp(buffer); 144 BitstreamReader source_buffer(rbsp_buffer); 145 std::optional<SpsParser::SpsState> sps_state = 146 SpsParser::ParseSpsUpToVui(source_buffer); 147 if (!sps_state) 148 return ParseResult::kFailure; 149 150 *sps = sps_state; 151 152 // We're going to completely muck up alignment, so we need a BitBufferWriter 153 // to write with. 154 Buffer out_buffer(buffer.size() + kMaxVuiSpsIncrease); 155 BitBufferWriter sps_writer(out_buffer.data(), out_buffer.size()); 156 157 // Check how far the SpsParser has read, and copy that data in bulk. 158 RTC_DCHECK(source_buffer.Ok()); 159 size_t total_bit_offset = 160 rbsp_buffer.size() * 8 - source_buffer.RemainingBitCount(); 161 size_t byte_offset = total_bit_offset / 8; 162 size_t bit_offset = total_bit_offset % 8; 163 memcpy(out_buffer.data(), rbsp_buffer.data(), 164 byte_offset + (bit_offset > 0 ? 1 : 0)); // OK to copy the last bits. 165 166 // SpsParser will have read the vui_params_present flag, which we want to 167 // modify, so back off a bit; 168 if (bit_offset == 0) { 169 --byte_offset; 170 bit_offset = 7; 171 } else { 172 --bit_offset; 173 } 174 sps_writer.Seek(byte_offset, bit_offset); 175 176 ParseResult vui_updated; 177 if (!CopyAndRewriteVui(*sps_state, source_buffer, sps_writer, color_space, 178 vui_updated)) { 179 RTC_LOG(LS_ERROR) << "Failed to parse/copy SPS VUI."; 180 return ParseResult::kFailure; 181 } 182 183 if (vui_updated == ParseResult::kVuiOk) { 184 // No update necessary after all, just return. 185 return vui_updated; 186 } 187 188 if (!CopyRemainingBits(source_buffer, sps_writer)) { 189 RTC_LOG(LS_ERROR) << "Failed to parse/copy SPS VUI."; 190 return ParseResult::kFailure; 191 } 192 193 // Pad up to next byte with zero bits. 194 sps_writer.GetCurrentOffset(&byte_offset, &bit_offset); 195 if (bit_offset > 0) { 196 sps_writer.WriteBits(0, 8 - bit_offset); 197 ++byte_offset; 198 bit_offset = 0; 199 } 200 201 RTC_DCHECK(byte_offset <= buffer.size() + kMaxVuiSpsIncrease); 202 RTC_CHECK(destination != nullptr); 203 204 out_buffer.SetSize(byte_offset); 205 206 // Write updates SPS to destination with added RBSP 207 H264::WriteRbsp(out_buffer, destination); 208 209 return ParseResult::kVuiRewritten; 210 } 211 212 SpsVuiRewriter::ParseResult SpsVuiRewriter::ParseAndRewriteSps( 213 ArrayView<const uint8_t> buffer, 214 std::optional<SpsParser::SpsState>* sps, 215 const ColorSpace* color_space, 216 Buffer* destination, 217 Direction direction) { 218 ParseResult result = 219 ParseAndRewriteSps(buffer, sps, color_space, destination); 220 UpdateStats(result, direction); 221 return result; 222 } 223 224 Buffer SpsVuiRewriter::ParseOutgoingBitstreamAndRewrite( 225 ArrayView<const uint8_t> buffer, 226 const ColorSpace* color_space) { 227 std::vector<H264::NaluIndex> nalus = H264::FindNaluIndices(buffer); 228 229 // Allocate some extra space for potentially adding a missing VUI. 230 Buffer output_buffer(/*size=*/0, /*capacity=*/buffer.size() + 231 nalus.size() * kMaxVuiSpsIncrease); 232 233 for (const H264::NaluIndex& nalu_index : nalus) { 234 // Copy NAL unit start code. 235 ArrayView<const uint8_t> start_code = buffer.subview( 236 nalu_index.start_offset, 237 nalu_index.payload_start_offset - nalu_index.start_offset); 238 ArrayView<const uint8_t> nalu = buffer.subview( 239 nalu_index.payload_start_offset, nalu_index.payload_size); 240 if (nalu.empty()) { 241 continue; 242 } 243 if (H264::ParseNaluType(nalu[0]) == H264::NaluType::kSps) { 244 // Check if stream uses picture order count type 0, and if so rewrite it 245 // to enable faster decoding. Streams in that format incur additional 246 // delay because it allows decode order to differ from render order. 247 // The mechanism used is to rewrite (edit or add) the SPS's VUI to contain 248 // restrictions on the maximum number of reordered pictures. This reduces 249 // latency significantly, though it still adds about a frame of latency to 250 // decoding. 251 // Note that we do this rewriting both here (send side, in order to 252 // protect legacy receive clients) in RtpDepacketizerH264::ParseSingleNalu 253 // (receive side, in orderer to protect us from unknown or legacy send 254 // clients). 255 std::optional<SpsParser::SpsState> sps; 256 Buffer output_nalu; 257 258 // Add the type header to the output buffer first, so that the rewriter 259 // can append modified payload on top of that. 260 output_nalu.AppendData(nalu[0]); 261 262 ParseResult result = 263 ParseAndRewriteSps(nalu.subview(H264::kNaluTypeSize), &sps, 264 color_space, &output_nalu, Direction::kOutgoing); 265 if (result == ParseResult::kVuiRewritten) { 266 output_buffer.AppendData(start_code); 267 output_buffer.AppendData(output_nalu.data(), output_nalu.size()); 268 continue; 269 } 270 } else if (H264::ParseNaluType(nalu[0]) == H264::NaluType::kAud) { 271 // Skip the access unit delimiter copy. 272 continue; 273 } 274 275 // vui wasn't rewritten and it is not aud, copy the nal unit as is. 276 output_buffer.AppendData(start_code); 277 output_buffer.AppendData(nalu); 278 } 279 return output_buffer; 280 } 281 282 namespace { 283 bool CopyAndRewriteVui(const SpsParser::SpsState& sps, 284 BitstreamReader& source, 285 BitBufferWriter& destination, 286 const ColorSpace* color_space, 287 SpsVuiRewriter::ParseResult& out_vui_rewritten) { 288 out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiOk; 289 290 // 291 // vui_parameters_present_flag: u(1) 292 // 293 RETURN_FALSE_ON_FAIL(destination.WriteBits(1, 1)); 294 295 // ********* IMPORTANT! ********** 296 // Now we're at the VUI, so we want to (1) add it if it isn't present, and 297 // (2) rewrite frame reordering values so no reordering is allowed. 298 if (!sps.vui_params_present) { 299 // Write a simple VUI with the parameters we want and 0 for all other flags. 300 301 // aspect_ratio_info_present_flag, overscan_info_present_flag. Both u(1). 302 RETURN_FALSE_ON_FAIL(destination.WriteBits(0, 2)); 303 304 uint32_t video_signal_type_present_flag = 305 (color_space && !IsDefaultColorSpace(*color_space)) ? 1 : 0; 306 RETURN_FALSE_ON_FAIL( 307 destination.WriteBits(video_signal_type_present_flag, 1)); 308 if (video_signal_type_present_flag) { 309 RETURN_FALSE_ON_FAIL(AddVideoSignalTypeInfo(destination, *color_space)); 310 } 311 // chroma_loc_info_present_flag, timing_info_present_flag, 312 // nal_hrd_parameters_present_flag, vcl_hrd_parameters_present_flag, 313 // pic_struct_present_flag, All u(1) 314 RETURN_FALSE_ON_FAIL(destination.WriteBits(0, 5)); 315 // bitstream_restriction_flag: u(1) 316 RETURN_FALSE_ON_FAIL(destination.WriteBits(1, 1)); 317 RETURN_FALSE_ON_FAIL( 318 AddBitstreamRestriction(&destination, sps.max_num_ref_frames)); 319 320 out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiRewritten; 321 } else { 322 // Parse out the full VUI. 323 // aspect_ratio_info_present_flag: u(1) 324 uint32_t aspect_ratio_info_present_flag = CopyBits(1, source, destination); 325 if (aspect_ratio_info_present_flag) { 326 // aspect_ratio_idc: u(8) 327 uint8_t aspect_ratio_idc = CopyUInt8(source, destination); 328 if (aspect_ratio_idc == 255u) { // Extended_SAR 329 // sar_width/sar_height: u(16) each. 330 CopyBits(32, source, destination); 331 } 332 } 333 // overscan_info_present_flag: u(1) 334 uint32_t overscan_info_present_flag = CopyBits(1, source, destination); 335 if (overscan_info_present_flag) { 336 // overscan_appropriate_flag: u(1) 337 CopyBits(1, source, destination); 338 } 339 340 CopyOrRewriteVideoSignalTypeInfo(source, destination, color_space, 341 out_vui_rewritten); 342 343 // chroma_loc_info_present_flag: u(1) 344 uint32_t chroma_loc_info_present_flag = CopyBits(1, source, destination); 345 if (chroma_loc_info_present_flag == 1) { 346 // chroma_sample_loc_type_(top|bottom)_field: ue(v) each. 347 CopyExpGolomb(source, destination); 348 CopyExpGolomb(source, destination); 349 } 350 // timing_info_present_flag: u(1) 351 uint32_t timing_info_present_flag = CopyBits(1, source, destination); 352 if (timing_info_present_flag == 1) { 353 // num_units_in_tick, time_scale: u(32) each 354 CopyBits(32, source, destination); 355 CopyBits(32, source, destination); 356 // fixed_frame_rate_flag: u(1) 357 CopyBits(1, source, destination); 358 } 359 // nal_hrd_parameters_present_flag: u(1) 360 uint32_t nal_hrd_parameters_present_flag = CopyBits(1, source, destination); 361 if (nal_hrd_parameters_present_flag == 1) { 362 CopyHrdParameters(source, destination); 363 } 364 // vcl_hrd_parameters_present_flag: u(1) 365 uint32_t vcl_hrd_parameters_present_flag = CopyBits(1, source, destination); 366 if (vcl_hrd_parameters_present_flag == 1) { 367 CopyHrdParameters(source, destination); 368 } 369 if (nal_hrd_parameters_present_flag == 1 || 370 vcl_hrd_parameters_present_flag == 1) { 371 // low_delay_hrd_flag: u(1) 372 CopyBits(1, source, destination); 373 } 374 // pic_struct_present_flag: u(1) 375 CopyBits(1, source, destination); 376 377 // bitstream_restriction_flag: u(1) 378 uint32_t bitstream_restriction_flag = source.ReadBit(); 379 RETURN_FALSE_ON_FAIL(destination.WriteBits(1, 1)); 380 if (bitstream_restriction_flag == 0) { 381 // We're adding one from scratch. 382 RETURN_FALSE_ON_FAIL( 383 AddBitstreamRestriction(&destination, sps.max_num_ref_frames)); 384 out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiRewritten; 385 } else { 386 // We're replacing. 387 // motion_vectors_over_pic_boundaries_flag: u(1) 388 CopyBits(1, source, destination); 389 // max_bytes_per_pic_denom: ue(v) 390 CopyExpGolomb(source, destination); 391 // max_bits_per_mb_denom: ue(v) 392 CopyExpGolomb(source, destination); 393 // log2_max_mv_length_horizontal: ue(v) 394 CopyExpGolomb(source, destination); 395 // log2_max_mv_length_vertical: ue(v) 396 CopyExpGolomb(source, destination); 397 // ********* IMPORTANT! ********** 398 // The next two are the ones we need to set to low numbers: 399 // max_num_reorder_frames: ue(v) 400 // max_dec_frame_buffering: ue(v) 401 // However, if they are already set to no greater than the numbers we 402 // want, then we don't need to be rewriting. 403 uint32_t max_num_reorder_frames = source.ReadExponentialGolomb(); 404 uint32_t max_dec_frame_buffering = source.ReadExponentialGolomb(); 405 RETURN_FALSE_ON_FAIL(destination.WriteExponentialGolomb(0)); 406 RETURN_FALSE_ON_FAIL( 407 destination.WriteExponentialGolomb(sps.max_num_ref_frames)); 408 if (max_num_reorder_frames != 0 || 409 max_dec_frame_buffering > sps.max_num_ref_frames) { 410 out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiRewritten; 411 } 412 } 413 } 414 return source.Ok(); 415 } 416 417 // Copies a VUI HRD parameters segment. 418 void CopyHrdParameters(BitstreamReader& source, BitBufferWriter& destination) { 419 // cbp_cnt_minus1: ue(v) 420 uint32_t cbp_cnt_minus1 = CopyExpGolomb(source, destination); 421 // bit_rate_scale and cbp_size_scale: u(4) each 422 CopyBits(8, source, destination); 423 for (size_t i = 0; source.Ok() && i <= cbp_cnt_minus1; ++i) { 424 // bit_rate_value_minus1 and cbp_size_value_minus1: ue(v) each 425 CopyExpGolomb(source, destination); 426 CopyExpGolomb(source, destination); 427 // cbr_flag: u(1) 428 CopyBits(1, source, destination); 429 } 430 // initial_cbp_removal_delay_length_minus1: u(5) 431 // cbp_removal_delay_length_minus1: u(5) 432 // dbp_output_delay_length_minus1: u(5) 433 // time_offset_length: u(5) 434 CopyBits(5 * 4, source, destination); 435 } 436 437 // These functions are similar to webrtc::H264SpsParser::Parse, and based on the 438 // same version of the H.264 standard. You can find it here: 439 // http://www.itu.int/rec/T-REC-H.264 440 441 // Adds a bitstream restriction VUI segment. 442 bool AddBitstreamRestriction(BitBufferWriter* destination, 443 uint32_t max_num_ref_frames) { 444 // motion_vectors_over_pic_boundaries_flag: u(1) 445 // Default is 1 when not present. 446 RETURN_FALSE_ON_FAIL(destination->WriteBits(1, 1)); 447 // max_bytes_per_pic_denom: ue(v) 448 // Default is 2 when not present. 449 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(2)); 450 // max_bits_per_mb_denom: ue(v) 451 // Default is 1 when not present. 452 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(1)); 453 // log2_max_mv_length_horizontal: ue(v) 454 // log2_max_mv_length_vertical: ue(v) 455 // Both default to 16 when not present. 456 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16)); 457 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(16)); 458 459 // ********* IMPORTANT! ********** 460 // max_num_reorder_frames: ue(v) 461 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(0)); 462 // max_dec_frame_buffering: ue(v) 463 RETURN_FALSE_ON_FAIL(destination->WriteExponentialGolomb(max_num_ref_frames)); 464 return true; 465 } 466 467 bool IsDefaultColorSpace(const ColorSpace& color_space) { 468 return color_space.range() != ColorSpace::RangeID::kFull && 469 color_space.primaries() == ColorSpace::PrimaryID::kUnspecified && 470 color_space.transfer() == ColorSpace::TransferID::kUnspecified && 471 color_space.matrix() == ColorSpace::MatrixID::kUnspecified; 472 } 473 474 bool AddVideoSignalTypeInfo(BitBufferWriter& destination, 475 const ColorSpace& color_space) { 476 // video_format: u(3). 477 RETURN_FALSE_ON_FAIL(destination.WriteBits(5, 3)); // 5 = Unspecified 478 // video_full_range_flag: u(1) 479 RETURN_FALSE_ON_FAIL(destination.WriteBits( 480 color_space.range() == ColorSpace::RangeID::kFull ? 1 : 0, 1)); 481 // colour_description_present_flag: u(1) 482 RETURN_FALSE_ON_FAIL(destination.WriteBits(1, 1)); 483 // colour_primaries: u(8) 484 RETURN_FALSE_ON_FAIL( 485 destination.WriteUInt8(static_cast<uint8_t>(color_space.primaries()))); 486 // transfer_characteristics: u(8) 487 RETURN_FALSE_ON_FAIL( 488 destination.WriteUInt8(static_cast<uint8_t>(color_space.transfer()))); 489 // matrix_coefficients: u(8) 490 RETURN_FALSE_ON_FAIL( 491 destination.WriteUInt8(static_cast<uint8_t>(color_space.matrix()))); 492 return true; 493 } 494 495 bool CopyOrRewriteVideoSignalTypeInfo( 496 BitstreamReader& source, 497 BitBufferWriter& destination, 498 const ColorSpace* color_space, 499 SpsVuiRewriter::ParseResult& out_vui_rewritten) { 500 // Read. 501 uint32_t video_format = 5; // H264 default: unspecified 502 uint32_t video_full_range_flag = 0; // H264 default: limited 503 uint32_t colour_description_present_flag = 0; 504 uint8_t colour_primaries = 3; // H264 default: unspecified 505 uint8_t transfer_characteristics = 3; // H264 default: unspecified 506 uint8_t matrix_coefficients = 3; // H264 default: unspecified 507 uint32_t video_signal_type_present_flag = source.ReadBit(); 508 if (video_signal_type_present_flag) { 509 video_format = source.ReadBits(3); 510 video_full_range_flag = source.ReadBit(); 511 colour_description_present_flag = source.ReadBit(); 512 if (colour_description_present_flag) { 513 colour_primaries = source.Read<uint8_t>(); 514 transfer_characteristics = source.Read<uint8_t>(); 515 matrix_coefficients = source.Read<uint8_t>(); 516 } 517 } 518 RETURN_FALSE_ON_FAIL(source.Ok()); 519 520 // Update. 521 uint32_t video_signal_type_present_flag_override = 522 video_signal_type_present_flag; 523 uint32_t video_format_override = video_format; 524 uint32_t video_full_range_flag_override = video_full_range_flag; 525 uint32_t colour_description_present_flag_override = 526 colour_description_present_flag; 527 uint8_t colour_primaries_override = colour_primaries; 528 uint8_t transfer_characteristics_override = transfer_characteristics; 529 uint8_t matrix_coefficients_override = matrix_coefficients; 530 if (color_space) { 531 if (IsDefaultColorSpace(*color_space)) { 532 video_signal_type_present_flag_override = 0; 533 } else { 534 video_signal_type_present_flag_override = 1; 535 video_format_override = 5; // unspecified 536 537 if (color_space->range() == ColorSpace::RangeID::kFull) { 538 video_full_range_flag_override = 1; 539 } else { 540 // ColorSpace::RangeID::kInvalid and kDerived are treated as limited. 541 video_full_range_flag_override = 0; 542 } 543 544 colour_description_present_flag_override = 545 color_space->primaries() != ColorSpace::PrimaryID::kUnspecified || 546 color_space->transfer() != ColorSpace::TransferID::kUnspecified || 547 color_space->matrix() != ColorSpace::MatrixID::kUnspecified; 548 colour_primaries_override = 549 static_cast<uint8_t>(color_space->primaries()); 550 transfer_characteristics_override = 551 static_cast<uint8_t>(color_space->transfer()); 552 matrix_coefficients_override = 553 static_cast<uint8_t>(color_space->matrix()); 554 } 555 } 556 557 // Write. 558 RETURN_FALSE_ON_FAIL( 559 destination.WriteBits(video_signal_type_present_flag_override, 1)); 560 if (video_signal_type_present_flag_override) { 561 RETURN_FALSE_ON_FAIL(destination.WriteBits(video_format_override, 3)); 562 RETURN_FALSE_ON_FAIL( 563 destination.WriteBits(video_full_range_flag_override, 1)); 564 RETURN_FALSE_ON_FAIL( 565 destination.WriteBits(colour_description_present_flag_override, 1)); 566 if (colour_description_present_flag_override) { 567 RETURN_FALSE_ON_FAIL(destination.WriteUInt8(colour_primaries_override)); 568 RETURN_FALSE_ON_FAIL( 569 destination.WriteUInt8(transfer_characteristics_override)); 570 RETURN_FALSE_ON_FAIL( 571 destination.WriteUInt8(matrix_coefficients_override)); 572 } 573 } 574 575 if (video_signal_type_present_flag_override != 576 video_signal_type_present_flag || 577 video_format_override != video_format || 578 video_full_range_flag_override != video_full_range_flag || 579 colour_description_present_flag_override != 580 colour_description_present_flag || 581 colour_primaries_override != colour_primaries || 582 transfer_characteristics_override != transfer_characteristics || 583 matrix_coefficients_override != matrix_coefficients) { 584 out_vui_rewritten = SpsVuiRewriter::ParseResult::kVuiRewritten; 585 } 586 587 return true; 588 } 589 590 bool CopyRemainingBits(BitstreamReader& source, BitBufferWriter& destination) { 591 // Try to get at least the destination aligned. 592 if (source.RemainingBitCount() > 0 && source.RemainingBitCount() % 8 != 0) { 593 size_t misaligned_bits = source.RemainingBitCount() % 8; 594 CopyBits(misaligned_bits, source, destination); 595 } 596 while (source.RemainingBitCount() > 0) { 597 int count = std::min(32, source.RemainingBitCount()); 598 CopyBits(count, source, destination); 599 } 600 // TODO(noahric): The last byte could be all zeroes now, which we should just 601 // strip. 602 return source.Ok(); 603 } 604 605 } // namespace 606 607 } // namespace webrtc