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