static decodeFrame_(frame) {
    const BufferUtils = shaka.util.BufferUtils;
    const StringUtils = shaka.util.StringUtils;

    const metadataFrame = {
      key: frame.type,
      description: '',
      data: '',
      mimeType: null,
      pictureType: null,
    };

    if (frame.type === 'APIC') {
      /*
       * Format:
       * [0]       = {Text Encoding}
       * [1 - X]   = {MIME Type}\0
       * [X+1]     = {Picture Type}
       * [X+2 - Y] = {Description}\0
       * [Y - ?]   = {Picture Data or Picture URL}
       */
      if (frame.size < 2) {
        return null;
      }
      if (frame.data[0] !== shaka.util.Id3Utils.UTF8_encoding) {
        shaka.log.warning('Ignore frame with unrecognized character ' +
            'encoding');
        return null;
      }

      const mimeTypeEndIndex = frame.data.subarray(1).indexOf(0);
      if (mimeTypeEndIndex === -1) {
        return null;
      }
      const mimeType = StringUtils.fromUTF8(
          BufferUtils.toUint8(frame.data, 1, mimeTypeEndIndex));
      const pictureType = frame.data[2 + mimeTypeEndIndex];
      const descriptionEndIndex = frame.data.subarray(3 + mimeTypeEndIndex)
          .indexOf(0);
      if (descriptionEndIndex === -1) {
        return null;
      }
      const description = StringUtils.fromUTF8(
          BufferUtils.toUint8(frame.data, 3 + mimeTypeEndIndex,
              descriptionEndIndex));
      let data;
      if (mimeType === '-->') {
        data = StringUtils.fromUTF8(
            BufferUtils.toUint8(
                frame.data, 4 + mimeTypeEndIndex + descriptionEndIndex));
      } else {
        data = BufferUtils.toArrayBuffer(
            frame.data.subarray(4 + mimeTypeEndIndex + descriptionEndIndex));
      }
      metadataFrame.mimeType = mimeType;
      metadataFrame.pictureType = pictureType;
      metadataFrame.description = description;
      metadataFrame.data = data;
      return metadataFrame;
    } else if (frame.type === 'TXXX') {
      /*
       * Format:
       * [0]   = {Text Encoding}
       * [1-?] = {Description}\0{Value}
       */
      if (frame.size < 2) {
        return null;
      }
      if (frame.data[0] !== shaka.util.Id3Utils.UTF8_encoding) {
        shaka.log.warning('Ignore frame with unrecognized character ' +
            'encoding');
        return null;
      }
      const descriptionEndIndex = frame.data.subarray(1).indexOf(0);

      if (descriptionEndIndex === -1) {
        return null;
      }
      const description = StringUtils.fromUTF8(
          BufferUtils.toUint8(frame.data, 1, descriptionEndIndex));
      const data = StringUtils.fromUTF8(
          BufferUtils.toUint8(frame.data, 2 + descriptionEndIndex))
          .replace(/\0*$/, '');

      metadataFrame.description = description;
      metadataFrame.data = data;
      return metadataFrame;
    } else if (frame.type === 'WXXX') {
      /*
       * Format:
       * [0]   = {Text Encoding}
       * [1-?] = {Description}\0{URL}
       */
      if (frame.size < 2) {
        return null;
      }
      if (frame.data[0] !== shaka.util.Id3Utils.UTF8_encoding) {
        shaka.log.warning('Ignore frame with unrecognized character ' +
            'encoding');
        return null;
      }
      const descriptionEndIndex = frame.data.subarray(1).indexOf(0);

      if (descriptionEndIndex === -1) {
        return null;
      }
      const description = StringUtils.fromUTF8(
          BufferUtils.toUint8(frame.data, 1, descriptionEndIndex));
      const data = StringUtils.fromUTF8(
          BufferUtils.toUint8(frame.data, 2 + descriptionEndIndex))
          .replace(/\0*$/, '');

      metadataFrame.description = description;
      metadataFrame.data = data;
      return metadataFrame;
    } else if (frame.type === 'PRIV') {
      /*
       * Format: <text string>\0<binary data>
       */
      if (frame.size < 2) {
        return null;
      }
      const textEndIndex = frame.data.indexOf(0);
      if (textEndIndex === -1) {
        return null;
      }
      const text = StringUtils.fromUTF8(
          BufferUtils.toUint8(frame.data, 0, textEndIndex));
      metadataFrame.description = text;
      if (text == 'com.apple.streaming.transportStreamTimestamp') {
        const data = frame.data.subarray(text.length + 1);
        // timestamp is 33 bit expressed as a big-endian eight-octet number,
        // with the upper 31 bits set to zero.
        const pts33Bit = data[3] & 0x1;
        let timestamp =
          (data[4] << 23) + (data[5] << 15) + (data[6] << 7) + data[7];
        timestamp /= 45;

        if (pts33Bit) {
          timestamp += 47721858.84;
        } // 2^32 / 90

        metadataFrame.data = timestamp;
      } else {
        const data = BufferUtils.toArrayBuffer(
            frame.data.subarray(text.length + 1));
        metadataFrame.data = data;
      }
      return metadataFrame;
    } else if (frame.type[0] === 'T') {
      /*
       * Format:
       * [0]   = {Text Encoding}
       * [1-?] = {Value}
       */
      if (frame.size < 2) {
        return null;
      }
      if (frame.data[0] !== shaka.util.Id3Utils.UTF8_encoding) {
        shaka.log.warning('Ignore frame with unrecognized character ' +
            'encoding');
        return null;
      }
      const text = StringUtils.fromUTF8(frame.data.subarray(1))
          .replace(/\0*$/, '');
      metadataFrame.data = text;
      return metadataFrame;
    } else if (frame.type[0] === 'W') {
      /*
       * Format:
       * [0-?] = {URL}
       */
      const url = StringUtils.fromUTF8(frame.data)
          .replace(/\0*$/, '');
      metadataFrame.data = url;
      return metadataFrame;
    } else if (frame.data) {
      shaka.log.warning('Unrecognized ID3 frame type:', frame.type);
      metadataFrame.data = BufferUtils.toArrayBuffer(frame.data);
      return metadataFrame;
    }

    return null;
  }
@param {shaka.extern.MetadataRawFrame} frame
@return {?shaka.extern.MetadataFrame}
@private