Remove ExoPlayer's RawCcExtractor

RawCC is a Google-internal subtitle format, and is no longer used with
ExoPlayer.

PiperOrigin-RevId: 446950691
This commit is contained in:
ibaker 2022-05-06 12:05:37 +01:00 committed by Ian Baker
parent e9919f6da1
commit 4f616d6003
7 changed files with 18 additions and 259 deletions

View File

@ -25,14 +25,16 @@
* Audio:
* Use LG AC3 audio decoder advertising non-standard MIME type.
* Ad playback / IMA:
* Decrease ad polling rate from every 100ms to every 200ms, to line up with
Media Rating Council (MRC) recommendations.
* Decrease ad polling rate from every 100ms to every 200ms, to line up
with Media Rating Council (MRC) recommendations.
* Text:
* SSA: Support `OutlineColour` style setting when `BorderStyle == 3` (i.e.
`OutlineColour` sets the background of the cue)
([#8435](https://github.com/google/ExoPlayer/issues/8435)).
* CEA-708: Parse data into multiple service blocks and ignore blocks not
associated with the currently selected service number.
* Remove `RawCcExtractor`, which was only used to handle a Google-internal
subtitle format.
* Extractors:
* Matroska: Parse `DiscardPadding` for Opus tracks.
* Parse bitrates from `esds` boxes.
@ -60,16 +62,16 @@
re-enables audio passthrough for DTS streams
([#10159](https://github.com/google/ExoPlayer/issues/10159)).
* HLS:
* Fallback to chunkful preparation if the playlist CODECS attribute
does not contain the audio codec
* Fallback to chunkful preparation if the playlist CODECS attribute does
not contain the audio codec
([#10065](https://github.com/google/ExoPlayer/issues/10065)).
* RTSP:
* Add RTP reader for MPEG4
([#35](https://github.com/androidx/media/pull/35)).
* Add RTP reader for HEVC
([#36](https://github.com/androidx/media/pull/36)).
* Add RTP reader for AMR. Currently only mono-channel, non-interleaved
AMR streams are supported. Compound AMR RTP payload is not supported.
* Add RTP reader for AMR. Currently only mono-channel, non-interleaved AMR
streams are supported. Compound AMR RTP payload is not supported.
([#46](https://github.com/androidx/media/pull/46))
* Add RTP reader for VP8
([#47](https://github.com/androidx/media/pull/47)).
@ -82,15 +84,19 @@
* Throw checked exception when parsing RTSP timing
([#10165](https://github.com/google/ExoPlayer/issues/10165)).
* Session:
* Fix NPE in MediaControllerImplLegacy
([#59](https://github.com/androidx/media/pull/59))
* Update session position info on timeline
change([#51](https://github.com/androidx/media/issues/51))
* Data sources:
* Rename `DummyDataSource` to `PlaceHolderDataSource`.
* Workaround OkHttp interrupt handling.
* Remove deprecated symbols:
* Remove `Player.Listener.onTracksChanged`. Use
`Player.Listener.onTracksInfoChanged` instead.
* Remove `Player.getCurrentTrackGroups` and

View File

@ -36,7 +36,6 @@ import androidx.media3.extractor.SeekMap;
import androidx.media3.extractor.TrackOutput;
import androidx.media3.extractor.mkv.MatroskaExtractor;
import androidx.media3.extractor.mp4.FragmentedMp4Extractor;
import androidx.media3.extractor.rawcc.RawCcExtractor;
import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
@ -58,13 +57,8 @@ public final class BundledChunkExtractor implements ExtractorOutput, ChunkExtrac
@Nullable String containerMimeType = format.containerMimeType;
Extractor extractor;
if (MimeTypes.isText(containerMimeType)) {
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
// RawCC is special because it's a text specific container format.
extractor = new RawCcExtractor(format);
} else {
// All other text types are raw formats that do not need an extractor.
return null;
}
// Text types do not need an extractor.
return null;
} else if (MimeTypes.isMatroska(containerMimeType)) {
extractor = new MatroskaExtractor(MatroskaExtractor.FLAG_DISABLE_SEEK_FOR_CUES);
} else {

View File

@ -1675,11 +1675,7 @@ public class DashManifestParser extends DefaultHandler
} else if (MimeTypes.isVideo(containerMimeType)) {
return MimeTypes.getVideoMediaMimeType(codecs);
} else if (MimeTypes.isText(containerMimeType)) {
if (MimeTypes.APPLICATION_RAWCC.equals(containerMimeType)) {
// RawCC is special because it's a text specific container format.
return MimeTypes.getTextMediaMimeType(codecs);
}
// All other text types are raw formats.
// Text types are raw formats.
return containerMimeType;
} else if (MimeTypes.isImage(containerMimeType)) {
// Image types are raw formats.

View File

@ -274,14 +274,6 @@ public class DashManifestParserTest {
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
Format format = adaptationSets.get(0).representations.get(0).format;
assertThat(format.containerMimeType).isEqualTo(MimeTypes.APPLICATION_RAWCC);
assertThat(format.sampleMimeType).isEqualTo(MimeTypes.APPLICATION_CEA608);
assertThat(format.codecs).isEqualTo("cea608");
assertThat(format.roleFlags).isEqualTo(C.ROLE_FLAG_SUBTITLE | C.ROLE_FLAG_MAIN);
assertThat(format.selectionFlags).isEqualTo(0);
assertThat(adaptationSets.get(0).type).isEqualTo(C.TRACK_TYPE_TEXT);
format = adaptationSets.get(1).representations.get(0).format;
assertThat(format.containerMimeType).isEqualTo(MimeTypes.APPLICATION_MP4);
assertThat(format.sampleMimeType).isEqualTo(MimeTypes.APPLICATION_TTML);
assertThat(format.codecs).isEqualTo("stpp.ttml.im1t");
@ -291,11 +283,11 @@ public class DashManifestParserTest {
// Ensure that forced-subtitle and forced_subtitle are both parsed as a 'forced' text track.
// https://github.com/google/ExoPlayer/issues/9727
format = adaptationSets.get(2).representations.get(0).format;
format = adaptationSets.get(1).representations.get(0).format;
assertThat(format.roleFlags).isEqualTo(C.ROLE_FLAG_SUBTITLE);
assertThat(format.selectionFlags).isEqualTo(C.SELECTION_FLAG_FORCED);
format = adaptationSets.get(3).representations.get(0).format;
format = adaptationSets.get(2).representations.get(0).format;
assertThat(format.containerMimeType).isEqualTo(MimeTypes.APPLICATION_TTML);
assertThat(format.sampleMimeType).isEqualTo(MimeTypes.APPLICATION_TTML);
assertThat(format.codecs).isNull();
@ -627,11 +619,10 @@ public class DashManifestParserTest {
assertThat(manifest.getPeriodCount()).isEqualTo(1);
List<AdaptationSet> adaptationSets = manifest.getPeriod(0).adaptationSets;
assertThat(adaptationSets).hasSize(4);
assertThat(adaptationSets).hasSize(3);
assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(0))).isEqualTo(C.TIME_UNSET);
assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(1))).isEqualTo(C.TIME_UNSET);
assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(2))).isEqualTo(C.TIME_UNSET);
assertThat(getAvailabilityTimeOffsetUs(adaptationSets.get(3))).isEqualTo(C.TIME_UNSET);
}
@Test

View File

@ -1,172 +0,0 @@
/*
* 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 androidx.media3.extractor.rawcc;
import androidx.media3.common.C;
import androidx.media3.common.Format;
import androidx.media3.common.ParserException;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.extractor.Extractor;
import androidx.media3.extractor.ExtractorInput;
import androidx.media3.extractor.ExtractorOutput;
import androidx.media3.extractor.PositionHolder;
import androidx.media3.extractor.SeekMap;
import androidx.media3.extractor.TrackOutput;
import java.io.IOException;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/** Extracts data from the RawCC container format. */
@UnstableApi
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 @MonotonicNonNull 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);
trackOutput.format(format);
output.endTracks();
}
@Override
public boolean sniff(ExtractorInput input) throws IOException {
dataScratch.reset(/* limit= */ HEADER_SIZE);
input.peekFully(dataScratch.getData(), 0, HEADER_SIZE);
return dataScratch.readInt() == HEADER_ID;
}
@Override
public int read(ExtractorInput input, PositionHolder seekPosition) throws IOException {
Assertions.checkStateNotNull(trackOutput); // Asserts that init has been called.
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 {
dataScratch.reset(/* limit= */ HEADER_SIZE);
if (input.readFully(dataScratch.getData(), 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 {
if (version == 0) {
dataScratch.reset(/* limit= */ TIMESTAMP_SIZE_V0 + 1);
if (!input.readFully(dataScratch.getData(), 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) {
dataScratch.reset(/* limit= */ TIMESTAMP_SIZE_V1 + 1);
if (!input.readFully(dataScratch.getData(), 0, TIMESTAMP_SIZE_V1 + 1, true)) {
return false;
}
timestampUs = dataScratch.readLong();
} else {
throw ParserException.createForMalformedContainer(
"Unsupported version number: " + version, /* cause= */ null);
}
remainingSampleCount = dataScratch.readUnsignedByte();
sampleBytesWritten = 0;
return true;
}
@RequiresNonNull("trackOutput")
private void parseSamples(ExtractorInput input) throws IOException {
for (; remainingSampleCount > 0; remainingSampleCount--) {
dataScratch.reset(/* limit= */ 3);
input.readFully(dataScratch.getData(), 0, 3);
trackOutput.sampleData(dataScratch, 3);
sampleBytesWritten += 3;
}
if (sampleBytesWritten > 0) {
trackOutput.sampleMetadata(timestampUs, C.BUFFER_FLAG_KEY_FRAME, sampleBytesWritten, 0, null);
}
}
}

View File

@ -1,49 +0,0 @@
/*
* 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 androidx.media3.extractor.rawcc;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.test.utils.ExtractorAsserts;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.ParameterizedRobolectricTestRunner;
/** Tests for {@link RawCcExtractor}. */
@RunWith(ParameterizedRobolectricTestRunner.class)
public final class RawCcExtractorTest {
@ParameterizedRobolectricTestRunner.Parameters(name = "{0}")
public static ImmutableList<ExtractorAsserts.SimulationConfig> params() {
return ExtractorAsserts.configs();
}
@ParameterizedRobolectricTestRunner.Parameter(0)
public ExtractorAsserts.SimulationConfig simulationConfig;
@Test
public void rawCcSample() throws Exception {
Format format =
new Format.Builder()
.setSampleMimeType(MimeTypes.APPLICATION_CEA608)
.setCodecs("cea608")
.setAccessibilityChannel(1)
.build();
ExtractorAsserts.assertBehavior(
() -> new RawCcExtractor(format), "media/rawcc/sample.rawcc", simulationConfig);
}
}

View File

@ -6,13 +6,6 @@
<S d="1000"/>
</SegmentTimeline>
</SegmentTemplate>
<AdaptationSet id="0" mimeType="application/x-rawcc" subsegmentAlignment="true">
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="subtitle"/>
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="main"/>
<Representation id="0" codecs="cea608" bandwidth="16">
<BaseURL>https://test.com/0</BaseURL>
</Representation>
</AdaptationSet>
<AdaptationSet id="0" mimeType="application/mp4" subsegmentAlignment="true">
<Role schemeIdUri="urn:mpeg:DASH:role:2011" value="forced-subtitle"/>
<Representation id="0" codecs="stpp.ttml.im1t" bandwidth="16">