summaryrefslogtreecommitdiffstats
path: root/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/mkv/Sniffer.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/mkv/Sniffer.java')
-rw-r--r--mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/mkv/Sniffer.java114
1 files changed, 114 insertions, 0 deletions
diff --git a/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/mkv/Sniffer.java b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/mkv/Sniffer.java
new file mode 100644
index 0000000000..f84cd084a3
--- /dev/null
+++ b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/mkv/Sniffer.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.mkv;
+
+import org.mozilla.thirdparty.com.google.android.exoplayer2.C;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.ExtractorInput;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.util.ParsableByteArray;
+import java.io.IOException;
+
+/**
+ * Utility class that peeks from the input stream in order to determine whether it appears to be
+ * compatible input for this extractor.
+ */
+/* package */ final class Sniffer {
+
+ /**
+ * The number of bytes to search for a valid header in {@link #sniff(ExtractorInput)}.
+ */
+ private static final int SEARCH_LENGTH = 1024;
+ private static final int ID_EBML = 0x1A45DFA3;
+
+ private final ParsableByteArray scratch;
+ private int peekLength;
+
+ public Sniffer() {
+ scratch = new ParsableByteArray(8);
+ }
+
+ /**
+ * @see com.google.android.exoplayer2.extractor.Extractor#sniff(ExtractorInput)
+ */
+ public boolean sniff(ExtractorInput input) throws IOException, InterruptedException {
+ long inputLength = input.getLength();
+ int bytesToSearch = (int) (inputLength == C.LENGTH_UNSET || inputLength > SEARCH_LENGTH
+ ? SEARCH_LENGTH : inputLength);
+ // Find four bytes equal to ID_EBML near the start of the input.
+ input.peekFully(scratch.data, 0, 4);
+ long tag = scratch.readUnsignedInt();
+ peekLength = 4;
+ while (tag != ID_EBML) {
+ if (++peekLength == bytesToSearch) {
+ return false;
+ }
+ input.peekFully(scratch.data, 0, 1);
+ tag = (tag << 8) & 0xFFFFFF00;
+ tag |= scratch.data[0] & 0xFF;
+ }
+
+ // Read the size of the EBML header and make sure it is within the stream.
+ long headerSize = readUint(input);
+ long headerStart = peekLength;
+ if (headerSize == Long.MIN_VALUE
+ || (inputLength != C.LENGTH_UNSET && headerStart + headerSize >= inputLength)) {
+ return false;
+ }
+
+ // Read the payload elements in the EBML header.
+ while (peekLength < headerStart + headerSize) {
+ long id = readUint(input);
+ if (id == Long.MIN_VALUE) {
+ return false;
+ }
+ long size = readUint(input);
+ if (size < 0 || size > Integer.MAX_VALUE) {
+ return false;
+ }
+ if (size != 0) {
+ int sizeInt = (int) size;
+ input.advancePeekPosition(sizeInt);
+ peekLength += sizeInt;
+ }
+ }
+ return peekLength == headerStart + headerSize;
+ }
+
+ /**
+ * Peeks a variable-length unsigned EBML integer from the input.
+ */
+ private long readUint(ExtractorInput input) throws IOException, InterruptedException {
+ input.peekFully(scratch.data, 0, 1);
+ int value = scratch.data[0] & 0xFF;
+ if (value == 0) {
+ return Long.MIN_VALUE;
+ }
+ int mask = 0x80;
+ int length = 0;
+ while ((value & mask) == 0) {
+ mask >>= 1;
+ length++;
+ }
+ value &= ~mask;
+ input.peekFully(scratch.data, 1, length);
+ for (int i = 0; i < length; i++) {
+ value <<= 8;
+ value += scratch.data[i + 1] & 0xFF;
+ }
+ peekLength += length + 1;
+ return value;
+ }
+
+}