diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 7c87e71a8e..a9ead31b88 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -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 diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java index 924eb0c4f0..99c15aa65f 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/source/chunk/BundledChunkExtractor.java @@ -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 { diff --git a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java index 7f5ef63373..36c3695193 100644 --- a/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java +++ b/libraries/exoplayer_dash/src/main/java/androidx/media3/exoplayer/dash/manifest/DashManifestParser.java @@ -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. diff --git a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java index 1238d756fd..667f55c197 100644 --- a/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java +++ b/libraries/exoplayer_dash/src/test/java/androidx/media3/exoplayer/dash/manifest/DashManifestParserTest.java @@ -274,14 +274,6 @@ public class DashManifestParserTest { List 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 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 diff --git a/libraries/extractor/src/main/java/androidx/media3/extractor/rawcc/RawCcExtractor.java b/libraries/extractor/src/main/java/androidx/media3/extractor/rawcc/RawCcExtractor.java deleted file mode 100644 index 45f80353d5..0000000000 --- a/libraries/extractor/src/main/java/androidx/media3/extractor/rawcc/RawCcExtractor.java +++ /dev/null @@ -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); - } - } -} diff --git a/libraries/extractor/src/test/java/androidx/media3/extractor/rawcc/RawCcExtractorTest.java b/libraries/extractor/src/test/java/androidx/media3/extractor/rawcc/RawCcExtractorTest.java deleted file mode 100644 index 4d2ef45ef0..0000000000 --- a/libraries/extractor/src/test/java/androidx/media3/extractor/rawcc/RawCcExtractorTest.java +++ /dev/null @@ -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 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); - } -} diff --git a/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text index 9af9e24915..adadafaef5 100644 --- a/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text +++ b/libraries/test_data/src/test/assets/media/mpd/sample_mpd_text @@ -6,13 +6,6 @@ - - - - - https://test.com/0 - -