Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / capture / video / android / video_capture_device_android.cc
blob69d8b056346d6535862aac7663527a25388f497f
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;
20 namespace media {
22 // static
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.
31 return "";
34 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name)
35 : state_(kIdle), got_first_frame_(false), device_name_(device_name) {
38 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
39 StopAndDeAllocate();
42 bool VideoCaptureDeviceAndroid::Init() {
43 int id;
44 if (!base::StringToInt(device_name_.id(), &id))
45 return false;
47 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid(
48 id, reinterpret_cast<intptr_t>(this)));
49 return true;
52 void VideoCaptureDeviceAndroid::AllocateAndStart(
53 const VideoCaptureParams& params,
54 scoped_ptr<Client> client) {
55 DVLOG(1) << "VideoCaptureDeviceAndroid::AllocateAndStart";
57 base::AutoLock lock(lock_);
58 if (state_ != kIdle)
59 return;
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);
70 if (!ret) {
71 SetErrorState("failed to allocate");
72 return;
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());
98 if (!ret) {
99 SetErrorState("failed to start capture");
100 return;
104 base::AutoLock lock(lock_);
105 state_ = kCapturing;
109 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
110 DVLOG(1) << "VideoCaptureDeviceAndroid::StopAndDeAllocate";
112 base::AutoLock lock(lock_);
113 if (state_ != kCapturing && state_ != kError)
114 return;
117 JNIEnv* env = AttachCurrentThread();
119 jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj());
120 if (!ret) {
121 SetErrorState("failed to stop capture");
122 return;
126 base::AutoLock lock(lock_);
127 state_ = kIdle;
128 client_.reset();
131 Java_VideoCapture_deallocate(env, j_capture_.obj());
134 void VideoCaptureDeviceAndroid::OnFrameAvailable(JNIEnv* env,
135 jobject obj,
136 jbyteArray data,
137 jint length,
138 jint rotation) {
139 DVLOG(3) << "VideoCaptureDeviceAndroid::OnFrameAvailable: length =" << length;
141 base::AutoLock lock(lock_);
142 if (state_ != kCapturing || !client_.get())
143 return;
145 jbyte* buffer = env->GetByteArrayElements(data, NULL);
146 if (!buffer) {
147 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
148 "failed to GetByteArrayElements";
149 return;
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,
172 jobject obj,
173 jstring message) {
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:
189 default:
190 return media::PIXEL_FORMAT_UNKNOWN;
194 void VideoCaptureDeviceAndroid::SetErrorState(const std::string& reason) {
196 base::AutoLock lock(lock_);
197 state_ = kError;
199 client_->OnError(reason);
202 } // namespace media