Fix release of DRM sessions
There were some edge cases in which we'd forget to release DRM sessions. For example if we read a format and acquired a pendingDrmSession (in onInputFormatChanged), then immediately read another format and overwrote pendingDrmSession, we'd forget to release the one that's been overwritten. This change hopefully makes release much clearer. We keep a list of all drm sessions we're currently holding. Whenever we update either drmSession or pendingDrmSession, we release any other sessions that are in the list. PiperOrigin-RevId: 228905465
This commit is contained in:
parent
71d4f39400
commit
2d30d66746
@ -127,8 +127,8 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
|||||||
private VpxDecoder decoder;
|
private VpxDecoder decoder;
|
||||||
private VpxInputBuffer inputBuffer;
|
private VpxInputBuffer inputBuffer;
|
||||||
private VpxOutputBuffer outputBuffer;
|
private VpxOutputBuffer outputBuffer;
|
||||||
private DrmSession<ExoMediaCrypto> drmSession;
|
@Nullable private DrmSession<ExoMediaCrypto> decoderDrmSession;
|
||||||
private DrmSession<ExoMediaCrypto> pendingDrmSession;
|
@Nullable private DrmSession<ExoMediaCrypto> sourceDrmSession;
|
||||||
|
|
||||||
private @ReinitializationState int decoderReinitializationState;
|
private @ReinitializationState int decoderReinitializationState;
|
||||||
private boolean decoderReceivedBuffers;
|
private boolean decoderReceivedBuffers;
|
||||||
@ -364,24 +364,10 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
|||||||
clearReportedVideoSize();
|
clearReportedVideoSize();
|
||||||
clearRenderedFirstFrame();
|
clearRenderedFirstFrame();
|
||||||
try {
|
try {
|
||||||
|
setSourceDrmSession(null);
|
||||||
releaseDecoder();
|
releaseDecoder();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
eventDispatcher.disabled(decoderCounters);
|
||||||
if (drmSession != null) {
|
|
||||||
drmSessionManager.releaseSession(drmSession);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (pendingDrmSession != null && pendingDrmSession != drmSession) {
|
|
||||||
drmSessionManager.releaseSession(pendingDrmSession);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
drmSession = null;
|
|
||||||
pendingDrmSession = null;
|
|
||||||
decoderCounters.ensureUpdated();
|
|
||||||
eventDispatcher.disabled(decoderCounters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -433,18 +419,35 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
|||||||
/** Releases the decoder. */
|
/** Releases the decoder. */
|
||||||
@CallSuper
|
@CallSuper
|
||||||
protected void releaseDecoder() {
|
protected void releaseDecoder() {
|
||||||
if (decoder == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputBuffer = null;
|
inputBuffer = null;
|
||||||
outputBuffer = null;
|
outputBuffer = null;
|
||||||
decoder.release();
|
|
||||||
decoder = null;
|
|
||||||
decoderCounters.decoderReleaseCount++;
|
|
||||||
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
|
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
|
||||||
decoderReceivedBuffers = false;
|
decoderReceivedBuffers = false;
|
||||||
buffersInCodecCount = 0;
|
buffersInCodecCount = 0;
|
||||||
|
if (decoder != null) {
|
||||||
|
decoder.release();
|
||||||
|
decoder = null;
|
||||||
|
decoderCounters.decoderReleaseCount++;
|
||||||
|
}
|
||||||
|
setDecoderDrmSession(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSourceDrmSession(@Nullable DrmSession<ExoMediaCrypto> session) {
|
||||||
|
DrmSession<ExoMediaCrypto> previous = sourceDrmSession;
|
||||||
|
sourceDrmSession = session;
|
||||||
|
releaseDrmSessionIfUnused(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDecoderDrmSession(@Nullable DrmSession<ExoMediaCrypto> session) {
|
||||||
|
DrmSession<ExoMediaCrypto> previous = decoderDrmSession;
|
||||||
|
decoderDrmSession = session;
|
||||||
|
releaseDrmSessionIfUnused(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseDrmSessionIfUnused(@Nullable DrmSession<ExoMediaCrypto> session) {
|
||||||
|
if (session != null && session != decoderDrmSession && session != sourceDrmSession) {
|
||||||
|
drmSessionManager.releaseSession(session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -467,16 +470,20 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
|||||||
throw ExoPlaybackException.createForRenderer(
|
throw ExoPlaybackException.createForRenderer(
|
||||||
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
||||||
}
|
}
|
||||||
pendingDrmSession = drmSessionManager.acquireSession(Looper.myLooper(), format.drmInitData);
|
DrmSession<ExoMediaCrypto> session =
|
||||||
if (pendingDrmSession == drmSession) {
|
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
|
||||||
drmSessionManager.releaseSession(pendingDrmSession);
|
if (session == decoderDrmSession || session == sourceDrmSession) {
|
||||||
|
// We already had this session. The manager must be reference counting, so release it once
|
||||||
|
// to get the count attributed to this renderer back down to 1.
|
||||||
|
drmSessionManager.releaseSession(session);
|
||||||
}
|
}
|
||||||
|
setSourceDrmSession(session);
|
||||||
} else {
|
} else {
|
||||||
pendingDrmSession = null;
|
setSourceDrmSession(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pendingDrmSession != drmSession) {
|
if (sourceDrmSession != decoderDrmSession) {
|
||||||
if (decoderReceivedBuffers) {
|
if (decoderReceivedBuffers) {
|
||||||
// Signal end of stream and wait for any final output buffers before re-initialization.
|
// Signal end of stream and wait for any final output buffers before re-initialization.
|
||||||
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
|
decoderReinitializationState = REINITIALIZATION_STATE_SIGNAL_END_OF_STREAM;
|
||||||
@ -704,12 +711,13 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
drmSession = pendingDrmSession;
|
setDecoderDrmSession(sourceDrmSession);
|
||||||
|
|
||||||
ExoMediaCrypto mediaCrypto = null;
|
ExoMediaCrypto mediaCrypto = null;
|
||||||
if (drmSession != null) {
|
if (decoderDrmSession != null) {
|
||||||
mediaCrypto = drmSession.getMediaCrypto();
|
mediaCrypto = decoderDrmSession.getMediaCrypto();
|
||||||
if (mediaCrypto == null) {
|
if (mediaCrypto == null) {
|
||||||
DrmSessionException drmError = drmSession.getError();
|
DrmSessionException drmError = decoderDrmSession.getError();
|
||||||
if (drmError != null) {
|
if (drmError != null) {
|
||||||
// Continue for now. We may be able to avoid failure if the session recovers, or if a new
|
// Continue for now. We may be able to avoid failure if the session recovers, or if a new
|
||||||
// input format causes the session to be replaced before it's used.
|
// input format causes the session to be replaced before it's used.
|
||||||
@ -922,12 +930,12 @@ public class LibvpxVideoRenderer extends BaseRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
|
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
|
||||||
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
|
if (decoderDrmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@DrmSession.State int drmSessionState = drmSession.getState();
|
@DrmSession.State int drmSessionState = decoderDrmSession.getState();
|
||||||
if (drmSessionState == DrmSession.STATE_ERROR) {
|
if (drmSessionState == DrmSession.STATE_ERROR) {
|
||||||
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
|
throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex());
|
||||||
}
|
}
|
||||||
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
||||||
}
|
}
|
||||||
|
@ -147,6 +147,7 @@ public interface AudioRendererEventListener {
|
|||||||
* Invokes {@link AudioRendererEventListener#onAudioDisabled(DecoderCounters)}.
|
* Invokes {@link AudioRendererEventListener#onAudioDisabled(DecoderCounters)}.
|
||||||
*/
|
*/
|
||||||
public void disabled(final DecoderCounters counters) {
|
public void disabled(final DecoderCounters counters) {
|
||||||
|
counters.ensureUpdated();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
handler.post(
|
handler.post(
|
||||||
() -> {
|
() -> {
|
||||||
|
@ -548,7 +548,6 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
|
|||||||
try {
|
try {
|
||||||
super.onDisabled();
|
super.onDisabled();
|
||||||
} finally {
|
} finally {
|
||||||
decoderCounters.ensureUpdated();
|
|
||||||
eventDispatcher.disabled(decoderCounters);
|
eventDispatcher.disabled(decoderCounters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,8 +106,8 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
? extends AudioDecoderException> decoder;
|
? extends AudioDecoderException> decoder;
|
||||||
private DecoderInputBuffer inputBuffer;
|
private DecoderInputBuffer inputBuffer;
|
||||||
private SimpleOutputBuffer outputBuffer;
|
private SimpleOutputBuffer outputBuffer;
|
||||||
private DrmSession<ExoMediaCrypto> drmSession;
|
@Nullable private DrmSession<ExoMediaCrypto> decoderDrmSession;
|
||||||
private DrmSession<ExoMediaCrypto> pendingDrmSession;
|
@Nullable private DrmSession<ExoMediaCrypto> sourceDrmSession;
|
||||||
|
|
||||||
@ReinitializationState private int decoderReinitializationState;
|
@ReinitializationState private int decoderReinitializationState;
|
||||||
private boolean decoderReceivedBuffers;
|
private boolean decoderReceivedBuffers;
|
||||||
@ -462,12 +462,12 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
|
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
|
||||||
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
|
if (decoderDrmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@DrmSession.State int drmSessionState = drmSession.getState();
|
@DrmSession.State int drmSessionState = decoderDrmSession.getState();
|
||||||
if (drmSessionState == DrmSession.STATE_ERROR) {
|
if (drmSessionState == DrmSession.STATE_ERROR) {
|
||||||
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
|
throw ExoPlaybackException.createForRenderer(decoderDrmSession.getError(), getIndex());
|
||||||
}
|
}
|
||||||
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
||||||
}
|
}
|
||||||
@ -568,25 +568,11 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
audioTrackNeedsConfigure = true;
|
audioTrackNeedsConfigure = true;
|
||||||
waitingForKeys = false;
|
waitingForKeys = false;
|
||||||
try {
|
try {
|
||||||
|
setSourceDrmSession(null);
|
||||||
releaseDecoder();
|
releaseDecoder();
|
||||||
audioSink.reset();
|
audioSink.reset();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
eventDispatcher.disabled(decoderCounters);
|
||||||
if (drmSession != null) {
|
|
||||||
drmSessionManager.releaseSession(drmSession);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (pendingDrmSession != null && pendingDrmSession != drmSession) {
|
|
||||||
drmSessionManager.releaseSession(pendingDrmSession);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
drmSession = null;
|
|
||||||
pendingDrmSession = null;
|
|
||||||
decoderCounters.ensureUpdated();
|
|
||||||
eventDispatcher.disabled(decoderCounters);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,12 +601,13 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
drmSession = pendingDrmSession;
|
setDecoderDrmSession(sourceDrmSession);
|
||||||
|
|
||||||
ExoMediaCrypto mediaCrypto = null;
|
ExoMediaCrypto mediaCrypto = null;
|
||||||
if (drmSession != null) {
|
if (decoderDrmSession != null) {
|
||||||
mediaCrypto = drmSession.getMediaCrypto();
|
mediaCrypto = decoderDrmSession.getMediaCrypto();
|
||||||
if (mediaCrypto == null) {
|
if (mediaCrypto == null) {
|
||||||
DrmSessionException drmError = drmSession.getError();
|
DrmSessionException drmError = decoderDrmSession.getError();
|
||||||
if (drmError != null) {
|
if (drmError != null) {
|
||||||
// Continue for now. We may be able to avoid failure if the session recovers, or if a new
|
// Continue for now. We may be able to avoid failure if the session recovers, or if a new
|
||||||
// input format causes the session to be replaced before it's used.
|
// input format causes the session to be replaced before it's used.
|
||||||
@ -646,17 +633,34 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void releaseDecoder() {
|
private void releaseDecoder() {
|
||||||
if (decoder == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
inputBuffer = null;
|
inputBuffer = null;
|
||||||
outputBuffer = null;
|
outputBuffer = null;
|
||||||
decoder.release();
|
|
||||||
decoder = null;
|
|
||||||
decoderCounters.decoderReleaseCount++;
|
|
||||||
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
|
decoderReinitializationState = REINITIALIZATION_STATE_NONE;
|
||||||
decoderReceivedBuffers = false;
|
decoderReceivedBuffers = false;
|
||||||
|
if (decoder != null) {
|
||||||
|
decoder.release();
|
||||||
|
decoder = null;
|
||||||
|
decoderCounters.decoderReleaseCount++;
|
||||||
|
}
|
||||||
|
setDecoderDrmSession(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSourceDrmSession(@Nullable DrmSession<ExoMediaCrypto> session) {
|
||||||
|
DrmSession<ExoMediaCrypto> previous = sourceDrmSession;
|
||||||
|
sourceDrmSession = session;
|
||||||
|
releaseDrmSessionIfUnused(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setDecoderDrmSession(@Nullable DrmSession<ExoMediaCrypto> session) {
|
||||||
|
DrmSession<ExoMediaCrypto> previous = decoderDrmSession;
|
||||||
|
decoderDrmSession = session;
|
||||||
|
releaseDrmSessionIfUnused(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseDrmSessionIfUnused(@Nullable DrmSession<ExoMediaCrypto> session) {
|
||||||
|
if (session != null && session != decoderDrmSession && session != sourceDrmSession) {
|
||||||
|
drmSessionManager.releaseSession(session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
|
private void onInputFormatChanged(Format newFormat) throws ExoPlaybackException {
|
||||||
@ -671,13 +675,16 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
|
|||||||
throw ExoPlaybackException.createForRenderer(
|
throw ExoPlaybackException.createForRenderer(
|
||||||
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
||||||
}
|
}
|
||||||
pendingDrmSession = drmSessionManager.acquireSession(Looper.myLooper(),
|
DrmSession<ExoMediaCrypto> session =
|
||||||
inputFormat.drmInitData);
|
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
|
||||||
if (pendingDrmSession == drmSession) {
|
if (session == decoderDrmSession || session == sourceDrmSession) {
|
||||||
drmSessionManager.releaseSession(pendingDrmSession);
|
// We already had this session. The manager must be reference counting, so release it once
|
||||||
|
// to get the count attributed to this renderer back down to 1.
|
||||||
|
drmSessionManager.releaseSession(session);
|
||||||
}
|
}
|
||||||
|
setSourceDrmSession(session);
|
||||||
} else {
|
} else {
|
||||||
pendingDrmSession = null;
|
setSourceDrmSession(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,13 +287,13 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
private final DecoderInputBuffer flagsOnlyBuffer;
|
private final DecoderInputBuffer flagsOnlyBuffer;
|
||||||
private final FormatHolder formatHolder;
|
private final FormatHolder formatHolder;
|
||||||
private final TimedValueQueue<Format> formatQueue;
|
private final TimedValueQueue<Format> formatQueue;
|
||||||
private final List<Long> decodeOnlyPresentationTimestamps;
|
private final ArrayList<Long> decodeOnlyPresentationTimestamps;
|
||||||
private final MediaCodec.BufferInfo outputBufferInfo;
|
private final MediaCodec.BufferInfo outputBufferInfo;
|
||||||
|
|
||||||
@Nullable private Format inputFormat;
|
@Nullable private Format inputFormat;
|
||||||
private Format outputFormat;
|
private Format outputFormat;
|
||||||
private DrmSession<FrameworkMediaCrypto> drmSession;
|
@Nullable private DrmSession<FrameworkMediaCrypto> codecDrmSession;
|
||||||
private DrmSession<FrameworkMediaCrypto> pendingDrmSession;
|
@Nullable private DrmSession<FrameworkMediaCrypto> sourceDrmSession;
|
||||||
private long renderTimeLimitMs;
|
private long renderTimeLimitMs;
|
||||||
private float rendererOperatingRate;
|
private float rendererOperatingRate;
|
||||||
@Nullable private MediaCodec codec;
|
@Nullable private MediaCodec codec;
|
||||||
@ -457,14 +457,15 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
drmSession = pendingDrmSession;
|
setCodecDrmSession(sourceDrmSession);
|
||||||
|
|
||||||
String mimeType = inputFormat.sampleMimeType;
|
String mimeType = inputFormat.sampleMimeType;
|
||||||
MediaCrypto wrappedMediaCrypto = null;
|
MediaCrypto wrappedMediaCrypto = null;
|
||||||
boolean drmSessionRequiresSecureDecoder = false;
|
boolean drmSessionRequiresSecureDecoder = false;
|
||||||
if (drmSession != null) {
|
if (codecDrmSession != null) {
|
||||||
FrameworkMediaCrypto mediaCrypto = drmSession.getMediaCrypto();
|
FrameworkMediaCrypto mediaCrypto = codecDrmSession.getMediaCrypto();
|
||||||
if (mediaCrypto == null) {
|
if (mediaCrypto == null) {
|
||||||
DrmSessionException drmError = drmSession.getError();
|
DrmSessionException drmError = codecDrmSession.getError();
|
||||||
if (drmError != null) {
|
if (drmError != null) {
|
||||||
// Continue for now. We may be able to avoid failure if the session recovers, or if a new
|
// Continue for now. We may be able to avoid failure if the session recovers, or if a new
|
||||||
// input format causes the session to be replaced before it's used.
|
// input format causes the session to be replaced before it's used.
|
||||||
@ -477,9 +478,9 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
drmSessionRequiresSecureDecoder = mediaCrypto.requiresSecureDecoderComponent(mimeType);
|
drmSessionRequiresSecureDecoder = mediaCrypto.requiresSecureDecoderComponent(mimeType);
|
||||||
}
|
}
|
||||||
if (deviceNeedsDrmKeysToConfigureCodecWorkaround()) {
|
if (deviceNeedsDrmKeysToConfigureCodecWorkaround()) {
|
||||||
@DrmSession.State int drmSessionState = drmSession.getState();
|
@DrmSession.State int drmSessionState = codecDrmSession.getState();
|
||||||
if (drmSessionState == DrmSession.STATE_ERROR) {
|
if (drmSessionState == DrmSession.STATE_ERROR) {
|
||||||
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
|
throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex());
|
||||||
} else if (drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS) {
|
} else if (drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS) {
|
||||||
// Wait for keys.
|
// Wait for keys.
|
||||||
return;
|
return;
|
||||||
@ -552,7 +553,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
@Override
|
@Override
|
||||||
protected void onDisabled() {
|
protected void onDisabled() {
|
||||||
inputFormat = null;
|
inputFormat = null;
|
||||||
if (drmSession != null || pendingDrmSession != null) {
|
if (codecDrmSession != null || sourceDrmSession != null) {
|
||||||
// TODO: Do something better with this case.
|
// TODO: Do something better with this case.
|
||||||
onReset();
|
onReset();
|
||||||
} else {
|
} else {
|
||||||
@ -565,51 +566,32 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
try {
|
try {
|
||||||
releaseCodec();
|
releaseCodec();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
setSourceDrmSession(null);
|
||||||
if (drmSession != null) {
|
|
||||||
drmSessionManager.releaseSession(drmSession);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (pendingDrmSession != null && pendingDrmSession != drmSession) {
|
|
||||||
drmSessionManager.releaseSession(pendingDrmSession);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
drmSession = null;
|
|
||||||
pendingDrmSession = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void releaseCodec() {
|
protected void releaseCodec() {
|
||||||
availableCodecInfos = null;
|
availableCodecInfos = null;
|
||||||
if (codec != null) {
|
codecInfo = null;
|
||||||
codecInfo = null;
|
codecFormat = null;
|
||||||
codecFormat = null;
|
resetInputBuffer();
|
||||||
resetInputBuffer();
|
resetOutputBuffer();
|
||||||
resetOutputBuffer();
|
resetCodecBuffers();
|
||||||
resetCodecBuffers();
|
waitingForKeys = false;
|
||||||
waitingForKeys = false;
|
codecHotswapDeadlineMs = C.TIME_UNSET;
|
||||||
codecHotswapDeadlineMs = C.TIME_UNSET;
|
decodeOnlyPresentationTimestamps.clear();
|
||||||
decodeOnlyPresentationTimestamps.clear();
|
try {
|
||||||
decoderCounters.decoderReleaseCount++;
|
if (codec != null) {
|
||||||
try {
|
decoderCounters.decoderReleaseCount++;
|
||||||
codec.stop();
|
|
||||||
} finally {
|
|
||||||
try {
|
try {
|
||||||
codec.release();
|
codec.stop();
|
||||||
} finally {
|
} finally {
|
||||||
codec = null;
|
codec.release();
|
||||||
if (drmSession != null && pendingDrmSession != drmSession) {
|
|
||||||
try {
|
|
||||||
drmSessionManager.releaseSession(drmSession);
|
|
||||||
} finally {
|
|
||||||
drmSession = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
codec = null;
|
||||||
|
setCodecDrmSession(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,6 +910,24 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
outputBuffer = null;
|
outputBuffer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setSourceDrmSession(@Nullable DrmSession<FrameworkMediaCrypto> session) {
|
||||||
|
DrmSession<FrameworkMediaCrypto> previous = sourceDrmSession;
|
||||||
|
sourceDrmSession = session;
|
||||||
|
releaseDrmSessionIfUnused(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCodecDrmSession(@Nullable DrmSession<FrameworkMediaCrypto> session) {
|
||||||
|
DrmSession<FrameworkMediaCrypto> previous = codecDrmSession;
|
||||||
|
codecDrmSession = session;
|
||||||
|
releaseDrmSessionIfUnused(previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void releaseDrmSessionIfUnused(@Nullable DrmSession<FrameworkMediaCrypto> session) {
|
||||||
|
if (session != null && session != codecDrmSession && session != sourceDrmSession) {
|
||||||
|
drmSessionManager.releaseSession(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether it may be possible to feed more input data.
|
* @return Whether it may be possible to feed more input data.
|
||||||
* @throws ExoPlaybackException If an error occurs feeding the input buffer.
|
* @throws ExoPlaybackException If an error occurs feeding the input buffer.
|
||||||
@ -1082,12 +1082,12 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
|
private boolean shouldWaitForKeys(boolean bufferEncrypted) throws ExoPlaybackException {
|
||||||
if (drmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
|
if (codecDrmSession == null || (!bufferEncrypted && playClearSamplesWithoutKeys)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@DrmSession.State int drmSessionState = drmSession.getState();
|
@DrmSession.State int drmSessionState = codecDrmSession.getState();
|
||||||
if (drmSessionState == DrmSession.STATE_ERROR) {
|
if (drmSessionState == DrmSession.STATE_ERROR) {
|
||||||
throw ExoPlaybackException.createForRenderer(drmSession.getError(), getIndex());
|
throw ExoPlaybackException.createForRenderer(codecDrmSession.getError(), getIndex());
|
||||||
}
|
}
|
||||||
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
return drmSessionState != DrmSession.STATE_OPENED_WITH_KEYS;
|
||||||
}
|
}
|
||||||
@ -1126,13 +1126,16 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
throw ExoPlaybackException.createForRenderer(
|
throw ExoPlaybackException.createForRenderer(
|
||||||
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
new IllegalStateException("Media requires a DrmSessionManager"), getIndex());
|
||||||
}
|
}
|
||||||
pendingDrmSession =
|
DrmSession<FrameworkMediaCrypto> session =
|
||||||
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
|
drmSessionManager.acquireSession(Looper.myLooper(), newFormat.drmInitData);
|
||||||
if (pendingDrmSession == drmSession) {
|
if (session == codecDrmSession || session == sourceDrmSession) {
|
||||||
drmSessionManager.releaseSession(pendingDrmSession);
|
// We already had this session. The manager must be reference counting, so release it once
|
||||||
|
// to get the count attributed to this renderer back down to 1.
|
||||||
|
drmSessionManager.releaseSession(session);
|
||||||
}
|
}
|
||||||
|
setSourceDrmSession(session);
|
||||||
} else {
|
} else {
|
||||||
pendingDrmSession = null;
|
setSourceDrmSession(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1143,7 +1146,7 @@ public abstract class MediaCodecRenderer extends BaseRenderer {
|
|||||||
|
|
||||||
// We have an existing codec that we may need to reconfigure or re-initialize. If the existing
|
// We have an existing codec that we may need to reconfigure or re-initialize. If the existing
|
||||||
// codec instance is being kept then its operating rate may need to be updated.
|
// codec instance is being kept then its operating rate may need to be updated.
|
||||||
if (pendingDrmSession != drmSession) {
|
if (sourceDrmSession != codecDrmSession) {
|
||||||
drainAndReinitializeCodec();
|
drainAndReinitializeCodec();
|
||||||
} else {
|
} else {
|
||||||
switch (canKeepCodec(codec, codecInfo, codecFormat, newFormat)) {
|
switch (canKeepCodec(codec, codecInfo, codecFormat, newFormat)) {
|
||||||
|
@ -375,7 +375,6 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
|
|||||||
try {
|
try {
|
||||||
super.onDisabled();
|
super.onDisabled();
|
||||||
} finally {
|
} finally {
|
||||||
decoderCounters.ensureUpdated();
|
|
||||||
eventDispatcher.disabled(decoderCounters);
|
eventDispatcher.disabled(decoderCounters);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,6 +179,7 @@ public interface VideoRendererEventListener {
|
|||||||
|
|
||||||
/** Invokes {@link VideoRendererEventListener#onVideoDisabled(DecoderCounters)}. */
|
/** Invokes {@link VideoRendererEventListener#onVideoDisabled(DecoderCounters)}. */
|
||||||
public void disabled(DecoderCounters counters) {
|
public void disabled(DecoderCounters counters) {
|
||||||
|
counters.ensureUpdated();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
handler.post(
|
handler.post(
|
||||||
() -> {
|
() -> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user