From 5bead4acbbe46ee382c61a830af02b6fb687eedd Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 10 Dec 2019 11:26:41 +0000 Subject: [PATCH 01/27] Make DefaultTimeBar exclude itself for gestures Issue: #6685 PiperOrigin-RevId: 284736041 --- RELEASENOTES.md | 5 +++++ .../android/exoplayer2/ui/DefaultTimeBar.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5add56ca08..0642a9a921 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,10 @@ # Release notes # +### 2.11.1 (2019-12-20) ### + +* UI: Exclude `DefaultTimeBar` region from system gesture detection + ([#6685](https://github.com/google/ExoPlayer/issues/6685)). + ### 2.11.0 (2019-12-11) ### * Core library: diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java index 8b737bc006..89bcaf84bc 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/DefaultTimeBar.java @@ -36,12 +36,15 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import androidx.annotation.ColorInt; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; +import java.util.Collections; import java.util.Formatter; import java.util.Locale; import java.util.concurrent.CopyOnWriteArraySet; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** * A time bar that shows a current position, buffered position, duration and ad markers. @@ -199,6 +202,7 @@ public class DefaultTimeBar extends View implements TimeBar { private int keyCountIncrement; private long keyTimeIncrement; private int lastCoarseScrubXPosition; + @MonotonicNonNull private Rect lastExclusionRectangle; private boolean scrubbing; private long scrubPosition; @@ -604,6 +608,9 @@ public class DefaultTimeBar extends View implements TimeBar { seekBounds.set(seekLeft, barY, seekRight, barY + touchTargetHeight); progressBar.set(seekBounds.left + scrubberPadding, progressY, seekBounds.right - scrubberPadding, progressY + barHeight); + if (Util.SDK_INT >= 29) { + setSystemGestureExclusionRectsV29(width, height); + } update(); } @@ -834,6 +841,18 @@ public class DefaultTimeBar extends View implements TimeBar { } } + @RequiresApi(29) + private void setSystemGestureExclusionRectsV29(int width, int height) { + if (lastExclusionRectangle != null + && lastExclusionRectangle.width() == width + && lastExclusionRectangle.height() == height) { + // Allocating inside onLayout is considered a DrawAllocation lint error, so avoid if possible. + return; + } + lastExclusionRectangle = new Rect(/* left= */ 0, /* top= */ 0, width, height); + setSystemGestureExclusionRects(Collections.singletonList(lastExclusionRectangle)); + } + private String getProgressText() { return Util.getStringForTime(formatBuilder, formatter, position); } From 53d30d80a599bcc0f64ceeec0a40916cc587dedb Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 13 Dec 2019 10:21:32 +0000 Subject: [PATCH 02/27] Fix bug where C.TIME_UNSET was used for calcutations. The presentationTimeOffsetMs may be C.TIME_UNSET for VOD content and shouldn't be used in calculations for the windowStartTime. PiperOrigin-RevId: 285363095 --- .../android/exoplayer2/source/dash/DashMediaSource.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java index 352131d70a..3f179d0e7e 100644 --- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java +++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/DashMediaSource.java @@ -1010,8 +1010,13 @@ public final class DashMediaSource extends BaseMediaSource { windowDurationUs / 2); } } - long windowStartTimeMs = manifest.availabilityStartTimeMs - + manifest.getPeriod(0).startMs + C.usToMs(currentStartTimeUs); + long windowStartTimeMs = C.TIME_UNSET; + if (manifest.availabilityStartTimeMs != C.TIME_UNSET) { + windowStartTimeMs = + manifest.availabilityStartTimeMs + + manifest.getPeriod(0).startMs + + C.usToMs(currentStartTimeUs); + } DashTimeline timeline = new DashTimeline( manifest.availabilityStartTimeMs, From 4653592d0eb61f8289617026edda5c57bb506405 Mon Sep 17 00:00:00 2001 From: ibaker Date: Fri, 13 Dec 2019 13:02:58 +0000 Subject: [PATCH 03/27] Propagate HTTP request headers through CacheDataSource This has been broken since https://github.com/google/ExoPlayer/commit/c3d6be3afdd7c0ca68dba15e443bc64aa3f61073 and broken for ICY (where I noticed the problem) since https://github.com/google/ExoPlayer/commit/5695bae9d8fde5e156fd38fa552e266c5611c71f. ICY symptom is that we see no repeated metadata, because the Icy-MetaData:1 header doesn't make it to the server so we never get back icy-metaint. PiperOrigin-RevId: 285379234 --- RELEASENOTES.md | 1 + .../upstream/cache/CacheDataSource.java | 31 ++++++++++++++-- .../upstream/cache/CacheDataSourceTest.java | 36 ++++++++++++++++--- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0642a9a921..198de62178 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -4,6 +4,7 @@ * UI: Exclude `DefaultTimeBar` region from system gesture detection ([#6685](https://github.com/google/ExoPlayer/issues/6685)). +* Propagate HTTP request headers through `CacheDataSource`. ### 2.11.0 (2019-12-11) ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java index 541c3b2d9d..94ec2c6dff 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/cache/CacheDataSource.java @@ -138,7 +138,8 @@ public final class CacheDataSource implements DataSource { @Nullable private Uri actualUri; @HttpMethod private int httpMethod; @Nullable private byte[] httpBody; - private int flags; + private Map httpRequestHeaders = Collections.emptyMap(); + @DataSpec.Flags private int flags; @Nullable private String key; private long readPosition; private long bytesRemaining; @@ -263,6 +264,7 @@ public final class CacheDataSource implements DataSource { actualUri = getRedirectedUriOrDefault(cache, key, /* defaultUri= */ uri); httpMethod = dataSpec.httpMethod; httpBody = dataSpec.httpBody; + httpRequestHeaders = dataSpec.httpRequestHeaders; flags = dataSpec.flags; readPosition = dataSpec.position; @@ -353,6 +355,10 @@ public final class CacheDataSource implements DataSource { actualUri = null; httpMethod = DataSpec.HTTP_METHOD_GET; httpBody = null; + httpRequestHeaders = Collections.emptyMap(); + flags = 0; + readPosition = 0; + key = null; notifyBytesRead(); try { closeCurrentSource(); @@ -399,7 +405,15 @@ public final class CacheDataSource implements DataSource { nextDataSource = upstreamDataSource; nextDataSpec = new DataSpec( - uri, httpMethod, httpBody, readPosition, readPosition, bytesRemaining, key, flags); + uri, + httpMethod, + httpBody, + readPosition, + readPosition, + bytesRemaining, + key, + flags, + httpRequestHeaders); } else if (nextSpan.isCached) { // Data is cached, read from cache. Uri fileUri = Uri.fromFile(nextSpan.file); @@ -408,6 +422,8 @@ public final class CacheDataSource implements DataSource { if (bytesRemaining != C.LENGTH_UNSET) { length = Math.min(length, bytesRemaining); } + // Deliberately skip the HTTP-related parameters since we're reading from the cache, not + // making an HTTP request. nextDataSpec = new DataSpec(fileUri, readPosition, filePosition, length, key, flags); nextDataSource = cacheReadDataSource; } else { @@ -422,7 +438,16 @@ public final class CacheDataSource implements DataSource { } } nextDataSpec = - new DataSpec(uri, httpMethod, httpBody, readPosition, readPosition, length, key, flags); + new DataSpec( + uri, + httpMethod, + httpBody, + readPosition, + readPosition, + length, + key, + flags, + httpRequestHeaders); if (cacheWriteDataSource != null) { nextDataSource = cacheWriteDataSource; } else { diff --git a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java index 83104119ad..27438fcac3 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/upstream/cache/CacheDataSourceTest.java @@ -34,6 +34,8 @@ import com.google.android.exoplayer2.util.Util; import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.NavigableSet; import org.junit.After; import org.junit.Before; @@ -48,20 +50,27 @@ public final class CacheDataSourceTest { private static final int CACHE_FRAGMENT_SIZE = 3; private static final String DATASPEC_KEY = "dataSpecKey"; + // Test data private Uri testDataUri; + private Map httpRequestHeaders; private DataSpec unboundedDataSpec; private DataSpec boundedDataSpec; private DataSpec unboundedDataSpecWithKey; private DataSpec boundedDataSpecWithKey; private String defaultCacheKey; private String customCacheKey; + + // Dependencies of SUT private CacheKeyFactory cacheKeyFactory; private File tempFolder; private SimpleCache cache; + private FakeDataSource upstreamDataSource; @Before public void setUp() throws Exception { testDataUri = Uri.parse("https://www.test.com/data"); + httpRequestHeaders = new HashMap<>(); + httpRequestHeaders.put("Test-key", "Test-val"); unboundedDataSpec = buildDataSpec(/* unbounded= */ true, /* key= */ null); boundedDataSpec = buildDataSpec(/* unbounded= */ false, /* key= */ null); unboundedDataSpecWithKey = buildDataSpec(/* unbounded= */ true, DATASPEC_KEY); @@ -69,9 +78,11 @@ public final class CacheDataSourceTest { defaultCacheKey = CacheUtil.DEFAULT_CACHE_KEY_FACTORY.buildCacheKey(unboundedDataSpec); customCacheKey = "customKey." + defaultCacheKey; cacheKeyFactory = dataSpec -> customCacheKey; + tempFolder = Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest"); cache = new SimpleCache(tempFolder, new NoOpCacheEvictor()); + upstreamDataSource = new FakeDataSource(); } @After @@ -111,6 +122,19 @@ public final class CacheDataSourceTest { assertCacheAndRead(boundedDataSpec, /* unknownLength= */ false); } + @Test + public void testPropagatesHttpHeadersUpstream() throws Exception { + CacheDataSource cacheDataSource = + createCacheDataSource(/* setReadException= */ false, /* unknownLength= */ false); + DataSpec dataSpec = buildDataSpec(/* position= */ 2, /* length= */ 5); + cacheDataSource.open(dataSpec); + + DataSpec[] upstreamDataSpecs = upstreamDataSource.getAndClearOpenedDataSpecs(); + + assertThat(upstreamDataSpecs).hasLength(1); + assertThat(upstreamDataSpecs[0].httpRequestHeaders).isEqualTo(this.httpRequestHeaders); + } + @Test public void testUnsatisfiableRange() throws Exception { // Bounded request but the content length is unknown. This forces all data to be cached but not @@ -572,9 +596,8 @@ public final class CacheDataSourceTest { @CacheDataSource.Flags int flags, CacheDataSink cacheWriteDataSink, CacheKeyFactory cacheKeyFactory) { - FakeDataSource upstream = new FakeDataSource(); FakeData fakeData = - upstream + upstreamDataSource .getDataSet() .newDefaultData() .setSimulateUnknownLength(unknownLength) @@ -584,7 +607,7 @@ public final class CacheDataSourceTest { } return new CacheDataSource( cache, - upstream, + upstreamDataSource, new FileDataSource(), cacheWriteDataSink, flags, @@ -602,6 +625,11 @@ public final class CacheDataSourceTest { private DataSpec buildDataSpec(long position, long length, @Nullable String key) { return new DataSpec( - testDataUri, position, length, key, DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION); + testDataUri, + position, + length, + key, + DataSpec.FLAG_ALLOW_CACHE_FRAGMENTATION, + httpRequestHeaders); } } From d8951a2a38e06acca52b69383168627f32144898 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 13 Dec 2019 18:16:59 +0000 Subject: [PATCH 04/27] Add an additional sanity check to FakeExtractorOutput PiperOrigin-RevId: 285422885 --- .../android/exoplayer2/testutil/FakeExtractorOutput.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java index 4022a0ccc1..9394848198 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertWithMessage; import android.content.Context; import android.util.SparseArray; +import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.extractor.ExtractorOutput; import com.google.android.exoplayer2.extractor.SeekMap; import java.io.File; @@ -67,6 +68,9 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab @Override public void seekMap(SeekMap seekMap) { + if (seekMap.isSeekable() && seekMap.getDurationUs() == C.TIME_UNSET) { + throw new IllegalStateException("SeekMap cannot be seekable and have an unknown duration"); + } this.seekMap = seekMap; } From 250a5deab503c10da06c0de918b7ce1f20943b92 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 16 Dec 2019 11:17:11 +0000 Subject: [PATCH 05/27] Add more SeekMap assertions, and "fix" MatroskaExtractor In MatroskaExtractor, if the last cue time exceeds the duration specified in the header, then we end up generating a negative duration chunk as the last item in the SeekMap. We should probably not do this, so drop it instead. Note: Matroska does have a CueDuration element, but it's not used in the one problematic file I've found. PiperOrigin-RevId: 285738418 --- .../extractor/mkv/MatroskaExtractor.java | 10 ++++ .../src/test/assets/mkv/sample.mkv.0.dump | 2 +- .../src/test/assets/mkv/sample.mkv.1.dump | 52 ++++++++----------- .../src/test/assets/mkv/sample.mkv.2.dump | 30 ++++------- .../src/test/assets/mkv/sample.mkv.3.dump | 2 +- .../testutil/FakeExtractorOutput.java | 14 ++++- 6 files changed, 57 insertions(+), 53 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java index 403f6c3d41..b30fbf105e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mkv/MatroskaExtractor.java @@ -1635,6 +1635,16 @@ public class MatroskaExtractor implements Extractor { sizes[cuePointsSize - 1] = (int) (segmentContentPosition + segmentContentSize - offsets[cuePointsSize - 1]); durationsUs[cuePointsSize - 1] = durationUs - timesUs[cuePointsSize - 1]; + + long lastDurationUs = durationsUs[cuePointsSize - 1]; + if (lastDurationUs <= 0) { + Log.w(TAG, "Discarding last cue point with unexpected duration: " + lastDurationUs); + sizes = Arrays.copyOf(sizes, sizes.length - 1); + offsets = Arrays.copyOf(offsets, offsets.length - 1); + durationsUs = Arrays.copyOf(durationsUs, durationsUs.length - 1); + timesUs = Arrays.copyOf(timesUs, timesUs.length - 1); + } + cueTimesUs = null; cueClusterPositions = null; return new ChunkIndex(sizes, offsets, durationsUs, timesUs); diff --git a/library/core/src/test/assets/mkv/sample.mkv.0.dump b/library/core/src/test/assets/mkv/sample.mkv.0.dump index 847799396d..d91f845199 100644 --- a/library/core/src/test/assets/mkv/sample.mkv.0.dump +++ b/library/core/src/test/assets/mkv/sample.mkv.0.dump @@ -1,6 +1,6 @@ seekMap: isSeekable = true - duration = 1072000 + duration = 1104000 getPosition(0) = [[timeUs=67000, position=5576]] numberOfTracks = 2 track 1: diff --git a/library/core/src/test/assets/mkv/sample.mkv.1.dump b/library/core/src/test/assets/mkv/sample.mkv.1.dump index 5caa638437..d9013a762e 100644 --- a/library/core/src/test/assets/mkv/sample.mkv.1.dump +++ b/library/core/src/test/assets/mkv/sample.mkv.1.dump @@ -1,6 +1,6 @@ seekMap: isSeekable = true - duration = 1072000 + duration = 1104000 getPosition(0) = [[timeUs=67000, position=5576]] numberOfTracks = 2 track 1: @@ -27,93 +27,85 @@ track 1: initializationData: data = length 30, hash F6F3D010 data = length 10, hash 7A0D0F2B - total output bytes = 30995 - sample count = 22 + total output bytes = 29422 + sample count = 20 sample 0: - time = 334000 - flags = 0 - data = length 953, hash 7160C661 - sample 1: - time = 300000 - flags = 0 - data = length 620, hash 7A7AE07C - sample 2: time = 367000 flags = 0 data = length 405, hash 5CC7F4E7 - sample 3: + sample 1: time = 500000 flags = 0 data = length 4852, hash 9DB6979D - sample 4: + sample 2: time = 467000 flags = 0 data = length 547, hash E31A6979 - sample 5: + sample 3: time = 434000 flags = 0 data = length 570, hash FEC40D00 - sample 6: + sample 4: time = 634000 flags = 0 data = length 5525, hash 7C478F7E - sample 7: + sample 5: time = 567000 flags = 0 data = length 1082, hash DA07059A - sample 8: + sample 6: time = 534000 flags = 0 data = length 807, hash 93478E6B - sample 9: + sample 7: time = 600000 flags = 0 data = length 744, hash 9A8E6026 - sample 10: + sample 8: time = 767000 flags = 0 data = length 4732, hash C73B23C0 - sample 11: + sample 9: time = 700000 flags = 0 data = length 1004, hash 8A19A228 - sample 12: + sample 10: time = 667000 flags = 0 data = length 794, hash 8126022C - sample 13: + sample 11: time = 734000 flags = 0 data = length 645, hash F08300E5 - sample 14: + sample 12: time = 900000 flags = 0 data = length 2684, hash 727FE378 - sample 15: + sample 13: time = 834000 flags = 0 data = length 787, hash 419A7821 - sample 16: + sample 14: time = 800000 flags = 0 data = length 649, hash 5C159346 - sample 17: + sample 15: time = 867000 flags = 0 data = length 509, hash F912D655 - sample 18: + sample 16: time = 1034000 flags = 0 data = length 1226, hash 29815C21 - sample 19: + sample 17: time = 967000 flags = 0 data = length 898, hash D997AD0A - sample 20: + sample 18: time = 934000 flags = 0 data = length 476, hash A0423645 - sample 21: + sample 19: time = 1000000 flags = 0 data = length 486, hash DDF32CBB diff --git a/library/core/src/test/assets/mkv/sample.mkv.2.dump b/library/core/src/test/assets/mkv/sample.mkv.2.dump index de4e2a58bf..b0f943e2f2 100644 --- a/library/core/src/test/assets/mkv/sample.mkv.2.dump +++ b/library/core/src/test/assets/mkv/sample.mkv.2.dump @@ -1,6 +1,6 @@ seekMap: isSeekable = true - duration = 1072000 + duration = 1104000 getPosition(0) = [[timeUs=67000, position=5576]] numberOfTracks = 2 track 1: @@ -27,49 +27,41 @@ track 1: initializationData: data = length 30, hash F6F3D010 data = length 10, hash 7A0D0F2B - total output bytes = 10158 - sample count = 11 + total output bytes = 8360 + sample count = 9 sample 0: - time = 700000 - flags = 0 - data = length 1004, hash 8A19A228 - sample 1: - time = 667000 - flags = 0 - data = length 794, hash 8126022C - sample 2: time = 734000 flags = 0 data = length 645, hash F08300E5 - sample 3: + sample 1: time = 900000 flags = 0 data = length 2684, hash 727FE378 - sample 4: + sample 2: time = 834000 flags = 0 data = length 787, hash 419A7821 - sample 5: + sample 3: time = 800000 flags = 0 data = length 649, hash 5C159346 - sample 6: + sample 4: time = 867000 flags = 0 data = length 509, hash F912D655 - sample 7: + sample 5: time = 1034000 flags = 0 data = length 1226, hash 29815C21 - sample 8: + sample 6: time = 967000 flags = 0 data = length 898, hash D997AD0A - sample 9: + sample 7: time = 934000 flags = 0 data = length 476, hash A0423645 - sample 10: + sample 8: time = 1000000 flags = 0 data = length 486, hash DDF32CBB diff --git a/library/core/src/test/assets/mkv/sample.mkv.3.dump b/library/core/src/test/assets/mkv/sample.mkv.3.dump index 6034c54dec..460aca0e90 100644 --- a/library/core/src/test/assets/mkv/sample.mkv.3.dump +++ b/library/core/src/test/assets/mkv/sample.mkv.3.dump @@ -1,6 +1,6 @@ seekMap: isSeekable = true - duration = 1072000 + duration = 1104000 getPosition(0) = [[timeUs=67000, position=5576]] numberOfTracks = 2 track 1: diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java index 9394848198..b5e90dc3ea 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java @@ -68,8 +68,18 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab @Override public void seekMap(SeekMap seekMap) { - if (seekMap.isSeekable() && seekMap.getDurationUs() == C.TIME_UNSET) { - throw new IllegalStateException("SeekMap cannot be seekable and have an unknown duration"); + if (seekMap.isSeekable()) { + if (seekMap.getDurationUs() == C.TIME_UNSET) { + throw new IllegalStateException("SeekMap cannot be seekable and have an unknown duration"); + } + SeekMap.SeekPoints seekPoints = seekMap.getSeekPoints(0); + if (!seekPoints.first.equals(seekPoints.second)) { + throw new IllegalStateException("SeekMap defines two seek points for t=0"); + } + seekPoints = seekMap.getSeekPoints(seekMap.getDurationUs()); + if (!seekPoints.first.equals(seekPoints.second)) { + throw new IllegalStateException("SeekMap defines two seek points for t=durationUs"); + } } this.seekMap = seekMap; } From 88be178e0fa8139a36d127a1a5cdaab4fbd3cda2 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 16 Dec 2019 15:35:06 +0000 Subject: [PATCH 06/27] Manual rollback of https://github.com/google/ExoPlayer/commit/b3f485d7d9c08e39574b72a949166ee4834c3b24 It's technically possible to output a seekable SeekMap with unknown duration. This can occur if the media defines seek points but doesn't define either the overall duration or the duration of the media from the last seek point to the end. PiperOrigin-RevId: 285769121 --- .../exoplayer2/testutil/FakeExtractorOutput.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java index b5e90dc3ea..0502707682 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeExtractorOutput.java @@ -69,16 +69,16 @@ public final class FakeExtractorOutput implements ExtractorOutput, Dumper.Dumpab @Override public void seekMap(SeekMap seekMap) { if (seekMap.isSeekable()) { - if (seekMap.getDurationUs() == C.TIME_UNSET) { - throw new IllegalStateException("SeekMap cannot be seekable and have an unknown duration"); - } SeekMap.SeekPoints seekPoints = seekMap.getSeekPoints(0); if (!seekPoints.first.equals(seekPoints.second)) { throw new IllegalStateException("SeekMap defines two seek points for t=0"); } - seekPoints = seekMap.getSeekPoints(seekMap.getDurationUs()); - if (!seekPoints.first.equals(seekPoints.second)) { - throw new IllegalStateException("SeekMap defines two seek points for t=durationUs"); + long durationUs = seekMap.getDurationUs(); + if (durationUs != C.TIME_UNSET) { + seekPoints = seekMap.getSeekPoints(durationUs); + if (!seekPoints.first.equals(seekPoints.second)) { + throw new IllegalStateException("SeekMap defines two seek points for t=durationUs"); + } } } this.seekMap = seekMap; From 5e822e160ed6831d4ca3754e30c1a1561f8f4b4a Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 16 Dec 2019 16:18:01 +0000 Subject: [PATCH 07/27] FakeTrackOutput: Throw if sample size exceeds maxInputSize This indicates the extractor has output a Format with a specified maxInputSize that's too small. Failing in FakeTrackOutput ensures this doesn't happen during Extractor tests. PiperOrigin-RevId: 285776069 --- .../google/android/exoplayer2/testutil/FakeTrackOutput.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java index 4dd00557ae..f78e835b48 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackOutput.java @@ -93,6 +93,12 @@ public final class FakeTrackOutput implements TrackOutput, Dumper.Dumpable { @Override public void sampleMetadata(long timeUs, @C.BufferFlags int flags, int size, int offset, CryptoData cryptoData) { + if (format == null) { + throw new IllegalStateException("TrackOutput must receive format before sampleMetadata"); + } + if (format.maxInputSize != Format.NO_VALUE && size > format.maxInputSize) { + throw new IllegalStateException("Sample size exceeds Format.maxInputSize"); + } sampleTimesUs.add(timeUs); sampleFlags.add(flags); sampleStartOffsets.add(sampleData.length - offset - size); From 739517bd5e32c7443c03d968354475e109356456 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 13 Dec 2019 20:29:54 +0000 Subject: [PATCH 08/27] Fix FLAC seeking when the last seek point is a placeholder PiperOrigin-RevId: 285449865 --- extensions/flac/src/main/jni/flac_parser.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/extensions/flac/src/main/jni/flac_parser.cc b/extensions/flac/src/main/jni/flac_parser.cc index b920560f3a..f39e4bd1f7 100644 --- a/extensions/flac/src/main/jni/flac_parser.cc +++ b/extensions/flac/src/main/jni/flac_parser.cc @@ -462,8 +462,9 @@ bool FLACParser::getSeekPositions(int64_t timeUs, if (sampleNumber <= targetSampleNumber) { result[0] = (sampleNumber * 1000000LL) / sampleRate; result[1] = firstFrameOffset + points[i - 1].stream_offset; - if (sampleNumber == targetSampleNumber || i >= length) { - // exact seek, or no following seek point. + if (sampleNumber == targetSampleNumber || i >= length || + points[i].sample_number == -1) { // placeholder + // exact seek, or no following non-placeholder seek point result[2] = result[0]; result[3] = result[1]; } else { From 0a701abafe2efb10b0ef840989f6e2ba232c74c8 Mon Sep 17 00:00:00 2001 From: olly Date: Tue, 17 Dec 2019 17:00:54 +0000 Subject: [PATCH 09/27] Retain AV1 constructor for DefaultRenderersFactory Issue: #6773 PiperOrigin-RevId: 285990377 --- RELEASENOTES.md | 2 ++ library/core/proguard-rules.txt | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 198de62178..58416fbcef 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -5,6 +5,8 @@ * UI: Exclude `DefaultTimeBar` region from system gesture detection ([#6685](https://github.com/google/ExoPlayer/issues/6685)). * Propagate HTTP request headers through `CacheDataSource`. +* AV1 extension: Fix ProGuard rules + ([6773](https://github.com/google/ExoPlayer/issues/6773)). ### 2.11.0 (2019-12-11) ### diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt index 67646be956..bfd691259b 100644 --- a/library/core/proguard-rules.txt +++ b/library/core/proguard-rules.txt @@ -5,6 +5,10 @@ -keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer { (long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int); } +-dontnote com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer +-keepclassmembers class com.google.android.exoplayer2.ext.av1.Libgav1VideoRenderer { + (long, android.os.Handler, com.google.android.exoplayer2.video.VideoRendererEventListener, int); +} -dontnote com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer -keepclassmembers class com.google.android.exoplayer2.ext.opus.LibopusAudioRenderer { (android.os.Handler, com.google.android.exoplayer2.audio.AudioRendererEventListener, com.google.android.exoplayer2.audio.AudioProcessor[]); From 166e389c563af4cd4cff3da0953e9fbf2fefd9ec Mon Sep 17 00:00:00 2001 From: ibaker Date: Tue, 17 Dec 2019 17:13:53 +0000 Subject: [PATCH 10/27] Suppress ProGuard warnings about javax.annotation These annotations are compile-only - so we don't mind they're not accessible at runtime. PiperOrigin-RevId: 285993063 --- RELEASENOTES.md | 2 ++ library/core/proguard-rules.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 58416fbcef..cfaca5088d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -7,6 +7,8 @@ * Propagate HTTP request headers through `CacheDataSource`. * AV1 extension: Fix ProGuard rules ([6773](https://github.com/google/ExoPlayer/issues/6773)). +* Suppress ProGuard warnings for compile-time `javax.annotation` package + ([#6771](https://github.com/google/ExoPlayer/issues/6771)). ### 2.11.0 (2019-12-11) ### diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt index bfd691259b..ab4af32da4 100644 --- a/library/core/proguard-rules.txt +++ b/library/core/proguard-rules.txt @@ -65,6 +65,7 @@ # Don't warn about checkerframework and Kotlin annotations -dontwarn org.checkerframework.** -dontwarn kotlin.annotations.jvm.** +-dontwarn javax.annotation.** # Some members of this class are being accessed from native methods. Keep them unobfuscated. -keep class com.google.android.exoplayer2.ext.video.VideoDecoderOutputBuffer { From c9109f437c506dd0eb5bdb19728d7d04d3ed202b Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 18 Dec 2019 10:24:10 +0000 Subject: [PATCH 11/27] Ensure raw resources are kept R8 does constant folding, so we need to keep buildRawResourceUri to ensure that resources passed to it are kept. PiperOrigin-RevId: 286153875 --- RELEASENOTES.md | 2 ++ library/core/proguard-rules.txt | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index cfaca5088d..fe8a639d1a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -9,6 +9,8 @@ ([6773](https://github.com/google/ExoPlayer/issues/6773)). * Suppress ProGuard warnings for compile-time `javax.annotation` package ([#6771](https://github.com/google/ExoPlayer/issues/6771)). +* Fix proguard rules for R8 to ensure raw resources used with + `RawResourceDataSource` are kept. ### 2.11.0 (2019-12-11) ### diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt index ab4af32da4..494837c3e9 100644 --- a/library/core/proguard-rules.txt +++ b/library/core/proguard-rules.txt @@ -1,5 +1,10 @@ # Proguard rules specific to the core module. +# Constant folding for resource integers may mean that a resource passed to this method appears to be unused. Keep the method to prevent this from happening. +-keep class com.google.android.exoplayer2.upstream.RawResourceDataSource { + public static android.net.Uri buildRawResourceUri(int); +} + # Constructors accessed via reflection in DefaultRenderersFactory -dontnote com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer -keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer { @@ -69,5 +74,5 @@ # Some members of this class are being accessed from native methods. Keep them unobfuscated. -keep class com.google.android.exoplayer2.ext.video.VideoDecoderOutputBuffer { - *; + *; } From b4873e55e129df8e05841d151e9653500dbc2b81 Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Wed, 18 Dec 2019 10:47:42 +0000 Subject: [PATCH 12/27] Fix keep rule for VideoDecoderOutputBuffer PiperOrigin-RevId: 286156361 --- RELEASENOTES.md | 2 ++ library/core/proguard-rules.txt | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index fe8a639d1a..0fcff4bb7d 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -11,6 +11,8 @@ ([#6771](https://github.com/google/ExoPlayer/issues/6771)). * Fix proguard rules for R8 to ensure raw resources used with `RawResourceDataSource` are kept. +* Fix proguard rules to keep `VideoDecoderOutputBuffer` for video decoder + extensions. ### 2.11.0 (2019-12-11) ### diff --git a/library/core/proguard-rules.txt b/library/core/proguard-rules.txt index 494837c3e9..fd4e196945 100644 --- a/library/core/proguard-rules.txt +++ b/library/core/proguard-rules.txt @@ -5,6 +5,11 @@ public static android.net.Uri buildRawResourceUri(int); } +# Some members of this class are being accessed from native methods. Keep them unobfuscated. +-keep class com.google.android.exoplayer2.video.VideoDecoderOutputBuffer { + *; +} + # Constructors accessed via reflection in DefaultRenderersFactory -dontnote com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer -keepclassmembers class com.google.android.exoplayer2.ext.vp9.LibvpxVideoRenderer { @@ -71,8 +76,3 @@ -dontwarn org.checkerframework.** -dontwarn kotlin.annotations.jvm.** -dontwarn javax.annotation.** - -# Some members of this class are being accessed from native methods. Keep them unobfuscated. --keep class com.google.android.exoplayer2.ext.video.VideoDecoderOutputBuffer { - *; -} From 1106aba3515db433f89aabb5f038350614408868 Mon Sep 17 00:00:00 2001 From: olly Date: Wed, 18 Dec 2019 16:56:31 +0000 Subject: [PATCH 13/27] Add omitted release note for 2.11 PiperOrigin-RevId: 286201458 --- RELEASENOTES.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 0fcff4bb7d..57eb4f9519 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -44,6 +44,10 @@ * Fix issue where player errors are thrown too early at playlist transitions ([#5407](https://github.com/google/ExoPlayer/issues/5407)). * Add `Format` and renderer support flags to renderer `ExoPlaybackException`s. + * Where there are multiple platform decoders for a given MIME type, prefer to + use one that advertises support for the profile and level of the media being + played over one that does not, even if it does not come first in the + `MediaCodecList`. * DRM: * Inject `DrmSessionManager` into the `MediaSources` instead of `Renderers`. This allows each `MediaSource` in a `ConcatenatingMediaSource` to use a From 5d2ca02c5a628f33a01fa7501cd762b6ed165dc1 Mon Sep 17 00:00:00 2001 From: ibaker Date: Wed, 18 Dec 2019 18:09:42 +0000 Subject: [PATCH 14/27] Unwrap all nested IntDef values This seems to work with R8 but interact badly with ProGuard. issue:#6771 PiperOrigin-RevId: 286215262 --- .../mediacodec/MediaCodecRenderer.java | 4 +- .../exoplayer2/text/ssa/SsaDecoder.java | 64 +++++------ .../android/exoplayer2/text/ssa/SsaStyle.java | 103 ++++++++++-------- .../exoplayer2/text/webvtt/WebvttCue.java | 97 +++++++++-------- .../text/webvtt/WebvttCueParser.java | 12 +- .../exoplayer2/source/hls/HlsMediaPeriod.java | 4 +- .../exoplayer2/source/hls/HlsMediaSource.java | 43 ++++++-- .../source/hls/HlsMetadataType.java | 38 ------- .../source/hls/HlsSampleStreamWrapper.java | 11 +- .../source/hls/HlsMediaPeriodTest.java | 2 +- 10 files changed, 192 insertions(+), 186 deletions(-) delete mode 100644 library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMetadataType.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java index 820f9f003e..6c405f7ced 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/mediacodec/MediaCodecRenderer.java @@ -59,9 +59,7 @@ import java.util.List; */ public abstract class MediaCodecRenderer extends BaseRenderer { - /** - * Thrown when a failure occurs instantiating a decoder. - */ + /** Thrown when a failure occurs instantiating a decoder. */ public static class DecoderInitializationException extends Exception { private static final int CUSTOM_ERROR_CODE_BASE = -50000; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java index 917ac8e36e..eef9d2eec1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaDecoder.java @@ -300,12 +300,12 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { float screenWidth, float screenHeight) { @SsaStyle.SsaAlignment int alignment; - if (styleOverrides.alignment != SsaStyle.SsaAlignment.UNKNOWN) { + if (styleOverrides.alignment != SsaStyle.SSA_ALIGNMENT_UNKNOWN) { alignment = styleOverrides.alignment; } else if (style != null) { alignment = style.alignment; } else { - alignment = SsaStyle.SsaAlignment.UNKNOWN; + alignment = SsaStyle.SSA_ALIGNMENT_UNKNOWN; } @Cue.AnchorType int positionAnchor = toPositionAnchor(alignment); @Cue.AnchorType int lineAnchor = toLineAnchor(alignment); @@ -337,19 +337,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { @Nullable private static Layout.Alignment toTextAlignment(@SsaStyle.SsaAlignment int alignment) { switch (alignment) { - case SsaStyle.SsaAlignment.BOTTOM_LEFT: - case SsaStyle.SsaAlignment.MIDDLE_LEFT: - case SsaStyle.SsaAlignment.TOP_LEFT: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT: + case SsaStyle.SSA_ALIGNMENT_TOP_LEFT: return Layout.Alignment.ALIGN_NORMAL; - case SsaStyle.SsaAlignment.BOTTOM_CENTER: - case SsaStyle.SsaAlignment.MIDDLE_CENTER: - case SsaStyle.SsaAlignment.TOP_CENTER: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER: + case SsaStyle.SSA_ALIGNMENT_TOP_CENTER: return Layout.Alignment.ALIGN_CENTER; - case SsaStyle.SsaAlignment.BOTTOM_RIGHT: - case SsaStyle.SsaAlignment.MIDDLE_RIGHT: - case SsaStyle.SsaAlignment.TOP_RIGHT: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT: + case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT: return Layout.Alignment.ALIGN_OPPOSITE; - case SsaStyle.SsaAlignment.UNKNOWN: + case SsaStyle.SSA_ALIGNMENT_UNKNOWN: return null; default: Log.w(TAG, "Unknown alignment: " + alignment); @@ -360,19 +360,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { @Cue.AnchorType private static int toLineAnchor(@SsaStyle.SsaAlignment int alignment) { switch (alignment) { - case SsaStyle.SsaAlignment.BOTTOM_LEFT: - case SsaStyle.SsaAlignment.BOTTOM_CENTER: - case SsaStyle.SsaAlignment.BOTTOM_RIGHT: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT: return Cue.ANCHOR_TYPE_END; - case SsaStyle.SsaAlignment.MIDDLE_LEFT: - case SsaStyle.SsaAlignment.MIDDLE_CENTER: - case SsaStyle.SsaAlignment.MIDDLE_RIGHT: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT: return Cue.ANCHOR_TYPE_MIDDLE; - case SsaStyle.SsaAlignment.TOP_LEFT: - case SsaStyle.SsaAlignment.TOP_CENTER: - case SsaStyle.SsaAlignment.TOP_RIGHT: + case SsaStyle.SSA_ALIGNMENT_TOP_LEFT: + case SsaStyle.SSA_ALIGNMENT_TOP_CENTER: + case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT: return Cue.ANCHOR_TYPE_START; - case SsaStyle.SsaAlignment.UNKNOWN: + case SsaStyle.SSA_ALIGNMENT_UNKNOWN: return Cue.TYPE_UNSET; default: Log.w(TAG, "Unknown alignment: " + alignment); @@ -383,19 +383,19 @@ public final class SsaDecoder extends SimpleSubtitleDecoder { @Cue.AnchorType private static int toPositionAnchor(@SsaStyle.SsaAlignment int alignment) { switch (alignment) { - case SsaStyle.SsaAlignment.BOTTOM_LEFT: - case SsaStyle.SsaAlignment.MIDDLE_LEFT: - case SsaStyle.SsaAlignment.TOP_LEFT: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_LEFT: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_LEFT: + case SsaStyle.SSA_ALIGNMENT_TOP_LEFT: return Cue.ANCHOR_TYPE_START; - case SsaStyle.SsaAlignment.BOTTOM_CENTER: - case SsaStyle.SsaAlignment.MIDDLE_CENTER: - case SsaStyle.SsaAlignment.TOP_CENTER: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_CENTER: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_CENTER: + case SsaStyle.SSA_ALIGNMENT_TOP_CENTER: return Cue.ANCHOR_TYPE_MIDDLE; - case SsaStyle.SsaAlignment.BOTTOM_RIGHT: - case SsaStyle.SsaAlignment.MIDDLE_RIGHT: - case SsaStyle.SsaAlignment.TOP_RIGHT: + case SsaStyle.SSA_ALIGNMENT_BOTTOM_RIGHT: + case SsaStyle.SSA_ALIGNMENT_MIDDLE_RIGHT: + case SsaStyle.SSA_ALIGNMENT_TOP_RIGHT: return Cue.ANCHOR_TYPE_END; - case SsaStyle.SsaAlignment.UNKNOWN: + case SsaStyle.SSA_ALIGNMENT_UNKNOWN: return Cue.TYPE_UNSET; default: Log.w(TAG, "Unknown alignment: " + alignment); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java index e8070976e7..fd2cb036b7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/ssa/SsaStyle.java @@ -37,6 +37,52 @@ import java.util.regex.Pattern; private static final String TAG = "SsaStyle"; + /** + * The SSA/ASS alignments. + * + *

Allowed values: + * + *

    + *
  • {@link #SSA_ALIGNMENT_UNKNOWN} + *
  • {@link #SSA_ALIGNMENT_BOTTOM_LEFT} + *
  • {@link #SSA_ALIGNMENT_BOTTOM_CENTER} + *
  • {@link #SSA_ALIGNMENT_BOTTOM_RIGHT} + *
  • {@link #SSA_ALIGNMENT_MIDDLE_LEFT} + *
  • {@link #SSA_ALIGNMENT_MIDDLE_CENTER} + *
  • {@link #SSA_ALIGNMENT_MIDDLE_RIGHT} + *
  • {@link #SSA_ALIGNMENT_TOP_LEFT} + *
  • {@link #SSA_ALIGNMENT_TOP_CENTER} + *
  • {@link #SSA_ALIGNMENT_TOP_RIGHT} + *
+ */ + @IntDef({ + SSA_ALIGNMENT_UNKNOWN, + SSA_ALIGNMENT_BOTTOM_LEFT, + SSA_ALIGNMENT_BOTTOM_CENTER, + SSA_ALIGNMENT_BOTTOM_RIGHT, + SSA_ALIGNMENT_MIDDLE_LEFT, + SSA_ALIGNMENT_MIDDLE_CENTER, + SSA_ALIGNMENT_MIDDLE_RIGHT, + SSA_ALIGNMENT_TOP_LEFT, + SSA_ALIGNMENT_TOP_CENTER, + SSA_ALIGNMENT_TOP_RIGHT, + }) + @Documented + @Retention(SOURCE) + public @interface SsaAlignment {} + + // The numbering follows the ASS (v4+) spec (i.e. the points on the number pad). + public static final int SSA_ALIGNMENT_UNKNOWN = -1; + public static final int SSA_ALIGNMENT_BOTTOM_LEFT = 1; + public static final int SSA_ALIGNMENT_BOTTOM_CENTER = 2; + public static final int SSA_ALIGNMENT_BOTTOM_RIGHT = 3; + public static final int SSA_ALIGNMENT_MIDDLE_LEFT = 4; + public static final int SSA_ALIGNMENT_MIDDLE_CENTER = 5; + public static final int SSA_ALIGNMENT_MIDDLE_RIGHT = 6; + public static final int SSA_ALIGNMENT_TOP_LEFT = 7; + public static final int SSA_ALIGNMENT_TOP_CENTER = 8; + public static final int SSA_ALIGNMENT_TOP_RIGHT = 9; + public final String name; @SsaAlignment public final int alignment; @@ -77,22 +123,22 @@ import java.util.regex.Pattern; // Swallow the exception and return UNKNOWN below. } Log.w(TAG, "Ignoring unknown alignment: " + alignmentStr); - return SsaAlignment.UNKNOWN; + return SSA_ALIGNMENT_UNKNOWN; } private static boolean isValidAlignment(@SsaAlignment int alignment) { switch (alignment) { - case SsaAlignment.BOTTOM_CENTER: - case SsaAlignment.BOTTOM_LEFT: - case SsaAlignment.BOTTOM_RIGHT: - case SsaAlignment.MIDDLE_CENTER: - case SsaAlignment.MIDDLE_LEFT: - case SsaAlignment.MIDDLE_RIGHT: - case SsaAlignment.TOP_CENTER: - case SsaAlignment.TOP_LEFT: - case SsaAlignment.TOP_RIGHT: + case SSA_ALIGNMENT_BOTTOM_CENTER: + case SSA_ALIGNMENT_BOTTOM_LEFT: + case SSA_ALIGNMENT_BOTTOM_RIGHT: + case SSA_ALIGNMENT_MIDDLE_CENTER: + case SSA_ALIGNMENT_MIDDLE_LEFT: + case SSA_ALIGNMENT_MIDDLE_RIGHT: + case SSA_ALIGNMENT_TOP_CENTER: + case SSA_ALIGNMENT_TOP_LEFT: + case SSA_ALIGNMENT_TOP_RIGHT: return true; - case SsaAlignment.UNKNOWN: + case SSA_ALIGNMENT_UNKNOWN: default: return false; } @@ -177,7 +223,7 @@ import java.util.regex.Pattern; } public static Overrides parseFromDialogue(String text) { - @SsaAlignment int alignment = SsaAlignment.UNKNOWN; + @SsaAlignment int alignment = SSA_ALIGNMENT_UNKNOWN; PointF position = null; Matcher matcher = BRACES_PATTERN.matcher(text); while (matcher.find()) { @@ -192,7 +238,7 @@ import java.util.regex.Pattern; } try { @SsaAlignment int parsedAlignment = parseAlignmentOverride(braceContents); - if (parsedAlignment != SsaAlignment.UNKNOWN) { + if (parsedAlignment != SSA_ALIGNMENT_UNKNOWN) { alignment = parsedAlignment; } } catch (RuntimeException e) { @@ -249,36 +295,7 @@ import java.util.regex.Pattern; @SsaAlignment private static int parseAlignmentOverride(String braceContents) { Matcher matcher = ALIGNMENT_OVERRIDE_PATTERN.matcher(braceContents); - return matcher.find() ? parseAlignment(matcher.group(1)) : SsaAlignment.UNKNOWN; + return matcher.find() ? parseAlignment(matcher.group(1)) : SSA_ALIGNMENT_UNKNOWN; } } - - /** The SSA/ASS alignments. */ - @IntDef({ - SsaAlignment.UNKNOWN, - SsaAlignment.BOTTOM_LEFT, - SsaAlignment.BOTTOM_CENTER, - SsaAlignment.BOTTOM_RIGHT, - SsaAlignment.MIDDLE_LEFT, - SsaAlignment.MIDDLE_CENTER, - SsaAlignment.MIDDLE_RIGHT, - SsaAlignment.TOP_LEFT, - SsaAlignment.TOP_CENTER, - SsaAlignment.TOP_RIGHT, - }) - @Documented - @Retention(SOURCE) - /* package */ @interface SsaAlignment { - // The numbering follows the ASS (v4+) spec (i.e. the points on the number pad). - int UNKNOWN = -1; - int BOTTOM_LEFT = 1; - int BOTTOM_CENTER = 2; - int BOTTOM_RIGHT = 3; - int MIDDLE_LEFT = 4; - int MIDDLE_CENTER = 5; - int MIDDLE_RIGHT = 6; - int TOP_LEFT = 7; - int TOP_CENTER = 8; - int TOP_RIGHT = 9; - } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCue.java b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCue.java index bfa067e322..55e568efa1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCue.java @@ -77,39 +77,40 @@ public final class WebvttCue extends Cue { @Documented @Retention(SOURCE) @IntDef({ - TextAlignment.START, - TextAlignment.CENTER, - TextAlignment.END, - TextAlignment.LEFT, - TextAlignment.RIGHT + TEXT_ALIGNMENT_START, + TEXT_ALIGNMENT_CENTER, + TEXT_ALIGNMENT_END, + TEXT_ALIGNMENT_LEFT, + TEXT_ALIGNMENT_RIGHT }) - public @interface TextAlignment { - /** - * See WebVTT's align:start. - */ - int START = 1; - /** - * See WebVTT's align:center. - */ - int CENTER = 2; - /** - * See WebVTT's align:end. - */ - int END = 3; - /** - * See WebVTT's align:left. - */ - int LEFT = 4; - /** - * See WebVTT's align:right. - */ - int RIGHT = 5; - } + public @interface TextAlignment {} + /** + * See WebVTT's align:start. + */ + public static final int TEXT_ALIGNMENT_START = 1; + + /** + * See WebVTT's align:center. + */ + public static final int TEXT_ALIGNMENT_CENTER = 2; + + /** + * See WebVTT's align:end. + */ + public static final int TEXT_ALIGNMENT_END = 3; + + /** + * See WebVTT's align:left. + */ + public static final int TEXT_ALIGNMENT_LEFT = 4; + + /** + * See WebVTT's align:right. + */ + public static final int TEXT_ALIGNMENT_RIGHT = 5; private static final String TAG = "WebvttCueBuilder"; @@ -140,7 +141,7 @@ public final class WebvttCue extends Cue { endTime = 0; text = null; // Default: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment - textAlignment = TextAlignment.CENTER; + textAlignment = TEXT_ALIGNMENT_CENTER; line = Cue.DIMEN_UNSET; // Defaults to NUMBER (true): https://www.w3.org/TR/webvtt1/#webvtt-cue-snap-to-lines-flag lineType = Cue.LINE_TYPE_NUMBER; @@ -251,13 +252,13 @@ public final class WebvttCue extends Cue { // https://www.w3.org/TR/webvtt1/#webvtt-cue-position private static float derivePosition(@TextAlignment int textAlignment) { switch (textAlignment) { - case TextAlignment.LEFT: + case TEXT_ALIGNMENT_LEFT: return 0.0f; - case TextAlignment.RIGHT: + case TEXT_ALIGNMENT_RIGHT: return 1.0f; - case TextAlignment.START: - case TextAlignment.CENTER: - case TextAlignment.END: + case TEXT_ALIGNMENT_START: + case TEXT_ALIGNMENT_CENTER: + case TEXT_ALIGNMENT_END: default: return DEFAULT_POSITION; } @@ -267,13 +268,13 @@ public final class WebvttCue extends Cue { @AnchorType private static int derivePositionAnchor(@TextAlignment int textAlignment) { switch (textAlignment) { - case TextAlignment.LEFT: - case TextAlignment.START: + case TEXT_ALIGNMENT_LEFT: + case TEXT_ALIGNMENT_START: return Cue.ANCHOR_TYPE_START; - case TextAlignment.RIGHT: - case TextAlignment.END: + case TEXT_ALIGNMENT_RIGHT: + case TEXT_ALIGNMENT_END: return Cue.ANCHOR_TYPE_END; - case TextAlignment.CENTER: + case TEXT_ALIGNMENT_CENTER: default: return Cue.ANCHOR_TYPE_MIDDLE; } @@ -282,13 +283,13 @@ public final class WebvttCue extends Cue { @Nullable private static Alignment convertTextAlignment(@TextAlignment int textAlignment) { switch (textAlignment) { - case TextAlignment.START: - case TextAlignment.LEFT: + case TEXT_ALIGNMENT_START: + case TEXT_ALIGNMENT_LEFT: return Alignment.ALIGN_NORMAL; - case TextAlignment.CENTER: + case TEXT_ALIGNMENT_CENTER: return Alignment.ALIGN_CENTER; - case TextAlignment.END: - case TextAlignment.RIGHT: + case TEXT_ALIGNMENT_END: + case TEXT_ALIGNMENT_RIGHT: return Alignment.ALIGN_OPPOSITE; default: Log.w(TAG, "Unknown textAlignment: " + textAlignment); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java index 6e5bd31b4b..b6ddf89dc3 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/webvtt/WebvttCueParser.java @@ -308,20 +308,20 @@ public final class WebvttCueParser { private static int parseTextAlignment(String s) { switch (s) { case "start": - return WebvttCue.Builder.TextAlignment.START; + return WebvttCue.Builder.TEXT_ALIGNMENT_START; case "left": - return WebvttCue.Builder.TextAlignment.LEFT; + return WebvttCue.Builder.TEXT_ALIGNMENT_LEFT; case "center": case "middle": - return WebvttCue.Builder.TextAlignment.CENTER; + return WebvttCue.Builder.TEXT_ALIGNMENT_CENTER; case "end": - return WebvttCue.Builder.TextAlignment.END; + return WebvttCue.Builder.TEXT_ALIGNMENT_END; case "right": - return WebvttCue.Builder.TextAlignment.RIGHT; + return WebvttCue.Builder.TEXT_ALIGNMENT_RIGHT; default: Log.w(TAG, "Invalid alignment value: " + s); // Default value: https://www.w3.org/TR/webvtt1/#webvtt-cue-text-alignment - return WebvttCue.Builder.TextAlignment.CENTER; + return WebvttCue.Builder.TEXT_ALIGNMENT_CENTER; } } diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java index f74d9b0b0c..3b723af435 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriod.java @@ -75,7 +75,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper private final TimestampAdjusterProvider timestampAdjusterProvider; private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory; private final boolean allowChunklessPreparation; - private final @HlsMetadataType int metadataType; + private final @HlsMediaSource.MetadataType int metadataType; private final boolean useSessionKeys; @Nullable private Callback callback; @@ -118,7 +118,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper Allocator allocator, CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory, boolean allowChunklessPreparation, - @HlsMetadataType int metadataType, + @HlsMediaSource.MetadataType int metadataType, boolean useSessionKeys) { this.extractorFactory = extractorFactory; this.playlistTracker = playlistTracker; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java index 4f6a0405f2..db52fa1c02 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMediaSource.java @@ -15,8 +15,11 @@ */ package com.google.android.exoplayer2.source.hls; +import static java.lang.annotation.RetentionPolicy.SOURCE; + import android.net.Uri; import android.os.Handler; +import androidx.annotation.IntDef; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; @@ -47,6 +50,8 @@ import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.TransferListener; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; import java.util.List; /** An HLS {@link MediaSource}. */ @@ -57,6 +62,28 @@ public final class HlsMediaSource extends BaseMediaSource ExoPlayerLibraryInfo.registerModule("goog.exo.hls"); } + /** + * The types of metadata that can be extracted from HLS streams. + * + *

Allowed values: + * + *

    + *
  • {@link #METADATA_TYPE_ID3} + *
  • {@link #METADATA_TYPE_EMSG} + *
+ * + *

See {@link Factory#setMetadataType(int)}. + */ + @Documented + @Retention(SOURCE) + @IntDef({METADATA_TYPE_ID3, METADATA_TYPE_EMSG}) + public @interface MetadataType {} + + /** Type for ID3 metadata in HLS streams. */ + public static final int METADATA_TYPE_ID3 = 1; + /** Type for ESMG metadata in HLS streams. */ + public static final int METADATA_TYPE_EMSG = 3; + /** Factory for {@link HlsMediaSource}s. */ public static final class Factory implements MediaSourceFactory { @@ -70,7 +97,7 @@ public final class HlsMediaSource extends BaseMediaSource private DrmSessionManager drmSessionManager; private LoadErrorHandlingPolicy loadErrorHandlingPolicy; private boolean allowChunklessPreparation; - @HlsMetadataType private int metadataType; + @MetadataType private int metadataType; private boolean useSessionKeys; private boolean isCreateCalled; @Nullable private Object tag; @@ -100,7 +127,7 @@ public final class HlsMediaSource extends BaseMediaSource drmSessionManager = DrmSessionManager.getDummyDrmSessionManager(); loadErrorHandlingPolicy = new DefaultLoadErrorHandlingPolicy(); compositeSequenceableLoaderFactory = new DefaultCompositeSequenceableLoaderFactory(); - metadataType = HlsMetadataType.ID3; + metadataType = METADATA_TYPE_ID3; } /** @@ -246,24 +273,24 @@ public final class HlsMediaSource extends BaseMediaSource /** * Sets the type of metadata to extract from the HLS source (defaults to {@link - * HlsMetadataType#ID3}). + * #METADATA_TYPE_ID3}). * *

HLS supports in-band ID3 in both TS and fMP4 streams, but in the fMP4 case the data is * wrapped in an EMSG box [spec]. * - *

If this is set to {@link HlsMetadataType#ID3} then raw ID3 metadata of will be extracted + *

If this is set to {@link #METADATA_TYPE_ID3} then raw ID3 metadata of will be extracted * from TS sources. From fMP4 streams EMSGs containing metadata of this type (in the variant * stream only) will be unwrapped to expose the inner data. All other in-band metadata will be * dropped. * - *

If this is set to {@link HlsMetadataType#EMSG} then all EMSG data from the fMP4 variant + *

If this is set to {@link #METADATA_TYPE_EMSG} then all EMSG data from the fMP4 variant * stream will be extracted. No metadata will be extracted from TS streams, since they don't * support EMSG. * * @param metadataType The type of metadata to extract. * @return This factory, for convenience. */ - public Factory setMetadataType(@HlsMetadataType int metadataType) { + public Factory setMetadataType(@MetadataType int metadataType) { Assertions.checkState(!isCreateCalled); this.metadataType = metadataType; return this; @@ -347,7 +374,7 @@ public final class HlsMediaSource extends BaseMediaSource private final DrmSessionManager drmSessionManager; private final LoadErrorHandlingPolicy loadErrorHandlingPolicy; private final boolean allowChunklessPreparation; - private final @HlsMetadataType int metadataType; + private final @MetadataType int metadataType; private final boolean useSessionKeys; private final HlsPlaylistTracker playlistTracker; @Nullable private final Object tag; @@ -363,7 +390,7 @@ public final class HlsMediaSource extends BaseMediaSource LoadErrorHandlingPolicy loadErrorHandlingPolicy, HlsPlaylistTracker playlistTracker, boolean allowChunklessPreparation, - @HlsMetadataType int metadataType, + @MetadataType int metadataType, boolean useSessionKeys, @Nullable Object tag) { this.manifestUri = manifestUri; diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMetadataType.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMetadataType.java deleted file mode 100644 index 8fb6c220cf..0000000000 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsMetadataType.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2019 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.source.hls; - -import static java.lang.annotation.RetentionPolicy.SOURCE; - -import androidx.annotation.IntDef; -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; - -/** - * The types of metadata that can be extracted from HLS streams. - * - *

See {@link HlsMediaSource.Factory#setMetadataType(int)}. - */ -@Documented -@Retention(SOURCE) -@IntDef({HlsMetadataType.ID3, HlsMetadataType.EMSG}) -public @interface HlsMetadataType { - /** Type for ID3 metadata in HLS streams. */ - int ID3 = 1; - /** Type for ESMG metadata in HLS streams. */ - int EMSG = 3; -} diff --git a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java index 18465bcaf7..77242ea0fa 100644 --- a/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java +++ b/library/hls/src/main/java/com/google/android/exoplayer2/source/hls/HlsSampleStreamWrapper.java @@ -116,7 +116,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private final LoadErrorHandlingPolicy loadErrorHandlingPolicy; private final Loader loader; private final EventDispatcher eventDispatcher; - private final @HlsMetadataType int metadataType; + private final @HlsMediaSource.MetadataType int metadataType; private final HlsChunkSource.HlsChunkHolder nextChunkHolder; private final ArrayList mediaChunks; private final List readOnlyMediaChunks; @@ -190,7 +190,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; DrmSessionManager drmSessionManager, LoadErrorHandlingPolicy loadErrorHandlingPolicy, EventDispatcher eventDispatcher, - @HlsMetadataType int metadataType) { + @HlsMediaSource.MetadataType int metadataType) { this.trackType = trackType; this.callback = callback; this.chunkSource = chunkSource; @@ -1362,14 +1362,15 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; private byte[] buffer; private int bufferPosition; - public EmsgUnwrappingTrackOutput(TrackOutput delegate, @HlsMetadataType int metadataType) { + public EmsgUnwrappingTrackOutput( + TrackOutput delegate, @HlsMediaSource.MetadataType int metadataType) { this.emsgDecoder = new EventMessageDecoder(); this.delegate = delegate; switch (metadataType) { - case HlsMetadataType.ID3: + case HlsMediaSource.METADATA_TYPE_ID3: delegateFormat = ID3_FORMAT; break; - case HlsMetadataType.EMSG: + case HlsMediaSource.METADATA_TYPE_EMSG: delegateFormat = EMSG_FORMAT; break; default: diff --git a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java index 73ef11bda9..820c39c197 100644 --- a/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java +++ b/library/hls/src/test/java/com/google/android/exoplayer2/source/hls/HlsMediaPeriodTest.java @@ -92,7 +92,7 @@ public final class HlsMediaPeriodTest { mock(Allocator.class), mock(CompositeSequenceableLoaderFactory.class), /* allowChunklessPreparation =*/ true, - HlsMetadataType.ID3, + HlsMediaSource.METADATA_TYPE_ID3, /* useSessionKeys= */ false); }; From 63f7b99836114078248b9129ae366c92781c4a75 Mon Sep 17 00:00:00 2001 From: olly Date: Thu, 19 Dec 2019 12:22:24 +0000 Subject: [PATCH 15/27] Bump to 2.11.1 PiperOrigin-RevId: 286368964 --- RELEASENOTES.md | 21 +++++++++++-------- constants.gradle | 4 ++-- .../exoplayer2/ExoPlayerLibraryInfo.java | 6 +++--- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 57eb4f9519..322afc5769 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -4,15 +4,18 @@ * UI: Exclude `DefaultTimeBar` region from system gesture detection ([#6685](https://github.com/google/ExoPlayer/issues/6685)). -* Propagate HTTP request headers through `CacheDataSource`. -* AV1 extension: Fix ProGuard rules - ([6773](https://github.com/google/ExoPlayer/issues/6773)). -* Suppress ProGuard warnings for compile-time `javax.annotation` package - ([#6771](https://github.com/google/ExoPlayer/issues/6771)). -* Fix proguard rules for R8 to ensure raw resources used with - `RawResourceDataSource` are kept. -* Fix proguard rules to keep `VideoDecoderOutputBuffer` for video decoder - extensions. +* ProGuard fixes: + * Ensure `Libgav1VideoRenderer` constructor is kept for use by + `DefaultRenderersFactory` + ([#6773](https://github.com/google/ExoPlayer/issues/6773)). + * Ensure `VideoDecoderOutputBuffer` and its members are kept for use by video + decoder extensions. + * Ensure raw resources used with `RawResourceDataSource` are kept. + * Suppress spurious warnings about the `javax.annotation` package, and + restructure use of `IntDef` annotations to remove spurious warnings about + `SsaStyle$SsaAlignment` + ([#6771](https://github.com/google/ExoPlayer/issues/6771)). +* Fix `CacheDataSource` to correctly propagate `DataSpec.httpRequestHeaders`. ### 2.11.0 (2019-12-11) ### diff --git a/constants.gradle b/constants.gradle index 599af54dde..392c623455 100644 --- a/constants.gradle +++ b/constants.gradle @@ -13,8 +13,8 @@ // limitations under the License. project.ext { // ExoPlayer version and version code. - releaseVersion = '2.11.0' - releaseVersionCode = 2011000 + releaseVersion = '2.11.1' + releaseVersionCode = 2011001 minSdkVersion = 16 appTargetSdkVersion = 29 targetSdkVersion = 28 // TODO: Bump once b/143232359 is resolved diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java index 249ef7e44e..217f580e7b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerLibraryInfo.java @@ -29,11 +29,11 @@ public final class ExoPlayerLibraryInfo { /** The version of the library expressed as a string, for example "1.2.3". */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION_INT) or vice versa. - public static final String VERSION = "2.11.0"; + public static final String VERSION = "2.11.1"; /** The version of the library expressed as {@code "ExoPlayerLib/" + VERSION}. */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.0"; + public static final String VERSION_SLASHY = "ExoPlayerLib/2.11.1"; /** * The version of the library expressed as an integer, for example 1002003. @@ -43,7 +43,7 @@ public final class ExoPlayerLibraryInfo { * integer version 123045006 (123-045-006). */ // Intentionally hardcoded. Do not derive from other constants (e.g. VERSION) or vice versa. - public static final int VERSION_INT = 2011000; + public static final int VERSION_INT = 2011001; /** * Whether the library was compiled with {@link com.google.android.exoplayer2.util.Assertions} From b7bc1fee9f39362039efd3465a0e34a0920f1ebe Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 20 Dec 2019 10:23:27 +0000 Subject: [PATCH 16/27] Add missing @Nullable to MediaCodecAudioRenderer.getMediaClock Without this @Nullable, potential subclasses can't override the method to return null if they don't want to use the renderer as a media clock. Issue:#6792 PiperOrigin-RevId: 286545736 --- RELEASENOTES.md | 3 +++ .../android/exoplayer2/audio/MediaCodecAudioRenderer.java | 1 + .../android/exoplayer2/audio/SimpleDecoderAudioRenderer.java | 1 + 3 files changed, 5 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 322afc5769..074294ae0a 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -16,6 +16,9 @@ `SsaStyle$SsaAlignment` ([#6771](https://github.com/google/ExoPlayer/issues/6771)). * Fix `CacheDataSource` to correctly propagate `DataSpec.httpRequestHeaders`. +* Add missing @Nullable to `MediaCodecAudioRenderer.getMediaClock` and + `SimpleDecoderAudioRenderer.getMediaClock` + ([#6792](https://github.com/google/ExoPlayer/issues/6792)). ### 2.11.0 (2019-12-11) ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index ae50d14728..096f4ccd1f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -520,6 +520,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media } @Override + @Nullable public MediaClock getMediaClock() { return this; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index 5ccbf04c5c..60870204cc 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -218,6 +218,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements } @Override + @Nullable public MediaClock getMediaClock() { return this; } From e8cb7b237061b8e4ed4bd5cd2de020c4ddc882ce Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 20 Dec 2019 12:14:29 +0000 Subject: [PATCH 17/27] Fix typo Merge of https://github.com/google/ExoPlayer/pull/6793 PiperOrigin-RevId: 286556008 --- .../google/android/exoplayer2/trackselection/TrackSelector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java index fb74bd9d54..c2fbeb6e2d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelector.java @@ -75,7 +75,7 @@ import com.google.android.exoplayer2.util.Assertions; * the two are tightly bound together. It may only be possible to play a certain combination tracks * if the renderers are configured in a particular way. Equally, it may only be possible to * configure renderers in a particular way if certain tracks are selected. Hence it makes sense to - * determined the track selection and corresponding renderer configurations in a single step. + * determine the track selection and corresponding renderer configurations in a single step. * *

Threading model

* From 406acfc38fba096311678ba322fed244c0efb219 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 20 Dec 2019 15:37:08 +0000 Subject: [PATCH 18/27] Relax MP4 sniffing to allow an atom to extend beyond the file length Issue: #6774 PiperOrigin-RevId: 286575797 --- .../com/google/android/exoplayer2/extractor/mp4/Sniffer.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java index 95193785c0..dac74bfe2b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/extractor/mp4/Sniffer.java @@ -118,10 +118,6 @@ import java.io.IOException; } } - if (inputLength != C.LENGTH_UNSET && bytesSearched + atomSize > inputLength) { - // The file is invalid because the atom extends past the end of the file. - return false; - } if (atomSize < headerSize) { // The file is invalid because the atom size is too small for its header. return false; From 87865a5cc442f353fce1979a0047f726a0b8ffd6 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 20 Dec 2019 15:41:01 +0000 Subject: [PATCH 19/27] DefaultDownloadIndex: Clear failure reason when removing download The Download constructor considers it invalid to have a failure reason if the download isn't in the failed state. Unfortunately, calling DefaultDownloadIndex.removeAllDownloads when there's a failed download will change the state without clearing the reason. If the downloads are then read back from the DefaultDownloadIndex we end up violating the Download constructor assertion. This change clears the failed reason for any existing rows in the invalid state, and also fixes the root cause that allows invalid rows to enter the table in the first place. Issue: #6785 PiperOrigin-RevId: 286576242 --- RELEASENOTES.md | 4 ++++ .../offline/DefaultDownloadIndex.java | 17 +++++++++++++++-- .../android/exoplayer2/offline/Download.java | 4 ++-- .../offline/DefaultDownloadIndexTest.java | 17 +++++++++++++++++ 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 074294ae0a..3f97174278 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -16,6 +16,10 @@ `SsaStyle$SsaAlignment` ([#6771](https://github.com/google/ExoPlayer/issues/6771)). * Fix `CacheDataSource` to correctly propagate `DataSpec.httpRequestHeaders`. +* Fix issue with `DefaultDownloadIndex` that could result in an + `IllegalStateException` being thrown from + `DefaultDownloadIndex.getDownloadForCurrentRow` + ([#6785](https://github.com/google/ExoPlayer/issues/6785)). * Add missing @Nullable to `MediaCodecAudioRenderer.getMediaClock` and `SimpleDecoderAudioRenderer.getMediaClock` ([#6792](https://github.com/google/ExoPlayer/issues/6792)). diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java index 7ed1eb095f..f1c897813f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DefaultDownloadIndex.java @@ -26,6 +26,8 @@ import androidx.annotation.VisibleForTesting; import com.google.android.exoplayer2.database.DatabaseIOException; import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.VersionTable; +import com.google.android.exoplayer2.offline.Download.FailureReason; +import com.google.android.exoplayer2.offline.Download.State; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; @@ -239,6 +241,9 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { try { ContentValues values = new ContentValues(); values.put(COLUMN_STATE, Download.STATE_REMOVING); + // Only downloads in STATE_FAILED are allowed a failure reason, so we need to clear it here in + // case we're moving downloads from STATE_FAILED to STATE_REMOVING. + values.put(COLUMN_FAILURE_REASON, Download.FAILURE_REASON_NONE); SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase(); writableDatabase.update(tableName, values, /* whereClause= */ null, /* whereArgs= */ null); } catch (SQLException e) { @@ -351,14 +356,22 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex { DownloadProgress downloadProgress = new DownloadProgress(); downloadProgress.bytesDownloaded = cursor.getLong(COLUMN_INDEX_BYTES_DOWNLOADED); downloadProgress.percentDownloaded = cursor.getFloat(COLUMN_INDEX_PERCENT_DOWNLOADED); + @State int state = cursor.getInt(COLUMN_INDEX_STATE); + // It's possible the database contains failure reasons for non-failed downloads, which is + // invalid. Clear them here. See https://github.com/google/ExoPlayer/issues/6785. + @FailureReason + int failureReason = + state == Download.STATE_FAILED + ? cursor.getInt(COLUMN_INDEX_FAILURE_REASON) + : Download.FAILURE_REASON_NONE; return new Download( request, - /* state= */ cursor.getInt(COLUMN_INDEX_STATE), + state, /* startTimeMs= */ cursor.getLong(COLUMN_INDEX_START_TIME_MS), /* updateTimeMs= */ cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS), /* contentLength= */ cursor.getLong(COLUMN_INDEX_CONTENT_LENGTH), /* stopReason= */ cursor.getInt(COLUMN_INDEX_STOP_REASON), - /* failureReason= */ cursor.getInt(COLUMN_INDEX_FAILURE_REASON), + failureReason, downloadProgress); } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/Download.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/Download.java index 97dff8394e..da46120b29 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/Download.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/Download.java @@ -130,9 +130,9 @@ public final class Download { @FailureReason int failureReason, DownloadProgress progress) { Assertions.checkNotNull(progress); - Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED)); + Assertions.checkArgument((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED)); if (stopReason != 0) { - Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED); + Assertions.checkArgument(state != STATE_DOWNLOADING && state != STATE_QUEUED); } this.request = request; this.state = state; diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java index f42a1c6086..d7664e21ca 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DefaultDownloadIndexTest.java @@ -248,6 +248,23 @@ public class DefaultDownloadIndexTest { assertEqual(readDownload, download); } + @Test + public void setStatesToRemoving_setsStateAndClearsFailureReason() throws Exception { + String id = "id"; + DownloadBuilder downloadBuilder = + new DownloadBuilder(id) + .setState(Download.STATE_FAILED) + .setFailureReason(Download.FAILURE_REASON_UNKNOWN); + Download download = downloadBuilder.build(); + downloadIndex.putDownload(download); + + downloadIndex.setStatesToRemoving(); + + download = downloadIndex.getDownload(id); + assertThat(download.state).isEqualTo(Download.STATE_REMOVING); + assertThat(download.failureReason).isEqualTo(Download.FAILURE_REASON_NONE); + } + @Test public void setSingleDownloadStopReason_setReasonToNone() throws Exception { String id = "id"; From c6036d5271fad5e6e96db205fa001acd4a735587 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 20 Dec 2019 15:42:10 +0000 Subject: [PATCH 20/27] Add test case for mdat atom extending beyond the file length Issue: #6774 PiperOrigin-RevId: 286576383 --- .../test/assets/mp4/sample_mdat_too_long.mp4 | Bin 0 -> 101597 bytes .../mp4/sample_mdat_too_long.mp4.0.dump | 359 ++++++++++++++++++ .../mp4/sample_mdat_too_long.mp4.1.dump | 311 +++++++++++++++ .../mp4/sample_mdat_too_long.mp4.2.dump | 251 ++++++++++++ .../mp4/sample_mdat_too_long.mp4.3.dump | 191 ++++++++++ .../extractor/mp4/Mp4ExtractorTest.java | 9 + 6 files changed, 1121 insertions(+) create mode 100644 library/core/src/test/assets/mp4/sample_mdat_too_long.mp4 create mode 100644 library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump create mode 100644 library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump create mode 100644 library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump create mode 100644 library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump diff --git a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4 b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..f50d4f49de53c19d49856c047580278c9a5e80ec GIT binary patch literal 101597 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 Date: Fri, 20 Dec 2019 16:38:34 +0000 Subject: [PATCH 21/27] Fix potentially wrong window index in onMediaPeriodCreated. Issue:#6776 --- .../android/exoplayer2/analytics/AnalyticsCollector.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index 5a57844c83..b215fa5211 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -806,7 +806,10 @@ public class AnalyticsCollector public void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId) { boolean isInTimeline = timeline.getIndexOfPeriod(mediaPeriodId.periodUid) != C.INDEX_UNSET; MediaPeriodInfo mediaPeriodInfo = - new MediaPeriodInfo(mediaPeriodId, isInTimeline ? timeline : Timeline.EMPTY, windowIndex); + new MediaPeriodInfo( + mediaPeriodId, + isInTimeline ? timeline : Timeline.EMPTY, + isInTimeline ? timeline.getPeriod(periodIndex, period).windowIndex : windowIndex); mediaPeriodInfoQueue.add(mediaPeriodInfo); mediaPeriodIdToInfo.put(mediaPeriodId, mediaPeriodInfo); lastPlayingMediaPeriod = mediaPeriodInfoQueue.get(0); From c2997481322001e7700a9fe97a379b7ab6da658b Mon Sep 17 00:00:00 2001 From: tonihei Date: Fri, 20 Dec 2019 16:47:42 +0000 Subject: [PATCH 22/27] Fix build by saving periodIndex to separate variable --- .../android/exoplayer2/analytics/AnalyticsCollector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index b215fa5211..dc1089eca0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -804,7 +804,8 @@ public class AnalyticsCollector /** Updates the queue with a newly created media period. */ public void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId) { - boolean isInTimeline = timeline.getIndexOfPeriod(mediaPeriodId.periodUid) != C.INDEX_UNSET; + int periodIndex = timeline.getIndexOfPeriod(mediaPeriodId.periodUid); + boolean isInTimeline = periodIndex != C.INDEX_UNSET; MediaPeriodInfo mediaPeriodInfo = new MediaPeriodInfo( mediaPeriodId, From 72ff4504d360915101c3908577ecff4424262f9b Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 20 Dec 2019 16:51:02 +0000 Subject: [PATCH 23/27] Add troubleshooting instructions for decoding extensions PiperOrigin-RevId: 286585978 --- extensions/av1/README.md | 8 ++++++++ extensions/ffmpeg/README.md | 10 ++++++++++ extensions/flac/README.md | 8 ++++++++ extensions/opus/README.md | 8 ++++++++ extensions/vp9/README.md | 8 ++++++++ 5 files changed, 42 insertions(+) diff --git a/extensions/av1/README.md b/extensions/av1/README.md index 276daae4e2..54e27a3b87 100644 --- a/extensions/av1/README.md +++ b/extensions/av1/README.md @@ -96,6 +96,14 @@ a custom track selector the choice of `Renderer` is up to your implementation. You need to make sure you are passing a `Libgav1VideoRenderer` to the player and then you need to implement your own logic to use the renderer for a given track. +## Using the extension in the demo application ## + +To try out playback using the extension in the [demo application][], see +[enabling extension decoders][]. + +[demo application]: https://exoplayer.dev/demo-application.html +[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders + ## Rendering options ## There are two possibilities for rendering the output `Libgav1VideoRenderer` diff --git a/extensions/ffmpeg/README.md b/extensions/ffmpeg/README.md index fe4aca772a..1b2db8f0f4 100644 --- a/extensions/ffmpeg/README.md +++ b/extensions/ffmpeg/README.md @@ -106,9 +106,19 @@ then implement your own logic to use the renderer for a given track. [#2781]: https://github.com/google/ExoPlayer/issues/2781 [Supported formats]: https://exoplayer.dev/supported-formats.html#ffmpeg-extension +## Using the extension in the demo application ## + +To try out playback using the extension in the [demo application][], see +[enabling extension decoders][]. + +[demo application]: https://exoplayer.dev/demo-application.html +[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders + ## Links ## +* [Troubleshooting using extensions][] * [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.ffmpeg.*` belong to this module. +[Troubleshooting using extensions]: https://exoplayer.dev/troubleshooting.html#how-can-i-get-a-decoding-extension-to-load-and-be-used-for-playback [Javadoc]: https://exoplayer.dev/doc/reference/index.html diff --git a/extensions/flac/README.md b/extensions/flac/README.md index 84a92f9586..a9d4c3094e 100644 --- a/extensions/flac/README.md +++ b/extensions/flac/README.md @@ -97,6 +97,14 @@ a custom track selector the choice of `Renderer` is up to your implementation, so you need to make sure you are passing an `LibflacAudioRenderer` to the player, then implement your own logic to use the renderer for a given track. +## Using the extension in the demo application ## + +To try out playback using the extension in the [demo application][], see +[enabling extension decoders][]. + +[demo application]: https://exoplayer.dev/demo-application.html +[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders + ## Links ## * [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.flac.*` diff --git a/extensions/opus/README.md b/extensions/opus/README.md index 05448f2073..d3691b07bd 100644 --- a/extensions/opus/README.md +++ b/extensions/opus/README.md @@ -101,6 +101,14 @@ a custom track selector the choice of `Renderer` is up to your implementation, so you need to make sure you are passing an `LibopusAudioRenderer` to the player, then implement your own logic to use the renderer for a given track. +## Using the extension in the demo application ## + +To try out playback using the extension in the [demo application][], see +[enabling extension decoders][]. + +[demo application]: https://exoplayer.dev/demo-application.html +[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders + ## Links ## * [Javadoc][]: Classes matching `com.google.android.exoplayer2.ext.opus.*` diff --git a/extensions/vp9/README.md b/extensions/vp9/README.md index 71241d9a4f..fd0836648a 100644 --- a/extensions/vp9/README.md +++ b/extensions/vp9/README.md @@ -114,6 +114,14 @@ a custom track selector the choice of `Renderer` is up to your implementation, so you need to make sure you are passing an `LibvpxVideoRenderer` to the player, then implement your own logic to use the renderer for a given track. +## Using the extension in the demo application ## + +To try out playback using the extension in the [demo application][], see +[enabling extension decoders][]. + +[demo application]: https://exoplayer.dev/demo-application.html +[enabling extension decoders]: https://exoplayer.dev/demo-application.html#enabling-extension-decoders + ## Rendering options ## There are two possibilities for rendering the output `LibvpxVideoRenderer` From 472a4d2f5b5c32bf8fa969608f9f7af8967469ae Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 20 Dec 2019 16:57:42 +0000 Subject: [PATCH 24/27] Update release notes for #6776 PiperOrigin-RevId: 286586865 --- RELEASENOTES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3f97174278..c219ad813b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -20,6 +20,8 @@ `IllegalStateException` being thrown from `DefaultDownloadIndex.getDownloadForCurrentRow` ([#6785](https://github.com/google/ExoPlayer/issues/6785)). +* Fix `IndexOutOfBoundsException` in `SinglePeriodTimeline.getWindow` + ([#6776](https://github.com/google/ExoPlayer/issues/6776)). * Add missing @Nullable to `MediaCodecAudioRenderer.getMediaClock` and `SimpleDecoderAudioRenderer.getMediaClock` ([#6792](https://github.com/google/ExoPlayer/issues/6792)). From f6dad5cee0d0b21cda8d67ccf036579c642ccfb7 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 20 Dec 2019 20:15:27 +0000 Subject: [PATCH 25/27] Enable blacklisting for HTTP 416 Where media segments are specified using byte ranges, it makes sense that a server might return 416 (which we don't consider for blacklisting) if the segment is unavailable, rather than the 404 (which we do consider for blacklisting) that we expect when media segments are only specified using a URL. Issue: #6775 PiperOrigin-RevId: 286620698 --- .../exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java | 1 + 1 file changed, 1 insertion(+) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java index 307652f456..435f4bf578 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/upstream/DefaultLoadErrorHandlingPolicy.java @@ -71,6 +71,7 @@ public class DefaultLoadErrorHandlingPolicy implements LoadErrorHandlingPolicy { int responseCode = ((InvalidResponseCodeException) exception).responseCode; return responseCode == 404 // HTTP 404 Not Found. || responseCode == 410 // HTTP 410 Gone. + || responseCode == 416 // HTTP 416 Range Not Satisfiable. ? DEFAULT_TRACK_BLACKLIST_MS : C.TIME_UNSET; } From 924045be034c35d7378e6bdb185885e698d5b2f5 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 20 Dec 2019 17:04:06 +0000 Subject: [PATCH 26/27] Release notes tweak PiperOrigin-RevId: 286587978 --- RELEASENOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c219ad813b..49127a1099 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -22,7 +22,7 @@ ([#6785](https://github.com/google/ExoPlayer/issues/6785)). * Fix `IndexOutOfBoundsException` in `SinglePeriodTimeline.getWindow` ([#6776](https://github.com/google/ExoPlayer/issues/6776)). -* Add missing @Nullable to `MediaCodecAudioRenderer.getMediaClock` and +* Add missing `@Nullable` to `MediaCodecAudioRenderer.getMediaClock` and `SimpleDecoderAudioRenderer.getMediaClock` ([#6792](https://github.com/google/ExoPlayer/issues/6792)). From 27e48558304cdb672edf05383171215d32c255cb Mon Sep 17 00:00:00 2001 From: Oliver Woodman Date: Fri, 20 Dec 2019 22:18:52 +0000 Subject: [PATCH 27/27] Fix tests for 2.11.1 --- .../core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump | 2 -- .../core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump | 2 -- .../core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump | 2 -- .../core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump | 2 -- 4 files changed, 8 deletions(-) diff --git a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump index 3b1c90c783..4bc30a8bef 100644 --- a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump +++ b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.0.dump @@ -24,7 +24,6 @@ track 0: selectionFlags = 0 language = null drmInitData = - - metadata = null initializationData: data = length 29, hash 4746B5D9 data = length 10, hash 7A0D0F2B @@ -171,7 +170,6 @@ track 1: selectionFlags = 0 language = und drmInitData = - - metadata = entries=[TSSE: description=null: value=Lavf56.1.0] initializationData: data = length 2, hash 5F7 total output bytes = 9529 diff --git a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump index 7d8c3c1e5d..3b4906f063 100644 --- a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump +++ b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.1.dump @@ -24,7 +24,6 @@ track 0: selectionFlags = 0 language = null drmInitData = - - metadata = null initializationData: data = length 29, hash 4746B5D9 data = length 10, hash 7A0D0F2B @@ -171,7 +170,6 @@ track 1: selectionFlags = 0 language = und drmInitData = - - metadata = entries=[TSSE: description=null: value=Lavf56.1.0] initializationData: data = length 2, hash 5F7 total output bytes = 7464 diff --git a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump index a87f1678a4..b4db32c20c 100644 --- a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump +++ b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.2.dump @@ -24,7 +24,6 @@ track 0: selectionFlags = 0 language = null drmInitData = - - metadata = null initializationData: data = length 29, hash 4746B5D9 data = length 10, hash 7A0D0F2B @@ -171,7 +170,6 @@ track 1: selectionFlags = 0 language = und drmInitData = - - metadata = entries=[TSSE: description=null: value=Lavf56.1.0] initializationData: data = length 2, hash 5F7 total output bytes = 4019 diff --git a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump index 6431ca98c6..fd58d5042e 100644 --- a/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump +++ b/library/core/src/test/assets/mp4/sample_mdat_too_long.mp4.3.dump @@ -24,7 +24,6 @@ track 0: selectionFlags = 0 language = null drmInitData = - - metadata = null initializationData: data = length 29, hash 4746B5D9 data = length 10, hash 7A0D0F2B @@ -171,7 +170,6 @@ track 1: selectionFlags = 0 language = und drmInitData = - - metadata = entries=[TSSE: description=null: value=Lavf56.1.0] initializationData: data = length 2, hash 5F7 total output bytes = 470