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

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

Issue 2219813002: Revert of 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"
16 #include "jni/VideoCapture_jni.h" 15 #include "jni/VideoCapture_jni.h"
17 #include "media/capture/video/android/photo_capabilities.h" 16 #include "media/capture/video/android/photo_capabilities.h"
18 #include "media/capture/video/android/video_capture_device_factory_android.h" 17 #include "media/capture/video/android/video_capture_device_factory_android.h"
19 #include "third_party/libyuv/include/libyuv.h" 18 #include "third_party/libyuv/include/libyuv.h"
20 19
21 using base::android::AttachCurrentThread; 20 using base::android::AttachCurrentThread;
22 using base::android::CheckException; 21 using base::android::CheckException;
23 using base::android::GetClass; 22 using base::android::GetClass;
24 using base::android::MethodID; 23 using base::android::MethodID;
25 using base::android::JavaRef; 24 using base::android::JavaRef;
26 using base::android::ScopedJavaLocalRef; 25 using base::android::ScopedJavaLocalRef;
27 26
28 namespace media { 27 namespace media {
29 28
30 // static 29 // static
31 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) { 30 bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) {
32 return RegisterNativesImpl(env); 31 return RegisterNativesImpl(env);
33 } 32 }
34 33
35 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid( 34 VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid(
36 const VideoCaptureDeviceDescriptor& device_descriptor) 35 const VideoCaptureDeviceDescriptor& device_descriptor)
37 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), 36 : state_(kIdle),
38 state_(kIdle),
39 got_first_frame_(false), 37 got_first_frame_(false),
40 device_descriptor_(device_descriptor), 38 device_descriptor_(device_descriptor) {}
41 weak_ptr_factory_(this) {}
42 39
43 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { 40 VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() {
44 DCHECK(main_task_runner_->BelongsToCurrentThread()); 41 DCHECK(thread_checker_.CalledOnValidThread());
45 StopAndDeAllocate(); 42 StopAndDeAllocate();
46 } 43 }
47 44
48 bool VideoCaptureDeviceAndroid::Init() { 45 bool VideoCaptureDeviceAndroid::Init() {
49 int id; 46 int id;
50 if (!base::StringToInt(device_descriptor_.device_id, &id)) 47 if (!base::StringToInt(device_descriptor_.device_id, &id))
51 return false; 48 return false;
52 49
53 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid( 50 j_capture_.Reset(VideoCaptureDeviceFactoryAndroid::createVideoCaptureAndroid(
54 id, reinterpret_cast<intptr_t>(this))); 51 id, reinterpret_cast<intptr_t>(this)));
55 return true; 52 return true;
56 } 53 }
57 54
58 void VideoCaptureDeviceAndroid::AllocateAndStart( 55 void VideoCaptureDeviceAndroid::AllocateAndStart(
59 const VideoCaptureParams& params, 56 const VideoCaptureParams& params,
60 std::unique_ptr<Client> client) { 57 std::unique_ptr<Client> client) {
61 DCHECK(main_task_runner_->BelongsToCurrentThread()); 58 DCHECK(thread_checker_.CalledOnValidThread());
62 { 59 {
63 base::AutoLock lock(lock_); 60 base::AutoLock lock(lock_);
64 if (state_ != kIdle) 61 if (state_ != kIdle)
65 return; 62 return;
66 client_ = std::move(client); 63 client_ = std::move(client);
67 got_first_frame_ = false; 64 got_first_frame_ = false;
68 } 65 }
69 66
70 JNIEnv* env = AttachCurrentThread(); 67 JNIEnv* env = AttachCurrentThread();
71 68
(...skipping 28 matching lines...) Expand all
100 << capture_format_.frame_rate << "fps"; 97 << capture_format_.frame_rate << "fps";
101 98
102 ret = Java_VideoCapture_startCapture(env, j_capture_.obj()); 99 ret = Java_VideoCapture_startCapture(env, j_capture_.obj());
103 if (!ret) { 100 if (!ret) {
104 SetErrorState(FROM_HERE, "failed to start capture"); 101 SetErrorState(FROM_HERE, "failed to start capture");
105 return; 102 return;
106 } 103 }
107 104
108 { 105 {
109 base::AutoLock lock(lock_); 106 base::AutoLock lock(lock_);
110 state_ = kConfigured; 107 state_ = kCapturing;
111 } 108 }
112 } 109 }
113 110
114 void VideoCaptureDeviceAndroid::StopAndDeAllocate() { 111 void VideoCaptureDeviceAndroid::StopAndDeAllocate() {
115 DCHECK(main_task_runner_->BelongsToCurrentThread()); 112 DCHECK(thread_checker_.CalledOnValidThread());
116 { 113 {
117 base::AutoLock lock(lock_); 114 base::AutoLock lock(lock_);
118 if (state_ != kConfigured && state_ != kError) 115 if (state_ != kCapturing && state_ != kError)
119 return; 116 return;
120 } 117 }
121 118
122 JNIEnv* env = AttachCurrentThread(); 119 JNIEnv* env = AttachCurrentThread();
123 120
124 const jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj()); 121 const jboolean ret = Java_VideoCapture_stopCapture(env, j_capture_.obj());
125 if (!ret) { 122 if (!ret) {
126 SetErrorState(FROM_HERE, "failed to stop capture"); 123 SetErrorState(FROM_HERE, "failed to stop capture");
127 return; 124 return;
128 } 125 }
129 126
130 { 127 {
131 base::AutoLock lock(lock_); 128 base::AutoLock lock(lock_);
132 state_ = kIdle; 129 state_ = kIdle;
133 client_.reset(); 130 client_.reset();
134 } 131 }
135 132
136 Java_VideoCapture_deallocate(env, j_capture_.obj()); 133 Java_VideoCapture_deallocate(env, j_capture_.obj());
137 } 134 }
138 135
139 void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) { 136 void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) {
140 DCHECK(main_task_runner_->BelongsToCurrentThread()); 137 DCHECK(thread_checker_.CalledOnValidThread());
141 { 138 {
142 base::AutoLock lock(lock_); 139 base::AutoLock lock(lock_);
143 if (state_ != kConfigured) 140 if (state_ != kCapturing)
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 }
151 }
152 DoTakePhoto(std::move(callback));
153 }
154
155 void VideoCaptureDeviceAndroid::GetPhotoCapabilities(
156 GetPhotoCapabilitiesCallback callback) {
157 DCHECK(main_task_runner_->BelongsToCurrentThread());
158 {
159 base::AutoLock lock(lock_);
160 if (state_ != kConfigured)
161 return;
162 if (!got_first_frame_) { // We have to wait until we get the first frame.
163 photo_requests_queue_.push_back(
164 base::Bind(&VideoCaptureDeviceAndroid::DoGetPhotoCapabilities,
165 weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback)));
166 return;
167 }
168 }
169 DoGetPhotoCapabilities(std::move(callback));
170 }
171
172 void VideoCaptureDeviceAndroid::SetPhotoOptions(
173 mojom::PhotoSettingsPtr settings,
174 SetPhotoOptionsCallback callback) {
175 DCHECK(main_task_runner_->BelongsToCurrentThread());
176 {
177 base::AutoLock lock(lock_);
178 if (state_ != kConfigured)
179 return;
180 if (!got_first_frame_) { // We have to wait until we get the first frame.
181 photo_requests_queue_.push_back(
182 base::Bind(&VideoCaptureDeviceAndroid::DoSetPhotoOptions,
183 weak_ptr_factory_.GetWeakPtr(), base::Passed(&settings),
184 base::Passed(&callback)));
185 return;
186 }
187 }
188 DoSetPhotoOptions(std::move(settings), std::move(callback));
189 }
190
191 void VideoCaptureDeviceAndroid::OnFrameAvailable(
192 JNIEnv* env,
193 const JavaParamRef<jobject>& obj,
194 const JavaParamRef<jbyteArray>& data,
195 jint length,
196 jint rotation) {
197 {
198 base::AutoLock lock(lock_);
199 if (state_ != kConfigured || !client_)
200 return; 141 return;
201 } 142 }
202 143
203 jbyte* buffer = env->GetByteArrayElements(data, NULL);
204 if (!buffer) {
205 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
206 "failed to GetByteArrayElements";
207 return;
208 }
209
210 const base::TimeTicks current_time = base::TimeTicks::Now();
211 {
212 base::AutoLock lock(lock_);
213 if (!got_first_frame_) {
214 // Set aside one frame allowance for fluctuation.
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);
221 photo_requests_queue_.clear();
222 }
223 }
224
225 // Deliver the frame when it doesn't arrive too early.
226 if (expected_next_frame_time_ <= current_time) {
227 expected_next_frame_time_ += frame_interval_;
228
229 // TODO(qiangchen): Investigate how to get raw timestamp for Android,
230 // rather than using reference time to calculate timestamp.
231 base::AutoLock lock(lock_);
232 if (!client_)
233 return;
234 client_->OnIncomingCapturedData(reinterpret_cast<uint8_t*>(buffer), length,
235 capture_format_, rotation, current_time,
236 current_time - first_ref_time_);
237 }
238
239 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT);
240 }
241
242 void VideoCaptureDeviceAndroid::OnI420FrameAvailable(JNIEnv* env,
243 jobject obj,
244 jobject y_buffer,
245 jint y_stride,
246 jobject u_buffer,
247 jobject v_buffer,
248 jint uv_row_stride,
249 jint uv_pixel_stride,
250 jint width,
251 jint height,
252 jint rotation) {
253 {
254 base::AutoLock lock(lock_);
255 if (state_ != kConfigured || !client_)
256 return;
257 }
258
259 const base::TimeTicks current_time = base::TimeTicks::Now();
260 {
261 base::AutoLock lock(lock_);
262 if (!got_first_frame_) {
263 // Set aside one frame allowance for fluctuation.
264 expected_next_frame_time_ = current_time - frame_interval_;
265 first_ref_time_ = current_time;
266 got_first_frame_ = true;
267
268 for (const auto& request : photo_requests_queue_)
269 main_task_runner_->PostTask(FROM_HERE, request);
270 photo_requests_queue_.clear();
271 }
272 }
273
274 uint8_t* const y_src =
275 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer));
276 CHECK(y_src);
277 uint8_t* const u_src =
278 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer));
279 CHECK(u_src);
280 uint8_t* const v_src =
281 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer));
282 CHECK(v_src);
283
284 const int y_plane_length = width * height;
285 const int uv_plane_length = y_plane_length / 4;
286 const int buffer_length = y_plane_length + uv_plane_length * 2;
287 std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_length]);
288
289 libyuv::Android420ToI420(y_src, y_stride, u_src, uv_row_stride, v_src,
290 uv_row_stride, uv_pixel_stride, buffer.get(), width,
291 buffer.get() + y_plane_length, width / 2,
292 buffer.get() + y_plane_length + uv_plane_length,
293 width / 2, width, height);
294
295 // Deliver the frame when it doesn't arrive too early.
296 if (expected_next_frame_time_ <= current_time) {
297 expected_next_frame_time_ += frame_interval_;
298
299 // TODO(qiangchen): Investigate how to get raw timestamp for Android,
300 // rather than using reference time to calculate timestamp.
301 base::AutoLock lock(lock_);
302 if (!client_)
303 return;
304 client_->OnIncomingCapturedData(buffer.get(), buffer_length,
305 capture_format_, rotation, current_time,
306 current_time - first_ref_time_);
307 }
308 }
309
310 void VideoCaptureDeviceAndroid::OnError(JNIEnv* env,
311 const JavaParamRef<jobject>& obj,
312 const JavaParamRef<jstring>& message) {
313 SetErrorState(FROM_HERE,
314 base::android::ConvertJavaStringToUTF8(env, message));
315 }
316
317 void VideoCaptureDeviceAndroid::OnPhotoTaken(
318 JNIEnv* env,
319 const base::android::JavaParamRef<jobject>& obj,
320 jlong callback_id,
321 const base::android::JavaParamRef<jbyteArray>& data) {
322 DCHECK(callback_id);
323
324 base::AutoLock lock(photo_callbacks_lock_);
325
326 TakePhotoCallback* const cb =
327 reinterpret_cast<TakePhotoCallback*>(callback_id);
328 // Search for the pointer |cb| in the list of |photo_callbacks_|.
329 const auto reference_it =
330 std::find_if(photo_callbacks_.begin(), photo_callbacks_.end(),
331 [cb](const std::unique_ptr<TakePhotoCallback>& callback) {
332 return callback.get() == cb;
333 });
334 if (reference_it == photo_callbacks_.end()) {
335 NOTREACHED() << "|callback_id| not found.";
336 return;
337 }
338
339 mojom::BlobPtr blob = mojom::Blob::New();
340 base::android::JavaByteArrayToByteVector(env, data.obj(), &blob->data);
341 blob->mime_type = blob->data.empty() ? "" : "image/jpeg";
342 cb->Run(std::move(blob));
343
344 photo_callbacks_.erase(reference_it);
345 }
346
347 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() {
348 JNIEnv* env = AttachCurrentThread();
349 const int current_capture_colorspace =
350 Java_VideoCapture_getColorspace(env, j_capture_.obj());
351 switch (current_capture_colorspace) {
352 case ANDROID_IMAGE_FORMAT_YV12:
353 return media::PIXEL_FORMAT_YV12;
354 case ANDROID_IMAGE_FORMAT_YUV_420_888:
355 return media::PIXEL_FORMAT_I420;
356 case ANDROID_IMAGE_FORMAT_NV21:
357 return media::PIXEL_FORMAT_NV21;
358 case ANDROID_IMAGE_FORMAT_UNKNOWN:
359 default:
360 return media::PIXEL_FORMAT_UNKNOWN;
361 }
362 }
363
364 void VideoCaptureDeviceAndroid::SetErrorState(
365 const tracked_objects::Location& from_here,
366 const std::string& reason) {
367 {
368 base::AutoLock lock(lock_);
369 state_ = kError;
370 if (!client_)
371 return;
372 client_->OnError(from_here, reason);
373 }
374 }
375
376 void VideoCaptureDeviceAndroid::DoTakePhoto(TakePhotoCallback callback) {
377 DCHECK(main_task_runner_->BelongsToCurrentThread());
378 #if DCHECK_IS_ON()
379 {
380 base::AutoLock lock(lock_);
381 DCHECK_EQ(kConfigured, state_);
382 DCHECK(got_first_frame_);
383 }
384 #endif
385 JNIEnv* env = AttachCurrentThread(); 144 JNIEnv* env = AttachCurrentThread();
386 145
387 // Make copy on the heap so we can pass the pointer through JNI. 146 // Make copy on the heap so we can pass the pointer through JNI.
388 std::unique_ptr<TakePhotoCallback> heap_callback( 147 std::unique_ptr<TakePhotoCallback> heap_callback(
389 new TakePhotoCallback(std::move(callback))); 148 new TakePhotoCallback(std::move(callback)));
390 const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get()); 149 const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get());
391 if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id, 150 if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id,
392 next_photo_resolution_.width(), 151 next_photo_resolution_.width(),
393 next_photo_resolution_.height())) 152 next_photo_resolution_.height()))
394 return; 153 return;
395 154
396 { 155 {
397 base::AutoLock lock(photo_callbacks_lock_); 156 base::AutoLock lock(photo_callbacks_lock_);
398 photo_callbacks_.push_back(std::move(heap_callback)); 157 photo_callbacks_.push_back(std::move(heap_callback));
399 } 158 }
400 } 159 }
401 160
402 void VideoCaptureDeviceAndroid::DoGetPhotoCapabilities( 161 void VideoCaptureDeviceAndroid::GetPhotoCapabilities(
403 GetPhotoCapabilitiesCallback callback) { 162 GetPhotoCapabilitiesCallback callback) {
404 DCHECK(main_task_runner_->BelongsToCurrentThread()); 163 DCHECK(thread_checker_.CalledOnValidThread());
405 #if DCHECK_IS_ON()
406 {
407 base::AutoLock lock(lock_);
408 DCHECK_EQ(kConfigured, state_);
409 DCHECK(got_first_frame_);
410 }
411 #endif
412 JNIEnv* env = AttachCurrentThread(); 164 JNIEnv* env = AttachCurrentThread();
413 165
414 PhotoCapabilities caps( 166 PhotoCapabilities caps(
415 Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj())); 167 Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj()));
416 168
417 // TODO(mcasas): Manual member copying sucks, consider adding typemapping from 169 // TODO(mcasas): Manual member copying sucks, consider adding typemapping from
418 // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002. 170 // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002.
419 mojom::PhotoCapabilitiesPtr photo_capabilities = 171 mojom::PhotoCapabilitiesPtr photo_capabilities =
420 mojom::PhotoCapabilities::New(); 172 mojom::PhotoCapabilities::New();
421 photo_capabilities->iso = mojom::Range::New(); 173 photo_capabilities->iso = mojom::Range::New();
(...skipping 11 matching lines...) Expand all
433 photo_capabilities->zoom = mojom::Range::New(); 185 photo_capabilities->zoom = mojom::Range::New();
434 photo_capabilities->zoom->current = caps.getCurrentZoom(); 186 photo_capabilities->zoom->current = caps.getCurrentZoom();
435 photo_capabilities->zoom->max = caps.getMaxZoom(); 187 photo_capabilities->zoom->max = caps.getMaxZoom();
436 photo_capabilities->zoom->min = caps.getMinZoom(); 188 photo_capabilities->zoom->min = caps.getMinZoom();
437 photo_capabilities->focus_mode = caps.getAutoFocusInUse() 189 photo_capabilities->focus_mode = caps.getAutoFocusInUse()
438 ? mojom::FocusMode::AUTO 190 ? mojom::FocusMode::AUTO
439 : mojom::FocusMode::MANUAL; 191 : mojom::FocusMode::MANUAL;
440 callback.Run(std::move(photo_capabilities)); 192 callback.Run(std::move(photo_capabilities));
441 } 193 }
442 194
443 void VideoCaptureDeviceAndroid::DoSetPhotoOptions( 195 void VideoCaptureDeviceAndroid::SetPhotoOptions(
444 mojom::PhotoSettingsPtr settings, 196 mojom::PhotoSettingsPtr settings,
445 SetPhotoOptionsCallback callback) { 197 SetPhotoOptionsCallback callback) {
446 DCHECK(main_task_runner_->BelongsToCurrentThread()); 198 DCHECK(thread_checker_.CalledOnValidThread());
447 #if DCHECK_IS_ON()
448 {
449 base::AutoLock lock(lock_);
450 DCHECK_EQ(kConfigured, state_);
451 DCHECK(got_first_frame_);
452 }
453 #endif
454 JNIEnv* env = AttachCurrentThread(); 199 JNIEnv* env = AttachCurrentThread();
455
456 // |width| and/or |height| are kept for the next TakePhoto()s. 200 // |width| and/or |height| are kept for the next TakePhoto()s.
457 if (settings->has_width || settings->has_height) 201 if (settings->has_width || settings->has_height)
458 next_photo_resolution_.SetSize(0, 0); 202 next_photo_resolution_.SetSize(0, 0);
459 if (settings->has_width) { 203 if (settings->has_width) {
460 next_photo_resolution_.set_width( 204 next_photo_resolution_.set_width(
461 base::saturated_cast<int>(settings->width)); 205 base::saturated_cast<int>(settings->width));
462 } 206 }
463 if (settings->has_height) { 207 if (settings->has_height) {
464 next_photo_resolution_.set_height( 208 next_photo_resolution_.set_height(
465 base::saturated_cast<int>(settings->height)); 209 base::saturated_cast<int>(settings->height));
466 } 210 }
467 211
468 if (settings->has_zoom) 212 if (settings->has_zoom)
469 Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom); 213 Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom);
470
471 callback.Run(true); 214 callback.Run(true);
472 } 215 }
473 216
217 void VideoCaptureDeviceAndroid::OnFrameAvailable(
218 JNIEnv* env,
219 const JavaParamRef<jobject>& obj,
220 const JavaParamRef<jbyteArray>& data,
221 jint length,
222 jint rotation) {
223 {
224 base::AutoLock lock(lock_);
225 if (state_ != kCapturing || !client_)
226 return;
227 }
228
229 jbyte* buffer = env->GetByteArrayElements(data, NULL);
230 if (!buffer) {
231 LOG(ERROR) << "VideoCaptureDeviceAndroid::OnFrameAvailable: "
232 "failed to GetByteArrayElements";
233 return;
234 }
235
236 const base::TimeTicks current_time = base::TimeTicks::Now();
237 if (!got_first_frame_) {
238 // Set aside one frame allowance for fluctuation.
239 expected_next_frame_time_ = current_time - frame_interval_;
240 first_ref_time_ = current_time;
241 got_first_frame_ = true;
242 }
243
244 // Deliver the frame when it doesn't arrive too early.
245 if (expected_next_frame_time_ <= current_time) {
246 expected_next_frame_time_ += frame_interval_;
247
248 // TODO(qiangchen): Investigate how to get raw timestamp for Android,
249 // rather than using reference time to calculate timestamp.
250 base::AutoLock lock(lock_);
251 if (!client_)
252 return;
253 client_->OnIncomingCapturedData(reinterpret_cast<uint8_t*>(buffer), length,
254 capture_format_, rotation, current_time,
255 current_time - first_ref_time_);
256 }
257
258 env->ReleaseByteArrayElements(data, buffer, JNI_ABORT);
259 }
260
261 void VideoCaptureDeviceAndroid::OnI420FrameAvailable(JNIEnv* env,
262 jobject obj,
263 jobject y_buffer,
264 jint y_stride,
265 jobject u_buffer,
266 jobject v_buffer,
267 jint uv_row_stride,
268 jint uv_pixel_stride,
269 jint width,
270 jint height,
271 jint rotation) {
272 {
273 base::AutoLock lock(lock_);
274 if (state_ != kCapturing || !client_)
275 return;
276 }
277
278 const base::TimeTicks current_time = base::TimeTicks::Now();
279 if (!got_first_frame_) {
280 // Set aside one frame allowance for fluctuation.
281 expected_next_frame_time_ = current_time - frame_interval_;
282 first_ref_time_ = current_time;
283 got_first_frame_ = true;
284 }
285
286 uint8_t* const y_src =
287 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(y_buffer));
288 CHECK(y_src);
289 uint8_t* const u_src =
290 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(u_buffer));
291 CHECK(u_src);
292 uint8_t* const v_src =
293 reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(v_buffer));
294 CHECK(v_src);
295
296 const int y_plane_length = width * height;
297 const int uv_plane_length = y_plane_length / 4;
298 const int buffer_length = y_plane_length + uv_plane_length * 2;
299 std::unique_ptr<uint8_t> buffer(new uint8_t[buffer_length]);
300
301 libyuv::Android420ToI420(y_src, y_stride, u_src, uv_row_stride, v_src,
302 uv_row_stride, uv_pixel_stride, buffer.get(), width,
303 buffer.get() + y_plane_length, width / 2,
304 buffer.get() + y_plane_length + uv_plane_length,
305 width / 2, width, height);
306
307 // Deliver the frame when it doesn't arrive too early.
308 if (expected_next_frame_time_ <= current_time) {
309 expected_next_frame_time_ += frame_interval_;
310
311 // TODO(qiangchen): Investigate how to get raw timestamp for Android,
312 // rather than using reference time to calculate timestamp.
313 base::AutoLock lock(lock_);
314 if (!client_)
315 return;
316 client_->OnIncomingCapturedData(buffer.get(), buffer_length,
317 capture_format_, rotation, current_time,
318 current_time - first_ref_time_);
319 }
320 }
321
322 void VideoCaptureDeviceAndroid::OnError(JNIEnv* env,
323 const JavaParamRef<jobject>& obj,
324 const JavaParamRef<jstring>& message) {
325 SetErrorState(FROM_HERE,
326 base::android::ConvertJavaStringToUTF8(env, message));
327 }
328
329 void VideoCaptureDeviceAndroid::OnPhotoTaken(
330 JNIEnv* env,
331 const base::android::JavaParamRef<jobject>& obj,
332 jlong callback_id,
333 const base::android::JavaParamRef<jbyteArray>& data) {
334 DCHECK(callback_id);
335
336 base::AutoLock lock(photo_callbacks_lock_);
337
338 TakePhotoCallback* const cb =
339 reinterpret_cast<TakePhotoCallback*>(callback_id);
340 // Search for the pointer |cb| in the list of |photo_callbacks_|.
341 const auto reference_it =
342 std::find_if(photo_callbacks_.begin(), photo_callbacks_.end(),
343 [cb](const std::unique_ptr<TakePhotoCallback>& callback) {
344 return callback.get() == cb;
345 });
346 if (reference_it == photo_callbacks_.end()) {
347 NOTREACHED() << "|callback_id| not found.";
348 return;
349 }
350
351 mojom::BlobPtr blob = mojom::Blob::New();
352 base::android::JavaByteArrayToByteVector(env, data.obj(), &blob->data);
353 blob->mime_type = blob->data.empty() ? "" : "image/jpeg";
354 cb->Run(std::move(blob));
355
356 photo_callbacks_.erase(reference_it);
357 }
358
359 VideoPixelFormat VideoCaptureDeviceAndroid::GetColorspace() {
360 JNIEnv* env = AttachCurrentThread();
361 const int current_capture_colorspace =
362 Java_VideoCapture_getColorspace(env, j_capture_.obj());
363 switch (current_capture_colorspace) {
364 case ANDROID_IMAGE_FORMAT_YV12:
365 return media::PIXEL_FORMAT_YV12;
366 case ANDROID_IMAGE_FORMAT_YUV_420_888:
367 return media::PIXEL_FORMAT_I420;
368 case ANDROID_IMAGE_FORMAT_NV21:
369 return media::PIXEL_FORMAT_NV21;
370 case ANDROID_IMAGE_FORMAT_UNKNOWN:
371 default:
372 return media::PIXEL_FORMAT_UNKNOWN;
373 }
374 }
375
376 void VideoCaptureDeviceAndroid::SetErrorState(
377 const tracked_objects::Location& from_here,
378 const std::string& reason) {
379 {
380 base::AutoLock lock(lock_);
381 state_ = kError;
382 if (!client_)
383 return;
384 client_->OnError(from_here, reason);
385 }
386 }
387
474 } // namespace media 388 } // 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