tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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