Commit ba0e5246 by olly Committed by Oliver Woodman

Properly handle replacement of the DRM session in LibvpxVideoRenderer

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=160537100
parent db177db6
...@@ -20,6 +20,7 @@ import android.graphics.Canvas; ...@@ -20,6 +20,7 @@ import android.graphics.Canvas;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.view.Surface; import android.view.Surface;
import com.google.android.exoplayer2.BaseRenderer; import com.google.android.exoplayer2.BaseRenderer;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
...@@ -39,12 +40,35 @@ import com.google.android.exoplayer2.util.TraceUtil; ...@@ -39,12 +40,35 @@ import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoRendererEventListener; import com.google.android.exoplayer2.video.VideoRendererEventListener;
import com.google.android.exoplayer2.video.VideoRendererEventListener.EventDispatcher; import com.google.android.exoplayer2.video.VideoRendererEventListener.EventDispatcher;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/** /**
* Decodes and renders video using the native VP9 decoder. * Decodes and renders video using the native VP9 decoder.
*/ */
public final class LibvpxVideoRenderer extends BaseRenderer { public final class LibvpxVideoRenderer extends BaseRenderer {
@Retention(RetentionPolicy.SOURCE)
@IntDef({REINITIALIZATION_STATE_NONE, REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM,
REINITIALIZATION_STATE_WAIT_END_OF_STREAM})
private @interface ReinitializationState {}
/**
* The decoder does not need to be re-initialized.
*/
private static final int REINITIALIZATION_STATE_NONE = 0;
/**
* The input format has changed in a way that requires the decoder to be re-initialized, but we
* haven't yet signaled an end of stream to the existing decoder. We need to do so in order to
* ensure that it outputs any remaining buffers before we release it.
*/
private static final int REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM = 1;
/**
* The input format has changed in a way that requires the decoder to be re-initialized, and we've
* signaled an end of stream to the existing decoder. We're waiting for the decoder to output an
* end of stream signal to indicate that it has output any remaining buffers before we release it.
*/
private static final int REINITIALIZATION_STATE_WAIT_END_OF_STREAM = 2;
/** /**
* The type of a message that can be passed to an instance of this class via * The type of a message that can be passed to an instance of this class via
* {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object * {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object
...@@ -78,6 +102,10 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -78,6 +102,10 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
private DrmSession<ExoMediaCrypto> drmSession; private DrmSession<ExoMediaCrypto> drmSession;
private DrmSession<ExoMediaCrypto> pendingDrmSession; private DrmSession<ExoMediaCrypto> pendingDrmSession;
@ReinitializationState
private int decoderReinitializationState;
private boolean decoderReceivedBuffers;
private Bitmap bitmap; private Bitmap bitmap;
private boolean renderedFirstFrame; private boolean renderedFirstFrame;
private long joiningDeadlineMs; private long joiningDeadlineMs;
...@@ -154,6 +182,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -154,6 +182,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance(); flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
eventDispatcher = new EventDispatcher(eventHandler, eventListener); eventDispatcher = new EventDispatcher(eventHandler, eventListener);
outputMode = VpxDecoder.OUTPUT_MODE_NONE; outputMode = VpxDecoder.OUTPUT_MODE_NONE;
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
} }
@Override @Override
...@@ -203,11 +232,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -203,11 +232,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
} }
private boolean drainOutputBuffer(long positionUs) throws VpxDecoderException { private boolean drainOutputBuffer(long positionUs) throws ExoPlaybackException,
if (outputStreamEnded) { VpxDecoderException {
return false;
}
// Acquire outputBuffer either from nextOutputBuffer or from the decoder. // Acquire outputBuffer either from nextOutputBuffer or from the decoder.
if (outputBuffer == null) { if (outputBuffer == null) {
if (nextOutputBuffer != null) { if (nextOutputBuffer != null) {
...@@ -227,9 +253,15 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -227,9 +253,15 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
if (outputBuffer.isEndOfStream()) { if (outputBuffer.isEndOfStream()) {
outputStreamEnded = true; if (decoderReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) {
outputBuffer.release(); // We're waiting to re-initialize the decoder, and have now processed all final buffers.
outputBuffer = null; releaseDecoder();
maybeInitDecoder();
} else {
outputBuffer.release();
outputBuffer = null;
outputStreamEnded = true;
}
return false; return false;
} }
...@@ -333,7 +365,9 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -333,7 +365,9 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
private boolean feedInputBuffer() throws VpxDecoderException, ExoPlaybackException { private boolean feedInputBuffer() throws VpxDecoderException, ExoPlaybackException {
if (inputStreamEnded) { if (decoder == null || decoderReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM
|| inputStreamEnded) {
// We need to reinitialize the decoder or the input stream has ended.
return false; return false;
} }
...@@ -344,6 +378,14 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -344,6 +378,14 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
} }
if (decoderReinitializationState == REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM) {
inputBuffer.setFlags(C.BUFFER_FLAG_END_OF_STREAM);
decoder.queueInputBuffer(inputBuffer);
inputBuffer = null;
decoderReinitializationState = REINITIALIZATION_STATE_WAIT_END_OF_STREAM;
return false;
}
int result; int result;
if (waitingForKeys) { if (waitingForKeys) {
// We've already read an encrypted sample into buffer, and are waiting for keys. // We've already read an encrypted sample into buffer, and are waiting for keys.
...@@ -373,6 +415,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -373,6 +415,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
inputBuffer.flip(); inputBuffer.flip();
inputBuffer.colorInfo = formatHolder.format.colorInfo; inputBuffer.colorInfo = formatHolder.format.colorInfo;
decoder.queueInputBuffer(inputBuffer); decoder.queueInputBuffer(inputBuffer);
decoderReceivedBuffers = true;
decoderCounters.inputBufferCount++; decoderCounters.inputBufferCount++;
inputBuffer = null; inputBuffer = null;
return true; return true;
...@@ -389,18 +432,24 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -389,18 +432,24 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS; return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
} }
private void flushDecoder() { private void flushDecoder() throws ExoPlaybackException {
inputBuffer = null;
waitingForKeys = false; waitingForKeys = false;
if (outputBuffer != null) { if (decoderReinitializationState != REINITIALIZATION_STATE_NONE) {
outputBuffer.release(); releaseDecoder();
outputBuffer = null; maybeInitDecoder();
} } else {
if (nextOutputBuffer != null) { inputBuffer = null;
nextOutputBuffer.release(); if (outputBuffer != null) {
nextOutputBuffer = null; outputBuffer.release();
outputBuffer = null;
}
if (nextOutputBuffer != null) {
nextOutputBuffer.release();
nextOutputBuffer = null;
}
decoder.flush();
decoderReceivedBuffers = false;
} }
decoder.flush();
} }
@Override @Override
...@@ -438,7 +487,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -438,7 +487,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
@Override @Override
protected void onPositionReset(long positionUs, boolean joining) { protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
inputStreamEnded = false; inputStreamEnded = false;
outputStreamEnded = false; outputStreamEnded = false;
clearRenderedFirstFrame(); clearRenderedFirstFrame();
...@@ -467,8 +516,6 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -467,8 +516,6 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
@Override @Override
protected void onDisabled() { protected void onDisabled() {
inputBuffer = null;
outputBuffer = null;
format = null; format = null;
waitingForKeys = false; waitingForKeys = false;
clearReportedVideoSize(); clearReportedVideoSize();
...@@ -530,19 +577,18 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -530,19 +577,18 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
private void releaseDecoder() { private void releaseDecoder() {
if (decoder != null) { if (decoder == null) {
decoder.release(); return;
decoder = null;
decoderCounters.decoderReleaseCount++;
waitingForKeys = false;
if (drmSession != null && pendingDrmSession != drmSession) {
try {
drmSessionManager.releaseSession(drmSession);
} finally {
drmSession = null;
}
}
} }
inputBuffer = null;
outputBuffer = null;
nextOutputBuffer = null;
decoder.release();
decoder = null;
decoderCounters.decoderReleaseCount++;
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
decoderReceivedBuffers = false;
} }
private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException { private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
...@@ -566,6 +612,17 @@ public final class LibvpxVideoRenderer extends BaseRenderer { ...@@ -566,6 +612,17 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
} }
} }
if (pendingDrmSession != drmSession) {
if (decoderReceivedBuffers) {
// Signal end of stream and wait for any final output buffers before re-initialization.
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
} else {
// There aren't any final output buffers, so release the decoder immediately.
releaseDecoder();
maybeInitDecoder();
}
}
eventDispatcher.inputFormatChanged(format); eventDispatcher.inputFormatChanged(format);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment