video_capture_android.cc (9094B)
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 "AndroidBridge.h" 14 #include "device_info_android.h" 15 #include "modules/utility/include/helpers_android.h" 16 #include "rtc_base/logging.h" 17 #include "rtc_base/ref_counted_object.h" 18 #include "rtc_base/time_utils.h" 19 20 static JavaVM* g_jvm_capture = NULL; 21 static jclass g_java_capturer_class = NULL; // VideoCaptureAndroid.class. 22 23 namespace webrtc { 24 25 jobject JniCommon_allocateNativeByteBuffer(JNIEnv* env, jclass, jint size) { 26 void* new_data = ::operator new(size); 27 jobject byte_buffer = env->NewDirectByteBuffer(new_data, size); 28 return byte_buffer; 29 } 30 31 void JniCommon_freeNativeByteBuffer(JNIEnv* env, jclass, jobject byte_buffer) { 32 void* data = env->GetDirectBufferAddress(byte_buffer); 33 ::operator delete(data); 34 } 35 36 // Called by Java when the camera has a new frame to deliver. 37 void JNICALL ProvideCameraFrame(JNIEnv* env, jobject, jint width, jint height, 38 jobject javaDataY, jint strideY, 39 jobject javaDataU, jint strideU, 40 jobject javaDataV, jint strideV, jint rotation, 41 jlong timeStamp, jlong context) { 42 if (!context) { 43 return; 44 } 45 46 webrtc::videocapturemodule::VideoCaptureAndroid* captureModule = 47 reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>( 48 context); 49 uint8_t* dataY = 50 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(javaDataY)); 51 uint8_t* dataU = 52 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(javaDataU)); 53 uint8_t* dataV = 54 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(javaDataV)); 55 56 webrtc::scoped_refptr<I420Buffer> i420Buffer = I420Buffer::Copy( 57 width, height, dataY, strideY, dataU, strideU, dataV, strideV); 58 59 captureModule->OnIncomingFrame(i420Buffer, rotation, timeStamp); 60 } 61 62 int32_t SetCaptureAndroidVM(JavaVM* javaVM) { 63 if (g_java_capturer_class) { 64 return 0; 65 } 66 67 if (javaVM) { 68 assert(!g_jvm_capture); 69 g_jvm_capture = javaVM; 70 AttachThreadScoped ats(g_jvm_capture); 71 72 videocapturemodule::DeviceInfoAndroid::Initialize(g_jvm_capture); 73 74 { 75 jclass clsRef = mozilla::jni::GetClassRef( 76 ats.env(), "org/webrtc/videoengine/VideoCaptureAndroid"); 77 g_java_capturer_class = 78 static_cast<jclass>(ats.env()->NewGlobalRef(clsRef)); 79 ats.env()->DeleteLocalRef(clsRef); 80 assert(g_java_capturer_class); 81 82 JNINativeMethod native_methods[] = { 83 {"ProvideCameraFrame", 84 "(IILjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;ILjava/nio/" 85 "ByteBuffer;IIJJ)V", 86 reinterpret_cast<void*>(&ProvideCameraFrame)}}; 87 if (ats.env()->RegisterNatives(g_java_capturer_class, native_methods, 88 1) != 0) 89 assert(false); 90 } 91 92 { 93 jclass clsRef = 94 mozilla::jni::GetClassRef(ats.env(), "org/webrtc/JniCommon"); 95 96 JNINativeMethod native_methods[] = { 97 {"nativeAllocateByteBuffer", "(I)Ljava/nio/ByteBuffer;", 98 reinterpret_cast<void*>(&JniCommon_allocateNativeByteBuffer)}, 99 {"nativeFreeByteBuffer", "(Ljava/nio/ByteBuffer;)V", 100 reinterpret_cast<void*>(&JniCommon_freeNativeByteBuffer)}}; 101 if (ats.env()->RegisterNatives(clsRef, native_methods, 2) != 0) 102 assert(false); 103 } 104 } else { 105 if (g_jvm_capture) { 106 AttachThreadScoped ats(g_jvm_capture); 107 ats.env()->UnregisterNatives(g_java_capturer_class); 108 ats.env()->DeleteGlobalRef(g_java_capturer_class); 109 g_java_capturer_class = NULL; 110 videocapturemodule::DeviceInfoAndroid::DeInitialize(); 111 g_jvm_capture = NULL; 112 } 113 } 114 115 return 0; 116 } 117 118 namespace videocapturemodule { 119 120 webrtc::scoped_refptr<VideoCaptureModule> VideoCaptureImpl::Create( 121 Clock* clock, const char* deviceUniqueIdUTF8) { 122 webrtc::scoped_refptr<VideoCaptureAndroid> implementation( 123 new webrtc::RefCountedObject<VideoCaptureAndroid>(clock)); 124 if (implementation->Init(deviceUniqueIdUTF8) != 0) { 125 implementation = nullptr; 126 } 127 return implementation; 128 } 129 130 void VideoCaptureAndroid::OnIncomingFrame( 131 webrtc::scoped_refptr<I420Buffer> buffer, int32_t degrees, 132 int64_t captureTime) { 133 MutexLock lock(&api_lock_); 134 135 VideoRotation rotation = 136 (degrees <= 45 || degrees > 315) ? kVideoRotation_0 137 : (degrees > 45 && degrees <= 135) ? kVideoRotation_90 138 : (degrees > 135 && degrees <= 225) ? kVideoRotation_180 139 : (degrees > 225 && degrees <= 315) ? kVideoRotation_270 140 : kVideoRotation_0; // Impossible. 141 142 // Historically, we have ignored captureTime. Why? 143 VideoFrame captureFrame(I420Buffer::Rotate(*buffer, rotation), 0, 144 webrtc::TimeMillis(), rotation); 145 146 DeliverCapturedFrame(captureFrame); 147 } 148 149 VideoCaptureAndroid::VideoCaptureAndroid(Clock* clock) 150 : VideoCaptureImpl(clock), 151 _deviceInfo(), 152 _jCapturer(NULL), 153 _captureStarted(false) {} 154 155 int32_t VideoCaptureAndroid::Init(const char* deviceUniqueIdUTF8) { 156 const int nameLength = strlen(deviceUniqueIdUTF8); 157 if (nameLength >= kVideoCaptureUniqueNameLength) return -1; 158 159 RTC_DCHECK_RUN_ON(&api_checker_); 160 // Store the device name 161 RTC_LOG(LS_INFO) << "VideoCaptureAndroid::Init: " << deviceUniqueIdUTF8; 162 _deviceUniqueId = new char[nameLength + 1]; 163 memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1); 164 165 AttachThreadScoped ats(g_jvm_capture); 166 JNIEnv* env = ats.env(); 167 jmethodID factory = 168 env->GetStaticMethodID(g_java_capturer_class, "create", 169 "(Ljava/lang/String;)" 170 "Lorg/webrtc/videoengine/VideoCaptureAndroid;"); 171 assert(factory); 172 jstring j_deviceName = env->NewStringUTF(_deviceUniqueId); 173 _jCapturer = env->NewGlobalRef(env->CallStaticObjectMethod( 174 g_java_capturer_class, factory, j_deviceName)); 175 assert(_jCapturer); 176 return 0; 177 } 178 179 VideoCaptureAndroid::~VideoCaptureAndroid() { 180 // Ensure Java camera is released even if our caller didn't explicitly Stop. 181 if (_captureStarted) StopCapture(); 182 AttachThreadScoped ats(g_jvm_capture); 183 JNIEnv* env = ats.env(); 184 env->DeleteGlobalRef(_jCapturer); 185 } 186 187 int32_t VideoCaptureAndroid::StartCapture( 188 const VideoCaptureCapability& capability) { 189 AttachThreadScoped ats(g_jvm_capture); 190 JNIEnv* env = ats.env(); 191 int width = 0; 192 int height = 0; 193 int min_mfps = 0; 194 int max_mfps = 0; 195 { 196 RTC_DCHECK_RUN_ON(&api_checker_); 197 MutexLock lock(&api_lock_); 198 199 if (_deviceInfo.GetBestMatchedCapability(_deviceUniqueId, capability, 200 _captureCapability) < 0) { 201 RTC_LOG(LS_ERROR) << __FUNCTION__ 202 << "s: GetBestMatchedCapability failed: " 203 << capability.width << "x" << capability.height; 204 return -1; 205 } 206 207 width = _captureCapability.width; 208 height = _captureCapability.height; 209 _deviceInfo.GetMFpsRange(_deviceUniqueId, _captureCapability.maxFPS, 210 &min_mfps, &max_mfps); 211 212 // Exit critical section to avoid blocking camera thread inside 213 // onIncomingFrame() call. 214 } 215 216 jmethodID j_start = 217 env->GetMethodID(g_java_capturer_class, "startCapture", "(IIIIJ)Z"); 218 assert(j_start); 219 jlong j_this = reinterpret_cast<intptr_t>(this); 220 bool started = env->CallBooleanMethod(_jCapturer, j_start, width, height, 221 min_mfps, max_mfps, j_this); 222 if (started) { 223 RTC_DCHECK_RUN_ON(&api_checker_); 224 MutexLock lock(&api_lock_); 225 _requestedCapability = capability; 226 _captureStarted = true; 227 } 228 return started ? 0 : -1; 229 } 230 231 int32_t VideoCaptureAndroid::StopCapture() { 232 AttachThreadScoped ats(g_jvm_capture); 233 JNIEnv* env = ats.env(); 234 { 235 RTC_DCHECK_RUN_ON(&api_checker_); 236 MutexLock lock(&api_lock_); 237 238 memset(&_requestedCapability, 0, sizeof(_requestedCapability)); 239 memset(&_captureCapability, 0, sizeof(_captureCapability)); 240 _captureStarted = false; 241 // Exit critical section to avoid blocking camera thread inside 242 // onIncomingFrame() call. 243 } 244 245 // try to stop the capturer. 246 jmethodID j_stop = 247 env->GetMethodID(g_java_capturer_class, "stopCapture", "()Z"); 248 return env->CallBooleanMethod(_jCapturer, j_stop) ? 0 : -1; 249 } 250 251 bool VideoCaptureAndroid::CaptureStarted() { 252 MutexLock lock(&api_lock_); 253 return _captureStarted; 254 } 255 256 int32_t VideoCaptureAndroid::CaptureSettings(VideoCaptureCapability& settings) { 257 RTC_DCHECK_RUN_ON(&api_checker_); 258 MutexLock lock(&api_lock_); 259 settings = _requestedCapability; 260 return 0; 261 } 262 263 } // namespace videocapturemodule 264 } // namespace webrtc