From 1d79c26b3446ab921633419f29ea515319cb4c38 Mon Sep 17 00:00:00 2001 From: cdrolle Date: Mon, 25 Jul 2016 14:08:33 -0700 Subject: [PATCH] Added support for RawCC (i.e. out-of-band EIA-608) ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=128397367 --- .../src/androidTest/assets/rawcc/sample.rawcc | Bin 0 -> 1736 bytes .../assets/rawcc/sample.rawcc.0.dump | 329 ++++++++++++++++++ .../extractor/rawcc/RawCcExtractorTest.java | 38 ++ .../extractor/rawcc/RawCcExtractor.java | 172 +++++++++ .../source/chunk/ChunkExtractorWrapper.java | 24 +- .../source/dash/DefaultDashChunkSource.java | 31 +- .../dash/manifest/DashManifestParser.java | 9 +- .../android/exoplayer2/util/MimeTypes.java | 1 + 8 files changed, 592 insertions(+), 12 deletions(-) create mode 100644 library/src/androidTest/assets/rawcc/sample.rawcc create mode 100644 library/src/androidTest/assets/rawcc/sample.rawcc.0.dump create mode 100644 library/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java create mode 100644 library/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java diff --git a/library/src/androidTest/assets/rawcc/sample.rawcc b/library/src/androidTest/assets/rawcc/sample.rawcc new file mode 100644 index 0000000000000000000000000000000000000000..0ea4a283902d66b546b7f338eed29304ce7c09b7 GIT binary patch literal 1736 zcmZ{leQc9e6o>oXp5Av>WqgRiKv*dslcfqmAQ%#ou|?t%vSbD_fk0OF(vGoit}9p& ztQNsZMK*`yYk|zbP_#fGq6-A#WP!{y5Q$_20vV}cnJ_7XMZ%c(o*!NOhyAlWefpmB zo^$R!Ey~L?Z0gT4mTfmE60wXG8x4p4?_Fb1gUd3kC1C%%ileQb7`y@zEvl$7h|?=Qj)9lDo#rT${9I$yatr zhh5g?NL!AqS1~`03-vx6<+CQDWY~M|BbPD8|x5OoK1j)0HF@jVbHYl(a=oue$k;?z2b)>TBMDV@XTVsT~>#JPN; z5a%eZX3;hSqJ08U(4%vNkmKTTh>k&3N1x6S^zajjyAYSJ6Zw-|M-7WB9S~PriNYmZ;!NF|s+E>A02Y5ptcvBbnlgr@E=fGQ!g1=}2e;EVs*Z}@|HTaui z@a_fReY3&)Cxe?ufe#9B%YE?ox4=Ipz{k#jPy7J>X)pMfTJY%)!DoHoUl)VV=YucI z1b4W>i4nYg#ic>;ANP3sia&3FJAWVAzCzX-Je}*Ua5ujj+P+U&bnSvjZdE~wEO93U z?kROrW3%4AyPvat#l83VHj=s+_vaJU#m(qMwU(t+AM{N}nEou2I(yCb*QKjY=BT;z zjn;SR@i2Vj$$(m4{Cn_zCBM;N4-31vMpVu#GQ?NL?zjk%@iS3xzdlIiydv!{9)cLQ QGkyCi*XdC95u3I655ObGq5uE@ literal 0 HcmV?d00001 diff --git a/library/src/androidTest/assets/rawcc/sample.rawcc.0.dump b/library/src/androidTest/assets/rawcc/sample.rawcc.0.dump new file mode 100644 index 0000000000..13e7a93f19 --- /dev/null +++ b/library/src/androidTest/assets/rawcc/sample.rawcc.0.dump @@ -0,0 +1,329 @@ +seekMap: + isSeekable = false + duration = UNSET TIME + getPosition(0) = 0 +numberOfTracks = 1 +track 0: + format: + bitrate = -1 + id = null + containerMimeType = null + sampleMimeType = application/eia-608 + maxInputSize = -1 + width = -1 + height = -1 + frameRate = -1.0 + rotationDegrees = -1 + pixelWidthHeightRatio = -1.0 + channelCount = -1 + sampleRate = -1 + pcmEncoding = -1 + encoderDelay = -1 + encoderPadding = -1 + subsampleOffsetUs = 9223372036854775807 + selectionFlags = 0 + language = null + drmInitData = - + initializationData: + sample count = 75 + sample 0: + time = 37657512133 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 1: + time = 37657545511 + flags = 1 + data = length 2, hash FFFFF6CD + sample 2: + time = 37657578866 + flags = 1 + data = length 2, hash FFFFF6DC + sample 3: + time = 37657612244 + flags = 1 + data = length 2, hash FFFFF65B + sample 4: + time = 37657645600 + flags = 1 + data = length 2, hash FFFFF6CD + sample 5: + time = 37657678977 + flags = 1 + data = length 2, hash FFFFF67B + sample 6: + time = 37657712333 + flags = 1 + data = length 2, hash 2B5 + sample 7: + time = 37657745711 + flags = 1 + data = length 2, hash F5 + sample 8: + time = 37657779066 + flags = 1 + data = length 2, hash FFFFF87A + sample 9: + time = 37657812444 + flags = 1 + data = length 2, hash FFFFF698 + sample 10: + time = 37657845800 + flags = 1 + data = length 2, hash 1F4 + sample 11: + time = 37657879177 + flags = 1 + data = length 2, hash 803 + sample 12: + time = 37657912533 + flags = 1 + data = length 2, hash 1F8 + sample 13: + time = 37657945911 + flags = 1 + data = length 2, hash 117A + sample 14: + time = 37657979266 + flags = 1 + data = length 2, hash 166 + sample 15: + time = 37658012644 + flags = 1 + data = length 2, hash 105A + sample 16: + time = 37658046000 + flags = 1 + data = length 2, hash FCF + sample 17: + time = 37658079377 + flags = 1 + data = length 2, hash 1253 + sample 18: + time = 37658112733 + flags = 1 + data = length 2, hash 11DA + sample 19: + time = 37658146111 + flags = 1 + data = length 2, hash 795 + sample 20: + time = 37658179466 + flags = 1 + data = length 2, hash 103E + sample 21: + time = 37658212844 + flags = 1 + data = length 2, hash 120F + sample 22: + time = 37658246200 + flags = 1 + data = length 2, hash FFFFF698 + sample 23: + time = 37658279577 + flags = 1 + data = length 2, hash 1F4 + sample 24: + time = 37658312933 + flags = 1 + data = length 2, hash FFFFF71B + sample 25: + time = 37658346311 + flags = 1 + data = length 2, hash F91 + sample 26: + time = 37658379666 + flags = 1 + data = length 2, hash 166 + sample 27: + time = 37658413044 + flags = 1 + data = length 2, hash 1023 + sample 28: + time = 37658446400 + flags = 1 + data = length 2, hash 117A + sample 29: + time = 37658479777 + flags = 1 + data = length 2, hash 784 + sample 30: + time = 37658513133 + flags = 1 + data = length 2, hash 1F8 + sample 31: + time = 37658546511 + flags = 1 + data = length 2, hash 10D9 + sample 32: + time = 37658579866 + flags = 1 + data = length 2, hash 935 + sample 33: + time = 37658613244 + flags = 1 + data = length 2, hash 2B5 + sample 34: + time = 37658646600 + flags = 1 + data = length 2, hash F5 + sample 35: + time = 37658679977 + flags = 1 + data = length 2, hash FFFFF87A + sample 36: + time = 37658713333 + flags = 1 + data = length 2, hash FFFFF698 + sample 37: + time = 37658746711 + flags = 1 + data = length 2, hash 1F4 + sample 38: + time = 37658780066 + flags = 1 + data = length 2, hash 793 + sample 39: + time = 37658813444 + flags = 1 + data = length 2, hash FF0 + sample 40: + time = 37658846800 + flags = 1 + data = length 2, hash 16B + sample 41: + time = 37658880177 + flags = 1 + data = length 2, hash 2C0 + sample 42: + time = 37658913533 + flags = 1 + data = length 2, hash FFFFF953 + sample 43: + time = 37658946911 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 44: + time = 37658980266 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 45: + time = 37659013644 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 46: + time = 37659047000 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 47: + time = 37659080377 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 48: + time = 37659113733 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 49: + time = 37659147111 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 50: + time = 37659180466 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 51: + time = 37659213844 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 52: + time = 37659247200 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 53: + time = 37659280577 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 54: + time = 37659313933 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 55: + time = 37659347311 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 56: + time = 37659380666 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 57: + time = 37659414044 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 58: + time = 37659447400 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 59: + time = 37659480777 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 60: + time = 37659514133 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 61: + time = 37659547511 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 62: + time = 37659580866 + flags = 1 + data = length 2, hash FFFFF3C1 + sample 63: + time = 37659614244 + flags = 1 + data = length 2, hash FFFFF6CD + sample 64: + time = 37659647600 + flags = 1 + data = length 2, hash FFFFF6DC + sample 65: + time = 37659680977 + flags = 1 + data = length 2, hash FFFFF65B + sample 66: + time = 37659714333 + flags = 1 + data = length 2, hash FFFFF6CD + sample 67: + time = 37659747711 + flags = 1 + data = length 2, hash FFFFF6FF + sample 68: + time = 37659781066 + flags = 1 + data = length 2, hash FFFFF6AC + sample 69: + time = 37659814444 + flags = 1 + data = length 2, hash FFFFF5FE + sample 70: + time = 37659847800 + flags = 1 + data = length 2, hash FFFFFEF7 + sample 71: + time = 37659881177 + flags = 1 + data = length 2, hash 120C + sample 72: + time = 37659914533 + flags = 1 + data = length 2, hash 1124 + sample 73: + time = 37659947911 + flags = 1 + data = length 2, hash 1A9 + sample 74: + time = 37659981266 + flags = 1 + data = length 2, hash 935 +tracksEnded = true diff --git a/library/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java b/library/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java new file mode 100644 index 0000000000..2f4da01228 --- /dev/null +++ b/library/src/androidTest/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractorTest.java @@ -0,0 +1,38 @@ +/* + * 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 com.google.android.exoplayer2.extractor.rawcc; + +import android.annotation.TargetApi; +import android.test.InstrumentationTestCase; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.testutil.TestUtil; + +/** + * Tests for {@link RawCcExtractor}. + */ +@TargetApi(16) +public final class RawCcExtractorTest extends InstrumentationTestCase { + + public void testRawCcSample() throws Exception { + TestUtil.assertOutput(new TestUtil.ExtractorFactory() { + @Override + public Extractor create() { + return new RawCcExtractor(); + } + }, "rawcc/sample.rawcc", getInstrumentation()); + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java b/library/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java new file mode 100644 index 0000000000..8bbeb0b92a --- /dev/null +++ b/library/src/main/java/com/google/android/exoplayer2/extractor/rawcc/RawCcExtractor.java @@ -0,0 +1,172 @@ +/* + * 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 com.google.android.exoplayer2.extractor.rawcc; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Format; +import com.google.android.exoplayer2.ParserException; +import com.google.android.exoplayer2.extractor.Extractor; +import com.google.android.exoplayer2.extractor.ExtractorInput; +import com.google.android.exoplayer2.extractor.ExtractorOutput; +import com.google.android.exoplayer2.extractor.PositionHolder; +import com.google.android.exoplayer2.extractor.SeekMap; +import com.google.android.exoplayer2.extractor.TrackOutput; +import com.google.android.exoplayer2.util.MimeTypes; +import com.google.android.exoplayer2.util.ParsableByteArray; +import com.google.android.exoplayer2.util.Util; + +import java.io.IOException; + +/** + * Extracts EIA-608 data from a RawCC file + */ +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 = Util.getIntegerCodeForString("RCC\u0001"); + 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 ParsableByteArray dataScratch; + + private ExtractorOutput extractorOutput; + private TrackOutput trackOutput; + + private int parserState; + private int version; + private long timestampUs; + private int remainingSampleCount; + private int sampleBytesWritten; + + public RawCcExtractor() { + dataScratch = new ParsableByteArray(SCRATCH_SIZE); + parserState = STATE_READING_HEADER; + } + + @Override + public void init(ExtractorOutput output) { + this.extractorOutput = output; + extractorOutput.seekMap(new SeekMap.Unseekable(C.UNSET_TIME_US)); + trackOutput = extractorOutput.track(0); + extractorOutput.endTracks(); + + trackOutput.format(Format.createTextSampleFormat(null, MimeTypes.APPLICATION_EIA608, + null, Format.NO_VALUE, 0, null, null)); + } + + @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: + parseHeader(input); + parserState = STATE_READING_TIMESTAMP_AND_COUNT; + 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) { + parserState = STATE_READING_HEADER; + } + + @Override + public void release() { + // Do nothing + } + + private void parseHeader(ExtractorInput input) throws IOException, InterruptedException { + dataScratch.reset(); + input.readFully(dataScratch.data, 0, HEADER_SIZE); + if (dataScratch.readInt() != HEADER_ID) { + throw new IOException("Input not RawCC"); + } + version = dataScratch.readUnsignedByte(); + // no versions use the flag fields yet + } + + 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); + + // only accept EIA-608 packets which have validity (6th bit) == 1 and + // type (7-8th bits) == 0; i.e. ccDataPkt[0] == 0bXXXXX100 + int ccValidityAndType = dataScratch.readUnsignedByte() & 0x07; + if (ccValidityAndType == 0x04) { + trackOutput.sampleData(dataScratch, 2); + sampleBytesWritten += 2; + } + } + + if (sampleBytesWritten > 0) { + trackOutput.sampleMetadata(timestampUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null); + } + } + +} diff --git a/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java b/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java index fdb520e0bb..93c601ea94 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/chunk/ChunkExtractorWrapper.java @@ -50,10 +50,12 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput private final Extractor extractor; private final Format manifestFormat; private final boolean preferManifestDrmInitData; + private final boolean resendFormatOnInit; private boolean extractorInitialized; private SingleTrackMetadataOutput metadataOutput; private TrackOutput trackOutput; + private Format sentFormat; // Accessed only on the loader thread. private boolean seenTrack; @@ -67,9 +69,24 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput */ public ChunkExtractorWrapper(Extractor extractor, Format manifestFormat, boolean preferManifestDrmInitData) { + this(extractor, manifestFormat, preferManifestDrmInitData, true); + } + + /** + * @param extractor The extractor to wrap. + * @param manifestFormat A manifest defined {@link Format} whose data should be merged into any + * sample {@link Format} output from the {@link Extractor}. + * @param preferManifestDrmInitData Whether {@link DrmInitData} defined in {@code manifestFormat} + * should be preferred when the sample and manifest {@link Format}s are merged. + * @param resendFormatOnInit Whether the extractor should resend the previous {@link Format} when + * it is initialized via {@link #init(SingleTrackMetadataOutput, TrackOutput)}. + */ + public ChunkExtractorWrapper(Extractor extractor, Format manifestFormat, + boolean preferManifestDrmInitData, boolean resendFormatOnInit) { this.extractor = extractor; this.manifestFormat = manifestFormat; this.preferManifestDrmInitData = preferManifestDrmInitData; + this.resendFormatOnInit = resendFormatOnInit; } /** @@ -87,6 +104,9 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput extractorInitialized = true; } else { extractor.seek(0); + if (resendFormatOnInit && sentFormat != null) { + trackOutput.format(sentFormat); + } } } @@ -127,8 +147,8 @@ public final class ChunkExtractorWrapper implements ExtractorOutput, TrackOutput @Override public void format(Format format) { - trackOutput.format(format.copyWithManifestFormatInfo(manifestFormat, - preferManifestDrmInitData)); + sentFormat = format.copyWithManifestFormatInfo(manifestFormat, preferManifestDrmInitData); + trackOutput.format(sentFormat); } @Override diff --git a/library/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java b/library/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java index fc615f5e1f..254781af0c 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/dash/DefaultDashChunkSource.java @@ -15,12 +15,15 @@ */ package com.google.android.exoplayer2.source.dash; +import android.os.SystemClock; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.extractor.ChunkIndex; +import com.google.android.exoplayer2.extractor.Extractor; import com.google.android.exoplayer2.extractor.SeekMap; import com.google.android.exoplayer2.extractor.mkv.MatroskaExtractor; import com.google.android.exoplayer2.extractor.mp4.FragmentedMp4Extractor; +import com.google.android.exoplayer2.extractor.rawcc.RawCcExtractor; import com.google.android.exoplayer2.source.BehindLiveWindowException; import com.google.android.exoplayer2.source.chunk.Chunk; import com.google.android.exoplayer2.source.chunk.ChunkExtractorWrapper; @@ -41,9 +44,6 @@ import com.google.android.exoplayer2.upstream.HttpDataSource.InvalidResponseCode import com.google.android.exoplayer2.upstream.Loader; import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.Util; - -import android.os.SystemClock; - import java.io.IOException; import java.util.List; @@ -384,12 +384,25 @@ public class DefaultDashChunkSource implements DashChunkSource { this.periodDurationUs = periodDurationUs; this.representation = representation; String containerMimeType = representation.format.containerMimeType; - // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, - // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. - extractorWrapper = mimeTypeIsRawText(containerMimeType) ? null : new ChunkExtractorWrapper( - mimeTypeIsWebm(containerMimeType) ? new MatroskaExtractor() - : new FragmentedMp4Extractor(), - representation.format, true /* preferManifestDrmInitData */); + if (mimeTypeIsRawText(containerMimeType)) { + extractorWrapper = null; + } else { + boolean resendFormatOnInit = false; + Extractor extractor; + if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) { + extractor = new RawCcExtractor(); + resendFormatOnInit = true; + } else if (mimeTypeIsWebm(containerMimeType)) { + extractor = new MatroskaExtractor(); + } else { + extractor = new FragmentedMp4Extractor(); + } + // Prefer drmInitData obtained from the manifest over drmInitData obtained from the stream, + // as per DASH IF Interoperability Recommendations V3.0, 7.5.3. + extractorWrapper = new ChunkExtractorWrapper(extractor, + representation.format, true /* preferManifestDrmInitData */, + resendFormatOnInit); + } segmentIndex = representation.getIndex(); } diff --git a/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java b/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java index da66157092..5fc9c27705 100644 --- a/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java +++ b/library/src/main/java/com/google/android/exoplayer2/source/dash/manifest/DashManifestParser.java @@ -299,7 +299,8 @@ public class DashManifestParser extends DefaultHandler return C.TRACK_TYPE_VIDEO; } else if (MimeTypes.isAudio(sampleMimeType)) { return C.TRACK_TYPE_AUDIO; - } else if (mimeTypeIsRawText(sampleMimeType)) { + } else if (mimeTypeIsRawText(sampleMimeType) + || MimeTypes.APPLICATION_RAWCC.equals(format.containerMimeType)) { return C.TRACK_TYPE_TEXT; } return C.TRACK_TYPE_UNKNOWN; @@ -650,6 +651,12 @@ public class DashManifestParser extends DefaultHandler return MimeTypes.getAudioMediaMimeType(codecs); } else if (MimeTypes.isVideo(containerMimeType)) { return MimeTypes.getVideoMediaMimeType(codecs); + } else if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) { + // We currently only support EIA-608 through RawCC + if (codecs != null && codecs.contains("eia608")) { + return MimeTypes.APPLICATION_EIA608; + } + return null; } else if (mimeTypeIsRawText(containerMimeType)) { return containerMimeType; } else if (MimeTypes.APPLICATION_MP4.equals(containerMimeType)) { diff --git a/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java b/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java index c34d9c1da2..f99561fc22 100644 --- a/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java +++ b/library/src/main/java/com/google/android/exoplayer2/util/MimeTypes.java @@ -66,6 +66,7 @@ public final class MimeTypes { public static final String APPLICATION_M3U8 = BASE_TYPE_APPLICATION + "/x-mpegURL"; public static final String APPLICATION_TX3G = BASE_TYPE_APPLICATION + "/x-quicktime-tx3g"; public static final String APPLICATION_MP4VTT = BASE_TYPE_APPLICATION + "/x-mp4vtt"; + public static final String APPLICATION_RAWCC = BASE_TYPE_APPLICATION + "/x-rawcc"; public static final String APPLICATION_VOBSUB = BASE_TYPE_APPLICATION + "/vobsub"; public static final String APPLICATION_PGS = BASE_TYPE_APPLICATION + "/pgs";