andrew@webrtc.org | a7b57da | 2012-10-22 18:19:23 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | #include "video_capture_android.h" |
| 12 | |
| 13 | #include <stdio.h> |
| 14 | |
| 15 | #include "critical_section_wrapper.h" |
| 16 | #include "ref_count.h" |
| 17 | #include "trace.h" |
| 18 | |
| 19 | namespace webrtc |
| 20 | { |
| 21 | #if defined(WEBRTC_ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD) |
| 22 | // TODO(leozwang) These SetAndroidVM apis will be refactored, thus we only |
| 23 | // keep and reference java vm. |
| 24 | WebRtc_Word32 SetCaptureAndroidVM(void* javaVM, void* javaContext) { |
| 25 | return videocapturemodule::VideoCaptureAndroid::SetAndroidObjects( |
| 26 | javaVM, |
| 27 | javaContext); |
| 28 | } |
| 29 | #endif |
| 30 | |
| 31 | namespace videocapturemodule |
| 32 | { |
| 33 | |
| 34 | VideoCaptureModule* VideoCaptureImpl::Create( |
| 35 | const WebRtc_Word32 id, |
| 36 | const char* deviceUniqueIdUTF8) { |
| 37 | |
| 38 | RefCountImpl<videocapturemodule::VideoCaptureAndroid>* implementation = |
| 39 | new RefCountImpl<videocapturemodule::VideoCaptureAndroid>(id); |
| 40 | |
| 41 | if (!implementation || implementation->Init(id, deviceUniqueIdUTF8) != 0) { |
| 42 | delete implementation; |
| 43 | implementation = NULL; |
| 44 | } |
| 45 | return implementation; |
| 46 | } |
| 47 | |
| 48 | // Android logging, uncomment to print trace to |
| 49 | // logcat instead of trace file/callback |
| 50 | // #include <android/log.h> |
| 51 | // #undef WEBRTC_TRACE |
| 52 | // #define WEBRTC_TRACE(a,b,c,...) |
| 53 | // __android_log_print(ANDROID_LOG_DEBUG, "*WEBRTCN*", __VA_ARGS__) |
| 54 | |
| 55 | JavaVM* VideoCaptureAndroid::g_jvm = NULL; |
| 56 | //VideoCaptureAndroid.java |
| 57 | jclass VideoCaptureAndroid::g_javaCmClass = NULL; |
| 58 | //VideoCaptureDeviceInfoAndroid.java |
| 59 | jclass VideoCaptureAndroid::g_javaCmDevInfoClass = NULL; |
| 60 | //static instance of VideoCaptureDeviceInfoAndroid.java |
| 61 | jobject VideoCaptureAndroid::g_javaCmDevInfoObject = NULL; |
| 62 | jobject VideoCaptureAndroid::g_javaContext = NULL; |
| 63 | |
| 64 | /* |
| 65 | * Register references to Java Capture class. |
| 66 | */ |
| 67 | WebRtc_Word32 VideoCaptureAndroid::SetAndroidObjects(void* javaVM, |
| 68 | void* javaContext) { |
| 69 | |
| 70 | g_jvm = static_cast<JavaVM*> (javaVM); |
| 71 | g_javaContext = static_cast<jobject> (javaContext); |
| 72 | |
| 73 | if (javaVM) { |
| 74 | JNIEnv* env = NULL; |
| 75 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 76 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 77 | "%s: could not get Java environment", __FUNCTION__); |
| 78 | return -1; |
| 79 | } |
| 80 | // get java capture class type (note path to class packet) |
| 81 | jclass javaCmClassLocal = env->FindClass(AndroidJavaCaptureClass); |
| 82 | if (!javaCmClassLocal) { |
| 83 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 84 | "%s: could not find java class", __FUNCTION__); |
| 85 | return -1; |
| 86 | } |
| 87 | // create a global reference to the class |
| 88 | // (to tell JNI that we are referencing it |
| 89 | // after this function has returned) |
| 90 | g_javaCmClass = static_cast<jclass> |
| 91 | (env->NewGlobalRef(javaCmClassLocal)); |
| 92 | if (!g_javaCmClass) { |
| 93 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 94 | "%s: InitVideoEngineJava(): could not create" |
| 95 | " Java Camera class reference", |
| 96 | __FUNCTION__); |
| 97 | return -1; |
| 98 | } |
| 99 | // Delete local class ref, we only use the global ref |
| 100 | env->DeleteLocalRef(javaCmClassLocal); |
| 101 | JNINativeMethod nativeFunctions = |
| 102 | { "ProvideCameraFrame", "([BIJ)V", |
| 103 | (void*) &VideoCaptureAndroid::ProvideCameraFrame }; |
| 104 | if (env->RegisterNatives(g_javaCmClass, &nativeFunctions, 1) == 0) { |
| 105 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 106 | "%s: Registered native functions", __FUNCTION__); |
| 107 | } |
| 108 | else { |
| 109 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 110 | "%s: Failed to register native functions", |
| 111 | __FUNCTION__); |
| 112 | return -1; |
| 113 | } |
| 114 | |
| 115 | // get java capture class type (note path to class packet) |
| 116 | jclass javaCmDevInfoClassLocal = env->FindClass( |
| 117 | AndroidJavaCaptureDeviceInfoClass); |
| 118 | if (!javaCmDevInfoClassLocal) { |
| 119 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 120 | "%s: could not find java class", __FUNCTION__); |
| 121 | return -1; |
| 122 | } |
| 123 | |
| 124 | // create a global reference to the class |
| 125 | // (to tell JNI that we are referencing it |
| 126 | // after this function has returned) |
| 127 | g_javaCmDevInfoClass = static_cast<jclass> |
| 128 | (env->NewGlobalRef(javaCmDevInfoClassLocal)); |
| 129 | if (!g_javaCmDevInfoClass) { |
| 130 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 131 | "%s: InitVideoEngineJava(): could not create Java " |
| 132 | "Camera Device info class reference", |
| 133 | __FUNCTION__); |
| 134 | return -1; |
| 135 | } |
| 136 | // Delete local class ref, we only use the global ref |
| 137 | env->DeleteLocalRef(javaCmDevInfoClassLocal); |
| 138 | |
| 139 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 140 | "VideoCaptureDeviceInfoAndroid get method id"); |
| 141 | |
| 142 | // get the method ID for the Android Java CaptureClass static |
| 143 | //CreateVideoCaptureAndroid factory method. |
| 144 | jmethodID cid = env->GetStaticMethodID( |
| 145 | g_javaCmDevInfoClass, |
| 146 | "CreateVideoCaptureDeviceInfoAndroid", |
| 147 | "(ILandroid/content/Context;)" |
| 148 | "Lorg/webrtc/videoengine/VideoCaptureDeviceInfoAndroid;"); |
| 149 | if (cid == NULL) { |
| 150 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 151 | "%s: could not get java" |
| 152 | "VideoCaptureDeviceInfoAndroid constructor ID", |
| 153 | __FUNCTION__); |
| 154 | return -1; |
| 155 | } |
| 156 | |
| 157 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 158 | "%s: construct static java device object", __FUNCTION__); |
| 159 | |
| 160 | // construct the object by calling the static constructor object |
| 161 | jobject javaCameraDeviceInfoObjLocal = |
| 162 | env->CallStaticObjectMethod(g_javaCmDevInfoClass, |
| 163 | cid, (int) -1, |
| 164 | g_javaContext); |
| 165 | if (!javaCameraDeviceInfoObjLocal) { |
| 166 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, -1, |
| 167 | "%s: could not create Java Capture Device info object", |
| 168 | __FUNCTION__); |
| 169 | return -1; |
| 170 | } |
| 171 | // create a reference to the object (to tell JNI that |
| 172 | // we are referencing it after this function has returned) |
| 173 | g_javaCmDevInfoObject = env->NewGlobalRef(javaCameraDeviceInfoObjLocal); |
| 174 | if (!g_javaCmDevInfoObject) { |
| 175 | WEBRTC_TRACE(webrtc::kTraceError, |
| 176 | webrtc::kTraceAudioDevice, |
| 177 | -1, |
| 178 | "%s: could not create Java" |
| 179 | "cameradevinceinfo object reference", |
| 180 | __FUNCTION__); |
| 181 | return -1; |
| 182 | } |
| 183 | // Delete local object ref, we only use the global ref |
| 184 | env->DeleteLocalRef(javaCameraDeviceInfoObjLocal); |
| 185 | return 0; |
| 186 | } |
| 187 | else { |
| 188 | WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCapture, -1, |
| 189 | "%s: JVM is NULL, assuming deinit", __FUNCTION__); |
| 190 | if (!g_jvm) { |
| 191 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 192 | "%s: SetAndroidObjects not called with a valid JVM.", |
| 193 | __FUNCTION__); |
| 194 | return -1; |
| 195 | } |
| 196 | JNIEnv* env = NULL; |
| 197 | bool attached = false; |
| 198 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 199 | // try to attach the thread and get the env |
| 200 | // Attach this thread to JVM |
| 201 | jint res = g_jvm->AttachCurrentThread(&env, NULL); |
| 202 | if ((res < 0) || !env) { |
| 203 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, |
| 204 | -1, "%s: Could not attach thread to JVM (%d, %p)", |
| 205 | __FUNCTION__, res, env); |
| 206 | return -1; |
| 207 | } |
| 208 | attached = true; |
| 209 | } |
| 210 | env->DeleteGlobalRef(g_javaCmDevInfoObject); |
| 211 | env->DeleteGlobalRef(g_javaCmDevInfoClass); |
| 212 | env->DeleteGlobalRef(g_javaCmClass); |
| 213 | if (attached && g_jvm->DetachCurrentThread() < 0) { |
| 214 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, -1, |
| 215 | "%s: Could not detach thread from JVM", __FUNCTION__); |
| 216 | return -1; |
| 217 | } |
| 218 | return 0; |
| 219 | env = (JNIEnv *) NULL; |
| 220 | } |
| 221 | return 0; |
| 222 | } |
| 223 | |
| 224 | WebRtc_Word32 VideoCaptureAndroid::AttachAndUseAndroidDeviceInfoObjects( |
| 225 | JNIEnv*& env, |
| 226 | jclass& javaCmDevInfoClass, |
| 227 | jobject& javaCmDevInfoObject, |
| 228 | bool& attached) { |
| 229 | // get the JNI env for this thread |
| 230 | if (!g_jvm) { |
| 231 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 232 | "%s: SetAndroidObjects not called with a valid JVM.", |
| 233 | __FUNCTION__); |
| 234 | return -1; |
| 235 | } |
| 236 | attached = false; |
| 237 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 238 | // try to attach the thread and get the env |
| 239 | // Attach this thread to JVM |
| 240 | jint res = g_jvm->AttachCurrentThread(&env, NULL); |
| 241 | if ((res < 0) || !env) { |
| 242 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 243 | "%s: Could not attach thread to JVM (%d, %p)", |
| 244 | __FUNCTION__, res, env); |
| 245 | return -1; |
| 246 | } |
| 247 | attached = true; |
| 248 | } |
| 249 | javaCmDevInfoClass = g_javaCmDevInfoClass; |
| 250 | javaCmDevInfoObject = g_javaCmDevInfoObject; |
| 251 | return 0; |
| 252 | |
| 253 | } |
| 254 | |
| 255 | WebRtc_Word32 VideoCaptureAndroid::ReleaseAndroidDeviceInfoObjects( |
| 256 | bool attached) { |
| 257 | if (attached && g_jvm->DetachCurrentThread() < 0) { |
| 258 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, -1, |
| 259 | "%s: Could not detach thread from JVM", __FUNCTION__); |
| 260 | return -1; |
| 261 | } |
| 262 | return 0; |
| 263 | } |
| 264 | |
| 265 | /* |
| 266 | * JNI callback from Java class. Called |
| 267 | * when the camera has a new frame to deliver |
| 268 | * Class: org_webrtc_capturemodule_VideoCaptureAndroid |
| 269 | * Method: ProvideCameraFrame |
| 270 | * Signature: ([BIJ)V |
| 271 | */ |
| 272 | void JNICALL VideoCaptureAndroid::ProvideCameraFrame(JNIEnv * env, |
| 273 | jobject, |
| 274 | jbyteArray javaCameraFrame, |
| 275 | jint length, |
| 276 | jlong context) { |
| 277 | VideoCaptureAndroid* captureModule = |
| 278 | reinterpret_cast<VideoCaptureAndroid*>(context); |
| 279 | WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideoCapture, |
| 280 | -1, "%s: IncomingFrame %d", __FUNCTION__,length); |
| 281 | jbyte* cameraFrame= env->GetByteArrayElements(javaCameraFrame,NULL); |
| 282 | captureModule->IncomingFrame((WebRtc_UWord8*) cameraFrame, |
| 283 | length,captureModule->_frameInfo,0); |
| 284 | env->ReleaseByteArrayElements(javaCameraFrame,cameraFrame,JNI_ABORT); |
| 285 | } |
| 286 | |
| 287 | |
| 288 | |
| 289 | VideoCaptureAndroid::VideoCaptureAndroid(const WebRtc_Word32 id) |
| 290 | : VideoCaptureImpl(id), _capInfo(id), _javaCaptureObj(NULL), |
| 291 | _captureStarted(false) { |
| 292 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 293 | "%s: context %x", __FUNCTION__, (int) this); |
| 294 | } |
| 295 | |
| 296 | // ---------------------------------------------------------------------------- |
| 297 | // Init |
| 298 | // |
| 299 | // Initializes needed Java resources like the JNI interface to |
| 300 | // VideoCaptureAndroid.java |
| 301 | // ---------------------------------------------------------------------------- |
| 302 | WebRtc_Word32 VideoCaptureAndroid::Init(const WebRtc_Word32 id, |
| 303 | const char* deviceUniqueIdUTF8) { |
| 304 | const int nameLength = strlen(deviceUniqueIdUTF8); |
| 305 | if (nameLength >= kVideoCaptureUniqueNameLength) { |
| 306 | return -1; |
| 307 | } |
| 308 | |
| 309 | // Store the device name |
| 310 | _deviceUniqueId = new char[nameLength + 1]; |
| 311 | memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1); |
| 312 | |
| 313 | if (_capInfo.Init() != 0) { |
| 314 | WEBRTC_TRACE(webrtc::kTraceError, |
| 315 | webrtc::kTraceVideoCapture, |
| 316 | _id, |
| 317 | "%s: Failed to initialize CaptureDeviceInfo", |
| 318 | __FUNCTION__); |
| 319 | return -1; |
| 320 | } |
| 321 | |
| 322 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, "%s:", |
| 323 | __FUNCTION__); |
| 324 | // use the jvm that has been set |
| 325 | if (!g_jvm) { |
| 326 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| 327 | "%s: Not a valid Java VM pointer", __FUNCTION__); |
| 328 | return -1; |
| 329 | } |
| 330 | // get the JNI env for this thread |
| 331 | JNIEnv *env; |
| 332 | bool isAttached = false; |
| 333 | |
| 334 | // get the JNI env for this thread |
| 335 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 336 | // try to attach the thread and get the env |
| 337 | // Attach this thread to JVM |
| 338 | jint res = g_jvm->AttachCurrentThread(&env, NULL); |
| 339 | if ((res < 0) || !env) { |
| 340 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| 341 | "%s: Could not attach thread to JVM (%d, %p)", |
| 342 | __FUNCTION__, res, env); |
| 343 | return -1; |
| 344 | } |
| 345 | isAttached = true; |
| 346 | } |
| 347 | |
| 348 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id, |
| 349 | "get method id"); |
| 350 | |
| 351 | // get the method ID for the Android Java |
| 352 | // CaptureDeviceInfoClass AllocateCamera factory method. |
| 353 | char signature[256]; |
| 354 | sprintf(signature, "(IJLjava/lang/String;)L%s;", AndroidJavaCaptureClass); |
| 355 | |
| 356 | jmethodID cid = env->GetMethodID(g_javaCmDevInfoClass, "AllocateCamera", |
| 357 | signature); |
| 358 | if (cid == NULL) { |
| 359 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| 360 | "%s: could not get constructor ID", __FUNCTION__); |
| 361 | return -1; /* exception thrown */ |
| 362 | } |
| 363 | |
| 364 | jstring capureIdString = env->NewStringUTF((char*) deviceUniqueIdUTF8); |
| 365 | // construct the object by calling the static constructor object |
| 366 | jobject javaCameraObjLocal = env->CallObjectMethod(g_javaCmDevInfoObject, |
| 367 | cid, (jint) id, |
| 368 | (jlong) this, |
| 369 | capureIdString); |
| 370 | if (!javaCameraObjLocal) { |
| 371 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceVideoCapture, _id, |
| 372 | "%s: could not create Java Capture object", __FUNCTION__); |
| 373 | return -1; |
| 374 | } |
| 375 | |
| 376 | // create a reference to the object (to tell JNI that we are referencing it |
| 377 | // after this function has returned) |
| 378 | _javaCaptureObj = env->NewGlobalRef(javaCameraObjLocal); |
| 379 | if (!_javaCaptureObj) { |
| 380 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioDevice, _id, |
| 381 | "%s: could not create Java camera object reference", |
| 382 | __FUNCTION__); |
| 383 | return -1; |
| 384 | } |
| 385 | |
| 386 | // Delete local object ref, we only use the global ref |
| 387 | env->DeleteLocalRef(javaCameraObjLocal); |
| 388 | |
| 389 | // Detach this thread if it was attached |
| 390 | if (isAttached) { |
| 391 | if (g_jvm->DetachCurrentThread() < 0) { |
| 392 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioDevice, _id, |
| 393 | "%s: Could not detach thread from JVM", __FUNCTION__); |
| 394 | } |
| 395 | } |
| 396 | |
| 397 | return 0; |
| 398 | } |
| 399 | |
| 400 | VideoCaptureAndroid::~VideoCaptureAndroid() { |
| 401 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, "%s:", |
| 402 | __FUNCTION__); |
| 403 | if (_javaCaptureObj == NULL || g_jvm == NULL) { |
| 404 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 405 | "%s: Nothing to clean", __FUNCTION__); |
| 406 | } |
| 407 | else { |
| 408 | bool isAttached = false; |
| 409 | // get the JNI env for this thread |
| 410 | JNIEnv *env; |
| 411 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 412 | // try to attach the thread and get the env |
| 413 | // Attach this thread to JVM |
| 414 | jint res = g_jvm->AttachCurrentThread(&env, NULL); |
| 415 | if ((res < 0) || !env) { |
| 416 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, |
| 417 | _id, |
| 418 | "%s: Could not attach thread to JVM (%d, %p)", |
| 419 | __FUNCTION__, res, env); |
| 420 | } |
| 421 | else { |
| 422 | isAttached = true; |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | // get the method ID for the Android Java CaptureClass static |
| 427 | // DeleteVideoCaptureAndroid method. Call this to release the camera so |
| 428 | // another application can use it. |
| 429 | jmethodID cid = env->GetStaticMethodID( |
| 430 | g_javaCmClass, |
| 431 | "DeleteVideoCaptureAndroid", |
| 432 | "(Lorg/webrtc/videoengine/VideoCaptureAndroid;)V"); |
| 433 | if (cid != NULL) { |
| 434 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 435 | "%s: Call DeleteVideoCaptureAndroid", __FUNCTION__); |
| 436 | // Close the camera by calling the static destruct function. |
| 437 | env->CallStaticVoidMethod(g_javaCmClass, cid, _javaCaptureObj); |
| 438 | |
| 439 | // Delete global object ref to the camera. |
| 440 | env->DeleteGlobalRef(_javaCaptureObj); |
| 441 | _javaCaptureObj = NULL; |
| 442 | } |
| 443 | else { |
| 444 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 445 | "%s: Failed to find DeleteVideoCaptureAndroid id", |
| 446 | __FUNCTION__); |
| 447 | } |
| 448 | |
| 449 | // Detach this thread if it was attached |
| 450 | if (isAttached) { |
| 451 | if (g_jvm->DetachCurrentThread() < 0) { |
| 452 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioDevice, |
| 453 | _id, "%s: Could not detach thread from JVM", |
| 454 | __FUNCTION__); |
| 455 | } |
| 456 | } |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | WebRtc_Word32 VideoCaptureAndroid::StartCapture( |
| 461 | const VideoCaptureCapability& capability) { |
| 462 | CriticalSectionScoped cs(&_apiCs); |
| 463 | WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCapture, -1, |
| 464 | "%s: ", __FUNCTION__); |
| 465 | |
| 466 | bool isAttached = false; |
| 467 | WebRtc_Word32 result = 0; |
| 468 | // get the JNI env for this thread |
| 469 | JNIEnv *env; |
| 470 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 471 | // try to attach the thread and get the env |
| 472 | // Attach this thread to JVM |
| 473 | jint res = g_jvm->AttachCurrentThread(&env, NULL); |
| 474 | if ((res < 0) || !env) { |
| 475 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| 476 | "%s: Could not attach thread to JVM (%d, %p)", |
| 477 | __FUNCTION__, res, env); |
| 478 | } |
| 479 | else { |
| 480 | isAttached = true; |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | if (_capInfo.GetBestMatchedCapability(_deviceUniqueId, capability, |
| 485 | _frameInfo) < 0) { |
| 486 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 487 | "%s: GetBestMatchedCapability failed. Req cap w%d h%d", |
| 488 | __FUNCTION__, capability.width, capability.height); |
| 489 | return -1; |
| 490 | } |
| 491 | |
| 492 | // Store the new expected capture delay |
| 493 | _captureDelay = _frameInfo.expectedCaptureDelay; |
| 494 | |
| 495 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 496 | "%s: _frameInfo w%d h%d", __FUNCTION__, _frameInfo.width, |
| 497 | _frameInfo.height); |
| 498 | |
| 499 | // get the method ID for the Android Java |
| 500 | // CaptureClass static StartCapture method. |
| 501 | jmethodID cid = env->GetMethodID(g_javaCmClass, "StartCapture", "(III)I"); |
| 502 | if (cid != NULL) { |
| 503 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 504 | "%s: Call StartCapture", __FUNCTION__); |
| 505 | // Close the camera by calling the static destruct function. |
| 506 | result = env->CallIntMethod(_javaCaptureObj, cid, _frameInfo.width, |
| 507 | _frameInfo.height, _frameInfo.maxFPS); |
| 508 | } |
| 509 | else { |
| 510 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 511 | "%s: Failed to find StartCapture id", __FUNCTION__); |
| 512 | } |
| 513 | |
| 514 | // Detach this thread if it was attached |
| 515 | if (isAttached) { |
| 516 | if (g_jvm->DetachCurrentThread() < 0) { |
| 517 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioDevice, _id, |
| 518 | "%s: Could not detach thread from JVM", __FUNCTION__); |
| 519 | } |
| 520 | } |
| 521 | if (result == 0) { |
| 522 | _requestedCapability = capability; |
| 523 | _captureStarted = true; |
| 524 | } |
| 525 | WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCapture, -1, |
| 526 | "%s: result %d", __FUNCTION__, result); |
| 527 | return result; |
| 528 | } |
| 529 | |
| 530 | WebRtc_Word32 VideoCaptureAndroid::StopCapture() { |
| 531 | CriticalSectionScoped cs(&_apiCs); |
| 532 | WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCapture, -1, |
| 533 | "%s: ", __FUNCTION__); |
| 534 | |
| 535 | bool isAttached = false; |
| 536 | WebRtc_Word32 result = 0; |
| 537 | // get the JNI env for this thread |
| 538 | JNIEnv *env = NULL; |
| 539 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 540 | // try to attach the thread and get the env |
| 541 | // Attach this thread to JVM |
| 542 | jint res = g_jvm->AttachCurrentThread(&env, NULL); |
| 543 | if ((res < 0) || !env) { |
| 544 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, _id, |
| 545 | "%s: Could not attach thread to JVM (%d, %p)", |
| 546 | __FUNCTION__, res, env); |
| 547 | } |
| 548 | else { |
| 549 | isAttached = true; |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | memset(&_requestedCapability, 0, sizeof(_requestedCapability)); |
| 554 | memset(&_frameInfo, 0, sizeof(_frameInfo)); |
| 555 | |
| 556 | // get the method ID for the Android Java CaptureClass StopCapture method. |
| 557 | jmethodID cid = env->GetMethodID(g_javaCmClass, "StopCapture", "()I"); |
| 558 | if (cid != NULL) { |
| 559 | WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, -1, |
| 560 | "%s: Call StopCapture", __FUNCTION__); |
| 561 | // Close the camera by calling the static destruct function. |
| 562 | result = env->CallIntMethod(_javaCaptureObj, cid); |
| 563 | } |
| 564 | else { |
| 565 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 566 | "%s: Failed to find StopCapture id", __FUNCTION__); |
| 567 | } |
| 568 | |
| 569 | // Detach this thread if it was attached |
| 570 | if (isAttached) { |
| 571 | if (g_jvm->DetachCurrentThread() < 0) { |
| 572 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioDevice, _id, |
| 573 | "%s: Could not detach thread from JVM", __FUNCTION__); |
| 574 | } |
| 575 | } |
| 576 | _captureStarted = false; |
| 577 | |
| 578 | WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCapture, -1, |
| 579 | "%s: result %d", __FUNCTION__, result); |
| 580 | return result; |
| 581 | } |
| 582 | |
| 583 | bool VideoCaptureAndroid::CaptureStarted() { |
| 584 | CriticalSectionScoped cs(&_apiCs); |
| 585 | WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCapture, -1, |
| 586 | "%s: ", __FUNCTION__); |
| 587 | return _captureStarted; |
| 588 | } |
| 589 | |
| 590 | WebRtc_Word32 VideoCaptureAndroid::CaptureSettings( |
| 591 | VideoCaptureCapability& settings) { |
| 592 | CriticalSectionScoped cs(&_apiCs); |
| 593 | WEBRTC_TRACE(webrtc::kTraceStateInfo, webrtc::kTraceVideoCapture, -1, |
| 594 | "%s: ", __FUNCTION__); |
| 595 | settings = _requestedCapability; |
| 596 | return 0; |
| 597 | } |
| 598 | |
| 599 | WebRtc_Word32 VideoCaptureAndroid::SetCaptureRotation( |
| 600 | VideoCaptureRotation rotation) { |
| 601 | CriticalSectionScoped cs(&_apiCs); |
| 602 | if (VideoCaptureImpl::SetCaptureRotation(rotation) == 0) { |
| 603 | if (!g_jvm) |
| 604 | return -1; |
| 605 | |
| 606 | // get the JNI env for this thread |
| 607 | JNIEnv *env; |
| 608 | bool isAttached = false; |
| 609 | |
| 610 | // get the JNI env for this thread |
| 611 | if (g_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { |
| 612 | // try to attach the thread and get the env |
| 613 | // Attach this thread to JVM |
| 614 | jint res = g_jvm->AttachCurrentThread(&env, NULL); |
| 615 | if ((res < 0) || !env) { |
| 616 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, |
| 617 | _id, |
| 618 | "%s: Could not attach thread to JVM (%d, %p)", |
| 619 | __FUNCTION__, res, env); |
| 620 | return -1; |
| 621 | } |
| 622 | isAttached = true; |
| 623 | } |
| 624 | |
| 625 | jmethodID cid = env->GetMethodID(g_javaCmClass, "SetPreviewRotation", |
| 626 | "(I)V"); |
| 627 | if (cid == NULL) { |
| 628 | WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, |
| 629 | "%s: could not get java SetPreviewRotation ID", |
| 630 | __FUNCTION__); |
| 631 | return -1; |
| 632 | } |
| 633 | jint rotateFrame = 0; |
| 634 | switch (rotation) { |
| 635 | case kCameraRotate0: |
| 636 | rotateFrame = 0; |
| 637 | break; |
| 638 | case kCameraRotate90: |
| 639 | rotateFrame = 90; |
| 640 | break; |
| 641 | case kCameraRotate180: |
| 642 | rotateFrame = 180; |
| 643 | break; |
| 644 | case kCameraRotate270: |
| 645 | rotateFrame = 270; |
| 646 | break; |
| 647 | } |
| 648 | env->CallVoidMethod(_javaCaptureObj, cid, rotateFrame); |
| 649 | |
| 650 | // Detach this thread if it was attached |
| 651 | if (isAttached) { |
| 652 | if (g_jvm->DetachCurrentThread() < 0) { |
| 653 | WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioDevice, |
| 654 | _id, "%s: Could not detach thread from JVM", |
| 655 | __FUNCTION__); |
| 656 | } |
| 657 | } |
| 658 | |
| 659 | } |
| 660 | return 0; |
| 661 | } |
| 662 | |
| 663 | } // namespace videocapturemodule |
| 664 | } // namespace webrtc |