diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java index 0609b0242d..e1faa6e39e 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SampleQueue.java @@ -725,15 +725,12 @@ public class SampleQueue implements TrackOutput { return false; } - @Nullable SharedSampleMetadata upstreamCommittedMetadata = sharedSampleMetadata.getEndValue(); - @Nullable - Format upstreamCommittedFormat = - upstreamCommittedMetadata != null ? upstreamCommittedMetadata.format : null; - if (Util.areEqual(format, upstreamCommittedFormat)) { + if (!sharedSampleMetadata.isEmpty() + && sharedSampleMetadata.getEndValue().format.equals(format)) { // The format has changed back to the format of the last committed sample. If they are // different objects, we revert back to using upstreamCommittedFormat as the upstreamFormat // so we can detect format changes on the read side using cheap referential equality. - upstreamFormat = upstreamCommittedFormat; + upstreamFormat = sharedSampleMetadata.getEndValue().format; } else { upstreamFormat = format; } @@ -804,9 +801,8 @@ public class SampleQueue implements TrackOutput { cryptoDatas[relativeEndIndex] = cryptoData; sourceIds[relativeEndIndex] = upstreamSourceId; - @Nullable SharedSampleMetadata upstreamCommittedMetadata = sharedSampleMetadata.getEndValue(); - if (upstreamCommittedMetadata == null - || !upstreamCommittedMetadata.format.equals(upstreamFormat)) { + if (sharedSampleMetadata.isEmpty() + || !sharedSampleMetadata.getEndValue().format.equals(upstreamFormat)) { DrmSessionReference drmSessionReference = drmSessionManager != null ? drmSessionManager.preacquireSession( diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SpannedData.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SpannedData.java index a3903222d2..d17af6331d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SpannedData.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SpannedData.java @@ -20,7 +20,6 @@ import static com.google.android.exoplayer2.util.Assertions.checkState; import static java.lang.Math.min; import android.util.SparseArray; -import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.util.Consumer; @@ -60,8 +59,7 @@ import com.google.android.exoplayer2.util.Consumer; /** * Returns the value associated with the span covering {@code key}. * - *

{@link #appendSpan(int, Object)} must have been called at least once since the last call to - * {@link #clear()}. + *

The collection must not be {@link #isEmpty() empty}. * *

{@code key} must be greater than or equal to the previous value passed to {@link * #discardTo(int)} (or zero after {@link #clear()} has been called). @@ -103,14 +101,15 @@ import com.google.android.exoplayer2.util.Consumer; } /** - * Returns the value associated with the end span, or null if the collection is empty. + * Returns the value associated with the end span. + * + *

The collection must not be {@link #isEmpty() empty}. * *

This is either the last value passed to {@link #appendSpan(int, Object)}, or the value of * the span covering the index passed to {@link #discardFrom(int)}. */ - @Nullable public V getEndValue() { - return spans.size() != 0 ? spans.valueAt(spans.size() - 1) : null; + return spans.valueAt(spans.size() - 1); } /** @@ -150,4 +149,9 @@ import com.google.android.exoplayer2.util.Consumer; memoizedReadIndex = C.INDEX_UNSET; spans.clear(); } + + /** Returns true if the collection is empty. */ + public boolean isEmpty() { + return spans.size() == 0; + } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/source/SpannedDataTest.java b/library/core/src/test/java/com/google/android/exoplayer2/source/SpannedDataTest.java index 01411d97d7..4dcccbaaad 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/source/SpannedDataTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/source/SpannedDataTest.java @@ -16,6 +16,7 @@ package com.google.android.exoplayer2.source; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -73,6 +74,25 @@ public final class SpannedDataTest { assertThat(spannedData.get(3)).isEqualTo(value3); } + @Test + public void getEndValue() { + SpannedData spannedData = new SpannedData<>(); + + assertThrows(Exception.class, spannedData::getEndValue); + + spannedData.appendSpan(/* startKey= */ 0, "test 1"); + spannedData.appendSpan(/* startKey= */ 2, "test 2"); + spannedData.appendSpan(/* startKey= */ 4, "test 3"); + + assertThat(spannedData.getEndValue()).isEqualTo("test 3"); + + spannedData.discardFrom(2); + assertThat(spannedData.getEndValue()).isEqualTo("test 2"); + + spannedData.clear(); + assertThrows(Exception.class, spannedData::getEndValue); + } + @Test public void discardTo() { SpannedData spannedData = @@ -173,4 +193,30 @@ public final class SpannedDataTest { assertThat(spannedData.get(0)).isEqualTo(value3); assertThat(spannedData.get(1)).isEqualTo(value3); } + + @Test + public void isEmpty() { + SpannedData spannedData = new SpannedData<>(); + + assertThat(spannedData.isEmpty()).isTrue(); + + spannedData.appendSpan(/* startKey= */ 0, "test 1"); + spannedData.appendSpan(/* startKey= */ 2, "test 2"); + + assertThat(spannedData.isEmpty()).isFalse(); + + // Discarding from 0 still retains the 'first' span, so collection doesn't end up empty. + spannedData.discardFrom(0); + assertThat(spannedData.isEmpty()).isFalse(); + + spannedData.appendSpan(/* startKey= */ 2, "test 2"); + + // Discarding to 3 still retains the 'last' span, so collection doesn't end up empty. + spannedData.discardTo(3); + assertThat(spannedData.isEmpty()).isFalse(); + + spannedData.clear(); + + assertThat(spannedData.isEmpty()).isTrue(); + } }