summaryrefslogtreecommitdiffstats
path: root/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java')
-rw-r--r--mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java170
1 files changed, 170 insertions, 0 deletions
diff --git a/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java
new file mode 100644
index 0000000000..a7b32782ff
--- /dev/null
+++ b/mobile/android/exoplayer2/src/main/java/org/mozilla/thirdparty/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java
@@ -0,0 +1,170 @@
+/*
+ * 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.rawcc;
+
+import org.mozilla.thirdparty.com.google.android.exoplayer2.C;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.Format;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.ParserException;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.Extractor;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.ExtractorInput;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.ExtractorOutput;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.PositionHolder;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.SeekMap;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.extractor.TrackOutput;
+import org.mozilla.thirdparty.com.google.android.exoplayer2.util.ParsableByteArray;
+import java.io.IOException;
+
+/**
+ * Extracts data from the RawCC container format.
+ */
+public final class RawCcExtractor implements Extractor {
+
+ private static final int SCRATCH_SIZE = 9;
+ private static final int HEADER_SIZE = 8;
+ private static final int HEADER_ID = 0x52434301;
+ private static final int TIMESTAMP_SIZE_V0 = 4;
+ private static final int TIMESTAMP_SIZE_V1 = 8;
+
+ // Parser states.
+ private static final int STATE_READING_HEADER = 0;
+ private static final int STATE_READING_TIMESTAMP_AND_COUNT = 1;
+ private static final int STATE_READING_SAMPLES = 2;
+
+ private final Format format;
+
+ private final ParsableByteArray dataScratch;
+
+ private TrackOutput trackOutput;
+
+ private int parserState;
+ private int version;
+ private long timestampUs;
+ private int remainingSampleCount;
+ private int sampleBytesWritten;
+
+ public RawCcExtractor(Format format) {
+ this.format = format;
+ dataScratch = new ParsableByteArray(SCRATCH_SIZE);
+ parserState = STATE_READING_HEADER;
+ }
+
+ @Override
+ public void init(ExtractorOutput output) {
+ output.seekMap(new SeekMap.Unseekable(C.TIME_UNSET));
+ trackOutput = output.track(0, C.TRACK_TYPE_TEXT);
+ output.endTracks();
+ trackOutput.format(format);
+ }
+
+ @Override
+ public boolean sniff(ExtractorInput input) throws IOException, InterruptedException {
+ dataScratch.reset();
+ input.peekFully(dataScratch.data, 0, HEADER_SIZE);
+ return dataScratch.readInt() == HEADER_ID;
+ }
+
+ @Override
+ public int read(ExtractorInput input, PositionHolder seekPosition)
+ throws IOException, InterruptedException {
+ while (true) {
+ switch (parserState) {
+ case STATE_READING_HEADER:
+ if (parseHeader(input)) {
+ parserState = STATE_READING_TIMESTAMP_AND_COUNT;
+ } else {
+ return RESULT_END_OF_INPUT;
+ }
+ break;
+ case STATE_READING_TIMESTAMP_AND_COUNT:
+ if (parseTimestampAndSampleCount(input)) {
+ parserState = STATE_READING_SAMPLES;
+ } else {
+ parserState = STATE_READING_HEADER;
+ return RESULT_END_OF_INPUT;
+ }
+ break;
+ case STATE_READING_SAMPLES:
+ parseSamples(input);
+ parserState = STATE_READING_TIMESTAMP_AND_COUNT;
+ return RESULT_CONTINUE;
+ default:
+ throw new IllegalStateException();
+ }
+ }
+ }
+
+ @Override
+ public void seek(long position, long timeUs) {
+ parserState = STATE_READING_HEADER;
+ }
+
+ @Override
+ public void release() {
+ // Do nothing
+ }
+
+ private boolean parseHeader(ExtractorInput input) throws IOException, InterruptedException {
+ dataScratch.reset();
+ if (input.readFully(dataScratch.data, 0, HEADER_SIZE, true)) {
+ if (dataScratch.readInt() != HEADER_ID) {
+ throw new IOException("Input not RawCC");
+ }
+ version = dataScratch.readUnsignedByte();
+ // no versions use the flag fields yet
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean parseTimestampAndSampleCount(ExtractorInput input) throws IOException,
+ InterruptedException {
+ dataScratch.reset();
+ if (version == 0) {
+ if (!input.readFully(dataScratch.data, 0, TIMESTAMP_SIZE_V0 + 1, true)) {
+ return false;
+ }
+ // version 0 timestamps are 45kHz, so we need to convert them into us
+ timestampUs = dataScratch.readUnsignedInt() * 1000 / 45;
+ } else if (version == 1) {
+ if (!input.readFully(dataScratch.data, 0, TIMESTAMP_SIZE_V1 + 1, true)) {
+ return false;
+ }
+ timestampUs = dataScratch.readLong();
+ } else {
+ throw new ParserException("Unsupported version number: " + version);
+ }
+
+ remainingSampleCount = dataScratch.readUnsignedByte();
+ sampleBytesWritten = 0;
+ return true;
+ }
+
+ private void parseSamples(ExtractorInput input) throws IOException, InterruptedException {
+ for (; remainingSampleCount > 0; remainingSampleCount--) {
+ dataScratch.reset();
+ input.readFully(dataScratch.data, 0, 3);
+
+ trackOutput.sampleData(dataScratch, 3);
+ sampleBytesWritten += 3;
+ }
+
+ if (sampleBytesWritten > 0) {
+ trackOutput.sampleMetadata(timestampUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null);
+ }
+ }
+
+}