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

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

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

Powered by Google App Engine
This is Rietveld 408576698