static parseSPS_(data) {
    const gb = new shaka.util.ExpGolomb(data, /* convertEbsp2rbsp= */ true);

    // remove NALu Header
    gb.readUnsignedByte();
    gb.readUnsignedByte();

    let leftOffset = 0;
    let rightOffset = 0;
    let topOffset = 0;
    let bottomOffset = 0;

    // SPS
    gb.readBits(4); // video_parameter_set_id
    const maxSubLayersMinus1 = gb.readBits(3);
    gb.readBoolean(); // temporal_id_nesting_flag

    // profile_tier_level begin
    const generalProfileSpace = gb.readBits(2);
    const generalTierFlag = gb.readBits(1);
    const generalProfileIdc = gb.readBits(5);
    const generalProfileCompatibilityFlags1 = gb.readUnsignedByte();
    const generalProfileCompatibilityFlags2 = gb.readUnsignedByte();
    const generalProfileCompatibilityFlags3 = gb.readUnsignedByte();
    const generalProfileCompatibilityFlags4 = gb.readUnsignedByte();
    const generalConstraintIndicatorFlags1 = gb.readUnsignedByte();
    const generalConstraintIndicatorFlags2 = gb.readUnsignedByte();
    const generalConstraintIndicatorFlags3 = gb.readUnsignedByte();
    const generalConstraintIndicatorFlags4 = gb.readUnsignedByte();
    const generalConstraintIndicatorFlags5 = gb.readUnsignedByte();
    const generalConstraintIndicatorFlags6 = gb.readUnsignedByte();
    const generalLevelIdc = gb.readUnsignedByte();
    const subLayerProfilePresentFlag = [];
    const subLayerLevelPresentFlag = [];
    for (let i = 0; i < maxSubLayersMinus1; i++) {
      subLayerProfilePresentFlag.push(gb.readBoolean());
      subLayerLevelPresentFlag.push(gb.readBoolean());
    }
    if (maxSubLayersMinus1 > 0) {
      for (let i = maxSubLayersMinus1; i < 8; i++) {
        gb.readBits(2);
      }
    }
    for (let i = 0; i < maxSubLayersMinus1; i++) {
      if (subLayerProfilePresentFlag[i]) {
        gb.readBits(88);
      }
      if (subLayerLevelPresentFlag[i]) {
        gb.readUnsignedByte();
      }
    }
    // profile_tier_level end

    gb.readUnsignedExpGolomb(); // seq_parameter_set_id
    const chromaFormatIdc = gb.readUnsignedExpGolomb();
    if (chromaFormatIdc == 3) {
      gb.readBits(1); // separate_colour_plane_flag
    }
    const picWidthInLumaSamples = gb.readUnsignedExpGolomb();
    const picHeightInLumaSamples = gb.readUnsignedExpGolomb();
    const conformanceWindowFlag = gb.readBoolean();
    if (conformanceWindowFlag) {
      leftOffset += gb.readUnsignedExpGolomb();
      rightOffset += gb.readUnsignedExpGolomb();
      topOffset += gb.readUnsignedExpGolomb();
      bottomOffset += gb.readUnsignedExpGolomb();
    }
    const bitDepthLumaMinus8 = gb.readUnsignedExpGolomb();
    const bitDepthChromaMinus8 = gb.readUnsignedExpGolomb();
    const log2MaxPicOrderCntLsbMinus4 = gb.readUnsignedExpGolomb();
    const subLayerOrderingInfoPresentFlag = gb.readBoolean();
    if (subLayerOrderingInfoPresentFlag) {
      // Skip each layer
      for (let i = 0; i <= maxSubLayersMinus1; i++) {
        gb.readUnsignedExpGolomb(); // max_dec_pic_buffering_minus1[i]
        gb.readUnsignedExpGolomb(); // max_num_reorder_pics[i]
        gb.readUnsignedExpGolomb(); // max_latency_increase_plus1[i]
      }
    } else {
      // Skip one layer
      gb.readUnsignedExpGolomb(); // max_dec_pic_buffering_minus1[i]
      gb.readUnsignedExpGolomb(); // max_num_reorder_pics[i]
      gb.readUnsignedExpGolomb(); // max_latency_increase_plus1[i]
    }
    gb.readUnsignedExpGolomb(); // log2_min_luma_coding_block_size_minus3
    gb.readUnsignedExpGolomb(); // log2_diff_max_min_luma_coding_block_size
    gb.readUnsignedExpGolomb(); // log2_min_transform_block_size_minus2
    gb.readUnsignedExpGolomb(); // log2_diff_max_min_transform_block_size
    gb.readUnsignedExpGolomb(); // max_transform_hierarchy_depth_inter
    gb.readUnsignedExpGolomb(); // max_transform_hierarchy_depth_intra
    const scalingListEnabledFlag = gb.readBoolean();
    if (scalingListEnabledFlag) {
      const spsScalingListDataPresentFlag = gb.readBoolean();
      if (spsScalingListDataPresentFlag) {
        for (let sizeId = 0; sizeId < 4; sizeId++) {
          for (
            let matrixId = 0;
            matrixId < (sizeId === 3 ? 2 : 6);
            matrixId++
          ) {
            const scalingListPredModeFlag = gb.readBoolean();
            if (!scalingListPredModeFlag) {
              gb.readUnsignedExpGolomb(); // scaling_list_pred_matrix_id_delta
            } else {
              const coefNum = Math.min(64, 1 << (4 + (sizeId << 1)));
              if (sizeId > 1) {
                gb.readExpGolomb();
              }
              for (let i = 0; i < coefNum; i++) {
                gb.readExpGolomb();
              }
            }
          }
        }
      }
    }
    gb.readBoolean(); // amp_enabled_flag
    gb.readBoolean(); // sample_adaptive_offset_enabled_flag
    const pcmEnabledFlag = gb.readBoolean();
    if (pcmEnabledFlag) {
      gb.readUnsignedByte();
      gb.readUnsignedExpGolomb();
      gb.readUnsignedExpGolomb();
      gb.readBoolean();
    }
    const numShortTermRefPicSets = gb.readUnsignedExpGolomb();
    let numDeltaPocs = 0;
    for (let i = 0; i < numShortTermRefPicSets; i++) {
      let interRefPicSetPredictionFlag = false;
      if (i !== 0) {
        interRefPicSetPredictionFlag = gb.readBoolean();
      }
      if (interRefPicSetPredictionFlag) {
        if (i === numShortTermRefPicSets) {
          gb.readUnsignedExpGolomb();
        }
        gb.readBoolean();
        gb.readUnsignedExpGolomb();
        let nextNumDeltaPocs = 0;
        for (let j = 0; j <= numDeltaPocs; j++) {
          const usedByCurrPicFlag = gb.readBoolean();
          let useDeltaFlag = false;
          if (!usedByCurrPicFlag) {
            useDeltaFlag = gb.readBoolean();
          }
          if (usedByCurrPicFlag || useDeltaFlag) {
            nextNumDeltaPocs++;
          }
        }
        numDeltaPocs = nextNumDeltaPocs;
      } else {
        const numNegativePics = gb.readUnsignedExpGolomb();
        const numPositivePics = gb.readUnsignedExpGolomb();
        numDeltaPocs = numNegativePics + numPositivePics;
        for (let j = 0; j < numNegativePics; j++) {
          gb.readUnsignedExpGolomb();
          gb.readBoolean();
        }
        for (let j = 0; j < numPositivePics; j++) {
          gb.readUnsignedExpGolomb();
          gb.readBoolean();
        }
      }
    }
    const longTermRefPicsPresentFlag = gb.readBoolean();
    if (longTermRefPicsPresentFlag) {
      const numLongTermRefPicsSps = gb.readUnsignedExpGolomb();
      for (let i = 0; i < numLongTermRefPicsSps; i++) {
        for (let j = 0; j < log2MaxPicOrderCntLsbMinus4 + 4; j++) {
          gb.readBits(1);
        }
        gb.readBits(1);
      }
    }
    let defaultDisplayWindowFlag = false; // for calc offset
    let sarWidth = 1;
    let sarHeight = 1;
    let minSpatialSegmentationIdc = 0; // for hvcC
    gb.readBoolean(); // sps_temporal_mvp_enabled_flag
    gb.readBoolean(); // strong_intra_smoothing_enabled_flag
    const vuiParametersPresentFlag = gb.readBoolean();
    if (vuiParametersPresentFlag) {
      const aspectRatioInfoPresentFlag = gb.readBoolean();
      if (aspectRatioInfoPresentFlag) {
        const aspectRatioIdc = gb.readUnsignedByte();
        const sarWidthTable = [
          1, 12, 10, 16, 40, 24, 20, 32, 80, 18, 15, 64, 160, 4, 3, 2,
        ];
        const sarHeightTable = [
          1, 11, 11, 11, 33, 11, 11, 11, 33, 11, 11, 33, 99, 3, 2, 1,
        ];
        if (aspectRatioIdc > 0 && aspectRatioIdc <= 16) {
          sarWidth = sarWidthTable[aspectRatioIdc - 1];
          sarHeight = sarHeightTable[aspectRatioIdc - 1];
        } else if (aspectRatioIdc === 255) {
          sarWidth = gb.readBits(16);
          sarHeight = gb.readBits(16);
        }
      }
      const overscanInfoPresentFlag = gb.readBoolean();
      if (overscanInfoPresentFlag) {
        gb.readBoolean();
      }
      const videoSignalTypePresentFlag = gb.readBoolean();
      if (videoSignalTypePresentFlag) {
        gb.readBits(3);
        gb.readBoolean();
        const colourDescriptionPresentFlag = gb.readBoolean();
        if (colourDescriptionPresentFlag) {
          gb.readUnsignedByte();
          gb.readUnsignedByte();
          gb.readUnsignedByte();
        }
      }
      const chromaLocInfoPresentFlag = gb.readBoolean();
      if (chromaLocInfoPresentFlag) {
        gb.readUnsignedExpGolomb();
        gb.readUnsignedExpGolomb();
      }
      gb.readBoolean(); // neutral_chroma_indication_flag
      gb.readBoolean(); // field_seq_flag
      gb.readBoolean(); // frame_field_info_present_flag
      defaultDisplayWindowFlag = gb.readBoolean();
      if (defaultDisplayWindowFlag) {
        gb.readUnsignedExpGolomb();
        gb.readUnsignedExpGolomb();
        gb.readUnsignedExpGolomb();
        gb.readUnsignedExpGolomb();
      }
      const vuiTimingInfoPresentFlag = gb.readBoolean();
      if (vuiTimingInfoPresentFlag) {
        gb.readBits(32); // fps_den
        gb.readBits(32); // fps_num
        const vuiPocProportionalToTimingFlag = gb.readBoolean();
        if (vuiPocProportionalToTimingFlag) {
          gb.readUnsignedExpGolomb();
        }
        const vuiHrdParametersPresentFlag = gb.readBoolean();
        if (vuiHrdParametersPresentFlag) {
          const commonInfPresentFlag = 1;
          let nalHrdParametersPresentFlag = false;
          let vclHrdParametersPresentFlag = false;
          let subPicHrdParamsPresentFlag = false;
          if (commonInfPresentFlag) {
            nalHrdParametersPresentFlag = gb.readBoolean();
            vclHrdParametersPresentFlag = gb.readBoolean();
            if (nalHrdParametersPresentFlag || vclHrdParametersPresentFlag) {
              subPicHrdParamsPresentFlag = gb.readBoolean();
              if (subPicHrdParamsPresentFlag) {
                gb.readUnsignedByte();
                gb.readBits(5);
                gb.readBoolean();
                gb.readBits(5);
              }
              gb.readBits(4); // bit_rate_scale
              gb.readBits(4); // cpb_size_scale
              if (subPicHrdParamsPresentFlag) {
                gb.readBits(4);
              }
              gb.readBits(5);
              gb.readBits(5);
              gb.readBits(5);
            }
          }
          for (let i = 0; i <= maxSubLayersMinus1; i++) {
            const fixedPicRateGeneralFlag = gb.readBoolean();
            let fixedPicRateWithinCvsFlag = true;
            let cpbCnt = 1;
            if (!fixedPicRateGeneralFlag) {
              fixedPicRateWithinCvsFlag = gb.readBoolean();
            }
            let lowDelayHrdFlag = false;
            if (fixedPicRateWithinCvsFlag) {
              gb.readUnsignedExpGolomb();
            } else {
              lowDelayHrdFlag = gb.readBoolean();
            }
            if (!lowDelayHrdFlag) {
              cpbCnt = gb.readUnsignedExpGolomb() + 1;
            }
            if (nalHrdParametersPresentFlag) {
              for (let j = 0; j < cpbCnt; j++) {
                gb.readUnsignedExpGolomb();
                gb.readUnsignedExpGolomb();
                if (subPicHrdParamsPresentFlag) {
                  gb.readUnsignedExpGolomb();
                  gb.readUnsignedExpGolomb();
                }
              }
              gb.readBoolean();
            }
            if (vclHrdParametersPresentFlag) {
              for (let j = 0; j < cpbCnt; j++) {
                gb.readUnsignedExpGolomb();
                gb.readUnsignedExpGolomb();
                if (subPicHrdParamsPresentFlag) {
                  gb.readUnsignedExpGolomb();
                  gb.readUnsignedExpGolomb();
                }
              }
              gb.readBoolean();
            }
          }
        }
      }
      const bitstreamRestrictionFlag = gb.readBoolean();
      if (bitstreamRestrictionFlag) {
        gb.readBoolean(); // tiles_fixed_structure_flag
        gb.readBoolean(); // motion_vectors_over_pic_boundaries_flag
        gb.readBoolean(); // restricted_ref_pic_lists_flag
        minSpatialSegmentationIdc = gb.readUnsignedExpGolomb();
        gb.readUnsignedExpGolomb(); // max_bytes_per_pic_denom
        gb.readUnsignedExpGolomb(); // max_bits_per_min_cu_denom
        gb.readUnsignedExpGolomb(); // log2_max_mv_length_horizontal
        gb.readUnsignedExpGolomb(); // log2_max_mv_length_vertical
      }
    }

    const subWc = chromaFormatIdc === 1 || chromaFormatIdc === 2 ? 2 : 1;
    const subHc = chromaFormatIdc === 1 ? 2 : 1;
    const codecWidth =
        picWidthInLumaSamples - (leftOffset + rightOffset) * subWc;
    const codecHeight =
        picHeightInLumaSamples - (topOffset + bottomOffset) * subHc;

    return {
      generalLevelIdc,
      generalProfileSpace,
      generalTierFlag,
      generalProfileIdc,
      generalProfileCompatibilityFlags1,
      generalProfileCompatibilityFlags2,
      generalProfileCompatibilityFlags3,
      generalProfileCompatibilityFlags4,
      generalConstraintIndicatorFlags1,
      generalConstraintIndicatorFlags2,
      generalConstraintIndicatorFlags3,
      generalConstraintIndicatorFlags4,
      generalConstraintIndicatorFlags5,
      generalConstraintIndicatorFlags6,
      minSpatialSegmentationIdc,
      constantFrameRate: 0, // FIXME!!!
      chromaFormatIdc,
      bitDepthLumaMinus8,
      bitDepthChromaMinus8,
      width: codecWidth,
      height: codecHeight,
      sarWidth: sarWidth,
      sarHeight: sarHeight,
    };
  }
The code is based on mpegts.js
https://github.com/xqq/mpegts.js/blob/master/src/demux/h265-parser.js#L65

@param {!Uint8Array} data
@return {shaka.transmuxer.H265.SPSConfiguration}
@private