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

The following examples show how to use com.google.android.exoplayer2.util.ParsableByteArray#readUnsignedIntToInt() . 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: FragmentedMp4Extractor.java    From K-Sonic with MIT License 6 votes vote down vote up
/**
 * Parses a saio atom (defined in 14496-12).
 *
 * @param saio The saio atom to decode.
 * @param out The {@link TrackFragment} to populate with data from the saio atom.
 */
private static void parseSaio(ParsableByteArray saio, TrackFragment out) throws ParserException {
  saio.setPosition(Atom.HEADER_SIZE);
  int fullAtom = saio.readInt();
  int flags = Atom.parseFullAtomFlags(fullAtom);
  if ((flags & 0x01) == 1) {
    saio.skipBytes(8);
  }

  int entryCount = saio.readUnsignedIntToInt();
  if (entryCount != 1) {
    // We only support one trun element currently, so always expect one entry.
    throw new ParserException("Unexpected saio entry count: " + entryCount);
  }

  int version = Atom.parseFullAtomVersion(fullAtom);
  out.auxiliaryDataPosition +=
      version == 0 ? saio.readUnsignedInt() : saio.readUnsignedLongToLong();
}
 
Example 2
Source File: FragmentedMp4Extractor.java    From K-Sonic with MIT License 6 votes vote down vote up
private static void parseSenc(ParsableByteArray senc, int offset, TrackFragment out)
    throws ParserException {
  senc.setPosition(Atom.HEADER_SIZE + offset);
  int fullAtom = senc.readInt();
  int flags = Atom.parseFullAtomFlags(fullAtom);

  if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) {
    // TODO: Implement this.
    throw new ParserException("Overriding TrackEncryptionBox parameters is unsupported.");
  }

  boolean subsampleEncryption = (flags & 0x02 /* use_subsample_encryption */) != 0;
  int sampleCount = senc.readUnsignedIntToInt();
  if (sampleCount != out.sampleCount) {
    throw new ParserException("Length mismatch: " + sampleCount + ", " + out.sampleCount);
  }

  Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption);
  out.initEncryptionData(senc.bytesLeft());
  out.fillEncryptionData(senc);
}
 
Example 3
Source File: FragmentedMp4Extractor.java    From Telegram-FOSS with GNU General Public License v2.0 6 votes vote down vote up
private static void parseSenc(ParsableByteArray senc, int offset, TrackFragment out)
    throws ParserException {
  senc.setPosition(Atom.HEADER_SIZE + offset);
  int fullAtom = senc.readInt();
  int flags = Atom.parseFullAtomFlags(fullAtom);

  if ((flags & 0x01 /* override_track_encryption_box_parameters */) != 0) {
    // TODO: Implement this.
    throw new ParserException("Overriding TrackEncryptionBox parameters is unsupported.");
  }

  boolean subsampleEncryption = (flags & 0x02 /* use_subsample_encryption */) != 0;
  int sampleCount = senc.readUnsignedIntToInt();
  if (sampleCount != out.sampleCount) {
    throw new ParserException("Length mismatch: " + sampleCount + ", " + out.sampleCount);
  }

  Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption);
  out.initEncryptionData(senc.bytesLeft());
  out.fillEncryptionData(senc);
}
 
Example 4
Source File: AtomParsers.java    From TelePlus-Android with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Parses the edts atom (defined in 14496-12 subsection 8.6.5).
 *
 * @param edtsAtom edts (edit box) atom to decode.
 * @return Pair of edit list durations and edit list media times, or a pair of nulls if they are
 *     not present.
 */
private static Pair<long[], long[]> parseEdts(Atom.ContainerAtom edtsAtom) {
  Atom.LeafAtom elst;
  if (edtsAtom == null || (elst = edtsAtom.getLeafAtomOfType(Atom.TYPE_elst)) == null) {
    return Pair.create(null, null);
  }
  ParsableByteArray elstData = elst.data;
  elstData.setPosition(Atom.HEADER_SIZE);
  int fullAtom = elstData.readInt();
  int version = Atom.parseFullAtomVersion(fullAtom);
  int entryCount = elstData.readUnsignedIntToInt();
  long[] editListDurations = new long[entryCount];
  long[] editListMediaTimes = new long[entryCount];
  for (int i = 0; i < entryCount; i++) {
    editListDurations[i] =
        version == 1 ? elstData.readUnsignedLongToLong() : elstData.readUnsignedInt();
    editListMediaTimes[i] = version == 1 ? elstData.readLong() : elstData.readInt();
    int mediaRateInteger = elstData.readShort();
    if (mediaRateInteger != 1) {
      // The extractor does not handle dwell edits (mediaRateInteger == 0).
      throw new IllegalArgumentException("Unsupported media rate.");
    }
    elstData.skipBytes(2);
  }
  return Pair.create(editListDurations, editListMediaTimes);
}
 
Example 5
Source File: FragmentedMp4Extractor.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
private static void parseSaiz(TrackEncryptionBox encryptionBox, ParsableByteArray saiz,
    TrackFragment out) throws ParserException {
  int vectorSize = encryptionBox.perSampleIvSize;
  saiz.setPosition(Atom.HEADER_SIZE);
  int fullAtom = saiz.readInt();
  int flags = Atom.parseFullAtomFlags(fullAtom);
  if ((flags & 0x01) == 1) {
    saiz.skipBytes(8);
  }
  int defaultSampleInfoSize = saiz.readUnsignedByte();

  int sampleCount = saiz.readUnsignedIntToInt();
  if (sampleCount != out.sampleCount) {
    throw new ParserException("Length mismatch: " + sampleCount + ", " + out.sampleCount);
  }

  int totalSize = 0;
  if (defaultSampleInfoSize == 0) {
    boolean[] sampleHasSubsampleEncryptionTable = out.sampleHasSubsampleEncryptionTable;
    for (int i = 0; i < sampleCount; i++) {
      int sampleInfoSize = saiz.readUnsignedByte();
      totalSize += sampleInfoSize;
      sampleHasSubsampleEncryptionTable[i] = sampleInfoSize > vectorSize;
    }
  } else {
    boolean subsampleEncryption = defaultSampleInfoSize > vectorSize;
    totalSize += defaultSampleInfoSize * sampleCount;
    Arrays.fill(out.sampleHasSubsampleEncryptionTable, 0, sampleCount, subsampleEncryption);
  }
  out.initEncryptionData(totalSize);
}
 
Example 6
Source File: FragmentedMp4Extractor.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Parses a trex atom (defined in 14496-12).
 */
private static Pair<Integer, DefaultSampleValues> parseTrex(ParsableByteArray trex) {
  trex.setPosition(Atom.FULL_HEADER_SIZE);
  int trackId = trex.readInt();
  int defaultSampleDescriptionIndex = trex.readUnsignedIntToInt() - 1;
  int defaultSampleDuration = trex.readUnsignedIntToInt();
  int defaultSampleSize = trex.readUnsignedIntToInt();
  int defaultSampleFlags = trex.readInt();

  return Pair.create(trackId, new DefaultSampleValues(defaultSampleDescriptionIndex,
      defaultSampleDuration, defaultSampleSize, defaultSampleFlags));
}
 
Example 7
Source File: FragmentedMp4Extractor.java    From K-Sonic with MIT License 5 votes vote down vote up
private static void parseTruns(ContainerAtom traf, TrackBundle trackBundle, long decodeTime,
    @Flags int flags) {
  int trunCount = 0;
  int totalSampleCount = 0;
  List<LeafAtom> leafChildren = traf.leafChildren;
  int leafChildrenSize = leafChildren.size();
  for (int i = 0; i < leafChildrenSize; i++) {
    LeafAtom atom = leafChildren.get(i);
    if (atom.type == Atom.TYPE_trun) {
      ParsableByteArray trunData = atom.data;
      trunData.setPosition(Atom.FULL_HEADER_SIZE);
      int trunSampleCount = trunData.readUnsignedIntToInt();
      if (trunSampleCount > 0) {
        totalSampleCount += trunSampleCount;
        trunCount++;
      }
    }
  }
  trackBundle.currentTrackRunIndex = 0;
  trackBundle.currentSampleInTrackRun = 0;
  trackBundle.currentSampleIndex = 0;
  trackBundle.fragment.initTables(trunCount, totalSampleCount);

  int trunIndex = 0;
  int trunStartPosition = 0;
  for (int i = 0; i < leafChildrenSize; i++) {
    LeafAtom trun = leafChildren.get(i);
    if (trun.type == Atom.TYPE_trun) {
      trunStartPosition = parseTrun(trackBundle, trunIndex++, decodeTime, flags, trun.data,
          trunStartPosition);
    }
  }
}
 
Example 8
Source File: FragmentedMp4Extractor.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Parses a trex atom (defined in 14496-12).
 */
private static Pair<Integer, DefaultSampleValues> parseTrex(ParsableByteArray trex) {
  trex.setPosition(Atom.FULL_HEADER_SIZE);
  int trackId = trex.readInt();
  int defaultSampleDescriptionIndex = trex.readUnsignedIntToInt() - 1;
  int defaultSampleDuration = trex.readUnsignedIntToInt();
  int defaultSampleSize = trex.readUnsignedIntToInt();
  int defaultSampleFlags = trex.readInt();

  return Pair.create(trackId, new DefaultSampleValues(defaultSampleDescriptionIndex,
      defaultSampleDuration, defaultSampleSize, defaultSampleFlags));
}
 
Example 9
Source File: FfmpegDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
@Override
protected @Nullable FfmpegDecoderException decode(
    DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) {
  if (reset) {
    nativeContext = ffmpegReset(nativeContext, extraData);
    if (nativeContext == 0) {
      return new FfmpegDecoderException("Error resetting (see logcat).");
    }
  }
  ByteBuffer inputData = inputBuffer.data;
  int inputSize = inputData.limit();
  ByteBuffer outputData = outputBuffer.init(inputBuffer.timeUs, outputBufferSize);
  int result = ffmpegDecode(nativeContext, inputData, inputSize, outputData, outputBufferSize);
  if (result < 0) {
    return new FfmpegDecoderException("Error decoding (see logcat). Code: " + result);
  }
  if (!hasOutputFormat) {
    channelCount = ffmpegGetChannelCount(nativeContext);
    sampleRate = ffmpegGetSampleRate(nativeContext);
    if (sampleRate == 0 && "alac".equals(codecName)) {
      Assertions.checkNotNull(extraData);
      // ALAC decoder did not set the sample rate in earlier versions of FFMPEG.
      // See https://trac.ffmpeg.org/ticket/6096
      ParsableByteArray parsableExtraData = new ParsableByteArray(extraData);
      parsableExtraData.setPosition(extraData.length - 4);
      sampleRate = parsableExtraData.readUnsignedIntToInt();
    }
    hasOutputFormat = true;
  }
  outputBuffer.data.position(0);
  outputBuffer.data.limit(result);
  return null;
}
 
Example 10
Source File: FragmentedMp4Extractor.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Parses a tfhd atom (defined in 14496-12), updates the corresponding {@link TrackFragment} and
 * returns the {@link TrackBundle} of the corresponding {@link Track}. If the tfhd does not refer
 * to any {@link TrackBundle}, {@code null} is returned and no changes are made.
 *
 * @param tfhd The tfhd atom to decode.
 * @param trackBundles The track bundles, one of which corresponds to the tfhd atom being parsed.
 * @return The {@link TrackBundle} to which the {@link TrackFragment} belongs, or null if the tfhd
 *     does not refer to any {@link TrackBundle}.
 */
private static TrackBundle parseTfhd(
    ParsableByteArray tfhd, SparseArray<TrackBundle> trackBundles) {
  tfhd.setPosition(Atom.HEADER_SIZE);
  int fullAtom = tfhd.readInt();
  int atomFlags = Atom.parseFullAtomFlags(fullAtom);
  int trackId = tfhd.readInt();
  TrackBundle trackBundle = getTrackBundle(trackBundles, trackId);
  if (trackBundle == null) {
    return null;
  }
  if ((atomFlags & 0x01 /* base_data_offset_present */) != 0) {
    long baseDataPosition = tfhd.readUnsignedLongToLong();
    trackBundle.fragment.dataPosition = baseDataPosition;
    trackBundle.fragment.auxiliaryDataPosition = baseDataPosition;
  }

  DefaultSampleValues defaultSampleValues = trackBundle.defaultSampleValues;
  int defaultSampleDescriptionIndex =
      ((atomFlags & 0x02 /* default_sample_description_index_present */) != 0)
          ? tfhd.readUnsignedIntToInt() - 1 : defaultSampleValues.sampleDescriptionIndex;
  int defaultSampleDuration = ((atomFlags & 0x08 /* default_sample_duration_present */) != 0)
      ? tfhd.readUnsignedIntToInt() : defaultSampleValues.duration;
  int defaultSampleSize = ((atomFlags & 0x10 /* default_sample_size_present */) != 0)
      ? tfhd.readUnsignedIntToInt() : defaultSampleValues.size;
  int defaultSampleFlags = ((atomFlags & 0x20 /* default_sample_flags_present */) != 0)
      ? tfhd.readUnsignedIntToInt() : defaultSampleValues.flags;
  trackBundle.fragment.header = new DefaultSampleValues(defaultSampleDescriptionIndex,
      defaultSampleDuration, defaultSampleSize, defaultSampleFlags);
  return trackBundle;
}
 
Example 11
Source File: AtomParsers.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
public ChunkIterator(ParsableByteArray stsc, ParsableByteArray chunkOffsets,
    boolean chunkOffsetsAreLongs) {
  this.stsc = stsc;
  this.chunkOffsets = chunkOffsets;
  this.chunkOffsetsAreLongs = chunkOffsetsAreLongs;
  chunkOffsets.setPosition(Atom.FULL_HEADER_SIZE);
  length = chunkOffsets.readUnsignedIntToInt();
  stsc.setPosition(Atom.FULL_HEADER_SIZE);
  remainingSamplesPerChunkChanges = stsc.readUnsignedIntToInt();
  Assertions.checkState(stsc.readInt() == 1, "first_chunk must be 1");
  index = -1;
}
 
Example 12
Source File: FfmpegDecoder.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
@Override
protected @Nullable FfmpegDecoderException decode(
    DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) {
  if (reset) {
    nativeContext = ffmpegReset(nativeContext, extraData);
    if (nativeContext == 0) {
      return new FfmpegDecoderException("Error resetting (see logcat).");
    }
  }
  ByteBuffer inputData = inputBuffer.data;
  int inputSize = inputData.limit();
  ByteBuffer outputData = outputBuffer.init(inputBuffer.timeUs, outputBufferSize);
  int result = ffmpegDecode(nativeContext, inputData, inputSize, outputData, outputBufferSize);
  if (result == DECODER_ERROR_INVALID_DATA) {
    // Treat invalid data errors as non-fatal to match the behavior of MediaCodec. No output will
    // be produced for this buffer, so mark it as decode-only to ensure that the audio sink's
    // position is reset when more audio is produced.
    outputBuffer.setFlags(C.BUFFER_FLAG_DECODE_ONLY);
    return null;
  } else if (result == DECODER_ERROR_OTHER) {
    return new FfmpegDecoderException("Error decoding (see logcat).");
  }
  if (!hasOutputFormat) {
    channelCount = ffmpegGetChannelCount(nativeContext);
    sampleRate = ffmpegGetSampleRate(nativeContext);
    if (sampleRate == 0 && "alac".equals(codecName)) {
      Assertions.checkNotNull(extraData);
      // ALAC decoder did not set the sample rate in earlier versions of FFMPEG.
      // See https://trac.ffmpeg.org/ticket/6096
      ParsableByteArray parsableExtraData = new ParsableByteArray(extraData);
      parsableExtraData.setPosition(extraData.length - 4);
      sampleRate = parsableExtraData.readUnsignedIntToInt();
    }
    hasOutputFormat = true;
  }
  outputBuffer.data.position(0);
  outputBuffer.data.limit(result);
  return null;
}
 
Example 13
Source File: FragmentedMp4Extractor.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
private static void parseTruns(ContainerAtom traf, TrackBundle trackBundle, long decodeTime,
    @Flags int flags) {
  int trunCount = 0;
  int totalSampleCount = 0;
  List<LeafAtom> leafChildren = traf.leafChildren;
  int leafChildrenSize = leafChildren.size();
  for (int i = 0; i < leafChildrenSize; i++) {
    LeafAtom atom = leafChildren.get(i);
    if (atom.type == Atom.TYPE_trun) {
      ParsableByteArray trunData = atom.data;
      trunData.setPosition(Atom.FULL_HEADER_SIZE);
      int trunSampleCount = trunData.readUnsignedIntToInt();
      if (trunSampleCount > 0) {
        totalSampleCount += trunSampleCount;
        trunCount++;
      }
    }
  }
  trackBundle.currentTrackRunIndex = 0;
  trackBundle.currentSampleInTrackRun = 0;
  trackBundle.currentSampleIndex = 0;
  trackBundle.fragment.initTables(trunCount, totalSampleCount);

  int trunIndex = 0;
  int trunStartPosition = 0;
  for (int i = 0; i < leafChildrenSize; i++) {
    LeafAtom trun = leafChildren.get(i);
    if (trun.type == Atom.TYPE_trun) {
      trunStartPosition = parseTrun(trackBundle, trunIndex++, decodeTime, flags, trun.data,
          trunStartPosition);
    }
  }
}
 
Example 14
Source File: FragmentedMp4Extractor.java    From K-Sonic with MIT License 5 votes vote down vote up
/**
 * Parses a tfhd atom (defined in 14496-12), updates the corresponding {@link TrackFragment} and
 * returns the {@link TrackBundle} of the corresponding {@link Track}. If the tfhd does not refer
 * to any {@link TrackBundle}, {@code null} is returned and no changes are made.
 *
 * @param tfhd The tfhd atom to decode.
 * @param trackBundles The track bundles, one of which corresponds to the tfhd atom being parsed.
 * @return The {@link TrackBundle} to which the {@link TrackFragment} belongs, or null if the tfhd
 *     does not refer to any {@link TrackBundle}.
 */
private static TrackBundle parseTfhd(ParsableByteArray tfhd,
    SparseArray<TrackBundle> trackBundles, int flags) {
  tfhd.setPosition(Atom.HEADER_SIZE);
  int fullAtom = tfhd.readInt();
  int atomFlags = Atom.parseFullAtomFlags(fullAtom);
  int trackId = tfhd.readInt();
  TrackBundle trackBundle = trackBundles.get((flags & FLAG_SIDELOADED) == 0 ? trackId : 0);
  if (trackBundle == null) {
    return null;
  }
  if ((atomFlags & 0x01 /* base_data_offset_present */) != 0) {
    long baseDataPosition = tfhd.readUnsignedLongToLong();
    trackBundle.fragment.dataPosition = baseDataPosition;
    trackBundle.fragment.auxiliaryDataPosition = baseDataPosition;
  }

  DefaultSampleValues defaultSampleValues = trackBundle.defaultSampleValues;
  int defaultSampleDescriptionIndex =
      ((atomFlags & 0x02 /* default_sample_description_index_present */) != 0)
          ? tfhd.readUnsignedIntToInt() - 1 : defaultSampleValues.sampleDescriptionIndex;
  int defaultSampleDuration = ((atomFlags & 0x08 /* default_sample_duration_present */) != 0)
      ? tfhd.readUnsignedIntToInt() : defaultSampleValues.duration;
  int defaultSampleSize = ((atomFlags & 0x10 /* default_sample_size_present */) != 0)
      ? tfhd.readUnsignedIntToInt() : defaultSampleValues.size;
  int defaultSampleFlags = ((atomFlags & 0x20 /* default_sample_flags_present */) != 0)
      ? tfhd.readUnsignedIntToInt() : defaultSampleValues.flags;
  trackBundle.fragment.header = new DefaultSampleValues(defaultSampleDescriptionIndex,
      defaultSampleDuration, defaultSampleSize, defaultSampleFlags);
  return trackBundle;
}
 
Example 15
Source File: PsshAtomUtil.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Parses a PSSH atom. Version 0 and 1 PSSH atoms are supported.
 *
 * @param atom The atom to parse.
 * @return The parsed PSSH atom. Null if the input is not a valid PSSH atom, or if the PSSH atom
 *     has an unsupported version.
 */
// TODO: Support parsing of the key ids for version 1 PSSH atoms.
private static @Nullable PsshAtom parsePsshAtom(byte[] atom) {
  ParsableByteArray atomData = new ParsableByteArray(atom);
  if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) {
    // Data too short.
    return null;
  }
  atomData.setPosition(0);
  int atomSize = atomData.readInt();
  if (atomSize != atomData.bytesLeft() + 4) {
    // Not an atom, or incorrect atom size.
    return null;
  }
  int atomType = atomData.readInt();
  if (atomType != Atom.TYPE_pssh) {
    // Not an atom, or incorrect atom type.
    return null;
  }
  int atomVersion = Atom.parseFullAtomVersion(atomData.readInt());
  if (atomVersion > 1) {
    Log.w(TAG, "Unsupported pssh version: " + atomVersion);
    return null;
  }
  UUID uuid = new UUID(atomData.readLong(), atomData.readLong());
  if (atomVersion == 1) {
    int keyIdCount = atomData.readUnsignedIntToInt();
    atomData.skipBytes(16 * keyIdCount);
  }
  int dataSize = atomData.readUnsignedIntToInt();
  if (dataSize != atomData.bytesLeft()) {
    // Incorrect dataSize.
    return null;
  }
  byte[] data = new byte[dataSize];
  atomData.readBytes(data, 0, dataSize);
  return new PsshAtom(uuid, atomVersion, data);
}
 
Example 16
Source File: XingSeeker.java    From K-Sonic with MIT License 5 votes vote down vote up
/**
 * Returns a {@link XingSeeker} for seeking in the stream, if required information is present.
 * Returns {@code null} if not. On returning, {@code frame}'s position is not specified so the
 * caller should reset it.
 *
 * @param mpegAudioHeader The MPEG audio header associated with the frame.
 * @param frame The data in this audio frame, with its position set to immediately after the
 *    'Xing' or 'Info' tag.
 * @param position The position (byte offset) of the start of this frame in the stream.
 * @param inputLength The length of the stream in bytes.
 * @return A {@link XingSeeker} for seeking in the stream, or {@code null} if the required
 *     information is not present.
 */
public static XingSeeker create(MpegAudioHeader mpegAudioHeader, ParsableByteArray frame,
    long position, long inputLength) {
  int samplesPerFrame = mpegAudioHeader.samplesPerFrame;
  int sampleRate = mpegAudioHeader.sampleRate;
  long firstFramePosition = position + mpegAudioHeader.frameSize;

  int flags = frame.readInt();
  int frameCount;
  if ((flags & 0x01) != 0x01 || (frameCount = frame.readUnsignedIntToInt()) == 0) {
    // If the frame count is missing/invalid, the header can't be used to determine the duration.
    return null;
  }
  long durationUs = Util.scaleLargeTimestamp(frameCount, samplesPerFrame * C.MICROS_PER_SECOND,
      sampleRate);
  if ((flags & 0x06) != 0x06) {
    // If the size in bytes or table of contents is missing, the stream is not seekable.
    return new XingSeeker(firstFramePosition, durationUs, inputLength);
  }

  long sizeBytes = frame.readUnsignedIntToInt();
  frame.skipBytes(1);
  long[] tableOfContents = new long[99];
  for (int i = 0; i < 99; i++) {
    tableOfContents[i] = frame.readUnsignedByte();
  }

  // TODO: Handle encoder delay and padding in 3 bytes offset by xingBase + 213 bytes:
  // delay = (frame.readUnsignedByte() << 4) + (frame.readUnsignedByte() >> 4);
  // padding = ((frame.readUnsignedByte() & 0x0F) << 8) + frame.readUnsignedByte();
  return new XingSeeker(firstFramePosition, durationUs, inputLength, tableOfContents,
      sizeBytes, mpegAudioHeader.frameSize);
}
 
Example 17
Source File: FfmpegDecoder.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
@Override
protected @Nullable FfmpegDecoderException decode(
    DecoderInputBuffer inputBuffer, SimpleOutputBuffer outputBuffer, boolean reset) {
  if (reset) {
    nativeContext = ffmpegReset(nativeContext, extraData);
    if (nativeContext == 0) {
      return new FfmpegDecoderException("Error resetting (see logcat).");
    }
  }
  ByteBuffer inputData = inputBuffer.data;
  int inputSize = inputData.limit();
  ByteBuffer outputData = outputBuffer.init(inputBuffer.timeUs, outputBufferSize);
  int result = ffmpegDecode(nativeContext, inputData, inputSize, outputData, outputBufferSize);
  if (result < 0) {
    return new FfmpegDecoderException("Error decoding (see logcat). Code: " + result);
  }
  if (!hasOutputFormat) {
    channelCount = ffmpegGetChannelCount(nativeContext);
    sampleRate = ffmpegGetSampleRate(nativeContext);
    if (sampleRate == 0 && "alac".equals(codecName)) {
      Assertions.checkNotNull(extraData);
      // ALAC decoder did not set the sample rate in earlier versions of FFMPEG.
      // See https://trac.ffmpeg.org/ticket/6096
      ParsableByteArray parsableExtraData = new ParsableByteArray(extraData);
      parsableExtraData.setPosition(extraData.length - 4);
      sampleRate = parsableExtraData.readUnsignedIntToInt();
    }
    hasOutputFormat = true;
  }
  outputBuffer.data.position(0);
  outputBuffer.data.limit(result);
  return null;
}
 
Example 18
Source File: PsshAtomUtil.java    From MediaSDK with Apache License 2.0 5 votes vote down vote up
/**
 * Parses a PSSH atom. Version 0 and 1 PSSH atoms are supported.
 *
 * @param atom The atom to parse.
 * @return The parsed PSSH atom. Null if the input is not a valid PSSH atom, or if the PSSH atom
 *     has an unsupported version.
 */
// TODO: Support parsing of the key ids for version 1 PSSH atoms.
private static @Nullable PsshAtom parsePsshAtom(byte[] atom) {
  ParsableByteArray atomData = new ParsableByteArray(atom);
  if (atomData.limit() < Atom.FULL_HEADER_SIZE + 16 /* UUID */ + 4 /* DataSize */) {
    // Data too short.
    return null;
  }
  atomData.setPosition(0);
  int atomSize = atomData.readInt();
  if (atomSize != atomData.bytesLeft() + 4) {
    // Not an atom, or incorrect atom size.
    return null;
  }
  int atomType = atomData.readInt();
  if (atomType != Atom.TYPE_pssh) {
    // Not an atom, or incorrect atom type.
    return null;
  }
  int atomVersion = Atom.parseFullAtomVersion(atomData.readInt());
  if (atomVersion > 1) {
    Log.w(TAG, "Unsupported pssh version: " + atomVersion);
    return null;
  }
  UUID uuid = new UUID(atomData.readLong(), atomData.readLong());
  if (atomVersion == 1) {
    int keyIdCount = atomData.readUnsignedIntToInt();
    atomData.skipBytes(16 * keyIdCount);
  }
  int dataSize = atomData.readUnsignedIntToInt();
  if (dataSize != atomData.bytesLeft()) {
    // Incorrect dataSize.
    return null;
  }
  byte[] data = new byte[dataSize];
  atomData.readBytes(data, 0, dataSize);
  return new PsshAtom(uuid, atomVersion, data);
}
 
Example 19
Source File: VbriSeeker.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Returns a {@link VbriSeeker} for seeking in the stream, if required information is present.
 * Returns {@code null} if not. On returning, {@code frame}'s position is not specified so the
 * caller should reset it.
 *
 * @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown.
 * @param position The position of the start of this frame in the stream.
 * @param mpegAudioHeader The MPEG audio header associated with the frame.
 * @param frame The data in this audio frame, with its position set to immediately after the
 *     'VBRI' tag.
 * @return A {@link VbriSeeker} for seeking in the stream, or {@code null} if the required
 *     information is not present.
 */
public static VbriSeeker create(long inputLength, long position, MpegAudioHeader mpegAudioHeader,
    ParsableByteArray frame) {
  frame.skipBytes(10);
  int numFrames = frame.readInt();
  if (numFrames <= 0) {
    return null;
  }
  int sampleRate = mpegAudioHeader.sampleRate;
  long durationUs = Util.scaleLargeTimestamp(numFrames,
      C.MICROS_PER_SECOND * (sampleRate >= 32000 ? 1152 : 576), sampleRate);
  int entryCount = frame.readUnsignedShort();
  int scale = frame.readUnsignedShort();
  int entrySize = frame.readUnsignedShort();
  frame.skipBytes(2);

  long minPosition = position + mpegAudioHeader.frameSize;
  // Read table of contents entries.
  long[] timesUs = new long[entryCount];
  long[] positions = new long[entryCount];
  for (int index = 0; index < entryCount; index++) {
    timesUs[index] = (index * durationUs) / entryCount;
    // Ensure positions do not fall within the frame containing the VBRI header. This constraint
    // will normally only apply to the first entry in the table.
    positions[index] = Math.max(position, minPosition);
    int segmentSize;
    switch (entrySize) {
      case 1:
        segmentSize = frame.readUnsignedByte();
        break;
      case 2:
        segmentSize = frame.readUnsignedShort();
        break;
      case 3:
        segmentSize = frame.readUnsignedInt24();
        break;
      case 4:
        segmentSize = frame.readUnsignedIntToInt();
        break;
      default:
        return null;
    }
    position += segmentSize * scale;
  }
  if (inputLength != C.LENGTH_UNSET && inputLength != position) {
    Log.w(TAG, "VBRI data size mismatch: " + inputLength + ", " + position);
  }
  return new VbriSeeker(timesUs, positions, durationUs);
}
 
Example 20
Source File: VbriSeeker.java    From Telegram with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Returns a {@link VbriSeeker} for seeking in the stream, if required information is present.
 * Returns {@code null} if not. On returning, {@code frame}'s position is not specified so the
 * caller should reset it.
 *
 * @param inputLength The length of the stream in bytes, or {@link C#LENGTH_UNSET} if unknown.
 * @param position The position of the start of this frame in the stream.
 * @param mpegAudioHeader The MPEG audio header associated with the frame.
 * @param frame The data in this audio frame, with its position set to immediately after the
 *     'VBRI' tag.
 * @return A {@link VbriSeeker} for seeking in the stream, or {@code null} if the required
 *     information is not present.
 */
public static @Nullable VbriSeeker create(
    long inputLength, long position, MpegAudioHeader mpegAudioHeader, ParsableByteArray frame) {
  frame.skipBytes(10);
  int numFrames = frame.readInt();
  if (numFrames <= 0) {
    return null;
  }
  int sampleRate = mpegAudioHeader.sampleRate;
  long durationUs = Util.scaleLargeTimestamp(numFrames,
      C.MICROS_PER_SECOND * (sampleRate >= 32000 ? 1152 : 576), sampleRate);
  int entryCount = frame.readUnsignedShort();
  int scale = frame.readUnsignedShort();
  int entrySize = frame.readUnsignedShort();
  frame.skipBytes(2);

  long minPosition = position + mpegAudioHeader.frameSize;
  // Read table of contents entries.
  long[] timesUs = new long[entryCount];
  long[] positions = new long[entryCount];
  for (int index = 0; index < entryCount; index++) {
    timesUs[index] = (index * durationUs) / entryCount;
    // Ensure positions do not fall within the frame containing the VBRI header. This constraint
    // will normally only apply to the first entry in the table.
    positions[index] = Math.max(position, minPosition);
    int segmentSize;
    switch (entrySize) {
      case 1:
        segmentSize = frame.readUnsignedByte();
        break;
      case 2:
        segmentSize = frame.readUnsignedShort();
        break;
      case 3:
        segmentSize = frame.readUnsignedInt24();
        break;
      case 4:
        segmentSize = frame.readUnsignedIntToInt();
        break;
      default:
        return null;
    }
    position += segmentSize * scale;
  }
  if (inputLength != C.LENGTH_UNSET && inputLength != position) {
    Log.w(TAG, "VBRI data size mismatch: " + inputLength + ", " + position);
  }
  return new VbriSeeker(timesUs, positions, durationUs, /* dataEndPosition= */ position);
}