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/capture/video/android/video_capture_device_android.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "jni/VideoCapture_jni.h"
11 #include "media/capture/video/android/video_capture_device_factory_android.h"
13 using base::android::AttachCurrentThread
;
14 using base::android::CheckException
;
15 using base::android::GetClass
;
16 using base::android::MethodID
;
17 using base::android::JavaRef
;
18 using base::android::ScopedJavaLocalRef
;
23 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv
* env
) {
24 return RegisterNativesImpl(env
);
27 const std::string
VideoCaptureDevice::Name::GetModel() const {
28 // Android cameras are not typically USB devices, and this method is currently
29 // only used for USB model identifiers, so this implementation just indicates
30 // an unknown device model.
34 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name
& device_name
)
35 : state_(kIdle
), got_first_frame_(false), device_name_(device_name
) {
38 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
42 bool VideoCaptureDeviceAndroid::Init() {
44 if (!base::StringToInt(device_name_
.id(), &id
))
47 j_capture_
.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid(
48 id
, reinterpret_cast<intptr_t>(this)));
52 void VideoCaptureDeviceAndroid::AllocateAndStart(
53 const VideoCaptureParams
& params
,
54 scoped_ptr
<Client
> client
) {
55 DVLOG(1) << "VideoCaptureDeviceAndroid::AllocateAndStart";
57 base::AutoLock
lock(lock_
);
60 client_
= client
.Pass();
61 got_first_frame_
= false;
64 JNIEnv
* env
= AttachCurrentThread();
66 jboolean ret
= Java_VideoCapture_allocate(
67 env
, j_capture_
.obj(), params
.requested_format
.frame_size
.width(),
68 params
.requested_format
.frame_size
.height(),
69 params
.requested_format
.frame_rate
);
71 SetErrorState("failed to allocate");
75 // Store current width and height.
76 capture_format_
.frame_size
.SetSize(
77 Java_VideoCapture_queryWidth(env
, j_capture_
.obj()),
78 Java_VideoCapture_queryHeight(env
, j_capture_
.obj()));
79 capture_format_
.frame_rate
=
80 Java_VideoCapture_queryFrameRate(env
, j_capture_
.obj());
81 capture_format_
.pixel_format
= GetColorspace();
82 DCHECK_NE(capture_format_
.pixel_format
,
83 media::VIDEO_CAPTURE_PIXEL_FORMAT_UNKNOWN
);
84 CHECK(capture_format_
.frame_size
.GetArea() > 0);
85 CHECK(!(capture_format_
.frame_size
.width() % 2));
86 CHECK(!(capture_format_
.frame_size
.height() % 2));
88 if (capture_format_
.frame_rate
> 0) {
89 frame_interval_
= base::TimeDelta::FromMicroseconds(
90 (base::Time::kMicrosecondsPerSecond
+ capture_format_
.frame_rate
- 1) /
91 capture_format_
.frame_rate
);
94 DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size="
95 << capture_format_
.frame_size
.ToString()
96 << ", frame_rate=" << capture_format_
.frame_rate
;
98 ret
= Java_VideoCapture_startCapture(env
, j_capture_
.obj());
100 SetErrorState("failed to start capture");
105 base::AutoLock
lock(lock_
);
110 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
111 DVLOG(1) << "VideoCaptureDeviceAndroid::StopAndDeAllocate";
113 base::AutoLock
lock(lock_
);
114 if (state_
!= kCapturing
&& state_
!= kError
)
118 JNIEnv
* env
= AttachCurrentThread();
120 jboolean ret
= Java_VideoCapture_stopCapture(env
, j_capture_
.obj());
122 SetErrorState("failed to stop capture");
127 base::AutoLock
lock(lock_
);
132 Java_VideoCapture_deallocate(env
, j_capture_
.obj());
135 void VideoCaptureDeviceAndroid::OnFrameAvailable(JNIEnv
* env
,
140 DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length
;
142 base::AutoLock
lock(lock_
);
143 if (state_
!= kCapturing
|| !client_
.get())
146 jbyte
* buffer
= env
->GetByteArrayElements(data
, NULL
);
148 LOG(ERROR
) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
149 "failed to GetByteArrayElements";
153 base::TimeTicks current_time
= base::TimeTicks::Now();
154 if (!got_first_frame_
) {
155 // Set aside one frame allowance for fluctuation.
156 expected_next_frame_time_
= current_time
- frame_interval_
;
157 got_first_frame_
= true;
160 // Deliver the frame when it doesn't arrive too early.
161 if (expected_next_frame_time_
<= current_time
) {
162 expected_next_frame_time_
+= frame_interval_
;
164 client_
->OnIncomingCapturedData(reinterpret_cast<uint8
*>(buffer
), length
,
165 capture_format_
, rotation
,
166 base::TimeTicks::Now());
169 env
->ReleaseByteArrayElements(data
, buffer
, JNI_ABORT
);
172 void VideoCaptureDeviceAndroid::OnError(JNIEnv
* env
,
175 SetErrorState(base::android::ConvertJavaStringToUTF8(env
, message
));
178 VideoCapturePixelFormat
VideoCaptureDeviceAndroid::GetColorspace() {
179 JNIEnv
* env
= AttachCurrentThread();
180 int current_capture_colorspace
=
181 Java_VideoCapture_getColorspace(env
, j_capture_
.obj());
182 switch (current_capture_colorspace
) {
183 case ANDROID_IMAGE_FORMAT_YV12
:
184 return media::VIDEO_CAPTURE_PIXEL_FORMAT_YV12
;
185 case ANDROID_IMAGE_FORMAT_YUV_420_888
:
186 return media::VIDEO_CAPTURE_PIXEL_FORMAT_I420
;
187 case ANDROID_IMAGE_FORMAT_NV21
:
188 return media::VIDEO_CAPTURE_PIXEL_FORMAT_NV21
;
189 case ANDROID_IMAGE_FORMAT_UNKNOWN
:
191 return media::VIDEO_CAPTURE_PIXEL_FORMAT_UNKNOWN
;
195 void VideoCaptureDeviceAndroid::SetErrorState(const std::string
& reason
) {
197 base::AutoLock
lock(lock_
);
200 client_
->OnError(reason
);