Android SurfaceTextureHelper: Add stopListening() function
This CL replaces the function SurfaceTextureHelper.setListener() that could only be called once with the functions startListening() and stopListening() that can be called multiple times. This is necessary when the SurfaceTextureHelper will be passed to the VideoCapturerAndroid in startCapture(). startListening() will be called in startCapture() and stopListening() in stopCapture(). BUG=webrtc:5519 Review URL: https://codereview.webrtc.org/1755573002 Cr-Commit-Position: refs/heads/master@{#11855}
This commit is contained in:
@ -28,8 +28,8 @@ import java.util.concurrent.TimeUnit;
|
||||
* Helper class to create and synchronize access to a SurfaceTexture. The caller will get notified
|
||||
* of new frames in onTextureFrameAvailable(), and should call returnTextureFrame() when done with
|
||||
* the frame. Only one texture frame can be in flight at once, so returnTextureFrame() must be
|
||||
* called in order to receive a new frame. Call disconnect() to stop receiveing new frames and
|
||||
* release all resources.
|
||||
* called in order to receive a new frame. Call stopListening() to stop receiveing new frames. Call
|
||||
* dispose to release all resources once the texture frame is returned.
|
||||
* Note that there is a C++ counter part of this class that optionally can be used. It is used for
|
||||
* wrapping texture frames into webrtc::VideoFrames and also handles calling returnTextureFrame()
|
||||
* when the webrtc::VideoFrame is no longer used.
|
||||
@ -287,6 +287,7 @@ class SurfaceTextureHelper {
|
||||
private final int oesTextureId;
|
||||
private YuvConverter yuvConverter;
|
||||
|
||||
// These variables are only accessed from the |handler| thread.
|
||||
private OnTextureFrameAvailableListener listener;
|
||||
// The possible states of this class.
|
||||
private boolean hasPendingTexture = false;
|
||||
@ -305,6 +306,13 @@ class SurfaceTextureHelper {
|
||||
|
||||
oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
|
||||
surfaceTexture = new SurfaceTexture(oesTextureId);
|
||||
surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
|
||||
@Override
|
||||
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
|
||||
hasPendingTexture = true;
|
||||
tryDeliverTextureFrame();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private YuvConverter getYuvConverter() {
|
||||
@ -320,23 +328,35 @@ class SurfaceTextureHelper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start to stream textures to the given |listener|.
|
||||
* A Listener can only be set once.
|
||||
* Start to stream textures to the given |listener|. If you need to change listener, you need to
|
||||
* call stopListening() first.
|
||||
*/
|
||||
public void setListener(OnTextureFrameAvailableListener listener) {
|
||||
public void startListening(final OnTextureFrameAvailableListener listener) {
|
||||
if (this.listener != null) {
|
||||
throw new IllegalStateException("SurfaceTextureHelper listener has already been set.");
|
||||
}
|
||||
this.listener = listener;
|
||||
surfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
|
||||
handler.post(new Runnable() {
|
||||
@Override
|
||||
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
|
||||
hasPendingTexture = true;
|
||||
public void run() {
|
||||
SurfaceTextureHelper.this.listener = listener;
|
||||
// May alredy have a pending frame - try delivering it.
|
||||
tryDeliverTextureFrame();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening. The listener set in startListening() is guaranteded to not receive any more
|
||||
* onTextureFrameAvailable() callbacks after this function returns. This function must be called
|
||||
* on the getHandler() thread.
|
||||
*/
|
||||
public void stopListening() {
|
||||
if (handler.getLooper().getThread() != Thread.currentThread()) {
|
||||
throw new IllegalStateException("Wrong thread.");
|
||||
}
|
||||
this.listener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the underlying SurfaceTexture. The SurfaceTexture should be passed in to a video
|
||||
* producer such as a camera or decoder.
|
||||
@ -347,7 +367,7 @@ class SurfaceTextureHelper {
|
||||
|
||||
/**
|
||||
* Retrieve the handler that calls onTextureFrameAvailable(). This handler is valid until
|
||||
* disconnect() is called.
|
||||
* dispose() is called.
|
||||
*/
|
||||
public Handler getHandler() {
|
||||
return handler;
|
||||
@ -380,7 +400,7 @@ class SurfaceTextureHelper {
|
||||
* stopped when the texture frame has been returned by a call to returnTextureFrame(). You are
|
||||
* guaranteed to not receive any more onTextureFrameAvailable() after this function returns.
|
||||
*/
|
||||
public void disconnect() {
|
||||
public void dispose() {
|
||||
if (handler.getLooper().getThread() == Thread.currentThread()) {
|
||||
isQuitting = true;
|
||||
if (!isTextureInUse) {
|
||||
@ -413,7 +433,7 @@ class SurfaceTextureHelper {
|
||||
if (handler.getLooper().getThread() != Thread.currentThread()) {
|
||||
throw new IllegalStateException("Wrong thread.");
|
||||
}
|
||||
if (isQuitting || !hasPendingTexture || isTextureInUse) {
|
||||
if (isQuitting || !hasPendingTexture || isTextureInUse || listener == null) {
|
||||
return;
|
||||
}
|
||||
isTextureInUse = true;
|
||||
|
||||
@ -306,9 +306,6 @@ public class VideoCapturerAndroid implements
|
||||
surfaceHelper = SurfaceTextureHelper.create(sharedContext);
|
||||
cameraThreadHandler = surfaceHelper.getHandler();
|
||||
cameraThread = cameraThreadHandler.getLooper().getThread();
|
||||
if (isCapturingToTexture) {
|
||||
surfaceHelper.setListener(this);
|
||||
}
|
||||
Logging.d(TAG, "VideoCapturerAndroid isCapturingToTexture : " + isCapturingToTexture);
|
||||
}
|
||||
|
||||
@ -352,7 +349,7 @@ public class VideoCapturerAndroid implements
|
||||
}
|
||||
}
|
||||
});
|
||||
surfaceHelper.disconnect();
|
||||
surfaceHelper.dispose();
|
||||
cameraThread = null;
|
||||
}
|
||||
|
||||
@ -436,6 +433,9 @@ public class VideoCapturerAndroid implements
|
||||
camera.setErrorCallback(cameraErrorCallback);
|
||||
startPreviewOnCameraThread(width, height, framerate);
|
||||
frameObserver.onCapturerStarted(true);
|
||||
if (isCapturingToTexture) {
|
||||
surfaceHelper.startListening(this);
|
||||
}
|
||||
|
||||
// Start camera observer.
|
||||
cameraThreadHandler.postDelayed(cameraObserver, CAMERA_OBSERVER_PERIOD_MS);
|
||||
@ -544,6 +544,8 @@ public class VideoCapturerAndroid implements
|
||||
final CountDownLatch barrier = new CountDownLatch(1);
|
||||
cameraThreadHandler.post(new Runnable() {
|
||||
@Override public void run() {
|
||||
// Make sure onTextureFrameAvailable() is not called anymore.
|
||||
surfaceHelper.stopListening();
|
||||
stopCaptureOnCameraThread();
|
||||
barrier.countDown();
|
||||
}
|
||||
@ -669,12 +671,10 @@ public class VideoCapturerAndroid implements
|
||||
@Override
|
||||
public void onTextureFrameAvailable(
|
||||
int oesTextureId, float[] transformMatrix, long timestampNs) {
|
||||
checkIsOnCameraThread();
|
||||
if (camera == null) {
|
||||
// Camera is stopped, we need to return the buffer immediately.
|
||||
surfaceHelper.returnTextureFrame();
|
||||
return;
|
||||
throw new RuntimeException("onTextureFrameAvailable() called after stopCapture().");
|
||||
}
|
||||
checkIsOnCameraThread();
|
||||
if (dropNextFrame) {
|
||||
surfaceHelper.returnTextureFrame();
|
||||
dropNextFrame = false;
|
||||
|
||||
Reference in New Issue
Block a user