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 "webrtc/modules/video_capture/android/video_capture_android.h" 12 13 #include "webrtc/base/common.h" 14 #include "webrtc/modules/utility/interface/helpers_android.h" 15 #include "webrtc/modules/video_capture/android/device_info_android.h" 16 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" 17 #include "webrtc/system_wrappers/interface/logcat_trace_context.h" 18 #include "webrtc/system_wrappers/interface/ref_count.h" 19 #include "webrtc/system_wrappers/interface/trace.h" 20 21 static JavaVM* g_jvm = NULL; 22 static jclass g_java_capturer_class = NULL; // VideoCaptureAndroid.class. 23 static jobject g_context = NULL; // Owned android.content.Context. 24 25 namespace webrtc { 26 27 // Called by Java to get the global application context. 28 jobject JNICALL GetContext(JNIEnv* env, jclass) { 29 assert(g_context); 30 return g_context; 31 } 32 33 // Called by Java when the camera has a new frame to deliver. 34 void JNICALL ProvideCameraFrame( 35 JNIEnv* env, 36 jobject, 37 jbyteArray javaCameraFrame, 38 jint length, 39 jlong context) { 40 webrtc::videocapturemodule::VideoCaptureAndroid* captureModule = 41 reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>( 42 context); 43 jbyte* cameraFrame = env->GetByteArrayElements(javaCameraFrame, NULL); 44 captureModule->OnIncomingFrame( 45 reinterpret_cast<uint8_t*>(cameraFrame), length, 0); 46 env->ReleaseByteArrayElements(javaCameraFrame, cameraFrame, JNI_ABORT); 47 } 48 49 // Called by Java when the device orientation has changed. 50 void JNICALL OnOrientationChanged( 51 JNIEnv* env, jobject, jlong context, jint degrees) { 52 webrtc::videocapturemodule::VideoCaptureAndroid* captureModule = 53 reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>( 54 context); 55 degrees = (360 + degrees) % 360; 56 assert(degrees >= 0 && degrees < 360); 57 VideoCaptureRotation rotation = 58 (degrees <= 45 || degrees > 315) ? kCameraRotate0 : 59 (degrees > 45 && degrees <= 135) ? kCameraRotate90 : 60 (degrees > 135 && degrees <= 225) ? kCameraRotate180 : 61 (degrees > 225 && degrees <= 315) ? kCameraRotate270 : 62 kCameraRotate0; // Impossible. 63 int32_t status = 64 captureModule->VideoCaptureImpl::SetCaptureRotation(rotation); 65 RTC_UNUSED(status); 66 assert(status == 0); 67 } 68 69 int32_t SetCaptureAndroidVM(JavaVM* javaVM, jobject context) { 70 if (javaVM) { 71 assert(!g_jvm); 72 g_jvm = javaVM; 73 AttachThreadScoped ats(g_jvm); 74 g_context = ats.env()->NewGlobalRef(context); 75 76 videocapturemodule::DeviceInfoAndroid::Initialize(ats.env()); 77 78 jclass j_capture_class = 79 ats.env()->FindClass("org/webrtc/videoengine/VideoCaptureAndroid"); 80 assert(j_capture_class); 81 g_java_capturer_class = 82 reinterpret_cast<jclass>(ats.env()->NewGlobalRef(j_capture_class)); 83 assert(g_java_capturer_class); 84 85 JNINativeMethod native_methods[] = { 86 {"GetContext", 87 "()Landroid/content/Context;", 88 reinterpret_cast<void*>(&GetContext)}, 89 {"OnOrientationChanged", 90 "(JI)V", 91 reinterpret_cast<void*>(&OnOrientationChanged)}, 92 {"ProvideCameraFrame", 93 "([BIJ)V", 94 reinterpret_cast<void*>(&ProvideCameraFrame)}}; 95 if (ats.env()->RegisterNatives(g_java_capturer_class, 96 native_methods, 3) != 0) 97 assert(false); 98 } else { 99 if (g_jvm) { 100 AttachThreadScoped ats(g_jvm); 101 ats.env()->UnregisterNatives(g_java_capturer_class); 102 ats.env()->DeleteGlobalRef(g_java_capturer_class); 103 g_java_capturer_class = NULL; 104 ats.env()->DeleteGlobalRef(g_context); 105 g_context = NULL; 106 videocapturemodule::DeviceInfoAndroid::DeInitialize(); 107 g_jvm = NULL; 108 } 109 } 110 111 return 0; 112 } 113 114 namespace videocapturemodule { 115 116 VideoCaptureModule* VideoCaptureImpl::Create( 117 const int32_t id, 118 const char* deviceUniqueIdUTF8) { 119 RefCountImpl<videocapturemodule::VideoCaptureAndroid>* implementation = 120 new RefCountImpl<videocapturemodule::VideoCaptureAndroid>(id); 121 if (implementation->Init(id, deviceUniqueIdUTF8) != 0) { 122 delete implementation; 123 implementation = NULL; 124 } 125 return implementation; 126 } 127 128 int32_t VideoCaptureAndroid::OnIncomingFrame(uint8_t* videoFrame, 129 int32_t videoFrameLength, 130 int64_t captureTime) { 131 return IncomingFrame( 132 videoFrame, videoFrameLength, _captureCapability, captureTime); 133 } 134 135 VideoCaptureAndroid::VideoCaptureAndroid(const int32_t id) 136 : VideoCaptureImpl(id), 137 _deviceInfo(id), 138 _jCapturer(NULL), 139 _captureStarted(false) { 140 } 141 142 int32_t VideoCaptureAndroid::Init(const int32_t id, 143 const char* deviceUniqueIdUTF8) { 144 const int nameLength = strlen(deviceUniqueIdUTF8); 145 if (nameLength >= kVideoCaptureUniqueNameLength) 146 return -1; 147 148 // Store the device name 149 _deviceUniqueId = new char[nameLength + 1]; 150 memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1); 151 152 AttachThreadScoped ats(g_jvm); 153 JNIEnv* env = ats.env(); 154 155 jmethodID ctor = env->GetMethodID(g_java_capturer_class, "<init>", "(IJ)V"); 156 assert(ctor); 157 jlong j_this = reinterpret_cast<intptr_t>(this); 158 size_t camera_id = 0; 159 if (!_deviceInfo.FindCameraIndex(deviceUniqueIdUTF8, &camera_id)) 160 return -1; 161 _jCapturer = env->NewGlobalRef( 162 env->NewObject(g_java_capturer_class, ctor, camera_id, j_this)); 163 assert(_jCapturer); 164 return 0; 165 } 166 167 VideoCaptureAndroid::~VideoCaptureAndroid() { 168 // Ensure Java camera is released even if our caller didn't explicitly Stop. 169 if (_captureStarted) 170 StopCapture(); 171 AttachThreadScoped ats(g_jvm); 172 ats.env()->DeleteGlobalRef(_jCapturer); 173 } 174 175 int32_t VideoCaptureAndroid::StartCapture( 176 const VideoCaptureCapability& capability) { 177 CriticalSectionScoped cs(&_apiCs); 178 AttachThreadScoped ats(g_jvm); 179 JNIEnv* env = ats.env(); 180 181 if (_deviceInfo.GetBestMatchedCapability( 182 _deviceUniqueId, capability, _captureCapability) < 0) { 183 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, -1, 184 "%s: GetBestMatchedCapability failed: %dx%d", 185 __FUNCTION__, capability.width, capability.height); 186 return -1; 187 } 188 189 _captureDelay = _captureCapability.expectedCaptureDelay; 190 191 jmethodID j_start = 192 env->GetMethodID(g_java_capturer_class, "startCapture", "(IIII)Z"); 193 assert(j_start); 194 int min_mfps = 0; 195 int max_mfps = 0; 196 _deviceInfo.GetMFpsRange(_deviceUniqueId, _captureCapability.maxFPS, 197 &min_mfps, &max_mfps); 198 bool started = env->CallBooleanMethod(_jCapturer, j_start, 199 _captureCapability.width, 200 _captureCapability.height, 201 min_mfps, max_mfps); 202 if (started) { 203 _requestedCapability = capability; 204 _captureStarted = true; 205 } 206 return started ? 0 : -1; 207 } 208 209 int32_t VideoCaptureAndroid::StopCapture() { 210 CriticalSectionScoped cs(&_apiCs); 211 AttachThreadScoped ats(g_jvm); 212 JNIEnv* env = ats.env(); 213 214 memset(&_requestedCapability, 0, sizeof(_requestedCapability)); 215 memset(&_captureCapability, 0, sizeof(_captureCapability)); 216 _captureStarted = false; 217 218 jmethodID j_stop = 219 env->GetMethodID(g_java_capturer_class, "stopCapture", "()Z"); 220 return env->CallBooleanMethod(_jCapturer, j_stop) ? 0 : -1; 221 } 222 223 bool VideoCaptureAndroid::CaptureStarted() { 224 CriticalSectionScoped cs(&_apiCs); 225 return _captureStarted; 226 } 227 228 int32_t VideoCaptureAndroid::CaptureSettings( 229 VideoCaptureCapability& settings) { 230 CriticalSectionScoped cs(&_apiCs); 231 settings = _requestedCapability; 232 return 0; 233 } 234 235 int32_t VideoCaptureAndroid::SetCaptureRotation( 236 VideoCaptureRotation rotation) { 237 CriticalSectionScoped cs(&_apiCs); 238 int32_t status = VideoCaptureImpl::SetCaptureRotation(rotation); 239 if (status != 0) 240 return status; 241 242 AttachThreadScoped ats(g_jvm); 243 JNIEnv* env = ats.env(); 244 245 jmethodID j_spr = 246 env->GetMethodID(g_java_capturer_class, "setPreviewRotation", "(I)V"); 247 assert(j_spr); 248 int rotation_degrees; 249 if (RotationInDegrees(rotation, &rotation_degrees) != 0) { 250 assert(false); 251 } 252 env->CallVoidMethod(_jCapturer, j_spr, rotation_degrees); 253 return 0; 254 } 255 256 } // namespace videocapturemodule 257 } // namespace webrtc 258