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.
5 #include "media/video/capture/android/video_capture_device_android.h"
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"
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;
28 void VideoCaptureDevice::GetDeviceNames(Names* device_names) {
29 device_names->clear();
31 JNIEnv* env = AttachCurrentThread();
33 int num_cameras = Java_ChromiumCameraInfo_getNumberOfCameras(env);
34 DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: num_cameras=" << num_cameras;
38 for (int camera_id = num_cameras - 1; camera_id >= 0; --camera_id) {
39 ScopedJavaLocalRef<jobject> ci =
40 Java_ChromiumCameraInfo_getAt(env, camera_id);
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);
48 DVLOG(1) << "VideoCaptureDevice::GetDeviceNames: camera device_name="
53 << Java_ChromiumCameraInfo_getOrientation(env, ci.obj());
58 void VideoCaptureDevice::GetDeviceSupportedFormats(const Name& device,
59 VideoCaptureFormats* capture_formats) {
61 if (!base::StringToInt(device.id(), &id))
63 JNIEnv* env = AttachCurrentThread();
64 base::android::ScopedJavaLocalRef<jobjectArray> collected_formats =
65 Java_VideoCapture_getDeviceSupportedFormats(env, id);
66 if (collected_formats.is_null())
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));
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;
79 case VideoCaptureDeviceAndroid::ANDROID_IMAGEFORMAT_NV21:
80 pixel_format = media::PIXEL_FORMAT_NV21;
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()),
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;
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.
106 VideoCaptureDevice* VideoCaptureDevice::Create(const Name& device_name) {
107 return VideoCaptureDeviceAndroid::Create(device_name);
111 VideoCaptureDevice* VideoCaptureDeviceAndroid::Create(const Name& device_name) {
112 scoped_ptr<VideoCaptureDeviceAndroid> ret(
113 new VideoCaptureDeviceAndroid(device_name));
115 return ret.release();
120 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) {
121 return RegisterNativesImpl(env);
124 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name)
125 : state_(kIdle), got_first_frame_(false), device_name_(device_name) {}
127 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
131 bool VideoCaptureDeviceAndroid::Init() {
133 if (!base::StringToInt(device_name_.id(), &id))
136 JNIEnv* env = AttachCurrentThread();
138 j_capture_.Reset(Java_VideoCapture_createVideoCapture(
139 env, base::android::GetApplicationContext(), id,
140 reinterpret_cast<intptr_t>(this)));
145 void VideoCaptureDeviceAndroid::AllocateAndStart(
146 const VideoCaptureParams& params,
147 scoped_ptr<Client> client) {
148 DVLOG(1) << "VideoCaptureDeviceAndroid::AllocateAndStart";
150 base::AutoLock lock(lock_);
153 client_ = client.Pass();
154 got_first_frame_ = false;
157 JNIEnv* env = AttachCurrentThread();
160 Java_VideoCapture_allocate(env,
162 params.requested_format.frame_size.width(),
163 params.requested_format.frame_size.height(),
164 params.requested_format.frame_rate);
166 SetErrorState("failed to allocate");
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));
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);
188 DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size="
189 << capture_format_.frame_size.ToString()
190 << ", frame_rate=" << capture_format_.frame_rate;
192 jint result = Java_VideoCapture_startCapture(env, j_capture_.obj());
194 SetErrorState("failed to start capture");
199 base::AutoLock lock(lock_);
204 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
205 DVLOG(1) << "VideoCaptureDeviceAndroid::StopAndDeAllocate";
207 base::AutoLock lock(lock_);
208 if (state_ != kCapturing && state_ != kError)
212 JNIEnv* env = AttachCurrentThread();
214 jint ret = Java_VideoCapture_stopCapture(env, j_capture_.obj());
216 SetErrorState("failed to stop capture");
221 base::AutoLock lock(lock_);
226 Java_VideoCapture_deallocate(env, j_capture_.obj());
229 void VideoCaptureDeviceAndroid::OnFrameAvailable(
235 TRACE_EVENT0("video", "VideoCaptureDeviceAndroid::OnFrameAvailable");
236 DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length;
238 base::AutoLock lock(lock_);
239 if (state_ != kCapturing || !client_.get())
242 jbyte* buffer = env->GetByteArrayElements(data, NULL);
244 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
245 "failed to GetByteArrayElements";
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;
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_;
260 client_->OnIncomingCapturedFrame(reinterpret_cast<uint8*>(buffer),
262 base::TimeTicks::Now(),
267 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT);
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:
281 return media::PIXEL_FORMAT_UNKNOWN;
285 void VideoCaptureDeviceAndroid::SetErrorState(const std::string& reason) {
286 LOG(ERROR) << "VideoCaptureDeviceAndroid::SetErrorState: " << reason;
288 base::AutoLock lock(lock_);
291 client_->OnError(reason);