From a9c977a79e0be0cf40903aaa89ce7e8514de777d Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Tue, 19 May 2015 14:13:31 +0100 Subject: [PATCH] Fix Mp3Extractor synchronization when loading retries. Before preparation, and when seeking, Mp3Extractor did not handle retrying: - synchronizedHeader was set before the header was known to be valid, which means that after seeing one valid frame header and then failing to read, the synchronization would be treated as complete. - The input buffer would keep data loaded during synchronization but on the next call to synchronize when retrying it was not returned to the mark position to re-parse the data. This change fixes these issues. --- .../exoplayer/extractor/mp3/Mp3Extractor.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java index e7a30b170c..0b82bede91 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/mp3/Mp3Extractor.java @@ -175,6 +175,15 @@ public final class Mp3Extractor implements Extractor { } private long synchronize(ExtractorInput extractorInput) throws IOException, InterruptedException { + if (extractorInput.getPosition() == 0) { + // Before preparation completes, retrying loads from the start, so clear any buffered data. + inputBuffer.reset(); + } else { + // After preparation completes, retrying resumes loading from the old position, so return to + // the start of buffered data to parse it again. + inputBuffer.returnToMark(); + } + long startPosition = getPosition(extractorInput, inputBuffer); // Skip any ID3 header at the start of the file. @@ -198,6 +207,7 @@ public final class Mp3Extractor implements Extractor { inputBuffer.mark(); long headerPosition = startPosition; int validFrameCount = 0; + int candidateSynchronizedHeaderData = 0; while (true) { if (headerPosition - startPosition >= MAX_BYTES_TO_SEARCH) { throw new ParserException("Searched too many bytes while resynchronizing."); @@ -210,11 +220,11 @@ public final class Mp3Extractor implements Extractor { scratch.setPosition(0); int headerData = scratch.readInt(); int frameSize; - if ((synchronizedHeaderData != 0 - && (headerData & HEADER_MASK) != (synchronizedHeaderData & HEADER_MASK)) + if ((candidateSynchronizedHeaderData != 0 + && (headerData & HEADER_MASK) != (candidateSynchronizedHeaderData & HEADER_MASK)) || (frameSize = MpegAudioHeader.getFrameSize(headerData)) == -1) { validFrameCount = 0; - synchronizedHeaderData = 0; + candidateSynchronizedHeaderData = 0; // Try reading a header starting at the next byte. inputBuffer.returnToMark(); @@ -226,7 +236,7 @@ public final class Mp3Extractor implements Extractor { if (validFrameCount == 0) { MpegAudioHeader.populateHeader(headerData, synchronizedHeader); - synchronizedHeaderData = headerData; + candidateSynchronizedHeaderData = headerData; } // The header was valid and matching (if appropriate). Check another or end synchronization. @@ -241,6 +251,7 @@ public final class Mp3Extractor implements Extractor { // The input buffer read position is now synchronized. inputBuffer.returnToMark(); + synchronizedHeaderData = candidateSynchronizedHeaderData; if (seeker == null) { setupSeeker(extractorInput, headerPosition); extractorOutput.seekMap(seeker);