Android: Drop old frame in SurfaceTextureHelper.startListening()
Drop any pending texture frame when SurfaceTextureHelper.startListening()
is called because the frame might be from the previous
startListening()/stopListening() capture session. This typically happens
when switching between the front/back camera, and an old frame will get
incorrect rotation and mirroring because of the front/back camera
mismatch.
Dropping the frame in SurfaceTextureHelper also removes the need for
the |dropNextFrame| logic in VideoCapturerAndroid.
R=perkj@webrtc.org
Review URL: https://codereview.webrtc.org/2002963002 .
Cr-Original-Commit-Position: refs/heads/master@{#12849}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 181310fb6fe2aff416b112b7e9945d651566fab0
diff --git a/api/java/android/org/webrtc/SurfaceTextureHelper.java b/api/java/android/org/webrtc/SurfaceTextureHelper.java
index 09f78a5..ef43c5e 100644
--- a/api/java/android/org/webrtc/SurfaceTextureHelper.java
+++ b/api/java/android/org/webrtc/SurfaceTextureHelper.java
@@ -309,8 +309,12 @@
Logging.d(TAG, "Setting listener to " + pendingListener);
listener = pendingListener;
pendingListener = null;
- // May alredy have a pending frame - try delivering it.
- tryDeliverTextureFrame();
+ // May have a pending frame from the previous capture session - drop it.
+ if (hasPendingTexture) {
+ // Calling updateTexImage() is neccessary in order to receive new frames.
+ updateTexImage();
+ hasPendingTexture = false;
+ }
}
};
@@ -455,6 +459,15 @@
getYuvConverter().convert(buf, width, height, stride, textureId, transformMatrix);
}
+ private void updateTexImage() {
+ // SurfaceTexture.updateTexImage apparently can compete and deadlock with eglSwapBuffers,
+ // as observed on Nexus 5. Therefore, synchronize it with the EGL functions.
+ // See https://bugs.chromium.org/p/webrtc/issues/detail?id=5702 for more info.
+ synchronized (EglBase.lock) {
+ surfaceTexture.updateTexImage();
+ }
+ }
+
private void tryDeliverTextureFrame() {
if (handler.getLooper().getThread() != Thread.currentThread()) {
throw new IllegalStateException("Wrong thread.");
@@ -465,12 +478,7 @@
isTextureInUse = true;
hasPendingTexture = false;
- // SurfaceTexture.updateTexImage apparently can compete and deadlock with eglSwapBuffers,
- // as observed on Nexus 5. Therefore, synchronize it with the EGL functions.
- // See https://bugs.chromium.org/p/webrtc/issues/detail?id=5702 for more info.
- synchronized (EglBase.lock) {
- surfaceTexture.updateTexImage();
- }
+ updateTexImage();
final float[] transformMatrix = new float[16];
surfaceTexture.getTransformMatrix(transformMatrix);
diff --git a/api/java/android/org/webrtc/VideoCapturerAndroid.java b/api/java/android/org/webrtc/VideoCapturerAndroid.java
index 6352bf7..e4c33d5 100644
--- a/api/java/android/org/webrtc/VideoCapturerAndroid.java
+++ b/api/java/android/org/webrtc/VideoCapturerAndroid.java
@@ -78,9 +78,6 @@
private final Set<byte[]> queuedBuffers = new HashSet<byte[]>();
private final boolean isCapturingToTexture;
private SurfaceTextureHelper surfaceHelper;
- // The camera API can output one old frame after the camera has been switched or the resolution
- // has been changed. This flag is used for dropping the first frame after camera restart.
- private boolean dropNextFrame = false;
private final static int MAX_OPEN_CAMERA_ATTEMPTS = 3;
private final static int OPEN_CAMERA_DELAY_MS = 500;
private int openCameraAttempts;
@@ -462,7 +459,6 @@
// Temporarily stop preview if it's already running.
if (this.captureFormat != null) {
camera.stopPreview();
- dropNextFrame = true;
// Calling |setPreviewCallbackWithBuffer| with null should clear the internal camera buffer
// queue, but sometimes we receive a frame with the old resolution after this call anyway.
camera.setPreviewCallbackWithBuffer(null);
@@ -564,7 +560,6 @@
synchronized (cameraIdLock) {
id = (id + 1) % android.hardware.Camera.getNumberOfCameras();
}
- dropNextFrame = true;
startCaptureOnCameraThread(requestedWidth, requestedHeight, requestedFramerate, frameObserver,
applicationContext);
Logging.d(TAG, "switchCameraOnCameraThread done");
@@ -654,11 +649,6 @@
throw new RuntimeException("onTextureFrameAvailable() called after stopCapture().");
}
checkIsOnCameraThread();
- if (dropNextFrame) {
- surfaceHelper.returnTextureFrame();
- dropNextFrame = false;
- return;
- }
if (eventsHandler != null && !firstFrameReported) {
eventsHandler.onFirstFrameAvailable();
firstFrameReported = true;