2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/video_capture/android/video_capture_android.h"
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"
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.
28 // Called by Java to get the global application context.
29 jobject JNICALL GetContext(JNIEnv* env, jclass) {
34 // Called by Java when the camera has a new frame to deliver.
35 void JNICALL ProvideCameraFrame(
38 jbyteArray javaCameraFrame,
42 webrtc::videocapturemodule::VideoCaptureAndroid* captureModule =
43 reinterpret_cast<webrtc::videocapturemodule::VideoCaptureAndroid*>(
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);
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*>(
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.
66 captureModule->VideoCaptureImpl::SetCaptureRotation(rotation);
71 int32_t SetCaptureAndroidVM(JavaVM* javaVM, jobject context) {
75 AttachThreadScoped ats(g_jvm);
76 g_context = ats.env()->NewGlobalRef(context);
78 videocapturemodule::DeviceInfoAndroid::Initialize(ats.env());
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);
87 JNINativeMethod native_methods[] = {
89 "()Landroid/content/Context;",
90 reinterpret_cast<void*>(&GetContext)},
91 {"OnOrientationChanged",
93 reinterpret_cast<void*>(&OnOrientationChanged)},
94 {"ProvideCameraFrame",
96 reinterpret_cast<void*>(&ProvideCameraFrame)}};
97 if (ats.env()->RegisterNatives(g_java_capturer_class,
98 native_methods, 3) != 0)
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);
108 videocapturemodule::DeviceInfoAndroid::DeInitialize();
116 namespace videocapturemodule {
118 VideoCaptureModule* VideoCaptureImpl::Create(
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;
127 return implementation;
130 int32_t VideoCaptureAndroid::OnIncomingFrame(uint8_t* videoFrame,
131 int32_t videoFrameLength,
132 int64_t captureTime) {
133 if (!_captureStarted)
135 return IncomingFrame(
136 videoFrame, videoFrameLength, _captureCapability, captureTime);
139 VideoCaptureAndroid::VideoCaptureAndroid(const int32_t id)
140 : VideoCaptureImpl(id),
143 _captureStarted(false) {
146 int32_t VideoCaptureAndroid::Init(const int32_t id,
147 const char* deviceUniqueIdUTF8) {
148 const int nameLength = strlen(deviceUniqueIdUTF8);
149 if (nameLength >= kVideoCaptureUniqueNameLength)
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))
157 _deviceUniqueId = new char[nameLength + 1];
158 memcpy(_deviceUniqueId, deviceUniqueIdUTF8, nameLength + 1);
160 AttachThreadScoped ats(g_jvm);
161 JNIEnv* env = ats.env();
162 jmethodID ctor = env->GetMethodID(g_java_capturer_class, "<init>", "(IJ)V");
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));
171 VideoCaptureAndroid::~VideoCaptureAndroid() {
172 // Ensure Java camera is released even if our caller didn't explicitly Stop.
175 AttachThreadScoped ats(g_jvm);
176 ats.env()->DeleteGlobalRef(_jCapturer);
179 int32_t VideoCaptureAndroid::StartCapture(
180 const VideoCaptureCapability& capability) {
181 CriticalSectionScoped cs(&_apiCs);
182 AttachThreadScoped ats(g_jvm);
183 JNIEnv* env = ats.env();
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);
193 _captureDelay = _captureCapability.expectedCaptureDelay;
196 env->GetMethodID(g_java_capturer_class, "startCapture", "(IIII)Z");
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,
207 _requestedCapability = capability;
208 _captureStarted = true;
210 return started ? 0 : -1;
213 int32_t VideoCaptureAndroid::StopCapture() {
215 AttachThreadScoped ats(g_jvm);
216 JNIEnv* env = ats.env();
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.
226 env->GetMethodID(g_java_capturer_class, "stopCapture", "()Z");
227 return env->CallBooleanMethod(_jCapturer, j_stop) ? 0 : -1;
230 bool VideoCaptureAndroid::CaptureStarted() {
231 CriticalSectionScoped cs(&_apiCs);
232 return _captureStarted;
235 int32_t VideoCaptureAndroid::CaptureSettings(
236 VideoCaptureCapability& settings) {
237 CriticalSectionScoped cs(&_apiCs);
238 settings = _requestedCapability;
242 int32_t VideoCaptureAndroid::SetCaptureRotation(
243 VideoCaptureRotation rotation) {
244 int32_t status = VideoCaptureImpl::SetCaptureRotation(rotation);
248 AttachThreadScoped ats(g_jvm);
249 JNIEnv* env = ats.env();
252 env->GetMethodID(g_java_capturer_class, "setPreviewRotation", "(I)V");
254 int rotation_degrees;
255 if (RotationInDegrees(rotation, &rotation_degrees) != 0) {
258 env->CallVoidMethod(_jCapturer, j_spr, rotation_degrees);
262 } // namespace videocapturemodule
263 } // namespace webrtc