Android: Make VideoCapturer an interface for all VideoCapturers to implement
This CL factors out the interface that AndroidVideoCapturerJni is using to communicate with the Java counterpart. This interface is moved into VideoCapturer. The interface is not touched in this CL, and a follow-up CL is planned to simplify and improve it.
Another change is that the native part of VideoCapturer is created in PeerConnectionFactory.createVideoSource() instead of doing it immediately in the ctor.
BUG=webrtc:5519
R=perkj@webrtc.org
Review URL: https://codereview.webrtc.org/1696553003 .
Cr-Commit-Position: refs/heads/master@{#11606}
diff --git a/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java b/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java
index 27cffd2..f465ce7 100644
--- a/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java
+++ b/webrtc/api/java/android/org/webrtc/CameraEnumerationAndroid.java
@@ -50,9 +50,8 @@
public final int height;
public final int maxFramerate;
public final int minFramerate;
- // TODO(hbos): If VideoCapturerAndroid.startCapture is updated to support
- // other image formats then this needs to be updated and
- // VideoCapturerAndroid.getSupportedFormats need to return CaptureFormats of
+ // TODO(hbos): If VideoCapturer.startCapture is updated to support other image formats then this
+ // needs to be updated and VideoCapturer.getSupportedFormats need to return CaptureFormats of
// all imageFormats.
public final int imageFormat = ImageFormat.NV21;
diff --git a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java
index 5edca3b..0ae03ca 100644
--- a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java
+++ b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java
@@ -45,7 +45,8 @@
// camera thread. The internal *OnCameraThread() methods must check |camera| for null to check if
// the camera has been stopped.
@SuppressWarnings("deprecation")
-public class VideoCapturerAndroid extends VideoCapturer implements
+public class VideoCapturerAndroid implements
+ VideoCapturer,
android.hardware.Camera.PreviewCallback,
SurfaceTextureHelper.OnTextureFrameAvailableListener {
private final static String TAG = "VideoCapturerAndroid";
@@ -196,12 +197,7 @@
if (cameraId == -1) {
return null;
}
-
- final VideoCapturerAndroid capturer = new VideoCapturerAndroid(cameraId, eventsHandler,
- sharedEglContext);
- capturer.setNativeCapturer(
- nativeCreateVideoCapturer(capturer, capturer.surfaceHelper));
- return capturer;
+ return new VideoCapturerAndroid(cameraId, eventsHandler, sharedEglContext);
}
public void printStackTrace() {
@@ -297,14 +293,14 @@
return isCapturingToTexture;
}
- // Called from native code.
- private String getSupportedFormatsAsJson() throws JSONException {
+ @Override
+ public String getSupportedFormatsAsJson() throws JSONException {
return CameraEnumerationAndroid.getSupportedFormatsAsJson(getCurrentCameraId());
}
- // Called from native VideoCapturer_nativeCreateVideoCapturer.
- private VideoCapturerAndroid(int cameraId) {
- this(cameraId, null, null);
+ @Override
+ public SurfaceTextureHelper getSurfaceTextureHelper() {
+ return surfaceHelper;
}
private VideoCapturerAndroid(int cameraId, CameraEventsHandler eventsHandler,
@@ -347,11 +343,12 @@
return -1;
}
- // Called by native code to quit the camera thread. This needs to be done manually, otherwise the
- // thread and handler will not be garbage collected.
- private void release() {
+ // Quits the camera thread. This needs to be done manually, otherwise the thread and handler will
+ // not be garbage collected.
+ @Override
+ public void dispose() {
Logging.d(TAG, "release");
- if (isReleased()) {
+ if (isDisposed()) {
throw new IllegalStateException("Already released");
}
ThreadUtils.invokeUninterruptibly(cameraThreadHandler, new Runnable() {
@@ -367,15 +364,14 @@
}
// Used for testing purposes to check if release() has been called.
- public boolean isReleased() {
+ public boolean isDisposed() {
return (cameraThread == null);
}
- // Called by native code.
- //
// Note that this actually opens the camera, and Camera callbacks run on the
// thread that calls open(), so this is done on the CameraThread.
- void startCapture(
+ @Override
+ public void startCapture(
final int width, final int height, final int framerate,
final Context applicationContext, final CapturerObserver frameObserver) {
Logging.d(TAG, "startCapture requested: " + width + "x" + height
@@ -548,8 +544,9 @@
camera.startPreview();
}
- // Called by native code. Returns true when camera is known to be stopped.
- void stopCapture() throws InterruptedException {
+ // Blocks until camera is known to be stopped.
+ @Override
+ public void stopCapture() throws InterruptedException {
Logging.d(TAG, "stopCapture");
final CountDownLatch barrier = new CountDownLatch(1);
cameraThreadHandler.post(new Runnable() {
@@ -702,75 +699,4 @@
frameObserver.onTextureFrameCaptured(captureFormat.width, captureFormat.height, oesTextureId,
transformMatrix, rotation, timestampNs);
}
-
- // Interface used for providing callbacks to an observer.
- interface CapturerObserver {
- // Notify if the camera have been started successfully or not.
- // Called on a Java thread owned by VideoCapturerAndroid.
- abstract void onCapturerStarted(boolean success);
-
- // Delivers a captured frame. Called on a Java thread owned by
- // VideoCapturerAndroid.
- abstract void onByteBufferFrameCaptured(byte[] data, int width, int height, int rotation,
- long timeStamp);
-
- // Delivers a captured frame in a texture with id |oesTextureId|. Called on a Java thread
- // owned by VideoCapturerAndroid.
- abstract void onTextureFrameCaptured(
- int width, int height, int oesTextureId, float[] transformMatrix, int rotation,
- long timestamp);
-
- // Requests an output format from the video capturer. Captured frames
- // by the camera will be scaled/or dropped by the video capturer.
- // Called on a Java thread owned by VideoCapturerAndroid.
- abstract void onOutputFormatRequest(int width, int height, int framerate);
- }
-
- // An implementation of CapturerObserver that forwards all calls from
- // Java to the C layer.
- static class NativeObserver implements CapturerObserver {
- private final long nativeCapturer;
-
- public NativeObserver(long nativeCapturer) {
- this.nativeCapturer = nativeCapturer;
- }
-
- @Override
- public void onCapturerStarted(boolean success) {
- nativeCapturerStarted(nativeCapturer, success);
- }
-
- @Override
- public void onByteBufferFrameCaptured(byte[] data, int width, int height,
- int rotation, long timeStamp) {
- nativeOnByteBufferFrameCaptured(nativeCapturer, data, data.length, width, height, rotation,
- timeStamp);
- }
-
- @Override
- public void onTextureFrameCaptured(
- int width, int height, int oesTextureId, float[] transformMatrix, int rotation,
- long timestamp) {
- nativeOnTextureFrameCaptured(nativeCapturer, width, height, oesTextureId, transformMatrix,
- rotation, timestamp);
- }
-
- @Override
- public void onOutputFormatRequest(int width, int height, int framerate) {
- nativeOnOutputFormatRequest(nativeCapturer, width, height, framerate);
- }
-
- private native void nativeCapturerStarted(long nativeCapturer,
- boolean success);
- private native void nativeOnByteBufferFrameCaptured(long nativeCapturer,
- byte[] data, int length, int width, int height, int rotation, long timeStamp);
- private native void nativeOnTextureFrameCaptured(long nativeCapturer, int width, int height,
- int oesTextureId, float[] transformMatrix, int rotation, long timestamp);
- private native void nativeOnOutputFormatRequest(long nativeCapturer,
- int width, int height, int framerate);
- }
-
- private static native long nativeCreateVideoCapturer(
- VideoCapturerAndroid videoCapturer,
- SurfaceTextureHelper surfaceHelper);
}
diff --git a/webrtc/api/java/jni/androidvideocapturer_jni.cc b/webrtc/api/java/jni/androidvideocapturer_jni.cc
index 98dfd63..8588dc2 100644
--- a/webrtc/api/java/jni/androidvideocapturer_jni.cc
+++ b/webrtc/api/java/jni/androidvideocapturer_jni.cc
@@ -36,11 +36,11 @@
jobject j_surface_texture_helper)
: j_video_capturer_(jni, j_video_capturer),
j_video_capturer_class_(
- jni, FindClass(jni, "org/webrtc/VideoCapturerAndroid")),
+ jni, FindClass(jni, "org/webrtc/VideoCapturer")),
j_observer_class_(
jni,
FindClass(jni,
- "org/webrtc/VideoCapturerAndroid$NativeObserver")),
+ "org/webrtc/VideoCapturer$NativeObserver")),
surface_texture_helper_(new rtc::RefCountedObject<SurfaceTextureHelper>(
jni, j_surface_texture_helper)),
capturer_(nullptr) {
@@ -52,8 +52,8 @@
LOG(LS_INFO) << "AndroidVideoCapturerJni dtor";
jni()->CallVoidMethod(
*j_video_capturer_,
- GetMethodID(jni(), *j_video_capturer_class_, "release", "()V"));
- CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.release()";
+ GetMethodID(jni(), *j_video_capturer_class_, "dispose", "()V"));
+ CHECK_EXCEPTION(jni()) << "error during VideoCapturer.dispose()";
}
void AndroidVideoCapturerJni::Start(int width, int height, int framerate,
@@ -76,13 +76,13 @@
jmethodID m = GetMethodID(
jni(), *j_video_capturer_class_, "startCapture",
"(IIILandroid/content/Context;"
- "Lorg/webrtc/VideoCapturerAndroid$CapturerObserver;)V");
+ "Lorg/webrtc/VideoCapturer$CapturerObserver;)V");
jni()->CallVoidMethod(*j_video_capturer_,
m, width, height,
framerate,
application_context_,
j_frame_observer);
- CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.startCapture";
+ CHECK_EXCEPTION(jni()) << "error during VideoCapturer.startCapture";
}
void AndroidVideoCapturerJni::Stop() {
@@ -97,7 +97,7 @@
jmethodID m = GetMethodID(jni(), *j_video_capturer_class_,
"stopCapture", "()V");
jni()->CallVoidMethod(*j_video_capturer_, m);
- CHECK_EXCEPTION(jni()) << "error during VideoCapturerAndroid.stopCapture";
+ CHECK_EXCEPTION(jni()) << "error during VideoCapturer.stopCapture";
LOG(LS_INFO) << "AndroidVideoCapturerJni stop done";
}
@@ -178,7 +178,7 @@
JNIEnv* AndroidVideoCapturerJni::jni() { return AttachCurrentThreadIfNeeded(); }
JOW(void,
- VideoCapturerAndroid_00024NativeObserver_nativeOnByteBufferFrameCaptured)
+ VideoCapturer_00024NativeObserver_nativeOnByteBufferFrameCaptured)
(JNIEnv* jni, jclass, jlong j_capturer, jbyteArray j_frame, jint length,
jint width, jint height, jint rotation, jlong timestamp) {
jboolean is_copy = true;
@@ -188,7 +188,7 @@
jni->ReleaseByteArrayElements(j_frame, bytes, JNI_ABORT);
}
-JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnTextureFrameCaptured)
+JOW(void, VideoCapturer_00024NativeObserver_nativeOnTextureFrameCaptured)
(JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height,
jint j_oes_texture_id, jfloatArray j_transform_matrix,
jint j_rotation, jlong j_timestamp) {
@@ -198,14 +198,14 @@
j_transform_matrix));
}
-JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeCapturerStarted)
+JOW(void, VideoCapturer_00024NativeObserver_nativeCapturerStarted)
(JNIEnv* jni, jclass, jlong j_capturer, jboolean j_success) {
LOG(LS_INFO) << "NativeObserver_nativeCapturerStarted";
reinterpret_cast<AndroidVideoCapturerJni*>(j_capturer)->OnCapturerStarted(
j_success);
}
-JOW(void, VideoCapturerAndroid_00024NativeObserver_nativeOnOutputFormatRequest)
+JOW(void, VideoCapturer_00024NativeObserver_nativeOnOutputFormatRequest)
(JNIEnv* jni, jclass, jlong j_capturer, jint j_width, jint j_height,
jint j_fps) {
LOG(LS_INFO) << "NativeObserver_nativeOnOutputFormatRequest";
@@ -213,16 +213,4 @@
j_width, j_height, j_fps);
}
-JOW(jlong, VideoCapturerAndroid_nativeCreateVideoCapturer)
- (JNIEnv* jni, jclass,
- jobject j_video_capturer, jobject j_surface_texture_helper) {
- rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate =
- new rtc::RefCountedObject<AndroidVideoCapturerJni>(
- jni, j_video_capturer, j_surface_texture_helper);
- rtc::scoped_ptr<cricket::VideoCapturer> capturer(
- new webrtc::AndroidVideoCapturer(delegate));
- // Caller takes ownership of the cricket::VideoCapturer* pointer.
- return jlongFromPointer(capturer.release());
-}
-
} // namespace webrtc_jni
diff --git a/webrtc/api/java/jni/androidvideocapturer_jni.h b/webrtc/api/java/jni/androidvideocapturer_jni.h
index 16210b1..9b3bb4f 100644
--- a/webrtc/api/java/jni/androidvideocapturer_jni.h
+++ b/webrtc/api/java/jni/androidvideocapturer_jni.h
@@ -42,7 +42,7 @@
std::string GetSupportedFormats() override;
- // Called from VideoCapturerAndroid::NativeObserver on a Java thread.
+ // Called from VideoCapturer::NativeObserver on a Java thread.
void OnCapturerStarted(bool success);
void OnMemoryBufferFrame(void* video_frame, int length, int width,
int height, int rotation, int64_t timestamp_ns);
diff --git a/webrtc/api/java/jni/classreferenceholder.cc b/webrtc/api/java/jni/classreferenceholder.cc
index 2f17db3..d6c7d56 100644
--- a/webrtc/api/java/jni/classreferenceholder.cc
+++ b/webrtc/api/java/jni/classreferenceholder.cc
@@ -90,8 +90,8 @@
LoadClass(jni, "org/webrtc/StatsReport");
LoadClass(jni, "org/webrtc/StatsReport$Value");
LoadClass(jni, "org/webrtc/SurfaceTextureHelper");
- LoadClass(jni, "org/webrtc/VideoCapturerAndroid");
- LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeObserver");
+ LoadClass(jni, "org/webrtc/VideoCapturer");
+ LoadClass(jni, "org/webrtc/VideoCapturer$NativeObserver");
LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
LoadClass(jni, "org/webrtc/VideoTrack");
}
diff --git a/webrtc/api/java/jni/peerconnection_jni.cc b/webrtc/api/java/jni/peerconnection_jni.cc
index 3997805..f7b9e90 100644
--- a/webrtc/api/java/jni/peerconnection_jni.cc
+++ b/webrtc/api/java/jni/peerconnection_jni.cc
@@ -910,10 +910,6 @@
CHECK_RELEASE(reinterpret_cast<MediaSourceInterface*>(j_p));
}
-JOW(void, VideoCapturer_free)(JNIEnv*, jclass, jlong j_p) {
- delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
-}
-
JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
}
@@ -1216,16 +1212,27 @@
}
JOW(jlong, PeerConnectionFactory_nativeCreateVideoSource)(
- JNIEnv* jni, jclass, jlong native_factory, jlong native_capturer,
+ JNIEnv* jni, jclass, jlong native_factory, jobject j_video_capturer,
jobject j_constraints) {
+ // Create a cricket::VideoCapturer from |j_video_capturer|.
+ jobject j_surface_texture_helper = jni->CallObjectMethod(
+ j_video_capturer,
+ GetMethodID(jni, FindClass(jni, "org/webrtc/VideoCapturer"),
+ "getSurfaceTextureHelper",
+ "()Lorg/webrtc/SurfaceTextureHelper;"));
+ rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate =
+ new rtc::RefCountedObject<AndroidVideoCapturerJni>(
+ jni, j_video_capturer, j_surface_texture_helper);
+ rtc::scoped_ptr<cricket::VideoCapturer> capturer(
+ new webrtc::AndroidVideoCapturer(delegate));
+ // Create a webrtc::VideoSourceInterface from the cricket::VideoCapturer,
+ // native factory and constraints.
scoped_ptr<ConstraintsWrapper> constraints(
new ConstraintsWrapper(jni, j_constraints));
rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
factoryFromJava(native_factory));
rtc::scoped_refptr<VideoSourceInterface> source(
- factory->CreateVideoSource(
- reinterpret_cast<cricket::VideoCapturer*>(native_capturer),
- constraints.get()));
+ factory->CreateVideoSource(capturer.release(), constraints.get()));
return (jlong)source.release();
}
diff --git a/webrtc/api/java/src/org/webrtc/PeerConnectionFactory.java b/webrtc/api/java/src/org/webrtc/PeerConnectionFactory.java
index ff6e89f..96a161b 100644
--- a/webrtc/api/java/src/org/webrtc/PeerConnectionFactory.java
+++ b/webrtc/api/java/src/org/webrtc/PeerConnectionFactory.java
@@ -108,10 +108,12 @@
nativeCreateLocalMediaStream(nativeFactory, label));
}
+ // The VideoSource takes ownership of |capturer|, so capturer.release() should not be called
+ // manually after this.
public VideoSource createVideoSource(
VideoCapturer capturer, MediaConstraints constraints) {
return new VideoSource(nativeCreateVideoSource(
- nativeFactory, capturer.takeNativeVideoCapturer(), constraints));
+ nativeFactory, capturer, constraints));
}
public VideoTrack createVideoTrack(String id, VideoSource source) {
@@ -221,8 +223,7 @@
long nativeFactory, String label);
private static native long nativeCreateVideoSource(
- long nativeFactory, long nativeVideoCapturer,
- MediaConstraints constraints);
+ long nativeFactory, VideoCapturer videoCapturer, MediaConstraints constraints);
private static native long nativeCreateVideoTrack(
long nativeFactory, String id, long nativeVideoSource);
diff --git a/webrtc/api/java/src/org/webrtc/VideoCapturer.java b/webrtc/api/java/src/org/webrtc/VideoCapturer.java
index 9a479a3..21bfafa 100644
--- a/webrtc/api/java/src/org/webrtc/VideoCapturer.java
+++ b/webrtc/api/java/src/org/webrtc/VideoCapturer.java
@@ -10,36 +10,89 @@
package org.webrtc;
-/** Java version of cricket::VideoCapturer. */
-// TODO(perkj): Merge VideoCapturer and VideoCapturerAndroid.
-public class VideoCapturer {
- private long nativeVideoCapturer;
+import android.content.Context;
- protected VideoCapturer() {
+import org.json.JSONException;
+
+// Base interface for all VideoCapturers to implement.
+// TODO(magjed): Simplify and improve this interface.
+public interface VideoCapturer {
+ // Interface used for providing callbacks to an observer.
+ public interface CapturerObserver {
+ // Notify if the camera have been started successfully or not.
+ // Called on a Java thread owned by VideoCapturer.
+ void onCapturerStarted(boolean success);
+
+ // Delivers a captured frame. Called on a Java thread owned by VideoCapturer.
+ void onByteBufferFrameCaptured(byte[] data, int width, int height, int rotation,
+ long timeStamp);
+
+ // Delivers a captured frame in a texture with id |oesTextureId|. Called on a Java thread
+ // owned by VideoCapturer.
+ void onTextureFrameCaptured(
+ int width, int height, int oesTextureId, float[] transformMatrix, int rotation,
+ long timestamp);
+
+ // Requests an output format from the video capturer. Captured frames
+ // by the camera will be scaled/or dropped by the video capturer.
+ // Called on a Java thread owned by VideoCapturer.
+ void onOutputFormatRequest(int width, int height, int framerate);
}
- // Sets |nativeCapturer| to be owned by VideoCapturer.
- protected void setNativeCapturer(long nativeCapturer) {
- this.nativeVideoCapturer = nativeCapturer;
- }
+ // An implementation of CapturerObserver that forwards all calls from
+ // Java to the C layer.
+ static class NativeObserver implements CapturerObserver {
+ private final long nativeCapturer;
- // Package-visible for PeerConnectionFactory.
- long takeNativeVideoCapturer() {
- if (nativeVideoCapturer == 0) {
- throw new RuntimeException("Capturer can only be taken once!");
+ public NativeObserver(long nativeCapturer) {
+ this.nativeCapturer = nativeCapturer;
}
- long ret = nativeVideoCapturer;
- nativeVideoCapturer = 0;
- return ret;
- }
- public void dispose() {
- // No-op iff this capturer is owned by a source (see comment on
- // PeerConnectionFactoryInterface::CreateVideoSource()).
- if (nativeVideoCapturer != 0) {
- free(nativeVideoCapturer);
+ @Override
+ public void onCapturerStarted(boolean success) {
+ nativeCapturerStarted(nativeCapturer, success);
}
+
+ @Override
+ public void onByteBufferFrameCaptured(byte[] data, int width, int height,
+ int rotation, long timeStamp) {
+ nativeOnByteBufferFrameCaptured(nativeCapturer, data, data.length, width, height, rotation,
+ timeStamp);
+ }
+
+ @Override
+ public void onTextureFrameCaptured(
+ int width, int height, int oesTextureId, float[] transformMatrix, int rotation,
+ long timestamp) {
+ nativeOnTextureFrameCaptured(nativeCapturer, width, height, oesTextureId, transformMatrix,
+ rotation, timestamp);
+ }
+
+ @Override
+ public void onOutputFormatRequest(int width, int height, int framerate) {
+ nativeOnOutputFormatRequest(nativeCapturer, width, height, framerate);
+ }
+
+ private native void nativeCapturerStarted(long nativeCapturer,
+ boolean success);
+ private native void nativeOnByteBufferFrameCaptured(long nativeCapturer,
+ byte[] data, int length, int width, int height, int rotation, long timeStamp);
+ private native void nativeOnTextureFrameCaptured(long nativeCapturer, int width, int height,
+ int oesTextureId, float[] transformMatrix, int rotation, long timestamp);
+ private native void nativeOnOutputFormatRequest(long nativeCapturer,
+ int width, int height, int framerate);
}
- private static native void free(long nativeVideoCapturer);
+ String getSupportedFormatsAsJson() throws JSONException;
+
+ SurfaceTextureHelper getSurfaceTextureHelper();
+
+ void startCapture(
+ final int width, final int height, final int framerate,
+ final Context applicationContext, final CapturerObserver frameObserver);
+
+ // Blocks until capture is stopped.
+ void stopCapture() throws InterruptedException;
+
+ void dispose();
}