Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / video / capture / android / video_capture_device_android.cc
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/video/capture/android/video_capture_device_android.h"
6
7 #include <string>
8
9 #include "base/android/jni_android.h"
10 #include "base/android/jni_string.h"
11 #include "base/android/scoped_java_ref.h"
12 #include "base/debug/trace_event.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/stringprintf.h"
15 #include "jni/VideoCapture_jni.h"
16 #include "media/base/video_util.h"
17
18 using base::android::AttachCurrentThread;
19 using base::android::CheckException;
20 using base::android::GetClass;
21 using base::android::MethodID;
22 using base::android::JavaRef;
23 using base::android::ScopedJavaLocalRef;
24
25 namespace media {
26
27 // static
28 void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
29   device_names->clear();
30
31   JNIEnv* env = AttachCurrentThread();
32
33   int num_cameras = Java_ChromiumCameraInfo_getNumberOfCameras(env);
34   DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: num_cameras=" << num_cameras;
35   if (num_cameras <= 0)
36     return;
37
38   for (int camera_id = num_cameras - 1; camera_id >= 0; --camera_id) {
39     ScopedJavaLocalRef<jobject> ci =
40         Java_ChromiumCameraInfo_getAt(env, camera_id);
41
42     Name name(
43         base::android::ConvertJavaStringToUTF8(
44             Java_ChromiumCameraInfo_getDeviceName(env, ci.obj())),
45         base::StringPrintf("%d", Java_ChromiumCameraInfo_getId(env, ci.obj())));
46     device_names->push_back(name);
47
48     DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: camera device_name="
49              << name.name()
50              << ", unique_id="
51              << name.id()
52              << ", orientation "
53              << Java_ChromiumCameraInfo_getOrientation(env, ci.obj());
54   }
55 }
56
57 // static
58 void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device,
59     VideoCaptureFormats* capture_formats) {
60   int id;
61   if (!base::StringToInt(device.id(), &id))
62     return;
63   JNIEnv* env = AttachCurrentThread();
64   base::android::ScopedJavaLocalRef<jobjectArray> collected_formats =
65       Java_VideoCapture_getDeviceSupportedFormats(env, id);
66   if (collected_formats.is_null())
67     return;
68
69   jsize num_formats = env->GetArrayLength(collected_formats.obj());
70   for (int i = 0; i < num_formats; ++i) {
71     base::android::ScopedJavaLocalRef<jobject> format(
72         env, env->GetObjectArrayElement(collected_formats.obj(), i));
73
74     VideoPixelFormat pixel_format = media::PIXEL_FORMAT_UNKNOWN;
75     switch (media::Java_CaptureFormat_getPixelFormat(env, format.obj())) {
76       case VideoCaptureDeviceAndroid::ANDROID_IMAGEFORMAT_YV12:
77         pixel_format = media::PIXEL_FORMAT_YV12;
78         break;
79       case VideoCaptureDeviceAndroid::ANDROID_IMAGEFORMAT_NV21:
80         pixel_format = media::PIXEL_FORMAT_NV21;
81         break;
82       default:
83         break;
84     }
85     VideoCaptureFormat capture_format(
86         gfx::Size(media::Java_CaptureFormat_getWidth(env, format.obj()),
87                   media::Java_CaptureFormat_getHeight(env, format.obj())),
88         media::Java_CaptureFormat_getFramerate(env, format.obj()),
89         pixel_format);
90     capture_formats->push_back(capture_format);
91     DVLOG(1) << device.name() << " resolution: "
92         << capture_format.frame_size.ToString() << ", fps: "
93         << capture_format.frame_rate << ", pixel format: "
94         << capture_format.pixel_format;
95   }
96 }
97
98 const std::string VideoCaptureDevice::Name::GetModel() const {
99   // Android cameras are not typically USB devices, and this method is currently
100   // only used for USB model identifiers, so this implementation just indicates
101   // an unknown device model.
102   return "";
103 }
104
105 // static
106 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
107   return VideoCaptureDeviceAndroid::Create(device_name);
108 }
109
110 // static
111 VideoCaptureDevice* VideoCaptureDeviceAndroid::Create(const Name& device_name) {
112   scoped_ptr<VideoCaptureDeviceAndroid> ret(
113       new VideoCaptureDeviceAndroid(device_name));
114   if (ret->Init())
115     return ret.release();
116   return NULL;
117 }
118
119 // static
120 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) {
121   return RegisterNativesImpl(env);
122 }
123
124 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name)
125     : state_(kIdle), got_first_frame_(false), device_name_(device_name) {}
126
127 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
128   StopAndDeAllocate();
129 }
130
131 bool VideoCaptureDeviceAndroid::Init() {
132   int id;
133   if (!base::StringToInt(device_name_.id(), &id))
134     return false;
135
136   JNIEnv* env = AttachCurrentThread();
137
138   j_capture_.Reset(Java_VideoCapture_createVideoCapture(
139       env, base::android::GetApplicationContext(), id,
140       reinterpret_cast<intptr_t>(this)));
141
142   return true;
143 }
144
145 void VideoCaptureDeviceAndroid::AllocateAndStart(
146     const VideoCaptureParams& params,
147     scoped_ptr<Client> client) {
148   DVLOG(1) << "VideoCaptureDeviceAndroid::AllocateAndStart";
149   {
150     base::AutoLock lock(lock_);
151     if (state_ != kIdle)
152       return;
153     client_ = client.Pass();
154     got_first_frame_ = false;
155   }
156
157   JNIEnv* env = AttachCurrentThread();
158
159   jboolean ret =
160       Java_VideoCapture_allocate(env,
161                                  j_capture_.obj(),
162                                  params.requested_format.frame_size.width(),
163                                  params.requested_format.frame_size.height(),
164                                  params.requested_format.frame_rate);
165   if (!ret) {
166     SetErrorState("failed to allocate");
167     return;
168   }
169
170   // Store current width and height.
171   capture_format_.frame_size.SetSize(
172       Java_VideoCapture_queryWidth(env, j_capture_.obj()),
173       Java_VideoCapture_queryHeight(env, j_capture_.obj()));
174   capture_format_.frame_rate =
175       Java_VideoCapture_queryFrameRate(env, j_capture_.obj());
176   capture_format_.pixel_format = GetColorspace();
177   DCHECK_NE(capture_format_.pixel_format, media::PIXEL_FORMAT_UNKNOWN);
178   CHECK(capture_format_.frame_size.GetArea() > 0);
179   CHECK(!(capture_format_.frame_size.width() % 2));
180   CHECK(!(capture_format_.frame_size.height() % 2));
181
182   if (capture_format_.frame_rate > 0) {
183     frame_interval_ = base::TimeDelta::FromMicroseconds(
184         (base::Time::kMicrosecondsPerSecond + capture_format_.frame_rate - 1) /
185         capture_format_.frame_rate);
186   }
187
188   DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size="
189            << capture_format_.frame_size.ToString()
190            << ", frame_rate=" << capture_format_.frame_rate;
191
192   jint result = Java_VideoCapture_startCapture(env, j_capture_.obj());
193   if (result < 0) {
194     SetErrorState("failed to start capture");
195     return;
196   }
197
198   {
199     base::AutoLock lock(lock_);
200     state_ = kCapturing;
201   }
202 }
203
204 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
205   DVLOG(1) << "VideoCaptureDeviceAndroid::StopAndDeAllocate";
206   {
207     base::AutoLock lock(lock_);
208     if (state_ != kCapturing && state_ != kError)
209       return;
210   }
211
212   JNIEnv* env = AttachCurrentThread();
213
214   jint ret = Java_VideoCapture_stopCapture(env, j_capture_.obj());
215   if (ret < 0) {
216     SetErrorState("failed to stop capture");
217     return;
218   }
219
220   {
221     base::AutoLock lock(lock_);
222     state_ = kIdle;
223     client_.reset();
224   }
225
226   Java_VideoCapture_deallocate(env, j_capture_.obj());
227 }
228
229 void VideoCaptureDeviceAndroid::OnFrameAvailable(
230     JNIEnv* env,
231     jobject obj,
232     jbyteArray data,
233     jint length,
234     jint rotation) {
235   TRACE_EVENT0("video", "VideoCaptureDeviceAndroid::OnFrameAvailable");
236   DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length;
237
238   base::AutoLock lock(lock_);
239   if (state_ != kCapturing || !client_.get())
240     return;
241
242   jbyte* buffer = env->GetByteArrayElements(data, NULL);
243   if (!buffer) {
244     LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
245                   "failed to GetByteArrayElements";
246     return;
247   }
248
249   base::TimeTicks current_time = base::TimeTicks::Now();
250   if (!got_first_frame_) {
251     // Set aside one frame allowance for fluctuation.
252     expected_next_frame_time_ = current_time - frame_interval_;
253     got_first_frame_ = true;
254   }
255
256   // Deliver the frame when it doesn't arrive too early.
257   if (expected_next_frame_time_ <= current_time) {
258     expected_next_frame_time_ += frame_interval_;
259
260     client_->OnIncomingCapturedFrame(reinterpret_cast<uint8*>(buffer),
261                                      length,
262                                      base::TimeTicks::Now(),
263                                      rotation,
264                                      capture_format_);
265   }
266
267   env->ReleaseByteArrayElements(data, buffer, JNI_ABORT);
268 }
269
270 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() {
271   JNIEnv* env = AttachCurrentThread();
272   int current_capture_colorspace =
273       Java_VideoCapture_getColorspace(env, j_capture_.obj());
274   switch (current_capture_colorspace) {
275     case ANDROID_IMAGEFORMAT_YV12:
276       return media::PIXEL_FORMAT_YV12;
277     case ANDROID_IMAGEFORMAT_NV21:
278       return media::PIXEL_FORMAT_NV21;
279     case ANDROID_IMAGEFORMAT_UNKNOWN:
280     default:
281       return media::PIXEL_FORMAT_UNKNOWN;
282   }
283 }
284
285 void VideoCaptureDeviceAndroid::SetErrorState(const std::string& reason) {
286   LOG(ERROR) << "VideoCaptureDeviceAndroid::SetErrorState: " << reason;
287   {
288     base::AutoLock lock(lock_);
289     state_ = kError;
290   }
291   client_->OnError(reason);
292 }
293
294 }  // namespace media