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
, media::PIXEL_FORMAT_UNKNOWN
);
83 CHECK(capture_format_
.frame_size
.GetArea() > 0);
84 CHECK(!(capture_format_
.frame_size
.width() % 2));
85 CHECK(!(capture_format_
.frame_size
.height() % 2));
87 if (capture_format_
.frame_rate
> 0) {
88 frame_interval_
= base::TimeDelta::FromMicroseconds(
89 (base::Time::kMicrosecondsPerSecond
+ capture_format_
.frame_rate
- 1) /
90 capture_format_
.frame_rate
);
93 DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size="
94 << capture_format_
.frame_size
.ToString()
95 << ", frame_rate=" << capture_format_
.frame_rate
;
97 ret
= Java_VideoCapture_startCapture(env
, j_capture_
.obj());
99 SetErrorState("failed to start capture");
104 base::AutoLock
lock(lock_
);
109 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
110 DVLOG(1) << "VideoCaptureDeviceAndroid::StopAndDeAllocate";
112 base::AutoLock
lock(lock_
);
113 if (state_
!= kCapturing
&& state_
!= kError
)
117 JNIEnv
* env
= AttachCurrentThread();
119 jboolean ret
= Java_VideoCapture_stopCapture(env
, j_capture_
.obj());
121 SetErrorState("failed to stop capture");
126 base::AutoLock
lock(lock_
);
131 Java_VideoCapture_deallocate(env
, j_capture_
.obj());
134 void VideoCaptureDeviceAndroid::OnFrameAvailable(JNIEnv
* env
,
139 DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length
;
141 base::AutoLock
lock(lock_
);
142 if (state_
!= kCapturing
|| !client_
.get())
145 jbyte
* buffer
= env
->GetByteArrayElements(data
, NULL
);
147 LOG(ERROR
) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
148 "failed to GetByteArrayElements";
152 base::TimeTicks current_time
= base::TimeTicks::Now();
153 if (!got_first_frame_
) {
154 // Set aside one frame allowance for fluctuation.
155 expected_next_frame_time_
= current_time
- frame_interval_
;
156 got_first_frame_
= true;
159 // Deliver the frame when it doesn't arrive too early.
160 if (expected_next_frame_time_
<= current_time
) {
161 expected_next_frame_time_
+= frame_interval_
;
163 client_
->OnIncomingCapturedData(reinterpret_cast<uint8
*>(buffer
), length
,
164 capture_format_
, rotation
,
165 base::TimeTicks::Now());
168 env
->ReleaseByteArrayElements(data
, buffer
, JNI_ABORT
);
171 void VideoCaptureDeviceAndroid::OnError(JNIEnv
* env
,
174 SetErrorState(base::android::ConvertJavaStringToUTF8(env
, message
));
177 VideoPixelFormat
VideoCaptureDeviceAndroid::GetColorspace() {
178 JNIEnv
* env
= AttachCurrentThread();
179 const int current_capture_colorspace
=
180 Java_VideoCapture_getColorspace(env
, j_capture_
.obj());
181 switch (current_capture_colorspace
) {
182 case ANDROID_IMAGE_FORMAT_YV12
:
183 return media::PIXEL_FORMAT_YV12
;
184 case ANDROID_IMAGE_FORMAT_YUV_420_888
:
185 return media::PIXEL_FORMAT_I420
;
186 case ANDROID_IMAGE_FORMAT_NV21
:
187 return media::PIXEL_FORMAT_NV21
;
188 case ANDROID_IMAGE_FORMAT_UNKNOWN
:
190 return media::PIXEL_FORMAT_UNKNOWN
;
194 void VideoCaptureDeviceAndroid::SetErrorState(const std::string
& reason
) {
196 base::AutoLock
lock(lock_
);
199 client_
->OnError(reason
);