Bug 1808705 - test VideoCaptureAndroid with mock camera enumerator. r=pehrsons,geckoview-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D178893
This commit is contained in:
John Lin 2024-03-07 20:08:53 +00:00
parent b4c7f0a031
commit d5fdc792ff
3 changed files with 84 additions and 19 deletions

View File

@ -17,6 +17,7 @@ import android.content.Context;
import android.util.Log;
import android.view.Surface;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import java.util.concurrent.CountDownLatch;
@ -37,10 +38,8 @@ public class VideoCaptureAndroid implements CameraVideoCapturer.CameraEventsHand
private final String deviceName;
private volatile long native_capturer; // |VideoCaptureAndroid*| in C++.
private Context context;
private final Context context;
private CameraVideoCapturer cameraVideoCapturer;
private EglBase eglBase;
private SurfaceTextureHelper surfaceTextureHelper;
// This class is recreated everytime we start/stop capture, so we
// can safely create the CountDownLatches here.
@ -48,8 +47,16 @@ public class VideoCaptureAndroid implements CameraVideoCapturer.CameraEventsHand
private boolean capturerStartedSucceeded = false;
private final CountDownLatch capturerStopped = new CountDownLatch(1);
@WebRTCJNITarget
public VideoCaptureAndroid(String deviceName) {
@WebRTCJNITarget
public static VideoCaptureAndroid create(@NonNull final String deviceName) {
final Context context = GetContext();
return new VideoCaptureAndroid(context, deviceName,
Camera2Enumerator.isSupported(context)
? new Camera2Enumerator(context)
: new Camera1Enumerator());
}
private VideoCaptureAndroid(@NonNull final Context context, @NonNull final String deviceName, @NonNull final CameraEnumerator enumerator) {
// Remove the camera facing information from the name.
String[] parts = deviceName.split("Facing (front|back):");
if (parts.length == 2) {
@ -58,18 +65,12 @@ public class VideoCaptureAndroid implements CameraVideoCapturer.CameraEventsHand
Log.e(TAG, "VideoCaptureAndroid: Expected facing mode as part of name: " + deviceName);
this.deviceName = deviceName;
}
this.context = GetContext();
this.context = context;
CameraEnumerator enumerator;
if (Camera2Enumerator.isSupported(context)) {
enumerator = new Camera2Enumerator(context);
} else {
enumerator = new Camera1Enumerator();
}
try {
cameraVideoCapturer = enumerator.createCapturer(this.deviceName, this);
eglBase = EglBase.create();
surfaceTextureHelper = SurfaceTextureHelper.create("VideoCaptureAndroidSurfaceTextureHelper", eglBase.getEglBaseContext());
final EglBase eglBase = EglBase.create();
final SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("VideoCaptureAndroidSurfaceTextureHelper", eglBase.getEglBaseContext());
cameraVideoCapturer.initialize(surfaceTextureHelper, context, this);
} catch (java.lang.RuntimeException e) {
Log.e(TAG, "VideoCaptureAndroid: Exception while creating capturer: " + e);
@ -80,6 +81,10 @@ public class VideoCaptureAndroid implements CameraVideoCapturer.CameraEventsHand
@WebRTCJNITarget
private static native Context GetContext();
public boolean canCapture() {
return cameraVideoCapturer != null;
}
// Called by native code. Returns true if capturer is started.
//
// Note that this actually opens the camera, and Camera callbacks run on the

View File

@ -177,12 +177,14 @@ int32_t VideoCaptureAndroid::Init(const char* deviceUniqueIdUTF8) {
AttachThreadScoped ats(g_jvm_capture);
JNIEnv* env = ats.env();
jmethodID ctor = env->GetMethodID(g_java_capturer_class, "<init>",
"(Ljava/lang/String;)V");
assert(ctor);
jmethodID factory =
env->GetStaticMethodID(g_java_capturer_class, "create",
"(Ljava/lang/String;)"
"Lorg/webrtc/videoengine/VideoCaptureAndroid;");
assert(factory);
jstring j_deviceName = env->NewStringUTF(_deviceUniqueId);
_jCapturer = env->NewGlobalRef(
env->NewObject(g_java_capturer_class, ctor, j_deviceName));
_jCapturer = env->NewGlobalRef(env->CallStaticObjectMethod(
g_java_capturer_class, factory, j_deviceName));
assert(_jCapturer);
return 0;
}

View File

@ -0,0 +1,58 @@
package org.mozilla.geckoview.test
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.webrtc.CameraEnumerationAndroid.CaptureFormat
import org.webrtc.CameraEnumerator
import org.webrtc.CameraVideoCapturer
import org.webrtc.CameraVideoCapturer.CameraEventsHandler
import org.webrtc.videoengine.VideoCaptureAndroid
@RunWith(AndroidJUnit4::class)
@SmallTest
class VideoCaptureTest {
// Always throw exception.
class BadCameraEnumerator : CameraEnumerator {
override fun getDeviceNames(): Array<String?>? {
throw java.lang.RuntimeException("")
}
override fun isFrontFacing(deviceName: String?): Boolean {
throw java.lang.RuntimeException("")
}
override fun isBackFacing(deviceName: String?): Boolean {
throw java.lang.RuntimeException("")
}
override fun isInfrared(deviceName: String?): Boolean {
throw java.lang.RuntimeException("")
}
override fun getSupportedFormats(deviceName: String?): List<CaptureFormat?>? {
throw java.lang.RuntimeException("")
}
override fun createCapturer(
deviceName: String?,
eventsHandler: CameraEventsHandler?,
): CameraVideoCapturer? {
throw java.lang.RuntimeException("")
}
}
@Test
fun constructWithBadEnumerator() {
val ctr = VideoCaptureAndroid::class.java.getDeclaredConstructors()[0].apply { isAccessible = true }
val capture = ctr.newInstance(
InstrumentationRegistry.getInstrumentation().targetContext,
"my camera",
BadCameraEnumerator(),
) as VideoCaptureAndroid
assertEquals(false, capture.canCapture())
}
}