parsePES_(data) {
    const startPrefix = (data[0] << 16) | (data[1] << 8) | data[2];
    // In certain live streams, the start of a TS fragment has ts packets
    // that are frame data that is continuing from the previous fragment. This
    // is to check that the pes data is the start of a new pes data
    if (startPrefix !== 1) {
      return null;
    }
    /** @type {shaka.extern.MPEG_PES} */
    const pes = {
      data: new Uint8Array(0),
      // get the packet length, this will be 0 for video
      packetLength: ((data[4] << 8) | data[5]),
      pts: null,
      dts: null,
      nalus: [],
    };

    // if PES parsed length is not zero and greater than total received length,
    // stop parsing. PES might be truncated. minus 6 : PES header size
    if (pes.packetLength && pes.packetLength > data.byteLength - 6) {
      return null;
    }

    // PES packets may be annotated with a PTS value, or a PTS value
    // and a DTS value. Determine what combination of values is
    // available to work with.
    const ptsDtsFlags = data[7];

    // PTS and DTS are normally stored as a 33-bit number.  Javascript
    // performs all bitwise operations on 32-bit integers but javascript
    // supports a much greater range (52-bits) of integer using standard
    // mathematical operations.
    // We construct a 31-bit value using bitwise operators over the 31
    // most significant bits and then multiply by 4 (equal to a left-shift
    // of 2) before we add the final 2 least significant bits of the
    // timestamp (equal to an OR.)
    if (ptsDtsFlags & 0xC0) {
      // the PTS and DTS are not written out directly. For information
      // on how they are encoded, see
      // http://dvd.sourceforge.net/dvdinfo/pes-hdr.html
      const pts =
        (data[9] & 0x0e) * 536870912 + // 1 << 29
        (data[10] & 0xff) * 4194304 + // 1 << 22
        (data[11] & 0xfe) * 16384 + // 1 << 14
        (data[12] & 0xff) * 128 + // 1 << 7
        (data[13] & 0xfe) / 2;

      if (this.referencePts_ == null) {
        this.referencePts_ = pts;
      }

      pes.pts = this.handleRollover_(pts, this.referencePts_);
      this.referencePts_ = pes.pts;

      pes.dts = pes.pts;
      if (ptsDtsFlags & 0x40) {
        const dts =
          (data[14] & 0x0e) * 536870912 + // 1 << 29
          (data[15] & 0xff) * 4194304 + // 1 << 22
          (data[16] & 0xfe) * 16384 + // 1 << 14
          (data[17] & 0xff) * 128 + // 1 << 7
          (data[18] & 0xfe) / 2;

        if (this.referenceDts_ == null) {
          this.referenceDts_ = dts;
        }

        if (pes.pts != pts) {
          pes.dts = this.handleRollover_(dts, this.referenceDts_);
        } else {
          pes.dts = dts;
        }
      }
      this.referenceDts_ = pes.dts;
    }

    const pesHdrLen = data[8];
    // 9 bytes : 6 bytes for PES header + 3 bytes for PES extension
    const payloadStartOffset = pesHdrLen + 9;
    if (data.byteLength <= payloadStartOffset) {
      return null;
    }

    pes.data = data.subarray(payloadStartOffset);

    return pes;
  }
Parse PES

@param {Uint8Array} data
@return {?shaka.extern.MPEG_PES}
@private