Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / video_capture / android / video_capture_android.cc
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