From 908e4dfd5df4840a1d1fcb45d293bebd011e3bce Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Tue, 15 Sep 2015 13:43:42 +0100 Subject: [PATCH] Search for synch' when sniffing ADTS and check four frames. Issue: #791 --- .../exoplayer/extractor/ts/AdtsExtractor.java | 54 ++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsExtractor.java b/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsExtractor.java index fd72242216..24b578b028 100644 --- a/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsExtractor.java +++ b/library/src/main/java/com/google/android/exoplayer/extractor/ts/AdtsExtractor.java @@ -20,6 +20,7 @@ import com.google.android.exoplayer.extractor.ExtractorInput; import com.google.android.exoplayer.extractor.ExtractorOutput; import com.google.android.exoplayer.extractor.PositionHolder; import com.google.android.exoplayer.extractor.SeekMap; +import com.google.android.exoplayer.util.ParsableBitArray; import com.google.android.exoplayer.util.ParsableByteArray; import com.google.android.exoplayer.util.Util; @@ -32,6 +33,12 @@ import java.io.IOException; public final class AdtsExtractor implements Extractor { private static final int MAX_PACKET_SIZE = 200; + private static final int ID3_TAG = Util.getIntegerCodeForString("ID3"); + /** + * The maximum number of bytes to search when sniffing, excluding the header, before giving up. + * Frame sizes are represented by 13-bit fields, so expect a valid frame in the first 8192 bytes. + */ + private static final int MAX_SNIFF_BYTES = 8 * 1024; private final long firstSampleTimestampUs; private final ParsableByteArray packetBuffer; @@ -52,20 +59,53 @@ public final class AdtsExtractor implements Extractor { @Override public boolean sniff(ExtractorInput input) throws IOException, InterruptedException { + // Skip any ID3 headers. ParsableByteArray scratch = new ParsableByteArray(10); - input.peekFully(scratch.data, 0, 10); - int value = scratch.readUnsignedInt24(); - if (value != Util.getIntegerCodeForString("ID3")) { - value = value >> 8; - } else { + ParsableBitArray scratchBits = new ParsableBitArray(scratch.data); + int startPosition = 0; + while (true) { + input.peekFully(scratch.data, 0, 10); + scratch.setPosition(0); + if (scratch.readUnsignedInt24() != ID3_TAG) { + break; + } int length = (scratch.data[6] & 0x7F) << 21 | ((scratch.data[7] & 0x7F) << 14) | ((scratch.data[8] & 0x7F) << 7) | (scratch.data[9] & 0x7F); + startPosition += 10 + length; input.advancePeekPosition(length); + } + input.resetPeekPosition(); + input.advancePeekPosition(startPosition); + + // Try to find four or more consecutive AAC audio frames, exceeding the MPEG TS packet size. + int headerPosition = startPosition; + int validFramesSize = 0; + int validFramesCount = 0; + while (true) { input.peekFully(scratch.data, 0, 2); scratch.setPosition(0); - value = scratch.readUnsignedShort(); + int syncBytes = scratch.readUnsignedShort(); + if ((syncBytes & 0xFFF6) != 0xFFF0) { + validFramesCount = 0; + validFramesSize = 0; + input.resetPeekPosition(); + if (++headerPosition - startPosition >= MAX_SNIFF_BYTES) { + return false; + } + input.advancePeekPosition(headerPosition); + } else { + if (++validFramesCount >= 4 && validFramesSize > 188) { + return true; + } + + // Skip the frame. + input.peekFully(scratch.data, 0, 4); + scratchBits.setPosition(14); + int frameSize = scratchBits.readBits(13); + input.advancePeekPosition(frameSize - 6); + validFramesSize += frameSize; + } } - return (value & 0xFFF6) == 0xFFF0; } @Override