Java Code Examples for com.google.android.exoplayer2.util.ParsableByteArray#readString()

The following examples show how to use com.google.android.exoplayer2.util.ParsableByteArray#readString() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: VorbisUtil.java    From MediaSDK with Apache License 2.0 5 votes vote down vote up
/**
 * Reads a vorbis comment header.
 *
 * @see <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3">
 *     Vorbis spec/Comment header</a>
 * @param headerData a {@link ParsableByteArray} wrapping the header data.
 * @return a {@link CommentHeader} with all the comments.
 * @throws ParserException thrown if invalid capture pattern is detected.
 */
public static CommentHeader readVorbisCommentHeader(ParsableByteArray headerData)
    throws ParserException {

  verifyVorbisHeaderCapturePattern(0x03, headerData, false);
  int length = 7;

  int len = (int) headerData.readLittleEndianUnsignedInt();
  length += 4;
  String vendor = headerData.readString(len);
  length += vendor.length();

  long commentListLen = headerData.readLittleEndianUnsignedInt();
  String[] comments = new String[(int) commentListLen];
  length += 4;
  for (int i = 0; i < commentListLen; i++) {
    len = (int) headerData.readLittleEndianUnsignedInt();
    length += 4;
    comments[i] = headerData.readString(len);
    length += comments[i].length();
  }
  if ((headerData.readUnsignedByte() & 0x01) == 0) {
    throw new ParserException("framing bit expected to be set");
  }
  length += 1;
  return new CommentHeader(vendor, comments, length);
}
 
Example 2
Source File: Tx3gDecoder.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
private static String readSubtitleText(ParsableByteArray parsableByteArray)
    throws SubtitleDecoderException {
  assertTrue(parsableByteArray.bytesLeft() >= SIZE_SHORT);
  int textLength = parsableByteArray.readUnsignedShort();
  if (textLength == 0) {
    return "";
  }
  if (parsableByteArray.bytesLeft() >= SIZE_BOM_UTF16) {
    char firstChar = parsableByteArray.peekChar();
    if (firstChar == BOM_UTF16_BE || firstChar == BOM_UTF16_LE) {
      return parsableByteArray.readString(textLength, Charset.forName(C.UTF16_NAME));
    }
  }
  return parsableByteArray.readString(textLength, Charset.forName(C.UTF8_NAME));
}
 
Example 3
Source File: FrameworkMediaDrm.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
/**
 * If the LA_URL tag is missing, injects a mock LA_URL value to avoid causing the CDM to throw
 * when creating the key request. The LA_URL attribute is optional but some Android PlayReady
 * implementations are known to require it. Does nothing it the provided {@code data} already
 * contains an LA_URL value.
 */
private static byte[] addLaUrlAttributeIfMissing(byte[] data) {
  ParsableByteArray byteArray = new ParsableByteArray(data);
  // See https://docs.microsoft.com/en-us/playready/specifications/specifications for more
  // information about the init data format.
  int length = byteArray.readLittleEndianInt();
  int objectRecordCount = byteArray.readLittleEndianShort();
  int recordType = byteArray.readLittleEndianShort();
  if (objectRecordCount != 1 || recordType != 1) {
    Log.i(TAG, "Unexpected record count or type. Skipping LA_URL workaround.");
    return data;
  }
  int recordLength = byteArray.readLittleEndianShort();
  String xml = byteArray.readString(recordLength, Charset.forName(C.UTF16LE_NAME));
  if (xml.contains("<LA_URL>")) {
    // LA_URL already present. Do nothing.
    return data;
  }
  // This PlayReady object record does not include an LA_URL. We add a mock value for it.
  int endOfDataTagIndex = xml.indexOf("</DATA>");
  if (endOfDataTagIndex == -1) {
    Log.w(TAG, "Could not find the </DATA> tag. Skipping LA_URL workaround.");
  }
  String xmlWithMockLaUrl =
      xml.substring(/* beginIndex= */ 0, /* endIndex= */ endOfDataTagIndex)
          + MOCK_LA_URL
          + xml.substring(/* beginIndex= */ endOfDataTagIndex);
  int extraBytes = MOCK_LA_URL.length() * UTF_16_BYTES_PER_CHARACTER;
  ByteBuffer newData = ByteBuffer.allocate(length + extraBytes);
  newData.order(ByteOrder.LITTLE_ENDIAN);
  newData.putInt(length + extraBytes);
  newData.putShort((short) objectRecordCount);
  newData.putShort((short) recordType);
  newData.putShort((short) (xmlWithMockLaUrl.length() * UTF_16_BYTES_PER_CHARACTER));
  newData.put(xmlWithMockLaUrl.getBytes(Charset.forName(C.UTF16LE_NAME)));
  return newData.array();
}
 
Example 4
Source File: CssParser.java    From K-Sonic with MIT License 5 votes vote down vote up
/**
 * Returns a string containing the selector. The input is expected to have the form
 * {@code ::cue(tag#id.class1.class2[voice="someone"]}, where every element is optional.
 *
 * @param input From which the selector is obtained.
 * @return A string containing the target, empty string if the selector is universal
 *     (targets all cues) or null if an error was encountered.
 */
private static String parseSelector(ParsableByteArray input, StringBuilder stringBuilder) {
  skipWhitespaceAndComments(input);
  if (input.bytesLeft() < 5) {
    return null;
  }
  String cueSelector = input.readString(5);
  if (!"::cue".equals(cueSelector)) {
    return null;
  }
  int position = input.getPosition();
  String token = parseNextToken(input, stringBuilder);
  if (token == null) {
    return null;
  }
  if (BLOCK_START.equals(token)) {
    input.setPosition(position);
    return "";
  }
  String target = null;
  if ("(".equals(token)) {
    target = readCueTarget(input);
  }
  token = parseNextToken(input, stringBuilder);
  if (!")".equals(token) || token == null) {
    return null;
  }
  return target;
}
 
Example 5
Source File: CssParser.java    From no-player with Apache License 2.0 5 votes vote down vote up
/**
 * Returns a string containing the selector. The input is expected to have the form
 * {@code ::cue(tag#id.class1.class2[voice="someone"]}, where every element is optional.
 *
 * @param input From which the selector is obtained.
 * @return A string containing the target, empty string if the selector is universal
 *     (targets all cues) or null if an error was encountered.
 */
private static String parseSelector(ParsableByteArray input, StringBuilder stringBuilder) {
  skipWhitespaceAndComments(input);
  if (input.bytesLeft() < 5) {
    return null;
  }
  String cueSelector = input.readString(5);
  if (!"::cue".equals(cueSelector)) {
    return null;
  }
  int position = input.getPosition();
  String token = parseNextToken(input, stringBuilder);
  if (token == null) {
    return null;
  }
  if (BLOCK_START.equals(token)) {
    input.setPosition(position);
    return "";
  }
  String target = null;
  if ("(".equals(token)) {
    target = readCueTarget(input);
  }
  token = parseNextToken(input, stringBuilder);
  if (!")".equals(token) || token == null) {
    return null;
  }
  return target;
}
 
Example 6
Source File: CssParser.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Returns a string containing the selector. The input is expected to have the form
 * {@code ::cue(tag#id.class1.class2[voice="someone"]}, where every element is optional.
 *
 * @param input From which the selector is obtained.
 * @return A string containing the target, empty string if the selector is universal
 *     (targets all cues) or null if an error was encountered.
 */
private static String parseSelector(ParsableByteArray input, StringBuilder stringBuilder) {
  skipWhitespaceAndComments(input);
  if (input.bytesLeft() < 5) {
    return null;
  }
  String cueSelector = input.readString(5);
  if (!"::cue".equals(cueSelector)) {
    return null;
  }
  int position = input.getPosition();
  String token = parseNextToken(input, stringBuilder);
  if (token == null) {
    return null;
  }
  if (BLOCK_START.equals(token)) {
    input.setPosition(position);
    return "";
  }
  String target = null;
  if ("(".equals(token)) {
    target = readCueTarget(input);
  }
  token = parseNextToken(input, stringBuilder);
  if (!")".equals(token) || token == null) {
    return null;
  }
  return target;
}
 
Example 7
Source File: Tx3gDecoder.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
private static String readSubtitleText(ParsableByteArray parsableByteArray)
    throws SubtitleDecoderException {
  assertTrue(parsableByteArray.bytesLeft() >= SIZE_SHORT);
  int textLength = parsableByteArray.readUnsignedShort();
  if (textLength == 0) {
    return "";
  }
  if (parsableByteArray.bytesLeft() >= SIZE_BOM_UTF16) {
    char firstChar = parsableByteArray.peekChar();
    if (firstChar == BOM_UTF16_BE || firstChar == BOM_UTF16_LE) {
      return parsableByteArray.readString(textLength, Charset.forName(C.UTF16_NAME));
    }
  }
  return parsableByteArray.readString(textLength, Charset.forName(C.UTF8_NAME));
}
 
Example 8
Source File: AtomParsers.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
static Pair<Integer, TrackEncryptionBox> parseCommonEncryptionSinfFromParent(
    ParsableByteArray parent, int position, int size) {
  int childPosition = position + Atom.HEADER_SIZE;
  int schemeInformationBoxPosition = C.POSITION_UNSET;
  int schemeInformationBoxSize = 0;
  String schemeType = null;
  Integer dataFormat = null;
  while (childPosition - position < size) {
    parent.setPosition(childPosition);
    int childAtomSize = parent.readInt();
    int childAtomType = parent.readInt();
    if (childAtomType == Atom.TYPE_frma) {
      dataFormat = parent.readInt();
    } else if (childAtomType == Atom.TYPE_schm) {
      parent.skipBytes(4);
      // Common encryption scheme_type values are defined in ISO/IEC 23001-7:2016, section 4.1.
      schemeType = parent.readString(4);
    } else if (childAtomType == Atom.TYPE_schi) {
      schemeInformationBoxPosition = childPosition;
      schemeInformationBoxSize = childAtomSize;
    }
    childPosition += childAtomSize;
  }

  if (C.CENC_TYPE_cenc.equals(schemeType) || C.CENC_TYPE_cbc1.equals(schemeType)
      || C.CENC_TYPE_cens.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType)) {
    Assertions.checkArgument(dataFormat != null, "frma atom is mandatory");
    Assertions.checkArgument(schemeInformationBoxPosition != C.POSITION_UNSET,
        "schi atom is mandatory");
    TrackEncryptionBox encryptionBox = parseSchiFromParent(parent, schemeInformationBoxPosition,
        schemeInformationBoxSize, schemeType);
    Assertions.checkArgument(encryptionBox != null, "tenc atom is mandatory");
    return Pair.create(dataFormat, encryptionBox);
  } else {
    return null;
  }
}
 
Example 9
Source File: VorbisUtil.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Reads a vorbis comment header.
 *
 * @see <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3">
 *     Vorbis spec/Comment header</a>
 * @param headerData a {@link ParsableByteArray} wrapping the header data.
 * @return a {@link VorbisUtil.CommentHeader} with all the comments.
 * @throws ParserException thrown if invalid capture pattern is detected.
 */
public static CommentHeader readVorbisCommentHeader(ParsableByteArray headerData)
    throws ParserException {

  verifyVorbisHeaderCapturePattern(0x03, headerData, false);
  int length = 7;

  int len = (int) headerData.readLittleEndianUnsignedInt();
  length += 4;
  String vendor = headerData.readString(len);
  length += vendor.length();

  long commentListLen = headerData.readLittleEndianUnsignedInt();
  String[] comments = new String[(int) commentListLen];
  length += 4;
  for (int i = 0; i < commentListLen; i++) {
    len = (int) headerData.readLittleEndianUnsignedInt();
    length += 4;
    comments[i] = headerData.readString(len);
    length += comments[i].length();
  }
  if ((headerData.readUnsignedByte() & 0x01) == 0) {
    throw new ParserException("framing bit expected to be set");
  }
  length += 1;
  return new CommentHeader(vendor, comments, length);
}
 
Example 10
Source File: AtomParsers.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
static Pair<Integer, TrackEncryptionBox> parseCommonEncryptionSinfFromParent(
    ParsableByteArray parent, int position, int size) {
  int childPosition = position + Atom.HEADER_SIZE;
  int schemeInformationBoxPosition = C.POSITION_UNSET;
  int schemeInformationBoxSize = 0;
  String schemeType = null;
  Integer dataFormat = null;
  while (childPosition - position < size) {
    parent.setPosition(childPosition);
    int childAtomSize = parent.readInt();
    int childAtomType = parent.readInt();
    if (childAtomType == Atom.TYPE_frma) {
      dataFormat = parent.readInt();
    } else if (childAtomType == Atom.TYPE_schm) {
      parent.skipBytes(4);
      // Common encryption scheme_type values are defined in ISO/IEC 23001-7:2016, section 4.1.
      schemeType = parent.readString(4);
    } else if (childAtomType == Atom.TYPE_schi) {
      schemeInformationBoxPosition = childPosition;
      schemeInformationBoxSize = childAtomSize;
    }
    childPosition += childAtomSize;
  }

  if (C.CENC_TYPE_cenc.equals(schemeType) || C.CENC_TYPE_cbc1.equals(schemeType)
      || C.CENC_TYPE_cens.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType)) {
    Assertions.checkArgument(dataFormat != null, "frma atom is mandatory");
    Assertions.checkArgument(schemeInformationBoxPosition != C.POSITION_UNSET,
        "schi atom is mandatory");
    TrackEncryptionBox encryptionBox = parseSchiFromParent(parent, schemeInformationBoxPosition,
        schemeInformationBoxSize, schemeType);
    Assertions.checkArgument(encryptionBox != null, "tenc atom is mandatory");
    return Pair.create(dataFormat, encryptionBox);
  } else {
    return null;
  }
}
 
Example 11
Source File: Tx3gDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
private static String readSubtitleText(ParsableByteArray parsableByteArray)
    throws SubtitleDecoderException {
  assertTrue(parsableByteArray.bytesLeft() >= SIZE_SHORT);
  int textLength = parsableByteArray.readUnsignedShort();
  if (textLength == 0) {
    return "";
  }
  if (parsableByteArray.bytesLeft() >= SIZE_BOM_UTF16) {
    char firstChar = parsableByteArray.peekChar();
    if (firstChar == BOM_UTF16_BE || firstChar == BOM_UTF16_LE) {
      return parsableByteArray.readString(textLength, Charset.forName(C.UTF16_NAME));
    }
  }
  return parsableByteArray.readString(textLength, Charset.forName(C.UTF8_NAME));
}
 
Example 12
Source File: AtomParsers.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
static Pair<Integer, TrackEncryptionBox> parseCommonEncryptionSinfFromParent(
    ParsableByteArray parent, int position, int size) {
  int childPosition = position + Atom.HEADER_SIZE;
  int schemeInformationBoxPosition = C.POSITION_UNSET;
  int schemeInformationBoxSize = 0;
  String schemeType = null;
  Integer dataFormat = null;
  while (childPosition - position < size) {
    parent.setPosition(childPosition);
    int childAtomSize = parent.readInt();
    int childAtomType = parent.readInt();
    if (childAtomType == Atom.TYPE_frma) {
      dataFormat = parent.readInt();
    } else if (childAtomType == Atom.TYPE_schm) {
      parent.skipBytes(4);
      // Common encryption scheme_type values are defined in ISO/IEC 23001-7:2016, section 4.1.
      schemeType = parent.readString(4);
    } else if (childAtomType == Atom.TYPE_schi) {
      schemeInformationBoxPosition = childPosition;
      schemeInformationBoxSize = childAtomSize;
    }
    childPosition += childAtomSize;
  }

  if (C.CENC_TYPE_cenc.equals(schemeType) || C.CENC_TYPE_cbc1.equals(schemeType)
      || C.CENC_TYPE_cens.equals(schemeType) || C.CENC_TYPE_cbcs.equals(schemeType)) {
    Assertions.checkArgument(dataFormat != null, "frma atom is mandatory");
    Assertions.checkArgument(schemeInformationBoxPosition != C.POSITION_UNSET,
        "schi atom is mandatory");
    TrackEncryptionBox encryptionBox = parseSchiFromParent(parent, schemeInformationBoxPosition,
        schemeInformationBoxSize, schemeType);
    Assertions.checkArgument(encryptionBox != null, "tenc atom is mandatory");
    return Pair.create(dataFormat, encryptionBox);
  } else {
    return null;
  }
}
 
Example 13
Source File: VorbisUtil.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Reads a vorbis comment header.
 *
 * @see <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3">
 *     Vorbis spec/Comment header</a>
 * @param headerData a {@link ParsableByteArray} wrapping the header data.
 * @return a {@link VorbisUtil.CommentHeader} with all the comments.
 * @throws ParserException thrown if invalid capture pattern is detected.
 */
public static CommentHeader readVorbisCommentHeader(ParsableByteArray headerData)
    throws ParserException {

  verifyVorbisHeaderCapturePattern(0x03, headerData, false);
  int length = 7;

  int len = (int) headerData.readLittleEndianUnsignedInt();
  length += 4;
  String vendor = headerData.readString(len);
  length += vendor.length();

  long commentListLen = headerData.readLittleEndianUnsignedInt();
  String[] comments = new String[(int) commentListLen];
  length += 4;
  for (int i = 0; i < commentListLen; i++) {
    len = (int) headerData.readLittleEndianUnsignedInt();
    length += 4;
    comments[i] = headerData.readString(len);
    length += comments[i].length();
  }
  if ((headerData.readUnsignedByte() & 0x01) == 0) {
    throw new ParserException("framing bit expected to be set");
  }
  length += 1;
  return new CommentHeader(vendor, comments, length);
}
 
Example 14
Source File: FrameworkMediaDrm.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
/**
 * If the LA_URL tag is missing, injects a mock LA_URL value to avoid causing the CDM to throw
 * when creating the key request. The LA_URL attribute is optional but some Android PlayReady
 * implementations are known to require it. Does nothing it the provided {@code data} already
 * contains an LA_URL value.
 */
private static byte[] addLaUrlAttributeIfMissing(byte[] data) {
  ParsableByteArray byteArray = new ParsableByteArray(data);
  // See https://docs.microsoft.com/en-us/playready/specifications/specifications for more
  // information about the init data format.
  int length = byteArray.readLittleEndianInt();
  int objectRecordCount = byteArray.readLittleEndianShort();
  int recordType = byteArray.readLittleEndianShort();
  if (objectRecordCount != 1 || recordType != 1) {
    Log.i(TAG, "Unexpected record count or type. Skipping LA_URL workaround.");
    return data;
  }
  int recordLength = byteArray.readLittleEndianShort();
  String xml = byteArray.readString(recordLength, Charset.forName(C.UTF16LE_NAME));
  if (xml.contains("<LA_URL>")) {
    // LA_URL already present. Do nothing.
    return data;
  }
  // This PlayReady object record does not include an LA_URL. We add a mock value for it.
  int endOfDataTagIndex = xml.indexOf("</DATA>");
  if (endOfDataTagIndex == -1) {
    Log.w(TAG, "Could not find the </DATA> tag. Skipping LA_URL workaround.");
  }
  String xmlWithMockLaUrl =
      xml.substring(/* beginIndex= */ 0, /* endIndex= */ endOfDataTagIndex)
          + MOCK_LA_URL
          + xml.substring(/* beginIndex= */ endOfDataTagIndex);
  int extraBytes = MOCK_LA_URL.length() * UTF_16_BYTES_PER_CHARACTER;
  ByteBuffer newData = ByteBuffer.allocate(length + extraBytes);
  newData.order(ByteOrder.LITTLE_ENDIAN);
  newData.putInt(length + extraBytes);
  newData.putShort((short) objectRecordCount);
  newData.putShort((short) recordType);
  newData.putShort((short) (xmlWithMockLaUrl.length() * UTF_16_BYTES_PER_CHARACTER));
  newData.put(xmlWithMockLaUrl.getBytes(Charset.forName(C.UTF16LE_NAME)));
  return newData.array();
}
 
Example 15
Source File: Tx3gDecoder.java    From MediaSDK with Apache License 2.0 5 votes vote down vote up
private static String readSubtitleText(ParsableByteArray parsableByteArray)
    throws SubtitleDecoderException {
  assertTrue(parsableByteArray.bytesLeft() >= SIZE_SHORT);
  int textLength = parsableByteArray.readUnsignedShort();
  if (textLength == 0) {
    return "";
  }
  if (parsableByteArray.bytesLeft() >= SIZE_BOM_UTF16) {
    char firstChar = parsableByteArray.peekChar();
    if (firstChar == BOM_UTF16_BE || firstChar == BOM_UTF16_LE) {
      return parsableByteArray.readString(textLength, Charset.forName(C.UTF16_NAME));
    }
  }
  return parsableByteArray.readString(textLength, Charset.forName(C.UTF8_NAME));
}
 
Example 16
Source File: CssParser.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Returns a string containing the selector. The input is expected to have the form
 * {@code ::cue(tag#id.class1.class2[voice="someone"]}, where every element is optional.
 *
 * @param input From which the selector is obtained.
 * @return A string containing the target, empty string if the selector is universal
 *     (targets all cues) or null if an error was encountered.
 */
private static String parseSelector(ParsableByteArray input, StringBuilder stringBuilder) {
  skipWhitespaceAndComments(input);
  if (input.bytesLeft() < 5) {
    return null;
  }
  String cueSelector = input.readString(5);
  if (!"::cue".equals(cueSelector)) {
    return null;
  }
  int position = input.getPosition();
  String token = parseNextToken(input, stringBuilder);
  if (token == null) {
    return null;
  }
  if (RULE_START.equals(token)) {
    input.setPosition(position);
    return "";
  }
  String target = null;
  if ("(".equals(token)) {
    target = readCueTarget(input);
  }
  token = parseNextToken(input, stringBuilder);
  if (!")".equals(token) || token == null) {
    return null;
  }
  return target;
}
 
Example 17
Source File: VorbisUtil.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Reads a vorbis comment header.
 *
 * @see <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-640004.2.3">
 *     Vorbis spec/Comment header</a>
 * @param headerData a {@link ParsableByteArray} wrapping the header data.
 * @return a {@link VorbisUtil.CommentHeader} with all the comments.
 * @throws ParserException thrown if invalid capture pattern is detected.
 */
public static CommentHeader readVorbisCommentHeader(ParsableByteArray headerData)
    throws ParserException {

  verifyVorbisHeaderCapturePattern(0x03, headerData, false);
  int length = 7;

  int len = (int) headerData.readLittleEndianUnsignedInt();
  length += 4;
  String vendor = headerData.readString(len);
  length += vendor.length();

  long commentListLen = headerData.readLittleEndianUnsignedInt();
  String[] comments = new String[(int) commentListLen];
  length += 4;
  for (int i = 0; i < commentListLen; i++) {
    len = (int) headerData.readLittleEndianUnsignedInt();
    length += 4;
    comments[i] = headerData.readString(len);
    length += comments[i].length();
  }
  if ((headerData.readUnsignedByte() & 0x01) == 0) {
    throw new ParserException("framing bit expected to be set");
  }
  length += 1;
  return new CommentHeader(vendor, comments, length);
}
 
Example 18
Source File: AtomParsers.java    From Telegram with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Parses a metadata meta atom if it contains metadata with handler 'mdta'.
 *
 * @param meta The metadata atom to decode.
 * @return Parsed metadata, or null.
 */
@Nullable
public static Metadata parseMdtaFromMeta(Atom.ContainerAtom meta) {
  Atom.LeafAtom hdlrAtom = meta.getLeafAtomOfType(Atom.TYPE_hdlr);
  Atom.LeafAtom keysAtom = meta.getLeafAtomOfType(Atom.TYPE_keys);
  Atom.LeafAtom ilstAtom = meta.getLeafAtomOfType(Atom.TYPE_ilst);
  if (hdlrAtom == null
      || keysAtom == null
      || ilstAtom == null
      || AtomParsers.parseHdlr(hdlrAtom.data) != TYPE_mdta) {
    // There isn't enough information to parse the metadata, or the handler type is unexpected.
    return null;
  }

  // Parse metadata keys.
  ParsableByteArray keys = keysAtom.data;
  keys.setPosition(Atom.FULL_HEADER_SIZE);
  int entryCount = keys.readInt();
  String[] keyNames = new String[entryCount];
  for (int i = 0; i < entryCount; i++) {
    int entrySize = keys.readInt();
    keys.skipBytes(4); // keyNamespace
    int keySize = entrySize - 8;
    keyNames[i] = keys.readString(keySize);
  }

  // Parse metadata items.
  ParsableByteArray ilst = ilstAtom.data;
  ilst.setPosition(Atom.HEADER_SIZE);
  ArrayList<Metadata.Entry> entries = new ArrayList<>();
  while (ilst.bytesLeft() > Atom.HEADER_SIZE) {
    int atomPosition = ilst.getPosition();
    int atomSize = ilst.readInt();
    int keyIndex = ilst.readInt() - 1;
    if (keyIndex >= 0 && keyIndex < keyNames.length) {
      String key = keyNames[keyIndex];
      Metadata.Entry entry =
          MetadataUtil.parseMdtaMetadataEntryFromIlst(ilst, atomPosition + atomSize, key);
      if (entry != null) {
        entries.add(entry);
      }
    } else {
      Log.w(TAG, "Skipped metadata with unknown key index: " + keyIndex);
    }
    ilst.setPosition(atomPosition + atomSize);
  }
  return entries.isEmpty() ? null : new Metadata(entries);
}
 
Example 19
Source File: AtomParsers.java    From MediaSDK with Apache License 2.0 4 votes vote down vote up
/**
 * Parses a metadata meta atom if it contains metadata with handler 'mdta'.
 *
 * @param meta The metadata atom to decode.
 * @return Parsed metadata, or null.
 */
@Nullable
public static Metadata parseMdtaFromMeta(Atom.ContainerAtom meta) {
  Atom.LeafAtom hdlrAtom = meta.getLeafAtomOfType(Atom.TYPE_hdlr);
  Atom.LeafAtom keysAtom = meta.getLeafAtomOfType(Atom.TYPE_keys);
  Atom.LeafAtom ilstAtom = meta.getLeafAtomOfType(Atom.TYPE_ilst);
  if (hdlrAtom == null
      || keysAtom == null
      || ilstAtom == null
      || AtomParsers.parseHdlr(hdlrAtom.data) != TYPE_mdta) {
    // There isn't enough information to parse the metadata, or the handler type is unexpected.
    return null;
  }

  // Parse metadata keys.
  ParsableByteArray keys = keysAtom.data;
  keys.setPosition(Atom.FULL_HEADER_SIZE);
  int entryCount = keys.readInt();
  String[] keyNames = new String[entryCount];
  for (int i = 0; i < entryCount; i++) {
    int entrySize = keys.readInt();
    keys.skipBytes(4); // keyNamespace
    int keySize = entrySize - 8;
    keyNames[i] = keys.readString(keySize);
  }

  // Parse metadata items.
  ParsableByteArray ilst = ilstAtom.data;
  ilst.setPosition(Atom.HEADER_SIZE);
  ArrayList<Metadata.Entry> entries = new ArrayList<>();
  while (ilst.bytesLeft() > Atom.HEADER_SIZE) {
    int atomPosition = ilst.getPosition();
    int atomSize = ilst.readInt();
    int keyIndex = ilst.readInt() - 1;
    if (keyIndex >= 0 && keyIndex < keyNames.length) {
      String key = keyNames[keyIndex];
      Metadata.Entry entry =
          MetadataUtil.parseMdtaMetadataEntryFromIlst(ilst, atomPosition + atomSize, key);
      if (entry != null) {
        entries.add(entry);
      }
    } else {
      Log.w(TAG, "Skipped metadata with unknown key index: " + keyIndex);
    }
    ilst.setPosition(atomPosition + atomSize);
  }
  return entries.isEmpty() ? null : new Metadata(entries);
}
 
Example 20
Source File: AtomParsers.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Parses a metadata meta atom if it contains metadata with handler 'mdta'.
 *
 * @param meta The metadata atom to decode.
 * @return Parsed metadata, or null.
 */
@Nullable
public static Metadata parseMdtaFromMeta(Atom.ContainerAtom meta) {
  Atom.LeafAtom hdlrAtom = meta.getLeafAtomOfType(Atom.TYPE_hdlr);
  Atom.LeafAtom keysAtom = meta.getLeafAtomOfType(Atom.TYPE_keys);
  Atom.LeafAtom ilstAtom = meta.getLeafAtomOfType(Atom.TYPE_ilst);
  if (hdlrAtom == null
      || keysAtom == null
      || ilstAtom == null
      || AtomParsers.parseHdlr(hdlrAtom.data) != TYPE_mdta) {
    // There isn't enough information to parse the metadata, or the handler type is unexpected.
    return null;
  }

  // Parse metadata keys.
  ParsableByteArray keys = keysAtom.data;
  keys.setPosition(Atom.FULL_HEADER_SIZE);
  int entryCount = keys.readInt();
  String[] keyNames = new String[entryCount];
  for (int i = 0; i < entryCount; i++) {
    int entrySize = keys.readInt();
    keys.skipBytes(4); // keyNamespace
    int keySize = entrySize - 8;
    keyNames[i] = keys.readString(keySize);
  }

  // Parse metadata items.
  ParsableByteArray ilst = ilstAtom.data;
  ilst.setPosition(Atom.HEADER_SIZE);
  ArrayList<Metadata.Entry> entries = new ArrayList<>();
  while (ilst.bytesLeft() > Atom.HEADER_SIZE) {
    int atomPosition = ilst.getPosition();
    int atomSize = ilst.readInt();
    int keyIndex = ilst.readInt() - 1;
    if (keyIndex >= 0 && keyIndex < keyNames.length) {
      String key = keyNames[keyIndex];
      Metadata.Entry entry =
          MetadataUtil.parseMdtaMetadataEntryFromIlst(ilst, atomPosition + atomSize, key);
      if (entry != null) {
        entries.add(entry);
      }
    } else {
      Log.w(TAG, "Skipped metadata with unknown key index: " + keyIndex);
    }
    ilst.setPosition(atomPosition + atomSize);
  }
  return entries.isEmpty() ? null : new Metadata(entries);
}