H265.cpp (61353B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "H265.h" 6 7 #include <stdint.h> 8 9 #include <cmath> 10 11 #include "AnnexB.h" 12 #include "BitReader.h" 13 #include "BitWriter.h" 14 #include "BufferReader.h" 15 #include "ByteStreamsUtils.h" 16 #include "ByteWriter.h" 17 #include "MediaData.h" 18 #include "MediaInfo.h" 19 #include "mozilla/Span.h" 20 #include "nsFmtString.h" 21 22 mozilla::LazyLogModule gH265("H265"); 23 24 #define LOG(msg, ...) MOZ_LOG(gH265, LogLevel::Debug, (msg, ##__VA_ARGS__)) 25 #define LOGV(msg, ...) MOZ_LOG(gH265, LogLevel::Verbose, (msg, ##__VA_ARGS__)) 26 27 #define TRUE_OR_RETURN(condition) \ 28 do { \ 29 if (!(condition)) { \ 30 LOG(#condition " should be true!"); \ 31 return mozilla::Err(NS_ERROR_FAILURE); \ 32 } \ 33 } while (0) 34 35 #define IN_RANGE_OR_RETURN(val, min, max) \ 36 do { \ 37 int64_t temp = AssertedCast<int64_t>(val); \ 38 if ((temp) < (min) || (max) < (temp)) { \ 39 LOG(#val " is not in the range of [" #min "," #max "]"); \ 40 return mozilla::Err(NS_ERROR_FAILURE); \ 41 } \ 42 } while (0) 43 44 #define NON_ZERO_OR_RETURN(dest, val) \ 45 do { \ 46 int64_t temp = AssertedCast<int64_t>(val); \ 47 if ((temp) != 0) { \ 48 (dest) = (temp); \ 49 } else { \ 50 LOG(#dest " should be non-zero"); \ 51 return mozilla::Err(NS_ERROR_FAILURE); \ 52 } \ 53 } while (0) 54 55 // For the comparison, we intended to not use memcpy due to its unreliability. 56 #define COMPARE_FIELD(field) ((field) == aOther.field) 57 #define COMPARE_ARRAY(field) \ 58 std::equal(std::begin(field), std::end(field), std::begin(aOther.field)) 59 60 namespace mozilla { 61 62 H265NALU::H265NALU(const uint8_t* aData, uint32_t aByteSize) 63 : mNALU(aData, aByteSize) { 64 // Per 7.3.1 NAL unit syntax 65 BitReader reader(aData, aByteSize * 8); 66 (void)reader.ReadBit(); // forbidden_zero_bit 67 mNalUnitType = reader.ReadBits(6); 68 mNuhLayerId = reader.ReadBits(6); 69 mNuhTemporalIdPlus1 = reader.ReadBits(3); 70 LOGV("Created H265NALU, type=%hhu, size=%u", mNalUnitType, aByteSize); 71 } 72 73 /* static */ Result<HVCCConfig, nsresult> HVCCConfig::Parse( 74 const mozilla::MediaRawData* aSample) { 75 if (!aSample) { 76 LOG("No sample"); 77 return mozilla::Err(NS_ERROR_FAILURE); 78 } 79 if (aSample->Size() < 3) { 80 LOG("Incorrect sample size %zu", aSample->Size()); 81 return mozilla::Err(NS_ERROR_FAILURE); 82 } 83 if (aSample->mTrackInfo && 84 !aSample->mTrackInfo->mMimeType.EqualsLiteral("video/hevc")) { 85 LOG("Only allow 'video/hevc' (mimeType=%s)", 86 aSample->mTrackInfo->mMimeType.get()); 87 return mozilla::Err(NS_ERROR_FAILURE); 88 } 89 return HVCCConfig::Parse(aSample->mExtraData); 90 } 91 92 /* static */ 93 Result<HVCCConfig, nsresult> HVCCConfig::Parse( 94 const mozilla::MediaByteBuffer* aExtraData) { 95 // From configurationVersion to numOfArrays, total 184 bits (23 bytes) 96 if (!aExtraData) { 97 LOG("No extra-data"); 98 return mozilla::Err(NS_ERROR_FAILURE); 99 } 100 if (aExtraData->Length() < 23) { 101 LOG("Incorrect extra-data size %zu", aExtraData->Length()); 102 return mozilla::Err(NS_ERROR_FAILURE); 103 } 104 const auto& byteBuffer = *aExtraData; 105 if (byteBuffer[0] != 1) { 106 LOG("Version should always be 1"); 107 return mozilla::Err(NS_ERROR_FAILURE); 108 } 109 HVCCConfig hvcc; 110 111 BitReader reader(aExtraData); 112 hvcc.configurationVersion = reader.ReadBits(8); 113 hvcc.general_profile_space = reader.ReadBits(2); 114 hvcc.general_tier_flag = reader.ReadBit(); 115 hvcc.general_profile_idc = reader.ReadBits(5); 116 hvcc.general_profile_compatibility_flags = reader.ReadU32(); 117 118 uint32_t flagHigh = reader.ReadU32(); 119 uint16_t flagLow = reader.ReadBits(16); 120 hvcc.general_constraint_indicator_flags = 121 ((uint64_t)(flagHigh) << 16) | (uint64_t)(flagLow); 122 123 hvcc.general_level_idc = reader.ReadBits(8); 124 (void)reader.ReadBits(4); // reserved 125 hvcc.min_spatial_segmentation_idc = reader.ReadBits(12); 126 (void)reader.ReadBits(6); // reserved 127 hvcc.parallelismType = reader.ReadBits(2); 128 (void)reader.ReadBits(6); // reserved 129 hvcc.chroma_format_idc = reader.ReadBits(2); 130 (void)reader.ReadBits(5); // reserved 131 hvcc.bit_depth_luma_minus8 = reader.ReadBits(3); 132 (void)reader.ReadBits(5); // reserved 133 hvcc.bit_depth_chroma_minus8 = reader.ReadBits(3); 134 hvcc.avgFrameRate = reader.ReadBits(16); 135 hvcc.constantFrameRate = reader.ReadBits(2); 136 hvcc.numTemporalLayers = reader.ReadBits(3); 137 hvcc.temporalIdNested = reader.ReadBit(); 138 hvcc.lengthSizeMinusOne = reader.ReadBits(2); 139 const uint8_t numOfArrays = reader.ReadBits(8); 140 for (uint8_t idx = 0; idx < numOfArrays; idx++) { 141 (void)reader.ReadBits(2); // array_completeness + reserved 142 const uint8_t nalUnitType = reader.ReadBits(6); 143 const uint16_t numNalus = reader.ReadBits(16); 144 LOGV("nalu-type=%u, nalu-num=%u", nalUnitType, numNalus); 145 for (uint16_t nIdx = 0; nIdx < numNalus; nIdx++) { 146 const uint16_t nalUnitLength = reader.ReadBits(16); 147 if (reader.BitsLeft() < nalUnitLength * 8) { 148 LOG("Aborting parsing, NALU size (%u bits) is larger than remaining " 149 "(%zu bits)!", 150 nalUnitLength * 8u, reader.BitsLeft()); 151 // We return what we've parsed so far and ignore the rest. 152 hvcc.mByteBuffer = aExtraData; 153 return hvcc; 154 } 155 const uint8_t* currentPtr = 156 aExtraData->Elements() + reader.BitCount() / 8; 157 H265NALU nalu(currentPtr, nalUnitLength); 158 uint32_t nalBitsLength = nalUnitLength * 8; 159 (void)reader.AdvanceBits(nalBitsLength); 160 // Per ISO_IEC-14496-15-2022, 8.3.2.1.3 Semantics, NALU should only be 161 // SPS/PPS/VPS or SEI, ignore all the other types of NALU. 162 if (nalu.IsSPS() || nalu.IsPPS() || nalu.IsVPS() || nalu.IsSEI()) { 163 hvcc.mNALUs.AppendElement(nalu); 164 } else { 165 LOG("Ignore NALU (%u) which is not SPS/PPS/VPS or SEI", 166 nalu.mNalUnitType); 167 } 168 } 169 } 170 hvcc.mByteBuffer = aExtraData; 171 return hvcc; 172 } 173 174 uint32_t HVCCConfig::NumSPS() const { 175 uint32_t spsCounter = 0; 176 for (const auto& nalu : mNALUs) { 177 if (nalu.IsSPS()) { 178 spsCounter++; 179 } 180 } 181 return spsCounter; 182 } 183 184 bool HVCCConfig::HasSPS() const { 185 bool hasSPS = false; 186 for (const auto& nalu : mNALUs) { 187 if (nalu.IsSPS()) { 188 hasSPS = true; 189 break; 190 } 191 } 192 return hasSPS; 193 } 194 195 nsCString HVCCConfig::ToString() const { 196 return nsFmtCString( 197 FMT_STRING( 198 "HVCCConfig - version={}, profile_space={}, tier={}, " 199 "profile_idc={}, profile_compatibility_flags={:#08x}, " 200 "constraint_indicator_flags={:#016x}, level_idc={}, " 201 "min_spatial_segmentation_idc={}, parallelismType={}, " 202 "chroma_format_idc={}, bit_depth_luma_minus8={}, " 203 "bit_depth_chroma_minus8={}, avgFrameRate={}, constantFrameRate={}, " 204 "numTemporalLayers={}, temporalIdNested={}, lengthSizeMinusOne={}, " 205 "nalus={}, buffer={}(bytes), NaluSize={}, NumSPS={}"), 206 configurationVersion, general_profile_space, general_tier_flag, 207 general_profile_idc, general_profile_compatibility_flags, 208 general_constraint_indicator_flags, general_level_idc, 209 min_spatial_segmentation_idc, parallelismType, chroma_format_idc, 210 bit_depth_luma_minus8, bit_depth_chroma_minus8, avgFrameRate, 211 constantFrameRate, numTemporalLayers, temporalIdNested, 212 lengthSizeMinusOne, mNALUs.Length(), 213 mByteBuffer ? mByteBuffer->Length() : 0, NALUSize(), NumSPS()); 214 } 215 216 Maybe<H265NALU> HVCCConfig::GetFirstAvaiableNALU( 217 H265NALU::NAL_TYPES aType) const { 218 for (const auto& nalu : mNALUs) { 219 if (nalu.mNalUnitType == aType) { 220 return Some(nalu); 221 } 222 } 223 return Nothing(); 224 } 225 226 /* static */ 227 Result<H265SPS, nsresult> H265::DecodeSPSFromSPSNALU(const H265NALU& aSPSNALU) { 228 MOZ_ASSERT(aSPSNALU.IsSPS()); 229 RefPtr<MediaByteBuffer> rbsp = H265::DecodeNALUnit(aSPSNALU.mNALU); 230 if (!rbsp) { 231 LOG("Failed to decode NALU"); 232 return Err(NS_ERROR_FAILURE); 233 } 234 235 // H265 spec, 7.3.2.2.1 seq_parameter_set_rbsp 236 H265SPS sps; 237 BitReader reader(rbsp); 238 sps.sps_video_parameter_set_id = reader.ReadBits(4); 239 IN_RANGE_OR_RETURN(sps.sps_video_parameter_set_id, 0, 15); 240 sps.sps_max_sub_layers_minus1 = reader.ReadBits(3); 241 IN_RANGE_OR_RETURN(sps.sps_max_sub_layers_minus1, 0, 6); 242 sps.sps_temporal_id_nesting_flag = reader.ReadBit(); 243 244 if (auto rv = ParseProfileTierLevel( 245 reader, true /* aProfilePresentFlag, true per spec*/, 246 sps.sps_max_sub_layers_minus1, sps.profile_tier_level); 247 rv.isErr()) { 248 LOG("Failed to parse the profile tier level."); 249 return Err(NS_ERROR_FAILURE); 250 } 251 252 sps.sps_seq_parameter_set_id = reader.ReadUE(); 253 IN_RANGE_OR_RETURN(sps.sps_seq_parameter_set_id, 0, 15); 254 sps.chroma_format_idc = reader.ReadUE(); 255 IN_RANGE_OR_RETURN(sps.chroma_format_idc, 0, 3); 256 257 if (sps.chroma_format_idc == 3) { 258 sps.separate_colour_plane_flag = reader.ReadBit(); 259 } 260 261 // From Table 6-1. 262 if (sps.chroma_format_idc == 1) { 263 sps.subWidthC = sps.subHeightC = 2; 264 } else if (sps.chroma_format_idc == 2) { 265 sps.subWidthC = 2; 266 sps.subHeightC = 1; 267 } else { 268 sps.subWidthC = sps.subHeightC = 1; 269 } 270 271 NON_ZERO_OR_RETURN(sps.pic_width_in_luma_samples, reader.ReadUE()); 272 NON_ZERO_OR_RETURN(sps.pic_height_in_luma_samples, reader.ReadUE()); 273 { 274 // (A-2) Calculate maxDpbSize 275 const auto maxLumaPs = sps.profile_tier_level.GetMaxLumaPs(); 276 CheckedUint32 picSize = sps.pic_height_in_luma_samples; 277 picSize *= sps.pic_width_in_luma_samples; 278 if (!picSize.isValid()) { 279 LOG("Invalid picture size"); 280 return Err(NS_ERROR_FAILURE); 281 } 282 const auto picSizeInSamplesY = picSize.value(); 283 const auto maxDpbPicBuf = sps.profile_tier_level.GetDpbMaxPicBuf(); 284 if (picSizeInSamplesY <= (maxLumaPs >> 2)) { 285 sps.maxDpbSize = std::min(4 * maxDpbPicBuf, 16u); 286 } else if (picSizeInSamplesY <= (maxLumaPs >> 1)) { 287 sps.maxDpbSize = std::min(2 * maxDpbPicBuf, 16u); 288 } else if (picSizeInSamplesY <= ((3 * maxLumaPs) >> 2)) { 289 sps.maxDpbSize = std::min((4 * maxDpbPicBuf) / 3, 16u); 290 } else { 291 sps.maxDpbSize = maxDpbPicBuf; 292 } 293 } 294 295 sps.conformance_window_flag = reader.ReadBit(); 296 if (sps.conformance_window_flag) { 297 sps.conf_win_left_offset = reader.ReadUE(); 298 sps.conf_win_right_offset = reader.ReadUE(); 299 sps.conf_win_top_offset = reader.ReadUE(); 300 sps.conf_win_bottom_offset = reader.ReadUE(); 301 // The following formulas are specified under the definition of 302 // `conf_win_xxx_offset` in the spec. 303 CheckedUint32 width = sps.pic_width_in_luma_samples; 304 width -= 305 sps.subWidthC * (sps.conf_win_right_offset - sps.conf_win_left_offset); 306 if (!width.isValid()) { 307 LOG("width overflow when applying the conformance window!"); 308 return Err(NS_ERROR_FAILURE); 309 } 310 IN_RANGE_OR_RETURN(width.value(), 0, sps.pic_width_in_luma_samples); 311 CheckedUint32 height = sps.pic_height_in_luma_samples; 312 height -= 313 sps.subHeightC * (sps.conf_win_bottom_offset - sps.conf_win_top_offset); 314 if (!height.isValid()) { 315 LOG("height overflow when applying the conformance window!"); 316 return Err(NS_ERROR_FAILURE); 317 } 318 IN_RANGE_OR_RETURN(height.value(), 0, sps.pic_height_in_luma_samples); 319 // These values specify the width and height of the cropped image. 320 sps.mCroppedWidth = Some(width.value()); 321 sps.mCroppedHeight = Some(height.value()); 322 } 323 sps.bit_depth_luma_minus8 = reader.ReadUE(); 324 IN_RANGE_OR_RETURN(sps.bit_depth_luma_minus8, 0, 8); 325 sps.bit_depth_chroma_minus8 = reader.ReadUE(); 326 IN_RANGE_OR_RETURN(sps.bit_depth_chroma_minus8, 0, 8); 327 sps.log2_max_pic_order_cnt_lsb_minus4 = reader.ReadUE(); 328 IN_RANGE_OR_RETURN(sps.log2_max_pic_order_cnt_lsb_minus4, 0, 12); 329 sps.sps_sub_layer_ordering_info_present_flag = reader.ReadBit(); 330 for (auto i = sps.sps_sub_layer_ordering_info_present_flag 331 ? 0 332 : sps.sps_max_sub_layers_minus1; 333 i <= sps.sps_max_sub_layers_minus1; i++) { 334 sps.sps_max_dec_pic_buffering_minus1[i] = reader.ReadUE(); 335 IN_RANGE_OR_RETURN(sps.sps_max_dec_pic_buffering_minus1[i], 0, 336 sps.maxDpbSize - 1); 337 sps.sps_max_num_reorder_pics[i] = reader.ReadUE(); 338 IN_RANGE_OR_RETURN(sps.sps_max_num_reorder_pics[i], 0, 339 sps.sps_max_dec_pic_buffering_minus1[i]); 340 // 7.4.3.2.1, see sps_max_dec_pic_buffering_minus1 and 341 // sps_max_num_reorder_pics, "When i is greater than 0, ....". 342 if (i > 0) { 343 TRUE_OR_RETURN(sps.sps_max_dec_pic_buffering_minus1[i] >= 344 sps.sps_max_dec_pic_buffering_minus1[i - 1]); 345 TRUE_OR_RETURN(sps.sps_max_num_reorder_pics[i] >= 346 sps.sps_max_num_reorder_pics[i - 1]); 347 } 348 sps.sps_max_latency_increase_plus1[i] = reader.ReadUE(); 349 IN_RANGE_OR_RETURN(sps.sps_max_latency_increase_plus1[i], 0, 0xFFFFFFFE); 350 } 351 sps.log2_min_luma_coding_block_size_minus3 = reader.ReadUE(); 352 sps.log2_diff_max_min_luma_coding_block_size = reader.ReadUE(); 353 sps.log2_min_luma_transform_block_size_minus2 = reader.ReadUE(); 354 sps.log2_diff_max_min_luma_transform_block_size = reader.ReadUE(); 355 sps.max_transform_hierarchy_depth_inter = reader.ReadUE(); 356 sps.max_transform_hierarchy_depth_intra = reader.ReadUE(); 357 const auto scaling_list_enabled_flag = reader.ReadBit(); 358 if (scaling_list_enabled_flag) { 359 const auto sps_scaling_list_data_present_flag = reader.ReadBit(); 360 if (sps_scaling_list_data_present_flag) { 361 if (auto rv = ParseAndIgnoreScalingListData(reader); rv.isErr()) { 362 LOG("Failed to parse scaling list data."); 363 return Err(NS_ERROR_FAILURE); 364 } 365 } 366 } 367 368 // amp_enabled_flag and sample_adaptive_offset_enabled_flag 369 (void)reader.ReadBits(2); 370 371 sps.pcm_enabled_flag = reader.ReadBit(); 372 if (sps.pcm_enabled_flag) { 373 sps.pcm_sample_bit_depth_luma_minus1 = reader.ReadBits(3); 374 IN_RANGE_OR_RETURN(sps.pcm_sample_bit_depth_luma_minus1, 0, 375 sps.BitDepthLuma()); 376 sps.pcm_sample_bit_depth_chroma_minus1 = reader.ReadBits(3); 377 IN_RANGE_OR_RETURN(sps.pcm_sample_bit_depth_chroma_minus1, 0, 378 sps.BitDepthChroma()); 379 sps.log2_min_pcm_luma_coding_block_size_minus3 = reader.ReadUE(); 380 IN_RANGE_OR_RETURN(sps.log2_min_pcm_luma_coding_block_size_minus3, 0, 2); 381 uint32_t log2MinIpcmCbSizeY{sps.log2_min_pcm_luma_coding_block_size_minus3 + 382 3}; 383 sps.log2_diff_max_min_pcm_luma_coding_block_size = reader.ReadUE(); 384 { 385 // Validate value 386 CheckedUint32 log2MaxIpcmCbSizeY{ 387 sps.log2_diff_max_min_pcm_luma_coding_block_size}; 388 log2MaxIpcmCbSizeY += log2MinIpcmCbSizeY; 389 CheckedUint32 minCbLog2SizeY{sps.log2_min_luma_coding_block_size_minus3}; 390 minCbLog2SizeY += 3; // (7-10) 391 CheckedUint32 ctbLog2SizeY{minCbLog2SizeY}; 392 ctbLog2SizeY += sps.log2_diff_max_min_luma_coding_block_size; // (7-11) 393 IN_RANGE_OR_RETURN(log2MaxIpcmCbSizeY.value(), 0, 394 std::min(ctbLog2SizeY.value(), uint32_t(5))); 395 } 396 sps.pcm_loop_filter_disabled_flag = reader.ReadBit(); 397 } 398 399 sps.num_short_term_ref_pic_sets = reader.ReadUE(); 400 IN_RANGE_OR_RETURN(sps.num_short_term_ref_pic_sets, 0, 401 kMaxShortTermRefPicSets); 402 for (auto i = 0; i < sps.num_short_term_ref_pic_sets; i++) { 403 if (auto rv = ParseStRefPicSet(reader, i, sps); rv.isErr()) { 404 LOG("Failed to parse short-term reference picture set."); 405 return Err(NS_ERROR_FAILURE); 406 } 407 } 408 const auto long_term_ref_pics_present_flag = reader.ReadBit(); 409 if (long_term_ref_pics_present_flag) { 410 uint32_t num_long_term_ref_pics_sps; 411 num_long_term_ref_pics_sps = reader.ReadUE(); 412 IN_RANGE_OR_RETURN(num_long_term_ref_pics_sps, 0, kMaxLongTermRefPicSets); 413 for (auto i = 0; i < num_long_term_ref_pics_sps; i++) { 414 (void)reader.ReadBits(sps.log2_max_pic_order_cnt_lsb_minus4 + 415 4); // lt_ref_pic_poc_lsb_sps[i] 416 (void)reader.ReadBit(); // used_by_curr_pic_lt_sps_flag 417 } 418 } 419 sps.sps_temporal_mvp_enabled_flag = reader.ReadBit(); 420 sps.strong_intra_smoothing_enabled_flag = reader.ReadBit(); 421 const auto vui_parameters_present_flag = reader.ReadBit(); 422 if (vui_parameters_present_flag) { 423 if (auto rv = ParseVuiParameters(reader, sps); rv.isErr()) { 424 LOG("Failed to parse VUI parameter."); 425 return Err(NS_ERROR_FAILURE); 426 } 427 } 428 429 // The rest is extension data we don't care about, so no need to parse them. 430 return sps; 431 } 432 433 /* static */ 434 Result<H265SPS, nsresult> H265::DecodeSPSFromHVCCExtraData( 435 const mozilla::MediaByteBuffer* aExtraData) { 436 auto rv = HVCCConfig::Parse(aExtraData); 437 if (rv.isErr()) { 438 LOG("Only support HVCC extra-data"); 439 return Err(NS_ERROR_FAILURE); 440 } 441 const auto& hvcc = rv.unwrap(); 442 const H265NALU* spsNALU = nullptr; 443 for (const auto& nalu : hvcc.mNALUs) { 444 if (nalu.IsSPS()) { 445 spsNALU = &nalu; 446 break; 447 } 448 } 449 if (!spsNALU) { 450 LOG("No sps found"); 451 return Err(NS_ERROR_FAILURE); 452 } 453 return DecodeSPSFromSPSNALU(*spsNALU); 454 } 455 456 /* static */ 457 Result<Ok, nsresult> H265::ParseProfileTierLevel( 458 BitReader& aReader, bool aProfilePresentFlag, 459 uint8_t aMaxNumSubLayersMinus1, H265ProfileTierLevel& aProfile) { 460 // H265 spec, 7.3.3 Profile, tier and level syntax 461 if (aProfilePresentFlag) { 462 aProfile.general_profile_space = aReader.ReadBits(2); 463 aProfile.general_tier_flag = aReader.ReadBit(); 464 aProfile.general_profile_idc = aReader.ReadBits(5); 465 IN_RANGE_OR_RETURN(aProfile.general_profile_idc, 0, 11); 466 aProfile.general_profile_compatibility_flags = aReader.ReadU32(); 467 aProfile.general_progressive_source_flag = aReader.ReadBit(); 468 aProfile.general_interlaced_source_flag = aReader.ReadBit(); 469 aProfile.general_non_packed_constraint_flag = aReader.ReadBit(); 470 aProfile.general_frame_only_constraint_flag = aReader.ReadBit(); 471 // ignored attributes, in total general_reserved_zero_43bits 472 (void)aReader.ReadBits(32); 473 (void)aReader.ReadBits(11); 474 // general_inbld_flag or general_reserved_zero_bit 475 (void)aReader.ReadBit(); 476 } 477 aProfile.general_level_idc = aReader.ReadBits(8); 478 479 // Following are all ignored attributes. 480 bool sub_layer_profile_present_flag[8]; 481 bool sub_layer_level_present_flag[8]; 482 for (auto i = 0; i < aMaxNumSubLayersMinus1; i++) { 483 sub_layer_profile_present_flag[i] = aReader.ReadBit(); 484 sub_layer_level_present_flag[i] = aReader.ReadBit(); 485 } 486 if (aMaxNumSubLayersMinus1 > 0) { 487 for (auto i = aMaxNumSubLayersMinus1; i < 8; i++) { 488 // reserved_zero_2bits 489 (void)aReader.ReadBits(2); 490 } 491 } 492 for (auto i = 0; i < aMaxNumSubLayersMinus1; i++) { 493 if (sub_layer_profile_present_flag[i]) { 494 // sub_layer_profile_space, sub_layer_tier_flag, sub_layer_profile_idc 495 (void)aReader.ReadBits(8); 496 // sub_layer_profile_compatibility_flag 497 (void)aReader.ReadBits(32); 498 // sub_layer_progressive_source_flag, sub_layer_interlaced_source_flag, 499 // sub_layer_non_packed_constraint_flag, 500 // sub_layer_frame_only_constraint_flag 501 (void)aReader.ReadBits(4); 502 // ignored attributes, in total general_reserved_zero_43bits 503 (void)aReader.ReadBits(32); 504 (void)aReader.ReadBits(11); 505 // sub_layer_inbld_flag or reserved_zero_bit 506 (void)aReader.ReadBit(); 507 } 508 if (sub_layer_level_present_flag[i]) { 509 (void)aReader.ReadBits(8); // sub_layer_level_idc 510 } 511 } 512 return Ok(); 513 } 514 515 uint32_t H265ProfileTierLevel::GetMaxLumaPs() const { 516 // From Table A.8 - General tier and level limits. 517 // "general_level_idc and sub_layer_level_idc[ i ] shall be set equal to a 518 // value of 30 times the level number specified in Table A.8". 519 if (general_level_idc <= 30) { // level 1 520 return 36864; 521 } 522 if (general_level_idc <= 60) { // level 2 523 return 122880; 524 } 525 if (general_level_idc <= 63) { // level 2.1 526 return 245760; 527 } 528 if (general_level_idc <= 90) { // level 3 529 return 552960; 530 } 531 if (general_level_idc <= 93) { // level 3.1 532 return 983040; 533 } 534 if (general_level_idc <= 123) { // level 4, 4.1 535 return 2228224; 536 } 537 if (general_level_idc <= 156) { // level 5, 5.1, 5.2 538 return 8912896; 539 } 540 // level 6, 6.1, 6.2 - beyond that there's no actual limit. 541 return 35651584; 542 } 543 544 uint32_t H265ProfileTierLevel::GetDpbMaxPicBuf() const { 545 // From A.4.2 - Profile-specific level limits for the video profiles. 546 // "maxDpbPicBuf is equal to 6 for all profiles where the value of 547 // sps_curr_pic_ref_enabled_flag is required to be equal to 0 and 7 for all 548 // profiles where the value of sps_curr_pic_ref_enabled_flag is not required 549 // to be equal to 0." From A.3 Profile, the flag in the main, main still, 550 // range extensions and high throughput is required to be zero. 551 return (general_profile_idc >= H265ProfileIdc::kProfileIdcMain && 552 general_profile_idc <= H265ProfileIdc::kProfileIdcHighThroughput) 553 ? 6 554 : 7; 555 } 556 557 bool H265ProfileTierLevel::operator==( 558 const H265ProfileTierLevel& aOther) const { 559 return COMPARE_FIELD(general_profile_space) && 560 COMPARE_FIELD(general_tier_flag) && 561 COMPARE_FIELD(general_profile_idc) && 562 COMPARE_FIELD(general_profile_compatibility_flags) && 563 COMPARE_FIELD(general_progressive_source_flag) && 564 COMPARE_FIELD(general_interlaced_source_flag) && 565 COMPARE_FIELD(general_non_packed_constraint_flag) && 566 COMPARE_FIELD(general_frame_only_constraint_flag) && 567 COMPARE_FIELD(general_level_idc); 568 } 569 570 bool H265StRefPicSet::operator==(const H265StRefPicSet& aOther) const { 571 return COMPARE_FIELD(num_negative_pics) && COMPARE_FIELD(num_positive_pics) && 572 COMPARE_FIELD(numDeltaPocs) && COMPARE_ARRAY(usedByCurrPicS0) && 573 COMPARE_ARRAY(usedByCurrPicS1) && COMPARE_ARRAY(deltaPocS0) && 574 COMPARE_ARRAY(deltaPocS1); 575 } 576 577 bool H265VUIParameters::operator==(const H265VUIParameters& aOther) const { 578 return COMPARE_FIELD(sar_width) && COMPARE_FIELD(sar_height) && 579 COMPARE_FIELD(video_full_range_flag) && 580 COMPARE_FIELD(colour_primaries) && 581 COMPARE_FIELD(transfer_characteristics) && 582 COMPARE_FIELD(matrix_coeffs); 583 } 584 585 bool H265VUIParameters::HasValidAspectRatio() const { 586 return aspect_ratio_info_present_flag && mIsSARValid; 587 } 588 589 double H265VUIParameters::GetPixelAspectRatio() const { 590 MOZ_ASSERT(HasValidAspectRatio(), 591 "Shouldn't call this for an invalid ratio!"); 592 if (MOZ_UNLIKELY(!sar_height)) { 593 return 0.0; 594 } 595 // Sample Aspect Ratio (SAR) is equivalent to Pixel Aspect Ratio (PAR). 596 return static_cast<double>(sar_width) / static_cast<double>(sar_height); 597 } 598 599 /* static */ 600 Result<Ok, nsresult> H265::ParseAndIgnoreScalingListData(BitReader& aReader) { 601 // H265 spec, 7.3.4 Scaling list data syntax 602 for (auto sizeIdx = 0; sizeIdx < 4; sizeIdx++) { 603 for (auto matrixIdx = 0; matrixIdx < 6; 604 matrixIdx += (sizeIdx == 3) ? 3 : 1) { 605 const auto scaling_list_pred_mode_flag = aReader.ReadBit(); 606 if (!scaling_list_pred_mode_flag) { 607 (void)aReader.ReadUE(); // scaling_list_pred_matrix_id_delta 608 } else { 609 int32_t coefNum = std::min(64, (1 << (4 + (sizeIdx << 1)))); 610 if (sizeIdx > 1) { 611 (void)aReader.ReadSE(); // scaling_list_dc_coef_minus8 612 } 613 for (auto i = 0; i < coefNum; i++) { 614 (void)aReader.ReadSE(); // scaling_list_delta_coef 615 } 616 } 617 } 618 } 619 return Ok(); 620 } 621 622 /* static */ 623 Result<Ok, nsresult> H265::ParseStRefPicSet(BitReader& aReader, 624 uint32_t aStRpsIdx, H265SPS& aSPS) { 625 // H265 Spec, 7.3.7 Short-term reference picture set syntax 626 MOZ_ASSERT(aStRpsIdx < kMaxShortTermRefPicSets); 627 bool inter_ref_pic_set_prediction_flag = false; 628 H265StRefPicSet& curStRefPicSet = aSPS.st_ref_pic_set[aStRpsIdx]; 629 if (aStRpsIdx != 0) { 630 inter_ref_pic_set_prediction_flag = aReader.ReadBit(); 631 } 632 if (inter_ref_pic_set_prediction_flag) { 633 int delta_idx_minus1 = 0; 634 if (aStRpsIdx == aSPS.num_short_term_ref_pic_sets) { 635 delta_idx_minus1 = aReader.ReadUE(); 636 IN_RANGE_OR_RETURN(delta_idx_minus1, 0, aStRpsIdx - 1); 637 } 638 const uint32_t RefRpsIdx = aStRpsIdx - (delta_idx_minus1 + 1); // (7-59) 639 const bool delta_rps_sign = aReader.ReadBit(); 640 const uint32_t abs_delta_rps_minus1 = aReader.ReadUE(); 641 IN_RANGE_OR_RETURN(abs_delta_rps_minus1, 0, 0x7FFF); 642 const int32_t deltaRps = 643 (1 - 2 * delta_rps_sign) * 644 AssertedCast<int32_t>(abs_delta_rps_minus1 + 1); // (7-60) 645 646 bool used_by_curr_pic_flag[kMaxShortTermRefPicSets] = {}; 647 bool use_delta_flag[kMaxShortTermRefPicSets] = {}; 648 // 7.4.8 - use_delta_flag defaults to 1 if not present. 649 std::fill_n(use_delta_flag, kMaxShortTermRefPicSets, true); 650 const H265StRefPicSet& refSet = aSPS.st_ref_pic_set[RefRpsIdx]; 651 for (auto j = 0; j <= refSet.numDeltaPocs; j++) { 652 used_by_curr_pic_flag[j] = aReader.ReadBit(); 653 if (!used_by_curr_pic_flag[j]) { 654 use_delta_flag[j] = aReader.ReadBit(); 655 } 656 } 657 // Calculate fields (7-61) 658 uint32_t i = 0; 659 for (int64_t j = static_cast<int64_t>(refSet.num_positive_pics) - 1; j >= 0; 660 j--) { 661 MOZ_DIAGNOSTIC_ASSERT(j < kMaxShortTermRefPicSets); 662 int64_t d_poc = refSet.deltaPocS1[j] + deltaRps; 663 if (d_poc < 0 && use_delta_flag[refSet.num_negative_pics + j]) { 664 curStRefPicSet.deltaPocS0[i] = d_poc; 665 curStRefPicSet.usedByCurrPicS0[i++] = 666 used_by_curr_pic_flag[refSet.num_negative_pics + j]; 667 } 668 } 669 if (deltaRps < 0 && use_delta_flag[refSet.numDeltaPocs]) { 670 curStRefPicSet.deltaPocS0[i] = deltaRps; 671 curStRefPicSet.usedByCurrPicS0[i++] = 672 used_by_curr_pic_flag[refSet.numDeltaPocs]; 673 } 674 for (auto j = 0; j < refSet.num_negative_pics; j++) { 675 MOZ_DIAGNOSTIC_ASSERT(j < kMaxShortTermRefPicSets); 676 int64_t d_poc = refSet.deltaPocS0[j] + deltaRps; 677 if (d_poc < 0 && use_delta_flag[j]) { 678 curStRefPicSet.deltaPocS0[i] = d_poc; 679 curStRefPicSet.usedByCurrPicS0[i++] = used_by_curr_pic_flag[j]; 680 } 681 } 682 curStRefPicSet.num_negative_pics = i; 683 // Calculate fields (7-62) 684 i = 0; 685 for (int64_t j = static_cast<int64_t>(refSet.num_negative_pics) - 1; j >= 0; 686 j--) { 687 MOZ_DIAGNOSTIC_ASSERT(j < kMaxShortTermRefPicSets); 688 int64_t d_poc = refSet.deltaPocS0[j] + deltaRps; 689 if (d_poc > 0 && use_delta_flag[j]) { 690 curStRefPicSet.deltaPocS1[i] = d_poc; 691 curStRefPicSet.usedByCurrPicS1[i++] = used_by_curr_pic_flag[j]; 692 } 693 } 694 if (deltaRps > 0 && use_delta_flag[refSet.numDeltaPocs]) { 695 curStRefPicSet.deltaPocS1[i] = deltaRps; 696 curStRefPicSet.usedByCurrPicS1[i++] = 697 used_by_curr_pic_flag[refSet.numDeltaPocs]; 698 } 699 for (auto j = 0; j < refSet.num_positive_pics; j++) { 700 MOZ_DIAGNOSTIC_ASSERT(j < kMaxShortTermRefPicSets); 701 int64_t d_poc = refSet.deltaPocS1[j] + deltaRps; 702 if (d_poc > 0 && use_delta_flag[refSet.num_negative_pics + j]) { 703 curStRefPicSet.deltaPocS1[i] = d_poc; 704 curStRefPicSet.usedByCurrPicS1[i++] = 705 used_by_curr_pic_flag[refSet.num_negative_pics + j]; 706 } 707 } 708 curStRefPicSet.num_positive_pics = i; 709 } else { 710 curStRefPicSet.num_negative_pics = aReader.ReadUE(); 711 curStRefPicSet.num_positive_pics = aReader.ReadUE(); 712 const uint32_t spsMaxDecPicBufferingMinus1 = 713 aSPS.sps_max_dec_pic_buffering_minus1[aSPS.sps_max_sub_layers_minus1]; 714 IN_RANGE_OR_RETURN(curStRefPicSet.num_negative_pics, 0, 715 spsMaxDecPicBufferingMinus1); 716 CheckedUint32 maxPositivePics{spsMaxDecPicBufferingMinus1}; 717 maxPositivePics -= curStRefPicSet.num_negative_pics; 718 IN_RANGE_OR_RETURN(curStRefPicSet.num_positive_pics, 0, 719 maxPositivePics.value()); 720 for (auto i = 0; i < curStRefPicSet.num_negative_pics; i++) { 721 const uint32_t delta_poc_s0_minus1 = aReader.ReadUE(); 722 IN_RANGE_OR_RETURN(delta_poc_s0_minus1, 0, 0x7FFF); 723 if (i == 0) { 724 // (7-67) 725 curStRefPicSet.deltaPocS0[i] = -(delta_poc_s0_minus1 + 1); 726 } else { 727 // (7-69) 728 curStRefPicSet.deltaPocS0[i] = 729 curStRefPicSet.deltaPocS0[i - 1] - (delta_poc_s0_minus1 + 1); 730 } 731 curStRefPicSet.usedByCurrPicS0[i] = aReader.ReadBit(); 732 } 733 for (auto i = 0; i < curStRefPicSet.num_positive_pics; i++) { 734 const int delta_poc_s1_minus1 = aReader.ReadUE(); 735 IN_RANGE_OR_RETURN(delta_poc_s1_minus1, 0, 0x7FFF); 736 if (i == 0) { 737 // (7-68) 738 curStRefPicSet.deltaPocS1[i] = delta_poc_s1_minus1 + 1; 739 } else { 740 // (7-70) 741 curStRefPicSet.deltaPocS1[i] = 742 curStRefPicSet.deltaPocS1[i - 1] + delta_poc_s1_minus1 + 1; 743 } 744 curStRefPicSet.usedByCurrPicS1[i] = aReader.ReadBit(); 745 } 746 } 747 // (7-71) 748 curStRefPicSet.numDeltaPocs = 749 curStRefPicSet.num_negative_pics + curStRefPicSet.num_positive_pics; 750 return Ok(); 751 } 752 753 /* static */ 754 Result<Ok, nsresult> H265::ParseVuiParameters(BitReader& aReader, 755 H265SPS& aSPS) { 756 // VUI parameters: Table E.1 "Interpretation of sample aspect ratio indicator" 757 static constexpr int kTableSarWidth[] = {0, 1, 12, 10, 16, 40, 24, 20, 32, 758 80, 18, 15, 64, 160, 4, 3, 2}; 759 static constexpr int kTableSarHeight[] = {0, 1, 11, 11, 11, 33, 11, 11, 11, 760 33, 11, 11, 33, 99, 3, 2, 1}; 761 static_assert(std::size(kTableSarWidth) == std::size(kTableSarHeight), 762 "sar tables must have the same size"); 763 aSPS.vui_parameters = Some(H265VUIParameters()); 764 H265VUIParameters* vui = aSPS.vui_parameters.ptr(); 765 766 vui->aspect_ratio_info_present_flag = aReader.ReadBit(); 767 if (vui->aspect_ratio_info_present_flag) { 768 const auto aspect_ratio_idc = aReader.ReadBits(8); 769 constexpr int kExtendedSar = 255; 770 if (aspect_ratio_idc == kExtendedSar) { 771 vui->sar_width = aReader.ReadBits(16); 772 vui->sar_height = aReader.ReadBits(16); 773 } else { 774 const auto max_aspect_ratio_idc = std::size(kTableSarWidth) - 1; 775 IN_RANGE_OR_RETURN(aspect_ratio_idc, 0, max_aspect_ratio_idc); 776 vui->sar_width = kTableSarWidth[aspect_ratio_idc]; 777 vui->sar_height = kTableSarHeight[aspect_ratio_idc]; 778 } 779 // In E.3.1 VUI parameters semantics, "when aspect_ratio_idc is equal to 0 780 // or sar_width is equal to 0 or sar_height is equal to 0, the sample aspect 781 // ratio is unspecified in this Specification". 782 vui->mIsSARValid = vui->sar_width && vui->sar_height; 783 if (!vui->mIsSARValid) { 784 LOG("sar_width or sar_height should not be zero!"); 785 } 786 } 787 788 const auto overscan_info_present_flag = aReader.ReadBit(); 789 if (overscan_info_present_flag) { 790 (void)aReader.ReadBit(); // overscan_appropriate_flag 791 } 792 793 const auto video_signal_type_present_flag = aReader.ReadBit(); 794 if (video_signal_type_present_flag) { 795 (void)aReader.ReadBits(3); // video_format 796 vui->video_full_range_flag = aReader.ReadBit(); 797 const auto colour_description_present_flag = aReader.ReadBit(); 798 if (colour_description_present_flag) { 799 vui->colour_primaries.emplace(aReader.ReadBits(8)); 800 vui->transfer_characteristics.emplace(aReader.ReadBits(8)); 801 vui->matrix_coeffs.emplace(aReader.ReadBits(8)); 802 } 803 } 804 805 const auto chroma_loc_info_present_flag = aReader.ReadBit(); 806 if (chroma_loc_info_present_flag) { 807 (void)aReader.ReadUE(); // chroma_sample_loc_type_top_field 808 (void)aReader.ReadUE(); // chroma_sample_loc_type_bottom_field 809 } 810 811 // Ignore neutral_chroma_indication_flag, field_seq_flag and 812 // frame_field_info_present_flag. 813 (void)aReader.ReadBits(3); 814 815 const auto default_display_window_flag = aReader.ReadBit(); 816 if (default_display_window_flag) { 817 uint32_t def_disp_win_left_offset = aReader.ReadUE(); 818 uint32_t def_disp_win_right_offset = aReader.ReadUE(); 819 uint32_t def_disp_win_top_offset = aReader.ReadUE(); 820 uint32_t def_disp_win_bottom_offset = aReader.ReadUE(); 821 // (E-68) + (E-69) 822 aSPS.mDisplayWidth = aSPS.subWidthC; 823 aSPS.mDisplayWidth *= 824 (aSPS.conf_win_left_offset + def_disp_win_left_offset); 825 aSPS.mDisplayWidth *= 826 (aSPS.conf_win_right_offset + def_disp_win_right_offset); 827 if (!aSPS.mDisplayWidth.isValid()) { 828 LOG("mDisplayWidth overflow!"); 829 return Err(NS_ERROR_FAILURE); 830 } 831 IN_RANGE_OR_RETURN(aSPS.mDisplayWidth.value(), 0, 832 aSPS.pic_width_in_luma_samples); 833 834 // (E-70) + (E-71) 835 aSPS.mDisplayHeight = aSPS.subHeightC; 836 aSPS.mDisplayHeight *= (aSPS.conf_win_top_offset + def_disp_win_top_offset); 837 aSPS.mDisplayHeight *= 838 (aSPS.conf_win_bottom_offset + def_disp_win_bottom_offset); 839 if (!aSPS.mDisplayHeight.isValid()) { 840 LOG("mDisplayHeight overflow!"); 841 return Err(NS_ERROR_FAILURE); 842 } 843 IN_RANGE_OR_RETURN(aSPS.mDisplayHeight.value(), 0, 844 aSPS.pic_height_in_luma_samples); 845 } 846 847 const auto vui_timing_info_present_flag = aReader.ReadBit(); 848 if (vui_timing_info_present_flag) { 849 (void)aReader.ReadU32(); // vui_num_units_in_tick 850 (void)aReader.ReadU32(); // vui_time_scale 851 const auto vui_poc_proportional_to_timing_flag = aReader.ReadBit(); 852 if (vui_poc_proportional_to_timing_flag) { 853 (void)aReader.ReadUE(); // vui_num_ticks_poc_diff_one_minus1 854 } 855 const auto vui_hrd_parameters_present_flag = aReader.ReadBit(); 856 if (vui_hrd_parameters_present_flag) { 857 if (auto rv = ParseAndIgnoreHrdParameters(aReader, true, 858 aSPS.sps_max_sub_layers_minus1); 859 rv.isErr()) { 860 LOG("Failed to parse Hrd parameters"); 861 return rv; 862 } 863 } 864 } 865 866 const auto bitstream_restriction_flag = aReader.ReadBit(); 867 if (bitstream_restriction_flag) { 868 // Skip tiles_fixed_structure_flag, motion_vectors_over_pic_boundaries_flag 869 // and restricted_ref_pic_lists_flag. 870 (void)aReader.ReadBits(3); 871 (void)aReader.ReadUE(); // min_spatial_segmentation_idc 872 (void)aReader.ReadUE(); // max_bytes_per_pic_denom 873 (void)aReader.ReadUE(); // max_bits_per_min_cu_denom 874 (void)aReader.ReadUE(); // log2_max_mv_length_horizontal 875 (void)aReader.ReadUE(); // log2_max_mv_length_vertical 876 } 877 return Ok(); 878 } 879 880 /* static */ 881 Result<Ok, nsresult> H265::ParseAndIgnoreHrdParameters( 882 BitReader& aReader, bool aCommonInfPresentFlag, 883 int aMaxNumSubLayersMinus1) { 884 // H265 Spec, E.2.2 HRD parameters syntax 885 bool nal_hrd_parameters_present_flag = false; 886 bool vcl_hrd_parameters_present_flag = false; 887 bool sub_pic_hrd_params_present_flag = false; 888 if (aCommonInfPresentFlag) { 889 nal_hrd_parameters_present_flag = aReader.ReadBit(); 890 vcl_hrd_parameters_present_flag = aReader.ReadBit(); 891 if (nal_hrd_parameters_present_flag || vcl_hrd_parameters_present_flag) { 892 sub_pic_hrd_params_present_flag = aReader.ReadBit(); 893 if (sub_pic_hrd_params_present_flag) { 894 (void)aReader.ReadBits(8); // tick_divisor_minus2 895 // du_cpb_removal_delay_increment_length_minus1 896 (void)aReader.ReadBits(5); 897 // sub_pic_cpb_params_in_pic_timing_sei_flag 898 (void)aReader.ReadBits(1); 899 (void)aReader.ReadBits(5); // dpb_output_delay_du_length_minus1 900 } 901 902 (void)aReader.ReadBits(4); // bit_rate_scale 903 (void)aReader.ReadBits(4); // cpb_size_scale 904 if (sub_pic_hrd_params_present_flag) { 905 (void)aReader.ReadBits(4); // cpb_size_du_scale 906 } 907 (void)aReader.ReadBits(5); // initial_cpb_removal_delay_length_minus1 908 (void)aReader.ReadBits(5); // au_cpb_removal_delay_length_minus1 909 (void)aReader.ReadBits(5); // dpb_output_delay_length_minus1 910 } 911 } 912 for (int i = 0; i <= aMaxNumSubLayersMinus1; i++) { 913 bool fixed_pic_rate_within_cvs_flag = false; 914 if (auto fixed_pic_rate_general_flag = aReader.ReadBit(); 915 !fixed_pic_rate_general_flag) { 916 fixed_pic_rate_within_cvs_flag = aReader.ReadBit(); 917 } 918 bool low_delay_hrd_flag = false; 919 if (fixed_pic_rate_within_cvs_flag) { 920 (void)aReader.ReadUE(); // elemental_duration_in_tc_minus1 921 } else { 922 low_delay_hrd_flag = aReader.ReadBit(); 923 } 924 int cpb_cnt_minus1 = 0; 925 if (!low_delay_hrd_flag) { 926 cpb_cnt_minus1 = aReader.ReadUE(); 927 IN_RANGE_OR_RETURN(cpb_cnt_minus1, 0, 31); 928 } 929 if (nal_hrd_parameters_present_flag) { 930 if (auto rv = ParseAndIgnoreSubLayerHrdParameters( 931 aReader, cpb_cnt_minus1 + 1, sub_pic_hrd_params_present_flag); 932 rv.isErr()) { 933 LOG("Failed to parse nal Hrd parameters"); 934 return rv; 935 }; 936 } 937 if (vcl_hrd_parameters_present_flag) { 938 if (auto rv = ParseAndIgnoreSubLayerHrdParameters( 939 aReader, cpb_cnt_minus1 + 1, sub_pic_hrd_params_present_flag); 940 rv.isErr()) { 941 LOG("Failed to parse vcl Hrd parameters"); 942 return rv; 943 } 944 } 945 } 946 return Ok(); 947 } 948 949 /* static */ 950 Result<Ok, nsresult> H265::ParseAndIgnoreSubLayerHrdParameters( 951 BitReader& aReader, int aCpbCnt, bool aSubPicHrdParamsPresentFlag) { 952 // H265 Spec, E.2.3 Sub-layer HRD parameters syntax 953 for (auto i = 0; i < aCpbCnt; i++) { 954 (void)aReader.ReadUE(); // bit_rate_value_minus1 955 (void)aReader.ReadUE(); // cpb_size_value_minus1 956 if (aSubPicHrdParamsPresentFlag) { 957 (void)aReader.ReadUE(); // cpb_size_du_value_minus1 958 (void)aReader.ReadUE(); // bit_rate_du_value_minus1 959 } 960 (void)aReader.ReadBit(); // cbr_flag 961 } 962 return Ok(); 963 } 964 965 bool H265SPS::operator==(const H265SPS& aOther) const { 966 return COMPARE_FIELD(sps_video_parameter_set_id) && 967 COMPARE_FIELD(sps_max_sub_layers_minus1) && 968 COMPARE_FIELD(sps_temporal_id_nesting_flag) && 969 COMPARE_FIELD(profile_tier_level) && 970 COMPARE_FIELD(sps_seq_parameter_set_id) && 971 COMPARE_FIELD(chroma_format_idc) && 972 COMPARE_FIELD(separate_colour_plane_flag) && 973 COMPARE_FIELD(pic_width_in_luma_samples) && 974 COMPARE_FIELD(pic_height_in_luma_samples) && 975 COMPARE_FIELD(conformance_window_flag) && 976 COMPARE_FIELD(conf_win_left_offset) && 977 COMPARE_FIELD(conf_win_right_offset) && 978 COMPARE_FIELD(conf_win_top_offset) && 979 COMPARE_FIELD(conf_win_bottom_offset) && 980 COMPARE_FIELD(bit_depth_luma_minus8) && 981 COMPARE_FIELD(bit_depth_chroma_minus8) && 982 COMPARE_FIELD(log2_max_pic_order_cnt_lsb_minus4) && 983 COMPARE_FIELD(sps_sub_layer_ordering_info_present_flag) && 984 COMPARE_ARRAY(sps_max_dec_pic_buffering_minus1) && 985 COMPARE_ARRAY(sps_max_num_reorder_pics) && 986 COMPARE_ARRAY(sps_max_latency_increase_plus1) && 987 COMPARE_FIELD(log2_min_luma_coding_block_size_minus3) && 988 COMPARE_FIELD(log2_diff_max_min_luma_coding_block_size) && 989 COMPARE_FIELD(log2_min_luma_transform_block_size_minus2) && 990 COMPARE_FIELD(log2_diff_max_min_luma_transform_block_size) && 991 COMPARE_FIELD(max_transform_hierarchy_depth_inter) && 992 COMPARE_FIELD(max_transform_hierarchy_depth_intra) && 993 COMPARE_FIELD(pcm_enabled_flag) && 994 COMPARE_FIELD(pcm_sample_bit_depth_luma_minus1) && 995 COMPARE_FIELD(pcm_sample_bit_depth_chroma_minus1) && 996 COMPARE_FIELD(log2_min_pcm_luma_coding_block_size_minus3) && 997 COMPARE_FIELD(log2_diff_max_min_pcm_luma_coding_block_size) && 998 COMPARE_FIELD(pcm_loop_filter_disabled_flag) && 999 COMPARE_FIELD(num_short_term_ref_pic_sets) && 1000 COMPARE_ARRAY(st_ref_pic_set) && 1001 COMPARE_FIELD(sps_temporal_mvp_enabled_flag) && 1002 COMPARE_FIELD(strong_intra_smoothing_enabled_flag) && 1003 COMPARE_FIELD(vui_parameters) && COMPARE_FIELD(subWidthC) && 1004 COMPARE_FIELD(subHeightC) && COMPARE_FIELD(mDisplayWidth) && 1005 COMPARE_FIELD(mDisplayHeight) && COMPARE_FIELD(maxDpbSize); 1006 } 1007 1008 bool H265SPS::operator!=(const H265SPS& aOther) const { 1009 return !(operator==(aOther)); 1010 } 1011 1012 gfx::IntSize H265SPS::GetImageSize() const { 1013 if (mCroppedWidth && mCroppedHeight) { 1014 return gfx::IntSize(*mCroppedWidth, *mCroppedHeight); 1015 } 1016 return gfx::IntSize(pic_width_in_luma_samples, pic_height_in_luma_samples); 1017 } 1018 1019 gfx::IntSize H265SPS::GetDisplaySize() const { 1020 if (mDisplayWidth.value() == 0 || mDisplayHeight.value() == 0) { 1021 return GetImageSize(); 1022 } 1023 return gfx::IntSize(mDisplayWidth.value(), mDisplayHeight.value()); 1024 } 1025 1026 gfx::ColorDepth H265SPS::ColorDepth() const { 1027 if (bit_depth_luma_minus8 != 0 && bit_depth_luma_minus8 != 2 && 1028 bit_depth_luma_minus8 != 4) { 1029 // We don't know what that is, just assume 8 bits to prevent decoding 1030 // regressions if we ever encounter those. 1031 return gfx::ColorDepth::COLOR_8; 1032 } 1033 return gfx::ColorDepthForBitDepth(BitDepthLuma()); 1034 } 1035 1036 // PrimaryID, TransferID and MatrixID are defined in ByteStreamsUtils.h 1037 static PrimaryID GetPrimaryID(const Maybe<uint8_t>& aPrimary) { 1038 if (!aPrimary || *aPrimary < 1 || *aPrimary > 22 || *aPrimary == 3) { 1039 return PrimaryID::INVALID; 1040 } 1041 if (*aPrimary > 12 && *aPrimary < 22) { 1042 return PrimaryID::INVALID; 1043 } 1044 return static_cast<PrimaryID>(*aPrimary); 1045 } 1046 1047 static TransferID GetTransferID(const Maybe<uint8_t>& aTransfer) { 1048 if (!aTransfer || *aTransfer < 1 || *aTransfer > 18 || *aTransfer == 3) { 1049 return TransferID::INVALID; 1050 } 1051 return static_cast<TransferID>(*aTransfer); 1052 } 1053 1054 static MatrixID GetMatrixID(const Maybe<uint8_t>& aMatrix) { 1055 if (!aMatrix || *aMatrix > 11 || *aMatrix == 3) { 1056 return MatrixID::INVALID; 1057 } 1058 return static_cast<MatrixID>(*aMatrix); 1059 } 1060 1061 gfx::YUVColorSpace H265SPS::ColorSpace() const { 1062 // Bitfield, note that guesses with higher values take precedence over 1063 // guesses with lower values. 1064 enum Guess { 1065 GUESS_BT601 = 1 << 0, 1066 GUESS_BT709 = 1 << 1, 1067 GUESS_BT2020 = 1 << 2, 1068 }; 1069 1070 uint32_t guess = 0; 1071 if (vui_parameters) { 1072 switch (GetPrimaryID(vui_parameters->colour_primaries)) { 1073 case PrimaryID::BT709: 1074 guess |= GUESS_BT709; 1075 break; 1076 case PrimaryID::BT470M: 1077 case PrimaryID::BT470BG: 1078 case PrimaryID::SMPTE170M: 1079 case PrimaryID::SMPTE240M: 1080 guess |= GUESS_BT601; 1081 break; 1082 case PrimaryID::BT2020: 1083 guess |= GUESS_BT2020; 1084 break; 1085 case PrimaryID::FILM: 1086 case PrimaryID::SMPTEST428_1: 1087 case PrimaryID::SMPTEST431_2: 1088 case PrimaryID::SMPTEST432_1: 1089 case PrimaryID::EBU_3213_E: 1090 case PrimaryID::INVALID: 1091 case PrimaryID::UNSPECIFIED: 1092 break; 1093 } 1094 1095 switch (GetTransferID(vui_parameters->transfer_characteristics)) { 1096 case TransferID::BT709: 1097 guess |= GUESS_BT709; 1098 break; 1099 case TransferID::GAMMA22: 1100 case TransferID::GAMMA28: 1101 case TransferID::SMPTE170M: 1102 case TransferID::SMPTE240M: 1103 guess |= GUESS_BT601; 1104 break; 1105 case TransferID::BT2020_10: 1106 case TransferID::BT2020_12: 1107 guess |= GUESS_BT2020; 1108 break; 1109 case TransferID::LINEAR: 1110 case TransferID::LOG: 1111 case TransferID::LOG_SQRT: 1112 case TransferID::IEC61966_2_4: 1113 case TransferID::BT1361_ECG: 1114 case TransferID::IEC61966_2_1: 1115 case TransferID::SMPTEST2084: 1116 case TransferID::SMPTEST428_1: 1117 case TransferID::ARIB_STD_B67: 1118 case TransferID::INVALID: 1119 case TransferID::UNSPECIFIED: 1120 break; 1121 } 1122 1123 switch (GetMatrixID(vui_parameters->matrix_coeffs)) { 1124 case MatrixID::BT709: 1125 guess |= GUESS_BT709; 1126 break; 1127 case MatrixID::BT470BG: 1128 case MatrixID::SMPTE170M: 1129 case MatrixID::SMPTE240M: 1130 guess |= GUESS_BT601; 1131 break; 1132 case MatrixID::BT2020_NCL: 1133 case MatrixID::BT2020_CL: 1134 guess |= GUESS_BT2020; 1135 break; 1136 case MatrixID::RGB: 1137 case MatrixID::FCC: 1138 case MatrixID::YCOCG: 1139 case MatrixID::YDZDX: 1140 case MatrixID::INVALID: 1141 case MatrixID::UNSPECIFIED: 1142 break; 1143 } 1144 } 1145 1146 // Removes lowest bit until only a single bit remains. 1147 while (guess & (guess - 1)) { 1148 guess &= guess - 1; 1149 } 1150 if (!guess) { 1151 // A better default to BT601 which should die a slow death. 1152 guess = GUESS_BT709; 1153 } 1154 1155 switch (guess) { 1156 case GUESS_BT601: 1157 return gfx::YUVColorSpace::BT601; 1158 case GUESS_BT709: 1159 return gfx::YUVColorSpace::BT709; 1160 default: 1161 MOZ_DIAGNOSTIC_ASSERT(guess == GUESS_BT2020); 1162 return gfx::YUVColorSpace::BT2020; 1163 } 1164 } 1165 1166 bool H265SPS::IsFullColorRange() const { 1167 return vui_parameters ? vui_parameters->video_full_range_flag : false; 1168 } 1169 1170 uint8_t H265SPS::ColorPrimaries() const { 1171 // Per H265 spec E.3.1, "When the colour_primaries syntax element is not 1172 // present, the value of colour_primaries is inferred to be equal to 2 (the 1173 // chromaticity is unspecified or is determined by the application).". 1174 if (!vui_parameters || !vui_parameters->colour_primaries) { 1175 return 2; 1176 } 1177 return vui_parameters->colour_primaries.value(); 1178 } 1179 1180 uint8_t H265SPS::TransferFunction() const { 1181 // Per H265 spec E.3.1, "When the transfer_characteristics syntax element is 1182 // not present, the value of transfer_characteristics is inferred to be equal 1183 // to 2 (the transfer characteristics are unspecified or are determined by the 1184 // application)." 1185 if (!vui_parameters || !vui_parameters->transfer_characteristics) { 1186 return 2; 1187 } 1188 return vui_parameters->transfer_characteristics.value(); 1189 } 1190 1191 /* static */ 1192 already_AddRefed<mozilla::MediaByteBuffer> H265::DecodeNALUnit( 1193 const Span<const uint8_t>& aNALU) { 1194 RefPtr<mozilla::MediaByteBuffer> rbsp = new mozilla::MediaByteBuffer; 1195 BufferReader reader(aNALU.Elements(), aNALU.Length()); 1196 auto header = reader.ReadU16(); 1197 if (header.isErr()) { 1198 return nullptr; 1199 } 1200 uint32_t lastbytes = 0xffff; 1201 while (reader.Remaining()) { 1202 auto res = reader.ReadU8(); 1203 if (res.isErr()) { 1204 return nullptr; 1205 } 1206 uint8_t byte = res.unwrap(); 1207 if ((lastbytes & 0xffff) == 0 && byte == 0x03) { 1208 // reset last two bytes, to detect the 0x000003 sequence again. 1209 lastbytes = 0xffff; 1210 } else { 1211 rbsp->AppendElement(byte); 1212 } 1213 lastbytes = (lastbytes << 8) | byte; 1214 } 1215 return rbsp.forget(); 1216 } 1217 1218 /* static */ 1219 already_AddRefed<mozilla::MediaByteBuffer> H265::ExtractHVCCExtraData( 1220 const mozilla::MediaRawData* aSample) { 1221 size_t sampleSize = aSample->Size(); 1222 if (aSample->mCrypto.IsEncrypted()) { 1223 // The content is encrypted, we can only parse the non-encrypted data. 1224 MOZ_ASSERT(aSample->mCrypto.mPlainSizes.Length() > 0); 1225 if (aSample->mCrypto.mPlainSizes.Length() == 0 || 1226 aSample->mCrypto.mPlainSizes[0] > sampleSize) { 1227 LOG("Invalid crypto content"); 1228 return nullptr; 1229 } 1230 sampleSize = aSample->mCrypto.mPlainSizes[0]; 1231 } 1232 1233 auto hvcc = HVCCConfig::Parse(aSample); 1234 if (hvcc.isErr()) { 1235 LOG("Only support extracting extradata from HVCC"); 1236 return nullptr; 1237 } 1238 const auto nalLenSize = hvcc.unwrap().NALUSize(); 1239 BufferReader reader(aSample->Data(), sampleSize); 1240 1241 nsTHashMap<uint8_t, nsTArray<H265NALU>> nalusMap; 1242 1243 nsTArray<Maybe<H265SPS>> spsRefTable; 1244 // If we encounter SPS with the same id but different content, we will stop 1245 // attempting to detect duplicates. 1246 bool checkDuplicate = true; 1247 Maybe<uint8_t> firstSPSId; 1248 1249 RefPtr<mozilla::MediaByteBuffer> extradata = new mozilla::MediaByteBuffer; 1250 while (reader.Remaining() > nalLenSize) { 1251 // ISO/IEC 14496-15, 4.2.3.2 Syntax. (NALUSample) Reading the size of NALU. 1252 uint32_t nalLen = 0; 1253 switch (nalLenSize) { 1254 case 1: 1255 (void)reader.ReadU8().map( 1256 [&](uint8_t x) mutable { return nalLen = x; }); 1257 break; 1258 case 2: 1259 (void)reader.ReadU16().map( 1260 [&](uint16_t x) mutable { return nalLen = x; }); 1261 break; 1262 case 3: 1263 (void)reader.ReadU24().map( 1264 [&](uint32_t x) mutable { return nalLen = x; }); 1265 break; 1266 default: 1267 MOZ_DIAGNOSTIC_ASSERT(nalLenSize == 4); 1268 (void)reader.ReadU32().map( 1269 [&](uint32_t x) mutable { return nalLen = x; }); 1270 break; 1271 } 1272 const uint8_t* p = reader.Read(nalLen); 1273 if (!p) { 1274 // The read failed, but we may already have some SPS data so break out of 1275 // reading and process what we have, if any. 1276 break; 1277 } 1278 const H265NALU nalu(p, nalLen); 1279 LOGV("Found NALU, type=%u", nalu.mNalUnitType); 1280 if (nalu.IsSPS()) { 1281 auto rv = H265::DecodeSPSFromSPSNALU(nalu); 1282 if (rv.isErr()) { 1283 // Invalid SPS, ignore. 1284 LOG("Ignore invalid SPS"); 1285 continue; 1286 } 1287 const H265SPS sps = rv.unwrap(); 1288 const uint8_t spsId = sps.sps_seq_parameter_set_id; // 0~15 1289 if (spsId >= spsRefTable.Length()) { 1290 if (!spsRefTable.SetLength(spsId + 1, fallible)) { 1291 NS_WARNING("OOM while expanding spsRefTable!"); 1292 return nullptr; 1293 } 1294 } 1295 if (checkDuplicate && spsRefTable[spsId] && 1296 *(spsRefTable[spsId]) == sps) { 1297 // Duplicate ignore. 1298 continue; 1299 } 1300 if (spsRefTable[spsId]) { 1301 // We already have detected a SPS with this Id. Just to be safe we 1302 // disable SPS duplicate detection. 1303 checkDuplicate = false; 1304 } else { 1305 spsRefTable[spsId] = Some(sps); 1306 nalusMap.LookupOrInsert(nalu.mNalUnitType).AppendElement(nalu); 1307 if (!firstSPSId) { 1308 firstSPSId.emplace(spsId); 1309 } 1310 } 1311 } else if (nalu.IsVPS() || nalu.IsPPS()) { 1312 nalusMap.LookupOrInsert(nalu.mNalUnitType).AppendElement(nalu); 1313 } 1314 } 1315 1316 auto spsEntry = nalusMap.Lookup(H265NALU::SPS_NUT); 1317 auto vpsEntry = nalusMap.Lookup(H265NALU::VPS_NUT); 1318 auto ppsEntry = nalusMap.Lookup(H265NALU::PPS_NUT); 1319 1320 LOGV("Found %zu SPS NALU, %zu VPS NALU, %zu PPS NALU", 1321 spsEntry ? spsEntry.Data().Length() : 0, 1322 vpsEntry ? vpsEntry.Data().Length() : 0, 1323 ppsEntry ? ppsEntry.Data().Length() : 0); 1324 if (firstSPSId) { 1325 BitWriter writer(extradata); 1326 const H265SPS* firstSPS = spsRefTable[*firstSPSId].ptr(); 1327 MOZ_ASSERT(firstSPS); 1328 1329 // ISO/IEC 14496-15, HEVCDecoderConfigurationRecord. 1330 writer.WriteBits(1, 8); // version 1331 const auto& profile = firstSPS->profile_tier_level; 1332 writer.WriteBits(profile.general_profile_space, 2); 1333 writer.WriteBits(profile.general_tier_flag, 1); 1334 writer.WriteBits(profile.general_profile_idc, 5); 1335 writer.WriteU32(profile.general_profile_compatibility_flags); 1336 1337 // general_constraint_indicator_flags 1338 writer.WriteBit(profile.general_progressive_source_flag); 1339 writer.WriteBit(profile.general_interlaced_source_flag); 1340 writer.WriteBit(profile.general_non_packed_constraint_flag); 1341 writer.WriteBit(profile.general_frame_only_constraint_flag); 1342 writer.WriteBits(0, 44); /* ignored 44 bits */ 1343 1344 writer.WriteU8(profile.general_level_idc); 1345 writer.WriteBits(0, 4); // reserved 1346 writer.WriteBits(0, 12); // min_spatial_segmentation_idc 1347 writer.WriteBits(0, 6); // reserved 1348 writer.WriteBits(0, 2); // parallelismType 1349 writer.WriteBits(0, 6); // reserved 1350 writer.WriteBits(firstSPS->chroma_format_idc, 2); 1351 writer.WriteBits(0, 5); // reserved 1352 writer.WriteBits(firstSPS->bit_depth_luma_minus8, 3); 1353 writer.WriteBits(0, 5); // reserved 1354 writer.WriteBits(firstSPS->bit_depth_chroma_minus8, 3); 1355 // avgFrameRate + constantFrameRate + numTemporalLayers + temporalIdNested 1356 writer.WriteBits(0, 22); 1357 writer.WriteBits(nalLenSize - 1, 2); // lengthSizeMinusOne 1358 writer.WriteU8(static_cast<uint8_t>(nalusMap.Count())); // numOfArrays 1359 1360 // Append NALUs sorted by key value for easier extradata verification in 1361 // tests 1362 auto keys = ToTArray<nsTArray<uint8_t>>(nalusMap.Keys()); 1363 keys.Sort(); 1364 1365 for (const uint8_t& naluType : keys) { 1366 auto entry = nalusMap.Lookup(naluType); 1367 const auto& naluArray = entry.Data(); 1368 writer.WriteBits(0, 2); // array_completeness + reserved 1369 writer.WriteBits(naluType, 6); // NAL_unit_type 1370 writer.WriteBits(naluArray.Length(), 16); // numNalus 1371 for (const auto& nalu : naluArray) { 1372 writer.WriteBits(nalu.mNALU.Length(), 16); // nalUnitLength 1373 MOZ_ASSERT(writer.BitCount() % 8 == 0); 1374 extradata->AppendElements(nalu.mNALU.Elements(), nalu.mNALU.Length()); 1375 writer.AdvanceBytes(nalu.mNALU.Length()); 1376 } 1377 } 1378 } 1379 1380 return extradata.forget(); 1381 } 1382 1383 /* static */ 1384 bool AreTwoSPSIdentical(const H265NALU& aLhs, const H265NALU& aRhs) { 1385 MOZ_ASSERT(aLhs.IsSPS() && aRhs.IsSPS()); 1386 auto rv1 = H265::DecodeSPSFromSPSNALU(aLhs); 1387 auto rv2 = H265::DecodeSPSFromSPSNALU(aRhs); 1388 if (rv1.isErr() || rv2.isErr()) { 1389 return false; 1390 } 1391 return rv1.unwrap() == rv2.unwrap(); 1392 } 1393 1394 /* static */ 1395 bool H265::CompareExtraData(const mozilla::MediaByteBuffer* aExtraData1, 1396 const mozilla::MediaByteBuffer* aExtraData2) { 1397 if (aExtraData1 == aExtraData2) { 1398 return true; 1399 } 1400 1401 auto rv1 = HVCCConfig::Parse(aExtraData1); 1402 auto rv2 = HVCCConfig::Parse(aExtraData2); 1403 if (rv1.isErr() || rv2.isErr()) { 1404 return false; 1405 } 1406 1407 const auto config1 = rv1.unwrap(); 1408 const auto config2 = rv2.unwrap(); 1409 uint8_t numSPS = config1.NumSPS(); 1410 if (numSPS == 0 || numSPS != config2.NumSPS()) { 1411 return false; 1412 } 1413 1414 // We only compare if the SPS are the same as the various HEVC decoders can 1415 // deal with in-band change of PPS. 1416 SPSIterator it1(config1); 1417 SPSIterator it2(config2); 1418 while (it1 && it2) { 1419 const H265NALU* nalu1 = *it1; 1420 const H265NALU* nalu2 = *it2; 1421 if (!nalu1 || !nalu2) { 1422 return false; 1423 } 1424 if (!AreTwoSPSIdentical(*nalu1, *nalu2)) { 1425 return false; 1426 } 1427 ++it1; 1428 ++it2; 1429 } 1430 return true; 1431 } 1432 1433 /* static */ 1434 uint32_t H265::ComputeMaxRefFrames(const mozilla::MediaByteBuffer* aExtraData) { 1435 auto rv = DecodeSPSFromHVCCExtraData(aExtraData); 1436 if (rv.isErr()) { 1437 return 0; 1438 } 1439 return rv.unwrap().sps_max_dec_pic_buffering_minus1[0] + 1; 1440 } 1441 1442 /* static */ 1443 already_AddRefed<mozilla::MediaByteBuffer> H265::CreateFakeExtraData() { 1444 // Create fake VPS, SPS, PPS and append them into HVCC box 1445 static const uint8_t sFakeVPS[] = { 1446 0x40, 0x01, 0x0C, 0x01, 0xFF, 0xFF, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 1447 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x3F, 0x95, 0x98, 0x09}; 1448 static const uint8_t sFakeSPS[] = { 1449 0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 1450 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x3F, 0xA0, 0x05, 0x02, 0x01, 1451 0x69, 0x65, 0x95, 0x9A, 0x49, 0x32, 0xBC, 0x04, 0x04, 0x00, 0x00, 1452 0x03, 0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0x78, 0x20}; 1453 static const uint8_t sFakePPS[] = {0x44, 0x01, 0xC1, 0x72, 0xB4, 0x62, 0x40}; 1454 nsTArray<H265NALU> nalus; 1455 nalus.AppendElement(H265NALU{sFakeVPS, sizeof(sFakeVPS)}); 1456 nalus.AppendElement(H265NALU{sFakeSPS, sizeof(sFakeSPS)}); 1457 nalus.AppendElement(H265NALU{sFakePPS, sizeof(sFakePPS)}); 1458 1459 // HEVCDecoderConfigurationRecord (HVCC) is in ISO/IEC 14496-15 8.3.2.1.2 1460 const uint8_t nalLenSize = 4; 1461 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 1462 BitWriter writer(extradata); 1463 writer.WriteBits(1, 8); // version 1464 writer.WriteBits(0, 2); // general_profile_space 1465 writer.WriteBits(0, 1); // general_tier_flag 1466 writer.WriteBits(1 /* main */, 5); // general_profile_idc 1467 writer.WriteU32(0); // general_profile_compatibility_flags 1468 writer.WriteBits(0, 48); // general_constraint_indicator_flags 1469 writer.WriteU8(1 /* level 1 */); // general_level_idc 1470 writer.WriteBits(0, 4); // reserved 1471 writer.WriteBits(0, 12); // min_spatial_segmentation_idc 1472 writer.WriteBits(0, 6); // reserved 1473 writer.WriteBits(0, 2); // parallelismType 1474 writer.WriteBits(0, 6); // reserved 1475 writer.WriteBits(0, 2); // chroma_format_idc 1476 writer.WriteBits(0, 5); // reserved 1477 writer.WriteBits(0, 3); // bit_depth_luma_minus8 1478 writer.WriteBits(0, 5); // reserved 1479 writer.WriteBits(0, 3); // bit_depth_chroma_minus8 1480 writer.WriteBits(0, 22); // avgFrameRate + constantFrameRate + 1481 // numTemporalLayers + temporalIdNested 1482 writer.WriteBits(nalLenSize - 1, 2); // lengthSizeMinusOne 1483 writer.WriteU8(nalus.Length()); // numOfArrays 1484 for (auto& nalu : nalus) { 1485 writer.WriteBits(0, 2); // array_completeness + reserved 1486 writer.WriteBits(nalu.mNalUnitType, 6); // NAL_unit_type 1487 writer.WriteBits(1, 16); // numNalus 1488 writer.WriteBits(nalu.mNALU.Length(), 16); // nalUnitLength 1489 MOZ_ASSERT(writer.BitCount() % 8 == 0); 1490 extradata->AppendElements(nalu.mNALU.Elements(), nalu.mNALU.Length()); 1491 writer.AdvanceBytes(nalu.mNALU.Length()); 1492 } 1493 MOZ_ASSERT(HVCCConfig::Parse(extradata).isOk()); 1494 return extradata.forget(); 1495 } 1496 1497 /* static */ 1498 already_AddRefed<mozilla::MediaByteBuffer> H265::CreateNewExtraData( 1499 const HVCCConfig& aConfig, const nsTArray<H265NALU>& aNALUs) { 1500 // HEVCDecoderConfigurationRecord (HVCC) is in ISO/IEC 14496-15 8.3.2.1.2 1501 auto extradata = MakeRefPtr<mozilla::MediaByteBuffer>(); 1502 BitWriter writer(extradata); 1503 writer.WriteBits(aConfig.configurationVersion, 8); 1504 writer.WriteBits(aConfig.general_profile_space, 2); 1505 writer.WriteBits(aConfig.general_tier_flag, 1); 1506 writer.WriteBits(aConfig.general_profile_idc, 5); 1507 writer.WriteU32(aConfig.general_profile_compatibility_flags); 1508 writer.WriteBits(aConfig.general_constraint_indicator_flags, 48); 1509 writer.WriteU8(aConfig.general_level_idc); 1510 writer.WriteBits(0, 4); // reserved 1511 writer.WriteBits(aConfig.min_spatial_segmentation_idc, 12); 1512 writer.WriteBits(0, 6); // reserved 1513 writer.WriteBits(aConfig.parallelismType, 2); 1514 writer.WriteBits(0, 6); // reserved 1515 writer.WriteBits(aConfig.chroma_format_idc, 2); 1516 writer.WriteBits(0, 5); // reserved 1517 writer.WriteBits(aConfig.bit_depth_luma_minus8, 3); 1518 writer.WriteBits(0, 5); // reserved 1519 writer.WriteBits(aConfig.bit_depth_chroma_minus8, 3); 1520 writer.WriteBits(aConfig.avgFrameRate, 16); 1521 writer.WriteBits(aConfig.constantFrameRate, 2); 1522 writer.WriteBits(aConfig.numTemporalLayers, 3); 1523 writer.WriteBits(aConfig.temporalIdNested, 1); 1524 writer.WriteBits(aConfig.lengthSizeMinusOne, 2); 1525 writer.WriteU8(aNALUs.Length()); // numOfArrays 1526 for (auto& nalu : aNALUs) { 1527 writer.WriteBits(0, 2); // array_completeness + reserved 1528 writer.WriteBits(nalu.mNalUnitType, 6); // NAL_unit_type 1529 writer.WriteBits(1, 16); // numNalus 1530 writer.WriteBits(nalu.mNALU.Length(), 16); // nalUnitLength 1531 MOZ_ASSERT(writer.BitCount() % 8 == 0); 1532 extradata->AppendElements(nalu.mNALU.Elements(), nalu.mNALU.Length()); 1533 writer.AdvanceBytes(nalu.mNALU.Length()); 1534 } 1535 MOZ_ASSERT(HVCCConfig::Parse(extradata).isOk()); 1536 return extradata.forget(); 1537 } 1538 1539 /* static */ 1540 Result<bool, nsresult> H265::IsKeyFrame(const mozilla::MediaRawData* aSample) { 1541 if (aSample->mCrypto.IsEncrypted()) { 1542 LOG("Can't check if encrypted sample is keyframe"); 1543 return Err(NS_ERROR_DOM_MEDIA_DEMUXER_ERR); 1544 } 1545 1546 size_t sampleSize = aSample->Size(); 1547 auto hvcc = HVCCConfig::Parse(aSample); 1548 if (hvcc.isErr()) { 1549 LOG("Only support extracting extradata from HVCC"); 1550 return Err(NS_ERROR_DOM_MEDIA_DEMUXER_ERR); 1551 } 1552 const auto nalLenSize = hvcc.unwrap().NALUSize(); 1553 BufferReader reader(aSample->Data(), sampleSize); 1554 RefPtr<mozilla::MediaByteBuffer> extradata = new mozilla::MediaByteBuffer; 1555 while (reader.Remaining() > nalLenSize) { 1556 // ISO/IEC 14496-15, 4.2.3.2 Syntax. (NALUSample) Reading the size of NALU. 1557 uint32_t nalLen = 0; 1558 switch (nalLenSize) { 1559 case 1: 1560 (void)reader.ReadU8().map( 1561 [&](uint8_t x) mutable { return nalLen = x; }); 1562 break; 1563 case 2: 1564 (void)reader.ReadU16().map( 1565 [&](uint16_t x) mutable { return nalLen = x; }); 1566 break; 1567 case 3: 1568 (void)reader.ReadU24().map( 1569 [&](uint32_t x) mutable { return nalLen = x; }); 1570 break; 1571 default: 1572 MOZ_DIAGNOSTIC_ASSERT(nalLenSize == 4); 1573 (void)reader.ReadU32().map( 1574 [&](uint32_t x) mutable { return nalLen = x; }); 1575 break; 1576 } 1577 const uint8_t* p = reader.Read(nalLen); 1578 if (!p) { 1579 break; 1580 } 1581 const H265NALU nalu(p, nalLen); 1582 if (nalu.IsIframe()) { 1583 return true; 1584 } 1585 } 1586 return false; 1587 } 1588 1589 #undef LOG 1590 #undef LOGV 1591 1592 } // namespace mozilla