Java Code Examples for com.google.android.exoplayer2.metadata.id3.Id3Decoder#FramePredicate

The following examples show how to use com.google.android.exoplayer2.metadata.id3.Id3Decoder#FramePredicate . 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: Id3Peeker.java    From MediaSDK with Apache License 2.0 5 votes vote down vote up
/**
 * Peeks ID3 data from the input and parses the first ID3 tag.
 *
 * @param input The {@link ExtractorInput} from which data should be peeked.
 * @param id3FramePredicate Determines which ID3 frames are decoded. May be null to decode all
 *     frames.
 * @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
 *     present in the input.
 * @throws IOException If an error occurred peeking from the input.
 * @throws InterruptedException If the thread was interrupted.
 */
@Nullable
public Metadata peekId3Data(
    ExtractorInput input, @Nullable Id3Decoder.FramePredicate id3FramePredicate)
    throws IOException, InterruptedException {
  int peekedId3Bytes = 0;
  Metadata metadata = null;
  while (true) {
    try {
      input.peekFully(scratch.data, /* offset= */ 0, Id3Decoder.ID3_HEADER_LENGTH);
    } catch (EOFException e) {
      // If input has less than ID3_HEADER_LENGTH, ignore the rest.
      break;
    }
    scratch.setPosition(0);
    if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
      // Not an ID3 tag.
      break;
    }
    scratch.skipBytes(3); // Skip major version, minor version and flags.
    int framesLength = scratch.readSynchSafeInt();
    int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;

    if (metadata == null) {
      byte[] id3Data = new byte[tagLength];
      System.arraycopy(scratch.data, 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
      input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);

      metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
    } else {
      input.advancePeekPosition(framesLength);
    }

    peekedId3Bytes += tagLength;
  }

  input.resetPeekPosition();
  input.advancePeekPosition(peekedId3Bytes);
  return metadata;
}
 
Example 2
Source File: Id3Peeker.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 data from the input and parses the first ID3 tag.
 *
 * @param input The {@link ExtractorInput} from which data should be peeked.
 * @param id3FramePredicate Determines which ID3 frames are decoded. May be null to decode all
 *     frames.
 * @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
 *     present in the input.
 * @throws IOException If an error occurred peeking from the input.
 * @throws InterruptedException If the thread was interrupted.
 */
@Nullable
public Metadata peekId3Data(
    ExtractorInput input, @Nullable Id3Decoder.FramePredicate id3FramePredicate)
    throws IOException, InterruptedException {
  int peekedId3Bytes = 0;
  Metadata metadata = null;
  while (true) {
    try {
      input.peekFully(scratch.data, 0, Id3Decoder.ID3_HEADER_LENGTH);
    } catch (EOFException e) {
      // If input has less than ID3_HEADER_LENGTH, ignore the rest.
      break;
    }
    scratch.setPosition(0);
    if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
      // Not an ID3 tag.
      break;
    }
    scratch.skipBytes(3); // Skip major version, minor version and flags.
    int framesLength = scratch.readSynchSafeInt();
    int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;

    if (metadata == null) {
      byte[] id3Data = new byte[tagLength];
      System.arraycopy(scratch.data, 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
      input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);

      metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
    } else {
      input.advancePeekPosition(framesLength);
    }

    peekedId3Bytes += tagLength;
  }

  input.resetPeekPosition();
  input.advancePeekPosition(peekedId3Bytes);
  return metadata;
}
 
Example 3
Source File: FlacExtractor.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 tag data (if present) at the beginning of the input.
 *
 * @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
 *     present in the input.
 */
@Nullable
private Metadata peekId3Data(ExtractorInput input) throws IOException, InterruptedException {
  input.resetPeekPosition();
  Id3Decoder.FramePredicate id3FramePredicate =
      isId3MetadataDisabled ? Id3Decoder.NO_FRAMES_PREDICATE : null;
  return id3Peeker.peekId3Data(input, id3FramePredicate);
}
 
Example 4
Source File: Id3Peeker.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 data from the input and parses the first ID3 tag.
 *
 * @param input The {@link ExtractorInput} from which data should be peeked.
 * @param id3FramePredicate Determines which ID3 frames are decoded. May be null to decode all
 *     frames.
 * @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
 *     present in the input.
 * @throws IOException If an error occurred peeking from the input.
 * @throws InterruptedException If the thread was interrupted.
 */
@Nullable
public Metadata peekId3Data(
    ExtractorInput input, @Nullable Id3Decoder.FramePredicate id3FramePredicate)
    throws IOException, InterruptedException {
  int peekedId3Bytes = 0;
  Metadata metadata = null;
  while (true) {
    try {
      input.peekFully(scratch.data, 0, Id3Decoder.ID3_HEADER_LENGTH);
    } catch (EOFException e) {
      // If input has less than ID3_HEADER_LENGTH, ignore the rest.
      break;
    }
    scratch.setPosition(0);
    if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
      // Not an ID3 tag.
      break;
    }
    scratch.skipBytes(3); // Skip major version, minor version and flags.
    int framesLength = scratch.readSynchSafeInt();
    int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;

    if (metadata == null) {
      byte[] id3Data = new byte[tagLength];
      System.arraycopy(scratch.data, 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
      input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);

      metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
    } else {
      input.advancePeekPosition(framesLength);
    }

    peekedId3Bytes += tagLength;
  }

  input.resetPeekPosition();
  input.advancePeekPosition(peekedId3Bytes);
  return metadata;
}
 
Example 5
Source File: FlacExtractor.java    From TelePlus-Android with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 tag data (if present) at the beginning of the input.
 *
 * @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
 *     present in the input.
 */
@Nullable
private Metadata peekId3Data(ExtractorInput input) throws IOException, InterruptedException {
  input.resetPeekPosition();
  Id3Decoder.FramePredicate id3FramePredicate =
      isId3MetadataDisabled ? Id3Decoder.NO_FRAMES_PREDICATE : null;
  return id3Peeker.peekId3Data(input, id3FramePredicate);
}
 
Example 6
Source File: Mp3Extractor.java    From K-Sonic with MIT License 5 votes vote down vote up
/**
 * Peeks ID3 data from the input, including gapless playback information.
 *
 * @param input The {@link ExtractorInput} from which data should be peeked.
 * @throws IOException If an error occurred peeking from the input.
 * @throws InterruptedException If the thread was interrupted.
 */
private void peekId3Data(ExtractorInput input) throws IOException, InterruptedException {
  int peekedId3Bytes = 0;
  while (true) {
    input.peekFully(scratch.data, 0, Id3Decoder.ID3_HEADER_LENGTH);
    scratch.setPosition(0);
    if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
      // Not an ID3 tag.
      break;
    }
    scratch.skipBytes(3); // Skip major version, minor version and flags.
    int framesLength = scratch.readSynchSafeInt();
    int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;

    if (metadata == null) {
      byte[] id3Data = new byte[tagLength];
      System.arraycopy(scratch.data, 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
      input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);
      // We need to parse enough ID3 metadata to retrieve any gapless playback information even
      // if ID3 metadata parsing is disabled.
      Id3Decoder.FramePredicate id3FramePredicate = (flags & FLAG_DISABLE_ID3_METADATA) != 0
          ? GaplessInfoHolder.GAPLESS_INFO_ID3_FRAME_PREDICATE : null;
      metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
      if (metadata != null) {
        gaplessInfoHolder.setFromMetadata(metadata);
      }
    } else {
      input.advancePeekPosition(framesLength);
    }

    peekedId3Bytes += tagLength;
  }

  input.resetPeekPosition();
  input.advancePeekPosition(peekedId3Bytes);
}
 
Example 7
Source File: Id3Peeker.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 data from the input and parses the first ID3 tag.
 *
 * @param input The {@link ExtractorInput} from which data should be peeked.
 * @param id3FramePredicate Determines which ID3 frames are decoded. May be null to decode all
 *     frames.
 * @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
 *     present in the input.
 * @throws IOException If an error occurred peeking from the input.
 * @throws InterruptedException If the thread was interrupted.
 */
@Nullable
public Metadata peekId3Data(
    ExtractorInput input, @Nullable Id3Decoder.FramePredicate id3FramePredicate)
    throws IOException, InterruptedException {
  int peekedId3Bytes = 0;
  Metadata metadata = null;
  while (true) {
    try {
      input.peekFully(scratch.data, 0, Id3Decoder.ID3_HEADER_LENGTH);
    } catch (EOFException e) {
      // If input has less than ID3_HEADER_LENGTH, ignore the rest.
      break;
    }
    scratch.setPosition(0);
    if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
      // Not an ID3 tag.
      break;
    }
    scratch.skipBytes(3); // Skip major version, minor version and flags.
    int framesLength = scratch.readSynchSafeInt();
    int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;

    if (metadata == null) {
      byte[] id3Data = new byte[tagLength];
      System.arraycopy(scratch.data, 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
      input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);

      metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
    } else {
      input.advancePeekPosition(framesLength);
    }

    peekedId3Bytes += tagLength;
  }

  input.resetPeekPosition();
  input.advancePeekPosition(peekedId3Bytes);
  return metadata;
}
 
Example 8
Source File: FlacExtractor.java    From Telegram-FOSS with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 tag data at the beginning of the input.
 *
 * @return The first ID3 tag {@link Metadata}, or null if an ID3 tag is not present in the input.
 */
@Nullable
private Metadata peekId3Data(ExtractorInput input) throws IOException, InterruptedException {
  input.resetPeekPosition();
  Id3Decoder.FramePredicate id3FramePredicate =
      id3MetadataDisabled ? Id3Decoder.NO_FRAMES_PREDICATE : null;
  return id3Peeker.peekId3Data(input, id3FramePredicate);
}
 
Example 9
Source File: Id3Peeker.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 data from the input and parses the first ID3 tag.
 *
 * @param input The {@link ExtractorInput} from which data should be peeked.
 * @param id3FramePredicate Determines which ID3 frames are decoded. May be null to decode all
 *     frames.
 * @return The first ID3 tag decoded into a {@link Metadata} object. May be null if ID3 tag is not
 *     present in the input.
 * @throws IOException If an error occurred peeking from the input.
 * @throws InterruptedException If the thread was interrupted.
 */
@Nullable
public Metadata peekId3Data(
    ExtractorInput input, @Nullable Id3Decoder.FramePredicate id3FramePredicate)
    throws IOException, InterruptedException {
  int peekedId3Bytes = 0;
  Metadata metadata = null;
  while (true) {
    try {
      input.peekFully(scratch.data, 0, Id3Decoder.ID3_HEADER_LENGTH);
    } catch (EOFException e) {
      // If input has less than ID3_HEADER_LENGTH, ignore the rest.
      break;
    }
    scratch.setPosition(0);
    if (scratch.readUnsignedInt24() != Id3Decoder.ID3_TAG) {
      // Not an ID3 tag.
      break;
    }
    scratch.skipBytes(3); // Skip major version, minor version and flags.
    int framesLength = scratch.readSynchSafeInt();
    int tagLength = Id3Decoder.ID3_HEADER_LENGTH + framesLength;

    if (metadata == null) {
      byte[] id3Data = new byte[tagLength];
      System.arraycopy(scratch.data, 0, id3Data, 0, Id3Decoder.ID3_HEADER_LENGTH);
      input.peekFully(id3Data, Id3Decoder.ID3_HEADER_LENGTH, framesLength);

      metadata = new Id3Decoder(id3FramePredicate).decode(id3Data, tagLength);
    } else {
      input.advancePeekPosition(framesLength);
    }

    peekedId3Bytes += tagLength;
  }

  input.resetPeekPosition();
  input.advancePeekPosition(peekedId3Bytes);
  return metadata;
}
 
Example 10
Source File: FlacExtractor.java    From Telegram with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Peeks ID3 tag data at the beginning of the input.
 *
 * @return The first ID3 tag {@link Metadata}, or null if an ID3 tag is not present in the input.
 */
@Nullable
private Metadata peekId3Data(ExtractorInput input) throws IOException, InterruptedException {
  input.resetPeekPosition();
  Id3Decoder.FramePredicate id3FramePredicate =
      id3MetadataDisabled ? Id3Decoder.NO_FRAMES_PREDICATE : null;
  return id3Peeker.peekId3Data(input, id3FramePredicate);
}
 
Example 11
Source File: Mp3Extractor.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
private boolean synchronize(ExtractorInput input, boolean sniffing)
    throws IOException, InterruptedException {
  int validFrameCount = 0;
  int candidateSynchronizedHeaderData = 0;
  int peekedId3Bytes = 0;
  int searchedBytes = 0;
  int searchLimitBytes = sniffing ? MAX_SNIFF_BYTES : MAX_SYNC_BYTES;
  input.resetPeekPosition();
  if (input.getPosition() == 0) {
    // We need to parse enough ID3 metadata to retrieve any gapless playback information even
    // if ID3 metadata parsing is disabled.
    boolean onlyDecodeGaplessInfoFrames = (flags & FLAG_DISABLE_ID3_METADATA) != 0;
    Id3Decoder.FramePredicate id3FramePredicate =
        onlyDecodeGaplessInfoFrames ? GaplessInfoHolder.GAPLESS_INFO_ID3_FRAME_PREDICATE : null;
    metadata = id3Peeker.peekId3Data(input, id3FramePredicate);
    if (metadata != null) {
      gaplessInfoHolder.setFromMetadata(metadata);
    }
    peekedId3Bytes = (int) input.getPeekPosition();
    if (!sniffing) {
      input.skipFully(peekedId3Bytes);
    }
  }
  while (true) {
    if (!input.peekFully(scratch.data, 0, 4, validFrameCount > 0)) {
      // We reached the end of the stream but found at least one valid frame.
      break;
    }
    scratch.setPosition(0);
    int headerData = scratch.readInt();
    int frameSize;
    if ((candidateSynchronizedHeaderData != 0
        && !headersMatch(headerData, candidateSynchronizedHeaderData))
        || (frameSize = MpegAudioHeader.getFrameSize(headerData)) == C.LENGTH_UNSET) {
      // The header doesn't match the candidate header or is invalid. Try the next byte offset.
      if (searchedBytes++ == searchLimitBytes) {
        if (!sniffing) {
          throw new ParserException("Searched too many bytes.");
        }
        return false;
      }
      validFrameCount = 0;
      candidateSynchronizedHeaderData = 0;
      if (sniffing) {
        input.resetPeekPosition();
        input.advancePeekPosition(peekedId3Bytes + searchedBytes);
      } else {
        input.skipFully(1);
      }
    } else {
      // The header matches the candidate header and/or is valid.
      validFrameCount++;
      if (validFrameCount == 1) {
        MpegAudioHeader.populateHeader(headerData, synchronizedHeader);
        candidateSynchronizedHeaderData = headerData;
      } else if (validFrameCount == 4) {
        break;
      }
      input.advancePeekPosition(frameSize - 4);
    }
  }
  // Prepare to read the synchronized frame.
  if (sniffing) {
    input.skipFully(peekedId3Bytes + searchedBytes);
  } else {
    input.resetPeekPosition();
  }
  synchronizedHeaderData = candidateSynchronizedHeaderData;
  return true;
}
 
Example 12
Source File: Mp3Extractor.java    From TelePlus-Android with GNU General Public License v2.0 4 votes vote down vote up
private boolean synchronize(ExtractorInput input, boolean sniffing)
    throws IOException, InterruptedException {
  int validFrameCount = 0;
  int candidateSynchronizedHeaderData = 0;
  int peekedId3Bytes = 0;
  int searchedBytes = 0;
  int searchLimitBytes = sniffing ? MAX_SNIFF_BYTES : MAX_SYNC_BYTES;
  input.resetPeekPosition();
  if (input.getPosition() == 0) {
    // We need to parse enough ID3 metadata to retrieve any gapless playback information even
    // if ID3 metadata parsing is disabled.
    boolean onlyDecodeGaplessInfoFrames = (flags & FLAG_DISABLE_ID3_METADATA) != 0;
    Id3Decoder.FramePredicate id3FramePredicate =
        onlyDecodeGaplessInfoFrames ? GaplessInfoHolder.GAPLESS_INFO_ID3_FRAME_PREDICATE : null;
    metadata = id3Peeker.peekId3Data(input, id3FramePredicate);
    if (metadata != null) {
      gaplessInfoHolder.setFromMetadata(metadata);
    }
    peekedId3Bytes = (int) input.getPeekPosition();
    if (!sniffing) {
      input.skipFully(peekedId3Bytes);
    }
  }
  while (true) {
    if (!input.peekFully(scratch.data, 0, 4, validFrameCount > 0)) {
      // We reached the end of the stream but found at least one valid frame.
      break;
    }
    scratch.setPosition(0);
    int headerData = scratch.readInt();
    int frameSize;
    if ((candidateSynchronizedHeaderData != 0
        && !headersMatch(headerData, candidateSynchronizedHeaderData))
        || (frameSize = MpegAudioHeader.getFrameSize(headerData)) == C.LENGTH_UNSET) {
      // The header doesn't match the candidate header or is invalid. Try the next byte offset.
      if (searchedBytes++ == searchLimitBytes) {
        if (!sniffing) {
          throw new ParserException("Searched too many bytes.");
        }
        return false;
      }
      validFrameCount = 0;
      candidateSynchronizedHeaderData = 0;
      if (sniffing) {
        input.resetPeekPosition();
        input.advancePeekPosition(peekedId3Bytes + searchedBytes);
      } else {
        input.skipFully(1);
      }
    } else {
      // The header matches the candidate header and/or is valid.
      validFrameCount++;
      if (validFrameCount == 1) {
        MpegAudioHeader.populateHeader(headerData, synchronizedHeader);
        candidateSynchronizedHeaderData = headerData;
      } else if (validFrameCount == 4) {
        break;
      }
      input.advancePeekPosition(frameSize - 4);
    }
  }
  // Prepare to read the synchronized frame.
  if (sniffing) {
    input.skipFully(peekedId3Bytes + searchedBytes);
  } else {
    input.resetPeekPosition();
  }
  synchronizedHeaderData = candidateSynchronizedHeaderData;
  return true;
}
 
Example 13
Source File: Mp3Extractor.java    From Telegram-FOSS with GNU General Public License v2.0 4 votes vote down vote up
private boolean synchronize(ExtractorInput input, boolean sniffing)
    throws IOException, InterruptedException {
  int validFrameCount = 0;
  int candidateSynchronizedHeaderData = 0;
  int peekedId3Bytes = 0;
  int searchedBytes = 0;
  int searchLimitBytes = sniffing ? MAX_SNIFF_BYTES : MAX_SYNC_BYTES;
  input.resetPeekPosition();
  if (input.getPosition() == 0) {
    // We need to parse enough ID3 metadata to retrieve any gapless/seeking playback information
    // even if ID3 metadata parsing is disabled.
    boolean parseAllId3Frames = (flags & FLAG_DISABLE_ID3_METADATA) == 0;
    Id3Decoder.FramePredicate id3FramePredicate =
        parseAllId3Frames ? null : REQUIRED_ID3_FRAME_PREDICATE;
    metadata = id3Peeker.peekId3Data(input, id3FramePredicate);
    if (metadata != null) {
      gaplessInfoHolder.setFromMetadata(metadata);
    }
    peekedId3Bytes = (int) input.getPeekPosition();
    if (!sniffing) {
      input.skipFully(peekedId3Bytes);
    }
  }
  while (true) {
    if (peekEndOfStreamOrHeader(input)) {
      if (validFrameCount > 0) {
        // We reached the end of the stream but found at least one valid frame.
        break;
      }
      throw new EOFException();
    }
    scratch.setPosition(0);
    int headerData = scratch.readInt();
    int frameSize;
    if ((candidateSynchronizedHeaderData != 0
        && !headersMatch(headerData, candidateSynchronizedHeaderData))
        || (frameSize = MpegAudioHeader.getFrameSize(headerData)) == C.LENGTH_UNSET) {
      // The header doesn't match the candidate header or is invalid. Try the next byte offset.
      if (searchedBytes++ == searchLimitBytes) {
        if (!sniffing) {
          throw new ParserException("Searched too many bytes.");
        }
        return false;
      }
      validFrameCount = 0;
      candidateSynchronizedHeaderData = 0;
      if (sniffing) {
        input.resetPeekPosition();
        input.advancePeekPosition(peekedId3Bytes + searchedBytes);
      } else {
        input.skipFully(1);
      }
    } else {
      // The header matches the candidate header and/or is valid.
      validFrameCount++;
      if (validFrameCount == 1) {
        MpegAudioHeader.populateHeader(headerData, synchronizedHeader);
        candidateSynchronizedHeaderData = headerData;
      } else if (validFrameCount == 4) {
        break;
      }
      input.advancePeekPosition(frameSize - 4);
    }
  }
  // Prepare to read the synchronized frame.
  if (sniffing) {
    input.skipFully(peekedId3Bytes + searchedBytes);
  } else {
    input.resetPeekPosition();
  }
  synchronizedHeaderData = candidateSynchronizedHeaderData;
  return true;
}
 
Example 14
Source File: Mp3Extractor.java    From Telegram with GNU General Public License v2.0 4 votes vote down vote up
private boolean synchronize(ExtractorInput input, boolean sniffing)
    throws IOException, InterruptedException {
  int validFrameCount = 0;
  int candidateSynchronizedHeaderData = 0;
  int peekedId3Bytes = 0;
  int searchedBytes = 0;
  int searchLimitBytes = sniffing ? MAX_SNIFF_BYTES : MAX_SYNC_BYTES;
  input.resetPeekPosition();
  if (input.getPosition() == 0) {
    // We need to parse enough ID3 metadata to retrieve any gapless/seeking playback information
    // even if ID3 metadata parsing is disabled.
    boolean parseAllId3Frames = (flags & FLAG_DISABLE_ID3_METADATA) == 0;
    Id3Decoder.FramePredicate id3FramePredicate =
        parseAllId3Frames ? null : REQUIRED_ID3_FRAME_PREDICATE;
    metadata = id3Peeker.peekId3Data(input, id3FramePredicate);
    if (metadata != null) {
      gaplessInfoHolder.setFromMetadata(metadata);
    }
    peekedId3Bytes = (int) input.getPeekPosition();
    if (!sniffing) {
      input.skipFully(peekedId3Bytes);
    }
  }
  while (true) {
    if (peekEndOfStreamOrHeader(input)) {
      if (validFrameCount > 0) {
        // We reached the end of the stream but found at least one valid frame.
        break;
      }
      throw new EOFException();
    }
    scratch.setPosition(0);
    int headerData = scratch.readInt();
    int frameSize;
    if ((candidateSynchronizedHeaderData != 0
        && !headersMatch(headerData, candidateSynchronizedHeaderData))
        || (frameSize = MpegAudioHeader.getFrameSize(headerData)) == C.LENGTH_UNSET) {
      // The header doesn't match the candidate header or is invalid. Try the next byte offset.
      if (searchedBytes++ == searchLimitBytes) {
        if (!sniffing) {
          throw new ParserException("Searched too many bytes.");
        }
        return false;
      }
      validFrameCount = 0;
      candidateSynchronizedHeaderData = 0;
      if (sniffing) {
        input.resetPeekPosition();
        input.advancePeekPosition(peekedId3Bytes + searchedBytes);
      } else {
        input.skipFully(1);
      }
    } else {
      // The header matches the candidate header and/or is valid.
      validFrameCount++;
      if (validFrameCount == 1) {
        MpegAudioHeader.populateHeader(headerData, synchronizedHeader);
        candidateSynchronizedHeaderData = headerData;
      } else if (validFrameCount == 4) {
        break;
      }
      input.advancePeekPosition(frameSize - 4);
    }
  }
  // Prepare to read the synchronized frame.
  if (sniffing) {
    input.skipFully(peekedId3Bytes + searchedBytes);
  } else {
    input.resetPeekPosition();
  }
  synchronizedHeaderData = candidateSynchronizedHeaderData;
  return true;
}