Cleanup tunneled onFrameRenderListener

Cleanup the handler to prevent stale messages and potential handler leaks
This commit is contained in:
Steve Mayhew 2019-11-15 13:35:48 -08:00
parent 45013ece1e
commit 245c9fec5a

View file

@ -563,6 +563,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
clearReportedVideoSize();
clearRenderedFirstFrame();
frameReleaseTimeHelper.disable();
if (tunnelingOnFrameRenderedListener != null && getCodec() != null) {
tunnelingOnFrameRenderedListener.destroyHandler(getCodec());
}
tunnelingOnFrameRenderedListener = null;
try {
super.onDisabled();
@ -687,6 +690,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
}
codec.configure(mediaFormat, surface, crypto, 0);
if (Util.SDK_INT >= 23 && tunneling) {
if (tunnelingOnFrameRenderedListener != null) {
tunnelingOnFrameRenderedListener.destroyHandler(codec);
}
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);
}
}
@ -1228,6 +1234,9 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
MediaCodec codec = getCodec();
// If codec is null then the listener will be instantiated in configureCodec.
if (codec != null) {
if (tunnelingOnFrameRenderedListener != null) {
tunnelingOnFrameRenderedListener.destroyHandler(codec);
}
tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec);
}
}
@ -1808,8 +1817,23 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@TargetApi(23)
private final class OnFrameRenderedListenerV23 implements MediaCodec.OnFrameRenderedListener {
private final Handler handler;
private OnFrameRenderedListenerV23(MediaCodec codec) {
codec.setOnFrameRenderedListener(/* listener= */ this, Util.createHandler());
handler = new Handler();
codec.setOnFrameRenderedListener(/* listener= */ this, handler);
}
/**
* Cleanup any messages pending for this listener before removing references to it
*
* @param codec optional, if the codec is still around it should be passed here
*/
void destroyHandler(@Nullable MediaCodec codec) {
if (codec != null) {
codec.setOnFrameRenderedListener(null, null);
}
handler.removeCallbacksAndMessages(null);
}
@Override
@ -1818,12 +1842,32 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
// Stale event.
return;
}
// Work around bug in MediaCodec that causes deadlocks if you call back a
// MediaCodec API that requires MediaCodec to use it's Looper, as it calls this
// listener method holding locks. This was fixed in:
// https://android-review.googlesource.com/1156807
//
// The work around simply queues the processing to a subsequent message, where
// the lock will not be held.
//
if (Util.SDK_INT < 30) {
handler.post(() -> {
if (this == tunnelingOnFrameRenderedListener) { // event not stale
handleFrameRendered(presentationTimeUs);
}
});
} else {
handleFrameRendered(presentationTimeUs);
}
}
private void handleFrameRendered(long presentationTimeUs) {
if (presentationTimeUs == TUNNELING_EOS_PRESENTATION_TIME_US) {
onProcessedTunneledEndOfStream();
} else {
onProcessedTunneledBuffer(presentationTimeUs);
}
}
}
}