diff --git a/libraries/common/src/main/java/androidx/media3/common/util/Util.java b/libraries/common/src/main/java/androidx/media3/common/util/Util.java index 374e70f689..98d1113eda 100644 --- a/libraries/common/src/main/java/androidx/media3/common/util/Util.java +++ b/libraries/common/src/main/java/androidx/media3/common/util/Util.java @@ -69,6 +69,7 @@ import android.security.NetworkSecurityPolicy; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Base64; +import android.util.SparseArray; import android.util.SparseLongArray; import android.view.Display; import android.view.SurfaceView; @@ -516,6 +517,16 @@ public final class Util { return false; } + /** + * Tests whether a {@link SparseArray} contains a given {@code key}. + * + *

This implements {@code SparseArray#contains} for lower API versions. + */ + @UnstableApi + public static boolean containsKey(SparseArray sparseArray, int key) { + return sparseArray.indexOfKey(key) >= 0; + } + /** * Removes an indexed range from a List. * diff --git a/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java b/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java index 058492ed8d..8edab8770b 100644 --- a/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java +++ b/libraries/effect/src/main/java/androidx/media3/effect/InputSwitcher.java @@ -20,6 +20,7 @@ package androidx.media3.effect; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkStateNotNull; +import static androidx.media3.common.util.Util.containsKey; import android.content.Context; import android.util.SparseArray; @@ -147,7 +148,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; */ public void switchToInput(@VideoFrameProcessor.InputType int newInputType) { checkStateNotNull(downstreamShaderProgram); - checkState(inputs.indexOfKey(newInputType) >= 0, "Input type not registered: " + newInputType); + checkState(containsKey(inputs, newInputType), "Input type not registered: " + newInputType); for (int i = 0; i < inputs.size(); i++) { @VideoFrameProcessor.InputType int inputType = inputs.keyAt(i); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioMixerImpl.java b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioMixerImpl.java index 8a27712906..8bee6e9172 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/AudioMixerImpl.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/AudioMixerImpl.java @@ -18,7 +18,7 @@ package androidx.media3.transformer; import static androidx.media3.common.audio.AudioProcessor.EMPTY_BUFFER; import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkState; -import static androidx.media3.common.util.Assertions.checkStateNotNull; +import static androidx.media3.common.util.Util.containsKey; import static java.lang.Math.max; import static java.lang.Math.min; @@ -153,7 +153,7 @@ import java.nio.ByteOrder; public boolean hasSource(int sourceId) { checkStateIsConfigured(); - return sources.get(sourceId) != null; + return containsKey(sources, sourceId); } @Override @@ -295,7 +295,8 @@ import java.nio.ByteOrder; } private SourceInfo getSourceById(int sourceId) { - return checkStateNotNull(sources.get(sourceId), "Source not found."); + checkState(containsKey(sources, sourceId), "Source not found."); + return sources.get(sourceId); } /** A buffer holding partially-mixed audio within an interval. */ diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java index ec3b2a18e3..8ebf121719 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/MuxerWrapper.java @@ -19,6 +19,7 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkState; +import static androidx.media3.common.util.Util.containsKey; import static java.lang.Math.max; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -174,9 +175,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; trackType == C.TRACK_TYPE_AUDIO || trackType == C.TRACK_TYPE_VIDEO, "Unsupported track format: " + sampleMimeType); - // SparseArray.get() returns null by default if the value is not found. checkState( - trackTypeToInfo.get(trackType) == null, "There is already a track of type " + trackType); + !containsKey(trackTypeToInfo, trackType), "There is already a track of type " + trackType); ensureMuxerInitialized(); @@ -218,10 +218,8 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; public boolean writeSample( @C.TrackType int trackType, ByteBuffer data, boolean isKeyFrame, long presentationTimeUs) throws Muxer.MuxerException { - @Nullable TrackInfo trackInfo = trackTypeToInfo.get(trackType); - // SparseArray.get() returns null by default if the value is not found. - checkArgument( - trackInfo != null, "Could not write sample because there is no track of type " + trackType); + checkArgument(containsKey(trackTypeToInfo, trackType)); + TrackInfo trackInfo = trackTypeToInfo.get(trackType); boolean canWriteSample = canWriteSample(trackType, presentationTimeUs); if (trackType == C.TRACK_TYPE_VIDEO) { DebugTraceUtil.logEvent( @@ -262,12 +260,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull; * @param trackType The {@link C.TrackType}. */ public void endTrack(@C.TrackType int trackType) { - @Nullable TrackInfo trackInfo = trackTypeToInfo.get(trackType); - if (trackInfo == null) { - // SparseArray.get() returns null by default if the value is not found. + if (!containsKey(trackTypeToInfo, trackType)) { return; } + TrackInfo trackInfo = trackTypeToInfo.get(trackType); maxEndedTrackTimeUs = max(maxEndedTrackTimeUs, trackInfo.timeUs); listener.onTrackEnded( trackType, trackInfo.format, trackInfo.getAverageBitrate(), trackInfo.sampleCount); diff --git a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java index 9dbf2b1233..696686a51a 100644 --- a/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java +++ b/libraries/transformer/src/main/java/androidx/media3/transformer/TransformerInternal.java @@ -18,6 +18,7 @@ package androidx.media3.transformer; import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkState; +import static androidx.media3.common.util.Util.containsKey; import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_DECODED; import static androidx.media3.transformer.AssetLoader.SUPPORTED_OUTPUT_TYPE_ENCODED; import static androidx.media3.transformer.Composition.HDR_MODE_KEEP_HDR; @@ -792,7 +793,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public Format getAssetLoaderInputFormat(int sequenceIndex, @C.TrackType int trackType) { SparseArray trackTypeToFirstAssetLoaderInputFormat = sequencesMetadata.get(sequenceIndex).trackTypeToFirstAssetLoaderInputFormat; - checkState(contains(trackTypeToFirstAssetLoaderInputFormat, trackType)); + checkState(containsKey(trackTypeToFirstAssetLoaderInputFormat, trackType)); return trackTypeToFirstAssetLoaderInputFormat.get(trackType); } @@ -833,7 +834,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; @C.TrackType int trackType = getProcessedTrackType(assetLoaderInputFormat.sampleMimeType); SparseArray trackTypeToFirstAssetLoaderInputFormat = sequencesMetadata.get(sequenceIndex).trackTypeToFirstAssetLoaderInputFormat; - checkState(!contains(trackTypeToFirstAssetLoaderInputFormat, trackType)); + checkState(!containsKey(trackTypeToFirstAssetLoaderInputFormat, trackType)); trackTypeToFirstAssetLoaderInputFormat.put(trackType, assetLoaderInputFormat); } @@ -841,7 +842,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; * Returns the index of the primary sequence for a given {@link C.TrackType trackType}. * *

A primary sequence for a {@link C.TrackType trackType} is defined as the lowest indexed - * sequence that contains a track of the given {@code trackType}. + * sequence that containsKey a track of the given {@code trackType}. */ public int getIndexForPrimarySequence(@C.TrackType int trackType) { checkState( @@ -850,7 +851,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; for (int i = 0; i < sequencesMetadata.size(); i++) { SparseArray trackTypeToFirstAssetLoaderInputFormat = sequencesMetadata.get(i).trackTypeToFirstAssetLoaderInputFormat; - if (contains(trackTypeToFirstAssetLoaderInputFormat, trackType)) { + if (containsKey(trackTypeToFirstAssetLoaderInputFormat, trackType)) { return i; } } @@ -881,7 +882,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; */ public void registerGraphInput(@C.TrackType int trackType) { int numberOfGraphInputForTrackType = 1; - if (contains(trackTypeToNumberOfRegisteredGraphInput, trackType)) { + if (containsKey(trackTypeToNumberOfRegisteredGraphInput, trackType)) { numberOfGraphInputForTrackType += trackTypeToNumberOfRegisteredGraphInput.get(trackType); } trackTypeToNumberOfRegisteredGraphInput.put(trackType, numberOfGraphInputForTrackType); @@ -894,7 +895,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; public boolean hasAssociatedAllTracksWithGraphInput(@C.TrackType int trackType) { int numberOfTracksForTrackType = 0; for (int i = 0; i < sequencesMetadata.size(); i++) { - if (contains(sequencesMetadata.get(i).trackTypeToFirstAssetLoaderInputFormat, trackType)) { + if (containsKey( + sequencesMetadata.get(i).trackTypeToFirstAssetLoaderInputFormat, trackType)) { numberOfTracksForTrackType++; } } @@ -908,10 +910,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; for (int i = 0; i < sequencesMetadata.size(); i++) { SparseArray trackTypeToFirstAssetLoaderInputFormat = sequencesMetadata.get(i).trackTypeToFirstAssetLoaderInputFormat; - if (contains(trackTypeToFirstAssetLoaderInputFormat, C.TRACK_TYPE_AUDIO)) { + if (containsKey(trackTypeToFirstAssetLoaderInputFormat, C.TRACK_TYPE_AUDIO)) { outputHasAudio = true; } - if (contains(trackTypeToFirstAssetLoaderInputFormat, C.TRACK_TYPE_VIDEO)) { + if (containsKey(trackTypeToFirstAssetLoaderInputFormat, C.TRACK_TYPE_VIDEO)) { outputHasVideo = true; } } @@ -921,14 +923,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Registers a {@link SampleExporter} for the given {@link C.TrackType trackType}. */ public void registerSampleExporter(int trackType, SampleExporter sampleExporter) { checkState( - !contains(trackTypeToSampleExporter, trackType), + !containsKey(trackTypeToSampleExporter, trackType), "Exactly one SampleExporter can be added for each track type."); trackTypeToSampleExporter.put(trackType, sampleExporter); } /** Sets whether a track should be transcoded. */ public void setShouldTranscode(@C.TrackType int trackType, boolean shouldTranscode) { - if (contains(trackTypeToShouldTranscode, trackType)) { + if (containsKey(trackTypeToShouldTranscode, trackType)) { checkState(shouldTranscode == trackTypeToShouldTranscode.get(trackType)); return; } @@ -937,7 +939,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; /** Returns whether a track should be transcoded. */ public boolean shouldTranscode(@C.TrackType int trackType) { - checkState(contains(trackTypeToShouldTranscode, trackType)); + checkState(containsKey(trackTypeToShouldTranscode, trackType)); return trackTypeToShouldTranscode.get(trackType); } @@ -962,10 +964,5 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull; requiredTrackCount = C.LENGTH_UNSET; } } - - /** Implements {@code SparseArray#contains} for lower API versions. */ - private static boolean contains(SparseArray sparseArray, int key) { - return sparseArray.get(key) != null; - } } }