Add nullness annotations to MediaCodecRenderer

#fixit

PiperOrigin-RevId: 570403923
(cherry picked from commit 7a91474af9)
This commit is contained in:
rohks 2023-10-03 09:02:40 -07:00 committed by oceanjules
parent 0480b70f36
commit 7957554442

View file

@ -17,6 +17,7 @@ package androidx.media3.exoplayer.mediacodec;
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.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_DRM_SESSION_CHANGED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_OPERATING_RATE_CHANGED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_REUSE_NOT_IMPLEMENTED;
@ -124,7 +125,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private static final int DECODER_QUERY_ERROR = CUSTOM_ERROR_CODE_BASE + 2;
/** The MIME type for which a decoder was being initialized. */
public final String mimeType;
@Nullable public final String mimeType;
/** Whether it was required that the decoder support a secure output path. */
public final boolean secureDecoderRequired;
@ -173,9 +174,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
private DecoderInitializationException(
String message,
@Nullable String message,
@Nullable Throwable cause,
String mimeType,
@Nullable String mimeType,
boolean secureDecoderRequired,
@Nullable MediaCodecInfo mediaCodecInfo,
@Nullable String diagnosticInfo,
@ -440,7 +441,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
targetPlaybackSpeed = 1f;
renderTimeLimitMs = C.TIME_UNSET;
pendingOutputStreamChanges = new ArrayDeque<>();
setOutputStreamInfo(OutputStreamInfo.UNSET);
outputStreamInfo = OutputStreamInfo.UNSET;
// MediaCodec outputs audio buffers in native endian:
// https://developer.android.com/reference/android/media/MediaCodec#raw-audio-buffers
// and code called from MediaCodecAudioRenderer.processOutputBuffer expects this endianness.
@ -461,6 +462,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
lastProcessedOutputBufferTimeUs = C.TIME_UNSET;
codecDrainState = DRAIN_STATE_NONE;
codecDrainAction = DRAIN_ACTION_NONE;
decoderCounters = new DecoderCounters();
}
/**
@ -544,7 +546,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
setCodecDrmSession(sourceDrmSession);
String mimeType = inputFormat.sampleMimeType;
String mimeType = checkNotNull(inputFormat).sampleMimeType;
@Nullable DrmSession codecDrmSession = this.codecDrmSession;
if (codecDrmSession != null) {
@Nullable CryptoConfig cryptoConfig = codecDrmSession.getCryptoConfig();
if (mediaCrypto == null) {
@ -568,7 +571,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
mediaCryptoRequiresSecureDecoder =
!frameworkCryptoConfig.forceAllowInsecureDecoderComponents
&& mediaCrypto.requiresSecureDecoderComponent(mimeType);
&& mediaCrypto.requiresSecureDecoderComponent(checkStateNotNull(mimeType));
}
}
if (FrameworkCryptoConfig.WORKAROUND_DEVICE_NEEDS_KEYS_TO_CONFIGURE_CODEC
@ -681,7 +684,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
outputFormatChanged = true;
}
if (outputFormatChanged || (codecOutputMediaFormatChanged && outputFormat != null)) {
onOutputFormatChanged(outputFormat, codecOutputMediaFormat);
onOutputFormatChanged(checkNotNull(outputFormat), codecOutputMediaFormat);
codecOutputMediaFormatChanged = false;
needToNotifyOutputFormatChangeAfterStreamChange = false;
}
@ -800,7 +803,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (codec != null) {
codec.release();
decoderCounters.decoderReleaseCount++;
onCodecReleased(codecInfo.name);
onCodecReleased(checkNotNull(codecInfo).name);
}
} finally {
codec = null;
@ -941,7 +944,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
/** Flushes the codec. */
private void flushCodec() {
try {
codec.flush();
checkStateNotNull(codec).flush();
} finally {
resetCodecStateForFlush();
}
@ -1035,6 +1038,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
private void maybeInitCodecWithFallback(
@Nullable MediaCrypto crypto, boolean mediaCryptoRequiresSecureDecoder)
throws DecoderInitializationException {
Format inputFormat = checkNotNull(this.inputFormat);
if (availableCodecInfos == null) {
try {
List<MediaCodecInfo> allAvailableCodecInfos =
@ -1063,9 +1067,10 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
DecoderInitializationException.NO_SUITABLE_DECODER_ERROR);
}
ArrayDeque<MediaCodecInfo> availableCodecInfos = checkNotNull(this.availableCodecInfos);
MediaCodecInfo preferredCodecInfo = availableCodecInfos.peekFirst();
while (codec == null) {
MediaCodecInfo codecInfo = availableCodecInfos.peekFirst();
MediaCodecInfo codecInfo = checkNotNull(availableCodecInfos.peekFirst());
if (!shouldInitCodec(codecInfo)) {
return;
}
@ -1106,11 +1111,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
}
availableCodecInfos = null;
this.availableCodecInfos = null;
}
private List<MediaCodecInfo> getAvailableCodecInfos(boolean mediaCryptoRequiresSecureDecoder)
throws DecoderQueryException {
Format inputFormat = checkNotNull(this.inputFormat);
List<MediaCodecInfo> codecInfos =
getDecoderInfos(mediaCodecSelector, inputFormat, mediaCryptoRequiresSecureDecoder);
if (codecInfos.isEmpty() && mediaCryptoRequiresSecureDecoder) {
@ -1150,6 +1156,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
private void initCodec(MediaCodecInfo codecInfo, @Nullable MediaCrypto crypto) throws Exception {
Format inputFormat = checkNotNull(this.inputFormat);
long codecInitializingTimestamp;
long codecInitializedTimestamp;
String codecName = codecInfo.name;
@ -1188,17 +1195,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
codecInputFormat = inputFormat;
codecAdaptationWorkaroundMode = codecAdaptationWorkaroundMode(codecName);
codecNeedsDiscardToSpsWorkaround =
codecNeedsDiscardToSpsWorkaround(codecName, codecInputFormat);
codecNeedsDiscardToSpsWorkaround(codecName, checkNotNull(codecInputFormat));
codecNeedsFlushWorkaround = codecNeedsFlushWorkaround(codecName);
codecNeedsSosFlushWorkaround = codecNeedsSosFlushWorkaround(codecName);
codecNeedsEosFlushWorkaround = codecNeedsEosFlushWorkaround(codecName);
codecNeedsEosOutputExceptionWorkaround = codecNeedsEosOutputExceptionWorkaround(codecName);
codecNeedsEosBufferTimestampWorkaround = codecNeedsEosBufferTimestampWorkaround(codecName);
codecNeedsMonoChannelCountWorkaround =
codecNeedsMonoChannelCountWorkaround(codecName, codecInputFormat);
codecNeedsMonoChannelCountWorkaround(codecName, checkNotNull(codecInputFormat));
codecNeedsEosPropagation =
codecNeedsEosPropagationWorkaround(codecInfo) || getCodecNeedsEosPropagation();
if (codec.needsReconfiguration()) {
if (checkNotNull(codec).needsReconfiguration()) {
this.codecReconfigured = true;
this.codecReconfigurationState = RECONFIGURATION_STATE_WRITE_PENDING;
this.codecNeedsAdaptationWorkaroundBuffer =
@ -1255,6 +1262,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
drainAndReinitializeCodec();
}
MediaCodecAdapter codec = checkNotNull(this.codec);
if (inputIndex < 0) {
inputIndex = codec.dequeueInputBufferIndex();
if (inputIndex < 0) {
@ -1280,7 +1288,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (codecNeedsAdaptationWorkaroundBuffer) {
codecNeedsAdaptationWorkaroundBuffer = false;
buffer.data.put(ADAPTATION_WORKAROUND_BUFFER);
checkNotNull(buffer.data).put(ADAPTATION_WORKAROUND_BUFFER);
codec.queueInputBuffer(inputIndex, 0, ADAPTATION_WORKAROUND_BUFFER.length, 0, 0);
resetInputBuffer();
codecReceivedBuffers = true;
@ -1290,13 +1298,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
// For adaptive reconfiguration, decoders expect all reconfiguration data to be supplied at
// the start of the buffer that also contains the first frame in the new format.
if (codecReconfigurationState == RECONFIGURATION_STATE_WRITE_PENDING) {
for (int i = 0; i < codecInputFormat.initializationData.size(); i++) {
for (int i = 0; i < checkNotNull(codecInputFormat).initializationData.size(); i++) {
byte[] data = codecInputFormat.initializationData.get(i);
buffer.data.put(data);
checkNotNull(buffer.data).put(data);
}
codecReconfigurationState = RECONFIGURATION_STATE_QUEUE_PENDING;
}
int adaptiveReconfigurationBytes = buffer.data.position();
int adaptiveReconfigurationBytes = checkNotNull(buffer.data).position();
FormatHolder formatHolder = getFormatHolder();
@ -1386,8 +1394,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
buffer.cryptoInfo.increaseClearDataFirstSubSampleBy(adaptiveReconfigurationBytes);
}
if (codecNeedsDiscardToSpsWorkaround && !bufferEncrypted) {
NalUnitUtil.discardToSps(buffer.data);
if (buffer.data.position() == 0) {
NalUnitUtil.discardToSps(checkNotNull(buffer.data));
if (checkNotNull(buffer.data).position() == 0) {
return true;
}
codecNeedsDiscardToSpsWorkaround = false;
@ -1397,9 +1405,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (waitingForFirstSampleInFormat) {
if (!pendingOutputStreamChanges.isEmpty()) {
pendingOutputStreamChanges.peekLast().formatQueue.add(presentationTimeUs, inputFormat);
pendingOutputStreamChanges
.peekLast()
.formatQueue
.add(presentationTimeUs, checkNotNull(inputFormat));
} else {
outputStreamInfo.formatQueue.add(presentationTimeUs, inputFormat);
outputStreamInfo.formatQueue.add(presentationTimeUs, checkNotNull(inputFormat));
}
waitingForFirstSampleInFormat = false;
}
@ -1416,11 +1427,17 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
onQueueInputBuffer(buffer);
try {
if (bufferEncrypted) {
codec.queueSecureInputBuffer(
inputIndex, /* offset= */ 0, buffer.cryptoInfo, presentationTimeUs, /* flags= */ 0);
checkNotNull(codec)
.queueSecureInputBuffer(
inputIndex, /* offset= */ 0, buffer.cryptoInfo, presentationTimeUs, /* flags= */ 0);
} else {
codec.queueInputBuffer(
inputIndex, /* offset= */ 0, buffer.data.limit(), presentationTimeUs, /* flags= */ 0);
checkNotNull(codec)
.queueInputBuffer(
inputIndex,
/* offset= */ 0,
checkNotNull(buffer.data).limit(),
presentationTimeUs,
/* flags= */ 0);
}
} catch (CryptoException e) {
throw createRendererException(
@ -1535,9 +1552,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
// Copy the current codec and codecInfo to local variables so they remain accessible if the
// member variables are updated during the logic below.
MediaCodecAdapter codec = this.codec;
MediaCodecInfo codecInfo = this.codecInfo;
MediaCodecInfo codecInfo = checkNotNull(this.codecInfo);
Format oldFormat = codecInputFormat;
Format oldFormat = checkNotNull(codecInputFormat);
if (drmNeedsCodecReinitialization(codecInfo, newFormat, codecDrmSession, sourceDrmSession)) {
drainAndReinitializeCodec();
return new DecoderReuseEvaluation(
@ -1663,7 +1680,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
lastProcessedOutputBufferTimeUs = presentationTimeUs;
while (!pendingOutputStreamChanges.isEmpty()
&& presentationTimeUs >= pendingOutputStreamChanges.peek().previousStreamLastBufferTimeUs) {
setOutputStreamInfo(pendingOutputStreamChanges.poll());
setOutputStreamInfo(checkNotNull(pendingOutputStreamChanges.poll()));
onProcessedStreamChange();
}
}
@ -1767,7 +1784,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
* @throws ExoPlaybackException If an error occurs releasing or initializing a codec.
* @return False if codec release and re-initialization was triggered. True in all other cases.
*/
private boolean updateCodecOperatingRate(Format format) throws ExoPlaybackException {
private boolean updateCodecOperatingRate(@Nullable Format format) throws ExoPlaybackException {
if (Util.SDK_INT < 23) {
return true;
}
@ -1780,7 +1797,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
}
float newCodecOperatingRate =
getCodecOperatingRateV23(targetPlaybackSpeed, format, getStreamFormats());
getCodecOperatingRateV23(targetPlaybackSpeed, checkNotNull(format), getStreamFormats());
if (codecOperatingRate == newCodecOperatingRate) {
// No change.
return true;
@ -1795,7 +1812,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
// above the assumed minimum rate.
Bundle codecParameters = new Bundle();
codecParameters.putFloat(MediaFormat.KEY_OPERATING_RATE, newCodecOperatingRate);
codec.setParameters(codecParameters);
checkNotNull(codec).setParameters(codecParameters);
codecOperatingRate = newCodecOperatingRate;
return true;
}
@ -1871,6 +1888,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
*/
private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs)
throws ExoPlaybackException {
MediaCodecAdapter codec = checkNotNull(this.codec);
if (!hasOutputBuffer()) {
int outputIndex;
if (codecNeedsEosOutputExceptionWorkaround && codecReceivedEos) {
@ -1950,7 +1968,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
outputBufferInfo.presentationTimeUs,
isDecodeOnlyOutputBuffer,
isLastOutputBuffer,
outputFormat);
checkNotNull(outputFormat));
} catch (IllegalStateException e) {
processEndOfStream();
if (outputStreamEnded) {
@ -1972,7 +1990,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
outputBufferInfo.presentationTimeUs,
isDecodeOnlyOutputBuffer,
isLastOutputBuffer,
outputFormat);
checkNotNull(outputFormat));
}
if (processedOutputBuffer) {
@ -1991,7 +2009,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
/** Processes a change in the decoder output {@link MediaFormat}. */
private void processOutputMediaFormatChanged() {
codecHasOutputMediaFormat = true;
MediaFormat mediaFormat = codec.getOutputFormat();
MediaFormat mediaFormat = checkNotNull(codec).getOutputFormat();
if (codecAdaptationWorkaroundMode != ADAPTATION_WORKAROUND_MODE_NEVER
&& mediaFormat.getInteger(MediaFormat.KEY_WIDTH) == ADAPTATION_WORKAROUND_SLICE_WIDTH_HEIGHT
&& mediaFormat.getInteger(MediaFormat.KEY_HEIGHT)
@ -2209,7 +2227,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
if (newFrameworkCryptoConfig.forceAllowInsecureDecoderComponents) {
requiresSecureDecoder = false;
} else {
requiresSecureDecoder = newSession.requiresSecureDecoder(newFormat.sampleMimeType);
requiresSecureDecoder =
newSession.requiresSecureDecoder(checkNotNull(newFormat.sampleMimeType));
}
if (!codecInfo.secure && requiresSecureDecoder) {
// Re-initialization is required because newSession might require switching to the secure
@ -2227,10 +2246,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
@RequiresApi(23)
private void updateDrmSessionV23() throws ExoPlaybackException {
CryptoConfig cryptoConfig = sourceDrmSession.getCryptoConfig();
CryptoConfig cryptoConfig = checkNotNull(sourceDrmSession).getCryptoConfig();
if (cryptoConfig instanceof FrameworkCryptoConfig) {
try {
mediaCrypto.setMediaDrmSession(((FrameworkCryptoConfig) cryptoConfig).sessionId);
checkNotNull(mediaCrypto)
.setMediaDrmSession(((FrameworkCryptoConfig) cryptoConfig).sessionId);
} catch (MediaCryptoException e) {
throw createRendererException(
e, inputFormat, PlaybackException.ERROR_CODE_DRM_SYSTEM_ERROR);
@ -2271,7 +2291,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
bypassBatchBuffer.getFirstSampleTimeUs(),
isDecodeOnly,
bypassBatchBuffer.isEndOfStream(),
outputFormat)) {
checkNotNull(outputFormat))) {
// The batch buffer has been fully processed.
onProcessedOutputBuffer(bypassBatchBuffer.getLastSampleTimeUs());
bypassBatchBuffer.clear();
@ -2347,7 +2367,11 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
// TODO(b/298634018): Adjust encoderDelay value based on starting position.
int numberPreSkipSamples =
OpusUtil.getPreSkipSamples(outputFormat.initializationData.get(0));
outputFormat = outputFormat.buildUpon().setEncoderDelay(numberPreSkipSamples).build();
outputFormat =
checkNotNull(outputFormat)
.buildUpon()
.setEncoderDelay(numberPreSkipSamples)
.build();
}
onOutputFormatChanged(outputFormat, /* mediaFormat= */ null);
waitingForFirstSampleInFormat = false;
@ -2362,7 +2386,8 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
bypassSampleBuffer.format = outputFormat;
handleInputBufferSupplementalData(bypassSampleBuffer);
}
oggOpusAudioPacketizer.packetize(bypassSampleBuffer, outputFormat.initializationData);
oggOpusAudioPacketizer.packetize(
bypassSampleBuffer, checkNotNull(outputFormat).initializationData);
}
if (!haveBypassBatchBufferAndNewSampleSameDecodeOnlyState()
|| !bypassBatchBuffer.append(bypassSampleBuffer)) {