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;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.view.Surface;
import com.google.android.exoplayer2.BaseRenderer;
import com.google.android.exoplayer2.C;
......@@ -39,12 +40,35 @@ import com.google.android.exoplayer2.util.TraceUtil;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
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.
*/
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
* {@link ExoPlayer#sendMessages} or {@link ExoPlayer#blockingSendMessages}. The message object
......@@ -78,6 +102,10 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
private DrmSession<ExoMediaCrypto> drmSession;
private DrmSession<ExoMediaCrypto> pendingDrmSession;
@ReinitializationState
private int decoderReinitializationState;
private boolean decoderReceivedBuffers;
private Bitmap bitmap;
private boolean renderedFirstFrame;
private long joiningDeadlineMs;
......@@ -154,6 +182,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
flagsOnlyBuffer = DecoderInputBuffer.newFlagsOnlyInstance();
eventDispatcher = new EventDispatcher(eventHandler, eventListener);
outputMode = VpxDecoder.OUTPUT_MODE_NONE;
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
}
@Override
......@@ -203,11 +232,8 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
}
}
private boolean drainOutputBuffer(long positionUs) throws VpxDecoderException {
if (outputStreamEnded) {
return false;
}
private boolean drainOutputBuffer(long positionUs) throws ExoPlaybackException,
VpxDecoderException {
// Acquire outputBuffer either from nextOutputBuffer or from the decoder.
if (outputBuffer == null) {
if (nextOutputBuffer != null) {
......@@ -227,9 +253,15 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
}
if (outputBuffer.isEndOfStream()) {
outputStreamEnded = true;
outputBuffer.release();
outputBuffer = null;
if (decoderReinitializationState == REINITIALIZATION_STATE_WAIT_END_OF_STREAM) {
// We're waiting to re-initialize the decoder, and have now processed all final buffers.
releaseDecoder();
maybeInitDecoder();
} else {
outputBuffer.release();
outputBuffer = null;
outputStreamEnded = true;
}
return false;
}
......@@ -333,7 +365,9 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
}
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;
}
......@@ -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;
if (waitingForKeys) {
// We've already read an encrypted sample into buffer, and are waiting for keys.
......@@ -373,6 +415,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
inputBuffer.flip();
inputBuffer.colorInfo = formatHolder.format.colorInfo;
decoder.queueInputBuffer(inputBuffer);
decoderReceivedBuffers = true;
decoderCounters.inputBufferCount++;
inputBuffer = null;
return true;
......@@ -389,18 +432,24 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
}
private void flushDecoder() {
inputBuffer = null;
private void flushDecoder() throws ExoPlaybackException {
waitingForKeys = false;
if (outputBuffer != null) {
outputBuffer.release();
outputBuffer = null;
}
if (nextOutputBuffer != null) {
nextOutputBuffer.release();
nextOutputBuffer = null;
if (decoderReinitializationState != REINITIALIZATION_STATE_NONE) {
releaseDecoder();
maybeInitDecoder();
} else {
inputBuffer = null;
if (outputBuffer != null) {
outputBuffer.release();
outputBuffer = null;
}
if (nextOutputBuffer != null) {
nextOutputBuffer.release();
nextOutputBuffer = null;
}
decoder.flush();
decoderReceivedBuffers = false;
}
decoder.flush();
}
@Override
......@@ -438,7 +487,7 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
}
@Override
protected void onPositionReset(long positionUs, boolean joining) {
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
inputStreamEnded = false;
outputStreamEnded = false;
clearRenderedFirstFrame();
......@@ -467,8 +516,6 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
@Override
protected void onDisabled() {
inputBuffer = null;
outputBuffer = null;
format = null;
waitingForKeys = false;
clearReportedVideoSize();
......@@ -530,19 +577,18 @@ public final class LibvpxVideoRenderer extends BaseRenderer {
}
private void releaseDecoder() {
if (decoder != null) {
decoder.release();
decoder = null;
decoderCounters.decoderReleaseCount++;
waitingForKeys = false;
if (drmSession != null && pendingDrmSession != drmSession) {
try {
drmSessionManager.releaseSession(drmSession);
} finally {
drmSession = null;
}
}
if (decoder == null) {
return;
}
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 {
......@@ -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);
}
......
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