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

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

Issue 2193213003: ImageCapture: Queue up requests while device not ready (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/capture/video/android/video_capture_device_android.h" 5 #include "media/capture/video/android/video_capture_device_android.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/android/jni_android.h" 10 #include "base/android/jni_android.h"
11 #include "base/android/jni_array.h" 11 #include "base/android/jni_array.h"
12 #include "base/android/jni_string.h" 12 #include "base/android/jni_string.h"
13 #include "base/numerics/safe_conversions.h" 13 #include "base/numerics/safe_conversions.h"
14 #include "base/strings/string_number_conversions.h" 14 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/thread_task_runner_handle.h"
15 #include "jni/VideoCapture_jni.h" 16 #include "jni/VideoCapture_jni.h"
16 #include "media/capture/video/android/photo_capabilities.h" 17 #include "media/capture/video/android/photo_capabilities.h"
17 #include "media/capture/video/android/video_capture_device_factory_android.h" 18 #include "media/capture/video/android/video_capture_device_factory_android.h"
18 #include "third_party/libyuv/include/libyuv.h" 19 #include "third_party/libyuv/include/libyuv.h"
19 20
20 using base::android::AttachCurrentThread; 21 using base::android::AttachCurrentThread;
21 using base::android::CheckException; 22 using base::android::CheckException;
22 using base::android::GetClass; 23 using base::android::GetClass;
23 using base::android::MethodID; 24 using base::android::MethodID;
24 using base::android::JavaRef; 25 using base::android::JavaRef;
25 using base::android::ScopedJavaLocalRef; 26 using base::android::ScopedJavaLocalRef;
26 27
27 namespace media { 28 namespace media {
28 29
29 // static 30 // static
30 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) { 31 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) {
31 return RegisterNativesImpl(env); 32 return RegisterNativesImpl(env);
32 } 33 }
33 34
34 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid( 35 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(
35 const VideoCaptureDeviceDescriptor& device_descriptor) 36 const VideoCaptureDeviceDescriptor& device_descriptor)
36 : state_(kIdle), 37 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
38 state_(kIdle),
37 got_first_frame_(false), 39 got_first_frame_(false),
38 device_descriptor_(device_descriptor) {} 40 device_descriptor_(device_descriptor),
41 weak_ptr_factory_(this) {}
39 42
40 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { 43 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
41 DCHECK(thread_checker_.CalledOnValidThread()); 44 DCHECK(main_task_runner_->BelongsToCurrentThread());
42 StopAndDeAllocate(); 45 StopAndDeAllocate();
43 } 46 }
44 47
45 bool VideoCaptureDeviceAndroid::Init() { 48 bool VideoCaptureDeviceAndroid::Init() {
46 int id; 49 int id;
47 if (!base::StringToInt(device_descriptor_.device_id, &id)) 50 if (!base::StringToInt(device_descriptor_.device_id, &id))
48 return false; 51 return false;
49 52
50 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid( 53 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid(
51 id, reinterpret_cast<intptr_t>(this))); 54 id, reinterpret_cast<intptr_t>(this)));
52 return true; 55 return true;
53 } 56 }
54 57
55 void VideoCaptureDeviceAndroid::AllocateAndStart( 58 void VideoCaptureDeviceAndroid::AllocateAndStart(
56 const VideoCaptureParams& params, 59 const VideoCaptureParams& params,
57 std::unique_ptr<Client> client) { 60 std::unique_ptr<Client> client) {
58 DCHECK(thread_checker_.CalledOnValidThread()); 61 DCHECK(main_task_runner_->BelongsToCurrentThread());
59 { 62 {
60 base::AutoLock lock(lock_); 63 base::AutoLock lock(lock_);
61 if (state_ != kIdle) 64 if (state_ != kIdle)
62 return; 65 return;
63 client_ = std::move(client); 66 client_ = std::move(client);
64 got_first_frame_ = false; 67 got_first_frame_ = false;
65 } 68 }
66 69
67 JNIEnv* env = AttachCurrentThread(); 70 JNIEnv* env = AttachCurrentThread();
68 71
(...skipping 28 matching lines...) Expand all
97 << capture_format_.frame_rate << "fps"; 100 << capture_format_.frame_rate << "fps";
98 101
99 ret = Java_VideoCapture_startCapture(env, j_capture_.obj()); 102 ret = Java_VideoCapture_startCapture(env, j_capture_.obj());
100 if (!ret) { 103 if (!ret) {
101 SetErrorState(FROM_HERE, "failed to start capture"); 104 SetErrorState(FROM_HERE, "failed to start capture");
102 return; 105 return;
103 } 106 }
104 107
105 { 108 {
106 base::AutoLock lock(lock_); 109 base::AutoLock lock(lock_);
107 state_ = kCapturing; 110 state_ = kConfigured;
108 } 111 }
109 } 112 }
110 113
111 void VideoCaptureDeviceAndroid::StopAndDeAllocate() { 114 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
112 DCHECK(thread_checker_.CalledOnValidThread()); 115 DCHECK(main_task_runner_->BelongsToCurrentThread());
113 { 116 {
114 base::AutoLock lock(lock_); 117 base::AutoLock lock(lock_);
115 if (state_ != kCapturing && state_ != kError) 118 if (state_ != kConfigured && state_ != kError)
116 return; 119 return;
117 } 120 }
118 121
119 JNIEnv* env = AttachCurrentThread(); 122 JNIEnv* env = AttachCurrentThread();
120 123
121 const jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj()); 124 const jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj());
122 if (!ret) { 125 if (!ret) {
123 SetErrorState(FROM_HERE, "failed to stop capture"); 126 SetErrorState(FROM_HERE, "failed to stop capture");
124 return; 127 return;
125 } 128 }
126 129
127 { 130 {
128 base::AutoLock lock(lock_); 131 base::AutoLock lock(lock_);
129 state_ = kIdle; 132 state_ = kIdle;
130 client_.reset(); 133 client_.reset();
131 } 134 }
132 135
133 Java_VideoCapture_deallocate(env, j_capture_.obj()); 136 Java_VideoCapture_deallocate(env, j_capture_.obj());
134 } 137 }
135 138
136 void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) { 139 void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) {
137 DCHECK(thread_checker_.CalledOnValidThread()); 140 DCHECK(main_task_runner_->BelongsToCurrentThread());
138 { 141 {
139 base::AutoLock lock(lock_); 142 base::AutoLock lock(lock_);
140 if (state_ != kCapturing) 143 if (state_ != kConfigured)
141 return; 144 return;
145 if (!got_first_frame_) { // We have to wait until we get the first frame.
146 photo_requests_queue_.push_back(
147 base::Bind(&VideoCaptureDeviceAndroid::DoTakePhoto,
148 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
149 return;
150 }
142 } 151 }
143 152 DoTakePhoto(std::move(callback));
144 JNIEnv* env = AttachCurrentThread();
145
146 // Make copy on the heap so we can pass the pointer through JNI.
147 std::unique_ptr<TakePhotoCallback> heap_callback(
148 new TakePhotoCallback(std::move(callback)));
149 const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get());
150 if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id,
151 next_photo_resolution_.width(),
152 next_photo_resolution_.height()))
153 return;
154
155 {
156 base::AutoLock lock(photo_callbacks_lock_);
157 photo_callbacks_.push_back(std::move(heap_callback));
158 }
159 } 153 }
160 154
161 void VideoCaptureDeviceAndroid::GetPhotoCapabilities( 155 void VideoCaptureDeviceAndroid::GetPhotoCapabilities(
162 GetPhotoCapabilitiesCallback callback) { 156 GetPhotoCapabilitiesCallback callback) {
163 DCHECK(thread_checker_.CalledOnValidThread()); 157 DCHECK(main_task_runner_->BelongsToCurrentThread());
164 JNIEnv* env = AttachCurrentThread(); 158 {
165 159 base::AutoLock lock(lock_);
166 PhotoCapabilities caps( 160 if (state_ != kConfigured)
167 Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj())); 161 return;
168 162 if (!got_first_frame_) { // We have to wait until we get the first frame.
169 // TODO(mcasas): Manual member copying sucks, consider adding typemapping from 163 photo_requests_queue_.push_back(
170 // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002. 164 base::Bind(&VideoCaptureDeviceAndroid::DoGetPhotoCapabilities,
171 mojom::PhotoCapabilitiesPtr photo_capabilities = 165 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
172 mojom::PhotoCapabilities::New(); 166 return;
173 photo_capabilities->iso = mojom::Range::New(); 167 }
174 photo_capabilities->iso->current = caps.getCurrentIso(); 168 }
175 photo_capabilities->iso->max = caps.getMaxIso(); 169 DoGetPhotoCapabilities(std::move(callback));
176 photo_capabilities->iso->min = caps.getMinIso();
177 photo_capabilities->height = mojom::Range::New();
178 photo_capabilities->height->current = caps.getCurrentHeight();
179 photo_capabilities->height->max = caps.getMaxHeight();
180 photo_capabilities->height->min = caps.getMinHeight();
181 photo_capabilities->width = mojom::Range::New();
182 photo_capabilities->width->current = caps.getCurrentWidth();
183 photo_capabilities->width->max = caps.getMaxWidth();
184 photo_capabilities->width->min = caps.getMinWidth();
185 photo_capabilities->zoom = mojom::Range::New();
186 photo_capabilities->zoom->current = caps.getCurrentZoom();
187 photo_capabilities->zoom->max = caps.getMaxZoom();
188 photo_capabilities->zoom->min = caps.getMinZoom();
189 photo_capabilities->focus_mode = caps.getAutoFocusInUse()
190 ? mojom::FocusMode::AUTO
191 : mojom::FocusMode::MANUAL;
192 callback.Run(std::move(photo_capabilities));
193 } 170 }
194 171
195 void VideoCaptureDeviceAndroid::SetPhotoOptions( 172 void VideoCaptureDeviceAndroid::SetPhotoOptions(
196 mojom::PhotoSettingsPtr settings, 173 mojom::PhotoSettingsPtr settings,
197 SetPhotoOptionsCallback callback) { 174 SetPhotoOptionsCallback callback) {
198 DCHECK(thread_checker_.CalledOnValidThread()); 175 DCHECK(main_task_runner_->BelongsToCurrentThread());
199 JNIEnv* env = AttachCurrentThread(); 176 {
200 // |width| and/or |height| are kept for the next TakePhoto()s. 177 base::AutoLock lock(lock_);
201 if (settings->has_width || settings->has_height) 178 if (state_ != kConfigured)
202 next_photo_resolution_.SetSize(0, 0); 179 return;
203 if (settings->has_width) { 180 if (!got_first_frame_) { // We have to wait until we get the first frame.
204 next_photo_resolution_.set_width( 181 photo_requests_queue_.push_back(
205 base::saturated_cast<int>(settings->width)); 182 base::Bind(&VideoCaptureDeviceAndroid::DoSetPhotoOptions,
183 weak_ptr_factory_.GetWeakPtr(), base::Passed(&settings),
184 base::Passed(&callback)));
185 return;
186 }
206 } 187 }
207 if (settings->has_height) { 188 DoSetPhotoOptions(std::move(settings), std::move(callback));
208 next_photo_resolution_.set_height(
209 base::saturated_cast<int>(settings->height));
210 }
211
212 if (settings->has_zoom)
213 Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom);
214 callback.Run(true);
215 } 189 }
216 190
217 void VideoCaptureDeviceAndroid::OnFrameAvailable( 191 void VideoCaptureDeviceAndroid::OnFrameAvailable(
218 JNIEnv* env, 192 JNIEnv* env,
219 const JavaParamRef<jobject>& obj, 193 const JavaParamRef<jobject>& obj,
220 const JavaParamRef<jbyteArray>& data, 194 const JavaParamRef<jbyteArray>& data,
221 jint length, 195 jint length,
222 jint rotation) { 196 jint rotation) {
223 { 197 {
224 base::AutoLock lock(lock_); 198 base::AutoLock lock(lock_);
225 if (state_ != kCapturing || !client_) 199 if (state_ != kConfigured || !client_)
226 return; 200 return;
227 } 201 }
228 202
229 jbyte* buffer = env->GetByteArrayElements(data, NULL); 203 jbyte* buffer = env->GetByteArrayElements(data, NULL);
230 if (!buffer) { 204 if (!buffer) {
231 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: " 205 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
232 "failed to GetByteArrayElements"; 206 "failed to GetByteArrayElements";
233 return; 207 return;
234 } 208 }
235 209
236 const base::TimeTicks current_time = base::TimeTicks::Now(); 210 const base::TimeTicks current_time = base::TimeTicks::Now();
237 if (!got_first_frame_) { 211 {
238 // Set aside one frame allowance for fluctuation. 212 base::AutoLock lock(lock_);
239 expected_next_frame_time_ = current_time - frame_interval_; 213 if (!got_first_frame_) {
240 first_ref_time_ = current_time; 214 // Set aside one frame allowance for fluctuation.
241 got_first_frame_ = true; 215 expected_next_frame_time_ = current_time - frame_interval_;
216 first_ref_time_ = current_time;
217 got_first_frame_ = true;
218
219 for (const auto& request : photo_requests_queue_)
220 main_task_runner_->PostTask(FROM_HERE, request);
emircan 2016/08/03 21:55:54 photo_requests_queue_.clear();
mcasas 2016/08/03 22:19:36 Done.
221 }
242 } 222 }
243 223
244 // Deliver the frame when it doesn't arrive too early. 224 // Deliver the frame when it doesn't arrive too early.
245 if (expected_next_frame_time_ <= current_time) { 225 if (expected_next_frame_time_ <= current_time) {
246 expected_next_frame_time_ += frame_interval_; 226 expected_next_frame_time_ += frame_interval_;
247 227
248 // TODO(qiangchen): Investigate how to get raw timestamp for Android, 228 // TODO(qiangchen): Investigate how to get raw timestamp for Android,
249 // rather than using reference time to calculate timestamp. 229 // rather than using reference time to calculate timestamp.
250 base::AutoLock lock(lock_); 230 base::AutoLock lock(lock_);
251 if (!client_) 231 if (!client_)
(...skipping 12 matching lines...) Expand all
264 jint y_stride, 244 jint y_stride,
265 jobject u_buffer, 245 jobject u_buffer,
266 jobject v_buffer, 246 jobject v_buffer,
267 jint uv_row_stride, 247 jint uv_row_stride,
268 jint uv_pixel_stride, 248 jint uv_pixel_stride,
269 jint width, 249 jint width,
270 jint height, 250 jint height,
271 jint rotation) { 251 jint rotation) {
272 { 252 {
273 base::AutoLock lock(lock_); 253 base::AutoLock lock(lock_);
274 if (state_ != kCapturing || !client_) 254 if (state_ != kConfigured || !client_)
275 return; 255 return;
276 } 256 }
277 257
278 const base::TimeTicks current_time = base::TimeTicks::Now(); 258 const base::TimeTicks current_time = base::TimeTicks::Now();
279 if (!got_first_frame_) { 259 {
280 // Set aside one frame allowance for fluctuation. 260 base::AutoLock lock(lock_);
281 expected_next_frame_time_ = current_time - frame_interval_; 261 if (!got_first_frame_) {
282 first_ref_time_ = current_time; 262 // Set aside one frame allowance for fluctuation.
283 got_first_frame_ = true; 263 expected_next_frame_time_ = current_time - frame_interval_;
264 first_ref_time_ = current_time;
265 got_first_frame_ = true;
266
267 for (const auto& request : photo_requests_queue_)
268 main_task_runner_->PostTask(FROM_HERE, request);
269 photo_requests_queue_.clear();
270 }
284 } 271 }
285 272
286 uint8_t* const y_src = 273 uint8_t* const y_src =
287 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer)); 274 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer));
288 CHECK(y_src); 275 CHECK(y_src);
289 uint8_t* const u_src = 276 uint8_t* const u_src =
290 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer)); 277 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer));
291 CHECK(u_src); 278 CHECK(u_src);
292 uint8_t* const v_src = 279 uint8_t* const v_src =
293 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer)); 280 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer));
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 const std::string& reason) { 365 const std::string& reason) {
379 { 366 {
380 base::AutoLock lock(lock_); 367 base::AutoLock lock(lock_);
381 state_ = kError; 368 state_ = kError;
382 if (!client_) 369 if (!client_)
383 return; 370 return;
384 client_->OnError(from_here, reason); 371 client_->OnError(from_here, reason);
385 } 372 }
386 } 373 }
387 374
375 void VideoCaptureDeviceAndroid::DoTakePhoto(TakePhotoCallback callback) {
376 DCHECK(main_task_runner_->BelongsToCurrentThread());
377 #if DCHECK_IS_ON()
378 {
379 base::AutoLock lock(lock_);
380 DCHECK_EQ(kConfigured, state_);
381 DCHECK(got_first_frame_);
382 }
383 #endif
384 JNIEnv* env = AttachCurrentThread();
385
386 // Make copy on the heap so we can pass the pointer through JNI.
387 std::unique_ptr<TakePhotoCallback> heap_callback(
388 new TakePhotoCallback(std::move(callback)));
389 const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get());
390 if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id,
391 next_photo_resolution_.width(),
392 next_photo_resolution_.height()))
393 return;
394
395 {
396 base::AutoLock lock(photo_callbacks_lock_);
397 photo_callbacks_.push_back(std::move(heap_callback));
398 }
399 }
400
401 void VideoCaptureDeviceAndroid::DoGetPhotoCapabilities(
402 GetPhotoCapabilitiesCallback callback) {
403 DCHECK(main_task_runner_->BelongsToCurrentThread());
404 #if DCHECK_IS_ON()
405 {
406 base::AutoLock lock(lock_);
407 DCHECK_EQ(kConfigured, state_);
408 DCHECK(got_first_frame_);
409 }
410 #endif
411 JNIEnv* env = AttachCurrentThread();
412
413 PhotoCapabilities caps(
414 Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj()));
415
416 // TODO(mcasas): Manual member copying sucks, consider adding typemapping from
417 // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002.
418 mojom::PhotoCapabilitiesPtr photo_capabilities =
419 mojom::PhotoCapabilities::New();
420 photo_capabilities->iso = mojom::Range::New();
421 photo_capabilities->iso->current = caps.getCurrentIso();
422 photo_capabilities->iso->max = caps.getMaxIso();
423 photo_capabilities->iso->min = caps.getMinIso();
424 photo_capabilities->height = mojom::Range::New();
425 photo_capabilities->height->current = caps.getCurrentHeight();
426 photo_capabilities->height->max = caps.getMaxHeight();
427 photo_capabilities->height->min = caps.getMinHeight();
428 photo_capabilities->width = mojom::Range::New();
429 photo_capabilities->width->current = caps.getCurrentWidth();
430 photo_capabilities->width->max = caps.getMaxWidth();
431 photo_capabilities->width->min = caps.getMinWidth();
432 photo_capabilities->zoom = mojom::Range::New();
433 photo_capabilities->zoom->current = caps.getCurrentZoom();
434 photo_capabilities->zoom->max = caps.getMaxZoom();
435 photo_capabilities->zoom->min = caps.getMinZoom();
436 photo_capabilities->focus_mode = caps.getAutoFocusInUse()
437 ? mojom::FocusMode::AUTO
438 : mojom::FocusMode::MANUAL;
439 callback.Run(std::move(photo_capabilities));
440 }
441
442 void VideoCaptureDeviceAndroid::DoSetPhotoOptions(
443 mojom::PhotoSettingsPtr settings,
444 SetPhotoOptionsCallback callback) {
445 DCHECK(main_task_runner_->BelongsToCurrentThread());
446 #if DCHECK_IS_ON()
447 {
448 base::AutoLock lock(lock_);
449 DCHECK_EQ(kConfigured, state_);
450 DCHECK(got_first_frame_);
451 }
452 #endif
453 JNIEnv* env = AttachCurrentThread();
454
455 // |width| and/or |height| are kept for the next TakePhoto()s.
456 if (settings->has_width || settings->has_height)
457 next_photo_resolution_.SetSize(0, 0);
458 if (settings->has_width) {
459 next_photo_resolution_.set_width(
460 base::saturated_cast<int>(settings->width));
461 }
462 if (settings->has_height) {
463 next_photo_resolution_.set_height(
464 base::saturated_cast<int>(settings->height));
465 }
466
467 if (settings->has_zoom)
468 Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom);
469
470 callback.Run(true);
471 }
472
388 } // namespace media 473 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698