Add nullness annotations to DecoderVideoRenderer

Also fixed a bug where format queue was polled with wrong timestamp value.

#fixit

PiperOrigin-RevId: 570420304
This commit is contained in:
rohks 2023-10-03 10:04:21 -07:00 committed by Copybara-Service
parent 7a91474af9
commit a879bae1ee
2 changed files with 44 additions and 37 deletions

View file

@ -15,6 +15,7 @@
*/ */
package androidx.media3.exoplayer.video; package androidx.media3.exoplayer.video;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Util.msToUs; import static androidx.media3.common.util.Util.msToUs;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_DRM_SESSION_CHANGED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_DRM_SESSION_CHANGED;
import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_REUSE_NOT_IMPLEMENTED; import static androidx.media3.exoplayer.DecoderReuseEvaluation.DISCARD_REASON_REUSE_NOT_IMPLEMENTED;
@ -116,16 +117,16 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
private final TimedValueQueue<Format> formatQueue; private final TimedValueQueue<Format> formatQueue;
private final DecoderInputBuffer flagsOnlyBuffer; private final DecoderInputBuffer flagsOnlyBuffer;
private Format inputFormat; @Nullable private Format inputFormat;
private Format outputFormat; @Nullable private Format outputFormat;
@Nullable @Nullable
private Decoder< private Decoder<
DecoderInputBuffer, ? extends VideoDecoderOutputBuffer, ? extends DecoderException> DecoderInputBuffer, ? extends VideoDecoderOutputBuffer, ? extends DecoderException>
decoder; decoder;
private DecoderInputBuffer inputBuffer; @Nullable private DecoderInputBuffer inputBuffer;
private VideoDecoderOutputBuffer outputBuffer; @Nullable private VideoDecoderOutputBuffer outputBuffer;
private @VideoOutputMode int outputMode; private @VideoOutputMode int outputMode;
@Nullable private Object output; @Nullable private Object output;
@Nullable private Surface outputSurface; @Nullable private Surface outputSurface;
@ -175,13 +176,13 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
this.allowedJoiningTimeMs = allowedJoiningTimeMs; this.allowedJoiningTimeMs = allowedJoiningTimeMs;
this.maxDroppedFramesToNotify = maxDroppedFramesToNotify; this.maxDroppedFramesToNotify = maxDroppedFramesToNotify;
joiningDeadlineMs = C.TIME_UNSET; joiningDeadlineMs = C.TIME_UNSET;
clearReportedVideoSize();
formatQueue = new TimedValueQueue<>(); formatQueue = new TimedValueQueue<>();
flagsOnlyBuffer = DecoderInputBuffer.newNoDataInstance(); flagsOnlyBuffer = DecoderInputBuffer.newNoDataInstance();
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
decoderReinitializationState = REINITIALIZATION_STATE_NONE; decoderReinitializationState = REINITIALIZATION_STATE_NONE;
outputMode = C.VIDEO_OUTPUT_MODE_NONE; outputMode = C.VIDEO_OUTPUT_MODE_NONE;
firstFrameState = C.FIRST_FRAME_NOT_RENDERED_ONLY_ALLOWED_IF_STARTED; firstFrameState = C.FIRST_FRAME_NOT_RENDERED_ONLY_ALLOWED_IF_STARTED;
decoderCounters = new DecoderCounters();
} }
// BaseRenderer implementation. // BaseRenderer implementation.
@ -324,7 +325,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
@Override @Override
protected void onDisabled() { protected void onDisabled() {
inputFormat = null; inputFormat = null;
clearReportedVideoSize(); reportedVideoSize = null;
lowerFirstFrameState(C.FIRST_FRAME_NOT_RENDERED_ONLY_ALLOWED_IF_STARTED); lowerFirstFrameState(C.FIRST_FRAME_NOT_RENDERED_ONLY_ALLOWED_IF_STARTED);
try { try {
setSourceDrmSession(null); setSourceDrmSession(null);
@ -365,7 +366,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
outputBuffer.release(); outputBuffer.release();
outputBuffer = null; outputBuffer = null;
} }
decoder.flush(); checkNotNull(decoder).flush();
decoderReceivedBuffers = false; decoderReceivedBuffers = false;
} }
} }
@ -403,7 +404,8 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
if (decoder == null) { if (decoder == null) {
maybeInitDecoder(); maybeInitDecoder();
eventDispatcher.inputFormatChanged(inputFormat, /* decoderReuseEvaluation= */ null); eventDispatcher.inputFormatChanged(
checkNotNull(inputFormat), /* decoderReuseEvaluation= */ null);
return; return;
} }
@ -412,12 +414,12 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
evaluation = evaluation =
new DecoderReuseEvaluation( new DecoderReuseEvaluation(
decoder.getName(), decoder.getName(),
oldFormat, checkNotNull(oldFormat),
newFormat, newFormat,
REUSE_RESULT_NO, REUSE_RESULT_NO,
DISCARD_REASON_DRM_SESSION_CHANGED); DISCARD_REASON_DRM_SESSION_CHANGED);
} else { } else {
evaluation = canReuseDecoder(decoder.getName(), oldFormat, newFormat); evaluation = canReuseDecoder(decoder.getName(), checkNotNull(oldFormat), newFormat);
} }
if (evaluation.result == REUSE_RESULT_NO) { if (evaluation.result == REUSE_RESULT_NO) {
@ -430,7 +432,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
maybeInitDecoder(); maybeInitDecoder();
} }
} }
eventDispatcher.inputFormatChanged(inputFormat, evaluation); eventDispatcher.inputFormatChanged(checkNotNull(inputFormat), evaluation);
} }
/** /**
@ -598,9 +600,9 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
} else { } else {
maybeNotifyVideoSizeChanged(outputBuffer.width, outputBuffer.height); maybeNotifyVideoSizeChanged(outputBuffer.width, outputBuffer.height);
if (renderYuv) { if (renderYuv) {
outputBufferRenderer.setOutputBuffer(outputBuffer); checkNotNull(outputBufferRenderer).setOutputBuffer(outputBuffer);
} else { } else {
renderOutputBufferToSurface(outputBuffer, outputSurface); renderOutputBufferToSurface(outputBuffer, checkNotNull(outputSurface));
} }
consecutiveDroppedFrameCount = 0; consecutiveDroppedFrameCount = 0;
decoderCounters.renderedOutputBufferCount++; decoderCounters.renderedOutputBufferCount++;
@ -715,11 +717,11 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
try { try {
long decoderInitializingTimestamp = SystemClock.elapsedRealtime(); long decoderInitializingTimestamp = SystemClock.elapsedRealtime();
decoder = createDecoder(inputFormat, cryptoConfig); decoder = createDecoder(checkNotNull(inputFormat), cryptoConfig);
setDecoderOutputMode(outputMode); setDecoderOutputMode(outputMode);
long decoderInitializedTimestamp = SystemClock.elapsedRealtime(); long decoderInitializedTimestamp = SystemClock.elapsedRealtime();
eventDispatcher.decoderInitialized( eventDispatcher.decoderInitialized(
decoder.getName(), checkNotNull(decoder).getName(),
decoderInitializedTimestamp, decoderInitializedTimestamp,
decoderInitializedTimestamp - decoderInitializingTimestamp); decoderInitializedTimestamp - decoderInitializingTimestamp);
decoderCounters.decoderInitCount++; decoderCounters.decoderInitCount++;
@ -749,10 +751,11 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
} }
} }
DecoderInputBuffer inputBuffer = checkNotNull(this.inputBuffer);
if (decoderReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) { if (decoderReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
inputBuffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM); inputBuffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
decoder.queueInputBuffer(inputBuffer); checkNotNull(decoder).queueInputBuffer(inputBuffer);
inputBuffer = null; this.inputBuffer = null;
decoderReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM; decoderReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM;
return false; return false;
} }
@ -767,12 +770,12 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
case C.RESULT_BUFFER_READ: case C.RESULT_BUFFER_READ:
if (inputBuffer.isEndOfStream()) { if (inputBuffer.isEndOfStream()) {
inputStreamEnded = true; inputStreamEnded = true;
decoder.queueInputBuffer(inputBuffer); checkNotNull(decoder).queueInputBuffer(inputBuffer);
inputBuffer = null; this.inputBuffer = null;
return false; return false;
} }
if (waitingForFirstSampleInFormat) { if (waitingForFirstSampleInFormat) {
formatQueue.add(inputBuffer.timeUs, inputFormat); formatQueue.add(inputBuffer.timeUs, checkNotNull(inputFormat));
waitingForFirstSampleInFormat = false; waitingForFirstSampleInFormat = false;
} }
if (inputBuffer.timeUs < getLastResetPositionUs()) { if (inputBuffer.timeUs < getLastResetPositionUs()) {
@ -781,11 +784,11 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
inputBuffer.flip(); inputBuffer.flip();
inputBuffer.format = inputFormat; inputBuffer.format = inputFormat;
onQueueInputBuffer(inputBuffer); onQueueInputBuffer(inputBuffer);
decoder.queueInputBuffer(inputBuffer); checkNotNull(decoder).queueInputBuffer(inputBuffer);
buffersInCodecCount++; buffersInCodecCount++;
decoderReceivedBuffers = true; decoderReceivedBuffers = true;
decoderCounters.queuedInputBufferCount++; decoderCounters.queuedInputBufferCount++;
inputBuffer = null; this.inputBuffer = null;
return true; return true;
default: default:
throw new IllegalStateException(); throw new IllegalStateException();
@ -805,7 +808,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs) private boolean drainOutputBuffer(long positionUs, long elapsedRealtimeUs)
throws ExoPlaybackException, DecoderException { throws ExoPlaybackException, DecoderException {
if (outputBuffer == null) { if (outputBuffer == null) {
outputBuffer = decoder.dequeueOutputBuffer(); outputBuffer = checkNotNull(decoder).dequeueOutputBuffer();
if (outputBuffer == null) { if (outputBuffer == null) {
return false; return false;
} }
@ -828,7 +831,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
boolean processedOutputBuffer = processOutputBuffer(positionUs, elapsedRealtimeUs); boolean processedOutputBuffer = processOutputBuffer(positionUs, elapsedRealtimeUs);
if (processedOutputBuffer) { if (processedOutputBuffer) {
onProcessedOutputBuffer(outputBuffer.timeUs); onProcessedOutputBuffer(checkNotNull(outputBuffer).timeUs);
outputBuffer = null; outputBuffer = null;
} }
return processedOutputBuffer; return processedOutputBuffer;
@ -850,7 +853,9 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
initialPositionUs = positionUs; initialPositionUs = positionUs;
} }
long earlyUs = outputBuffer.timeUs - positionUs; VideoDecoderOutputBuffer outputBuffer = checkNotNull(this.outputBuffer);
long bufferTimeUs = outputBuffer.timeUs;
long earlyUs = bufferTimeUs - positionUs;
if (!hasOutput()) { if (!hasOutput()) {
// Skip frames in sync with playback, so we'll be at the right frame if the mode changes. // Skip frames in sync with playback, so we'll be at the right frame if the mode changes.
if (isBufferLate(earlyUs)) { if (isBufferLate(earlyUs)) {
@ -860,14 +865,19 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
return false; return false;
} }
long presentationTimeUs = outputBuffer.timeUs - outputStreamOffsetUs; Format format = formatQueue.pollFloor(bufferTimeUs);
Format format = formatQueue.pollFloor(presentationTimeUs);
if (format != null) { if (format != null) {
outputFormat = format; outputFormat = format;
} else if (outputFormat == null) {
// After a stream change or after the initial start, there should be an input format change
// which we've not found. Check the Format queue in case the corresponding presentation
// timestamp is greater than bufferTimeUs
outputFormat = formatQueue.pollFirst();
} }
long presentationTimeUs = bufferTimeUs - outputStreamOffsetUs;
if (shouldForceRender(earlyUs)) { if (shouldForceRender(earlyUs)) {
renderOutputBuffer(outputBuffer, presentationTimeUs, outputFormat); renderOutputBuffer(outputBuffer, presentationTimeUs, checkNotNull(outputFormat));
return true; return true;
} }
@ -886,7 +896,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
} }
if (earlyUs < 30000) { if (earlyUs < 30000) {
renderOutputBuffer(outputBuffer, presentationTimeUs, outputFormat); renderOutputBuffer(outputBuffer, presentationTimeUs, checkNotNull(outputFormat));
return true; return true;
} }
@ -925,7 +935,7 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
} }
private void onOutputRemoved() { private void onOutputRemoved() {
clearReportedVideoSize(); reportedVideoSize = null;
lowerFirstFrameState(C.FIRST_FRAME_NOT_RENDERED); lowerFirstFrameState(C.FIRST_FRAME_NOT_RENDERED);
} }
@ -950,20 +960,18 @@ public abstract class DecoderVideoRenderer extends BaseRenderer {
private void maybeNotifyRenderedFirstFrame() { private void maybeNotifyRenderedFirstFrame() {
if (firstFrameState != C.FIRST_FRAME_RENDERED) { if (firstFrameState != C.FIRST_FRAME_RENDERED) {
firstFrameState = C.FIRST_FRAME_RENDERED; firstFrameState = C.FIRST_FRAME_RENDERED;
eventDispatcher.renderedFirstFrame(output); if (output != null) {
eventDispatcher.renderedFirstFrame(output);
}
} }
} }
private void maybeRenotifyRenderedFirstFrame() { private void maybeRenotifyRenderedFirstFrame() {
if (firstFrameState == C.FIRST_FRAME_RENDERED) { if (firstFrameState == C.FIRST_FRAME_RENDERED && output != null) {
eventDispatcher.renderedFirstFrame(output); eventDispatcher.renderedFirstFrame(output);
} }
} }
private void clearReportedVideoSize() {
reportedVideoSize = null;
}
private void maybeNotifyVideoSizeChanged(int width, int height) { private void maybeNotifyVideoSizeChanged(int width, int height) {
if (reportedVideoSize == null if (reportedVideoSize == null
|| reportedVideoSize.width != width || reportedVideoSize.width != width

View file

@ -408,7 +408,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer implements Video
decodedVideoSize = VideoSize.UNKNOWN; decodedVideoSize = VideoSize.UNKNOWN;
tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET; tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET;
firstFrameState = C.FIRST_FRAME_NOT_RENDERED_ONLY_ALLOWED_IF_STARTED; firstFrameState = C.FIRST_FRAME_NOT_RENDERED_ONLY_ALLOWED_IF_STARTED;
reportedVideoSize = null;
} }
@Override @Override