Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: media/capture/video/android/video_capture_device_android.cc

Issue 2143903003: [WIP] Move media/capture to device/capture (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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/capture/video/android/video_capture_device_android.h"
6
7 #include <stdint.h>
8 #include <utility>
9
10 #include "base/android/jni_android.h"
11 #include "base/android/jni_array.h"
12 #include "base/android/jni_string.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "jni/VideoCapture_jni.h"
15 #include "media/capture/video/android/photo_capabilities.h"
16 #include "media/capture/video/android/video_capture_device_factory_android.h"
17 #include "mojo/public/cpp/bindings/string.h"
18
19 using base::android::AttachCurrentThread;
20 using base::android::CheckException;
21 using base::android::GetClass;
22 using base::android::MethodID;
23 using base::android::JavaRef;
24 using base::android::ScopedJavaLocalRef;
25
26 namespace media {
27
28 // static
29 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) {
30 return RegisterNativesImpl(env);
31 }
32
33 const std::string VideoCaptureDevice::Name::GetModel() const {
34 // Android cameras are not typically USB devices, and this method is currently
35 // only used for USB model identifiers, so this implementation just indicates
36 // an unknown device model.
37 return "";
38 }
39
40 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(const Name& device_name)
41 : state_(kIdle), got_first_frame_(false), device_name_(device_name) {
42 }
43
44 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
45 StopAndDeAllocate();
46 }
47
48 bool VideoCaptureDeviceAndroid::Init() {
49 int id;
50 if (!base::StringToInt(device_name_.id(), &id))
51 return false;
52
53 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid(
54 id, reinterpret_cast<intptr_t>(this)));
55 return true;
56 }
57
58 void VideoCaptureDeviceAndroid::AllocateAndStart(
59 const VideoCaptureParams& params,
60 std::unique_ptr<Client> client) {
61 DVLOG(1) << __FUNCTION__;
62 {
63 base::AutoLock lock(lock_);
64 if (state_ != kIdle)
65 return;
66 client_ = std::move(client);
67 got_first_frame_ = false;
68 }
69
70 JNIEnv* env = AttachCurrentThread();
71
72 jboolean ret = Java_VideoCapture_allocate(
73 env, j_capture_.obj(), params.requested_format.frame_size.width(),
74 params.requested_format.frame_size.height(),
75 params.requested_format.frame_rate);
76 if (!ret) {
77 SetErrorState(FROM_HERE, "failed to allocate");
78 return;
79 }
80
81 // Store current width and height.
82 capture_format_.frame_size.SetSize(
83 Java_VideoCapture_queryWidth(env, j_capture_.obj()),
84 Java_VideoCapture_queryHeight(env, j_capture_.obj()));
85 capture_format_.frame_rate =
86 Java_VideoCapture_queryFrameRate(env, j_capture_.obj());
87 capture_format_.pixel_format = GetColorspace();
88 DCHECK_NE(capture_format_.pixel_format, media::PIXEL_FORMAT_UNKNOWN);
89 CHECK(capture_format_.frame_size.GetArea() > 0);
90 CHECK(!(capture_format_.frame_size.width() % 2));
91 CHECK(!(capture_format_.frame_size.height() % 2));
92
93 if (capture_format_.frame_rate > 0) {
94 frame_interval_ = base::TimeDelta::FromMicroseconds(
95 (base::Time::kMicrosecondsPerSecond + capture_format_.frame_rate - 1) /
96 capture_format_.frame_rate);
97 }
98
99 DVLOG(1) << "VideoCaptureDeviceAndroid::Allocate: queried frame_size="
100 << capture_format_.frame_size.ToString()
101 << ", frame_rate=" << capture_format_.frame_rate;
102
103 ret = Java_VideoCapture_startCapture(env, j_capture_.obj());
104 if (!ret) {
105 SetErrorState(FROM_HERE, "failed to start capture");
106 return;
107 }
108
109 {
110 base::AutoLock lock(lock_);
111 state_ = kCapturing;
112 }
113 }
114
115 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
116 DVLOG(1) << __FUNCTION__;
117 {
118 base::AutoLock lock(lock_);
119 if (state_ != kCapturing && state_ != kError)
120 return;
121 }
122
123 JNIEnv* env = AttachCurrentThread();
124
125 jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj());
126 if (!ret) {
127 SetErrorState(FROM_HERE, "failed to stop capture");
128 return;
129 }
130
131 {
132 base::AutoLock lock(lock_);
133 state_ = kIdle;
134 client_.reset();
135 }
136
137 Java_VideoCapture_deallocate(env, j_capture_.obj());
138 }
139
140 void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) {
141 DVLOG(1) << __FUNCTION__;
142 {
143 base::AutoLock lock(lock_);
144 if (state_ != kCapturing)
145 return;
146 }
147
148 JNIEnv* env = AttachCurrentThread();
149
150 // Make copy on the heap so we can pass the pointer through JNI.
151 std::unique_ptr<TakePhotoCallback> heap_callback(
152 new TakePhotoCallback(std::move(callback)));
153 const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get());
154 if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id))
155 return;
156
157 {
158 base::AutoLock lock(photo_callbacks_lock_);
159 photo_callbacks_.push_back(std::move(heap_callback));
160 }
161 }
162
163 void VideoCaptureDeviceAndroid::GetPhotoCapabilities(
164 GetPhotoCapabilitiesCallback callback) {
165 JNIEnv* env = AttachCurrentThread();
166
167 PhotoCapabilities caps(
168 Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj()));
169
170 // TODO(mcasas): Manual member copying sucks, consider adding typemapping from
171 // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002.
172 mojom::PhotoCapabilitiesPtr photo_capabilities =
173 mojom::PhotoCapabilities::New();
174 photo_capabilities->zoom = mojom::Range::New();
175 photo_capabilities->zoom->current = caps.getCurrentZoom();
176 photo_capabilities->zoom->max = caps.getMaxZoom();
177 photo_capabilities->zoom->min = caps.getMinZoom();
178 callback.Run(std::move(photo_capabilities));
179 }
180
181 void VideoCaptureDeviceAndroid::SetPhotoOptions(
182 mojom::PhotoSettingsPtr settings,
183 SetPhotoOptionsCallback callback) {
184 JNIEnv* env = AttachCurrentThread();
185 if (settings->has_zoom)
186 Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom);
187 callback.Run(true);
188 }
189
190 void VideoCaptureDeviceAndroid::OnFrameAvailable(
191 JNIEnv* env,
192 const JavaParamRef<jobject>& obj,
193 const JavaParamRef<jbyteArray>& data,
194 jint length,
195 jint rotation) {
196 DVLOG(3) << __FUNCTION__ << " length =" << length;
197
198 base::AutoLock lock(lock_);
199 if (state_ != kCapturing || !client_.get())
200 return;
201
202 jbyte* buffer = env->GetByteArrayElements(data, NULL);
203 if (!buffer) {
204 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
205 "failed to GetByteArrayElements";
206 return;
207 }
208
209 base::TimeTicks current_time = base::TimeTicks::Now();
210 if (!got_first_frame_) {
211 // Set aside one frame allowance for fluctuation.
212 expected_next_frame_time_ = current_time - frame_interval_;
213 first_ref_time_ = current_time;
214 got_first_frame_ = true;
215 }
216
217 // Deliver the frame when it doesn't arrive too early.
218 if (expected_next_frame_time_ <= current_time) {
219 expected_next_frame_time_ += frame_interval_;
220
221 // TODO(qiangchen): Investigate how to get raw timestamp for Android,
222 // rather than using reference time to calculate timestamp.
223 client_->OnIncomingCapturedData(reinterpret_cast<uint8_t*>(buffer), length,
224 capture_format_, rotation, current_time,
225 current_time - first_ref_time_);
226 }
227
228 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT);
229 }
230
231 void VideoCaptureDeviceAndroid::OnError(JNIEnv* env,
232 const JavaParamRef<jobject>& obj,
233 const JavaParamRef<jstring>& message) {
234 SetErrorState(FROM_HERE,
235 base::android::ConvertJavaStringToUTF8(env, message));
236 }
237
238 void VideoCaptureDeviceAndroid::OnPhotoTaken(
239 JNIEnv* env,
240 const base::android::JavaParamRef<jobject>& obj,
241 jlong callback_id,
242 const base::android::JavaParamRef<jbyteArray>& data) {
243 DCHECK(callback_id);
244
245 base::AutoLock lock(photo_callbacks_lock_);
246
247 TakePhotoCallback* const cb =
248 reinterpret_cast<TakePhotoCallback*>(callback_id);
249 // Search for the pointer |cb| in the list of |photo_callbacks_|.
250 const auto reference_it =
251 std::find_if(photo_callbacks_.begin(), photo_callbacks_.end(),
252 [cb](const std::unique_ptr<TakePhotoCallback>& callback) {
253 return callback.get() == cb;
254 });
255 if (reference_it == photo_callbacks_.end()) {
256 NOTREACHED() << "|callback_id| not found.";
257 return;
258 }
259
260 std::vector<uint8_t> native_data;
261 base::android::JavaByteArrayToByteVector(env, data.obj(), &native_data);
262
263 cb->Run(mojo::String::From(native_data.empty() ? "" : "image/jpeg"),
264 mojo::Array<uint8_t>::From(native_data));
265
266 photo_callbacks_.erase(reference_it);
267 }
268
269 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() {
270 JNIEnv* env = AttachCurrentThread();
271 const int current_capture_colorspace =
272 Java_VideoCapture_getColorspace(env, j_capture_.obj());
273 switch (current_capture_colorspace) {
274 case ANDROID_IMAGE_FORMAT_YV12:
275 return media::PIXEL_FORMAT_YV12;
276 case ANDROID_IMAGE_FORMAT_YUV_420_888:
277 return media::PIXEL_FORMAT_I420;
278 case ANDROID_IMAGE_FORMAT_NV21:
279 return media::PIXEL_FORMAT_NV21;
280 case ANDROID_IMAGE_FORMAT_UNKNOWN:
281 default:
282 return media::PIXEL_FORMAT_UNKNOWN;
283 }
284 }
285
286 void VideoCaptureDeviceAndroid::SetErrorState(
287 const tracked_objects::Location& from_here,
288 const std::string& reason) {
289 {
290 base::AutoLock lock(lock_);
291 state_ = kError;
292 }
293 client_->OnError(from_here, reason);
294 }
295
296 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698