Chromium Code Reviews| Index: media/capture/video/android/video_capture_device_android.cc |
| diff --git a/media/capture/video/android/video_capture_device_android.cc b/media/capture/video/android/video_capture_device_android.cc |
| index 3d0774c2307a907b8e3858b12e3c1e012d02232f..446bec6fb9716907727661bca177114276eead1e 100644 |
| --- a/media/capture/video/android/video_capture_device_android.cc |
| +++ b/media/capture/video/android/video_capture_device_android.cc |
| @@ -12,6 +12,7 @@ |
| #include "base/android/jni_string.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/strings/string_number_conversions.h" |
| +#include "base/threading/thread_task_runner_handle.h" |
| #include "jni/VideoCapture_jni.h" |
| #include "media/capture/video/android/photo_capabilities.h" |
| #include "media/capture/video/android/video_capture_device_factory_android.h" |
| @@ -33,12 +34,14 @@ bool VideoCaptureDeviceAndroid::RegisterVideoCaptureDevice(JNIEnv* env) { |
| VideoCaptureDeviceAndroid::VideoCaptureDeviceAndroid( |
| const VideoCaptureDeviceDescriptor& device_descriptor) |
| - : state_(kIdle), |
| + : main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| + state_(kIdle), |
| got_first_frame_(false), |
| - device_descriptor_(device_descriptor) {} |
| + device_descriptor_(device_descriptor), |
| + weak_ptr_factory_(this) {} |
| VideoCaptureDeviceAndroid::~VideoCaptureDeviceAndroid() { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| StopAndDeAllocate(); |
| } |
| @@ -55,7 +58,7 @@ bool VideoCaptureDeviceAndroid::Init() { |
| void VideoCaptureDeviceAndroid::AllocateAndStart( |
| const VideoCaptureParams& params, |
| std::unique_ptr<Client> client) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| { |
| base::AutoLock lock(lock_); |
| if (state_ != kIdle) |
| @@ -104,15 +107,15 @@ void VideoCaptureDeviceAndroid::AllocateAndStart( |
| { |
| base::AutoLock lock(lock_); |
| - state_ = kCapturing; |
| + state_ = kConfigured; |
| } |
| } |
| void VideoCaptureDeviceAndroid::StopAndDeAllocate() { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| { |
| base::AutoLock lock(lock_); |
| - if (state_ != kCapturing && state_ != kError) |
| + if (state_ != kConfigured && state_ != kError) |
| return; |
| } |
| @@ -134,84 +137,55 @@ void VideoCaptureDeviceAndroid::StopAndDeAllocate() { |
| } |
| void VideoCaptureDeviceAndroid::TakePhoto(TakePhotoCallback callback) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| { |
| base::AutoLock lock(lock_); |
| - if (state_ != kCapturing) |
| + if (state_ != kConfigured) |
| return; |
| + if (!got_first_frame_) { // We have to wait until we get the first frame. |
| + photo_requests_queue_.push_back( |
| + base::Bind(&VideoCaptureDeviceAndroid::DoTakePhoto, |
| + weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback))); |
| + return; |
| + } |
| } |
| - |
| - JNIEnv* env = AttachCurrentThread(); |
| - |
| - // Make copy on the heap so we can pass the pointer through JNI. |
| - std::unique_ptr<TakePhotoCallback> heap_callback( |
| - new TakePhotoCallback(std::move(callback))); |
| - const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get()); |
| - if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id, |
| - next_photo_resolution_.width(), |
| - next_photo_resolution_.height())) |
| - return; |
| - |
| - { |
| - base::AutoLock lock(photo_callbacks_lock_); |
| - photo_callbacks_.push_back(std::move(heap_callback)); |
| - } |
| + DoTakePhoto(std::move(callback)); |
| } |
| void VideoCaptureDeviceAndroid::GetPhotoCapabilities( |
| GetPhotoCapabilitiesCallback callback) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - JNIEnv* env = AttachCurrentThread(); |
| - |
| - PhotoCapabilities caps( |
| - Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj())); |
| - |
| - // TODO(mcasas): Manual member copying sucks, consider adding typemapping from |
| - // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002. |
| - mojom::PhotoCapabilitiesPtr photo_capabilities = |
| - mojom::PhotoCapabilities::New(); |
| - photo_capabilities->iso = mojom::Range::New(); |
| - photo_capabilities->iso->current = caps.getCurrentIso(); |
| - photo_capabilities->iso->max = caps.getMaxIso(); |
| - photo_capabilities->iso->min = caps.getMinIso(); |
| - photo_capabilities->height = mojom::Range::New(); |
| - photo_capabilities->height->current = caps.getCurrentHeight(); |
| - photo_capabilities->height->max = caps.getMaxHeight(); |
| - photo_capabilities->height->min = caps.getMinHeight(); |
| - photo_capabilities->width = mojom::Range::New(); |
| - photo_capabilities->width->current = caps.getCurrentWidth(); |
| - photo_capabilities->width->max = caps.getMaxWidth(); |
| - photo_capabilities->width->min = caps.getMinWidth(); |
| - photo_capabilities->zoom = mojom::Range::New(); |
| - photo_capabilities->zoom->current = caps.getCurrentZoom(); |
| - photo_capabilities->zoom->max = caps.getMaxZoom(); |
| - photo_capabilities->zoom->min = caps.getMinZoom(); |
| - photo_capabilities->focus_mode = caps.getAutoFocusInUse() |
| - ? mojom::FocusMode::AUTO |
| - : mojom::FocusMode::MANUAL; |
| - callback.Run(std::move(photo_capabilities)); |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| + { |
| + base::AutoLock lock(lock_); |
| + if (state_ != kConfigured) |
| + return; |
| + if (!got_first_frame_) { // We have to wait until we get the first frame. |
| + photo_requests_queue_.push_back( |
| + base::Bind(&VideoCaptureDeviceAndroid::DoGetPhotoCapabilities, |
| + weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback))); |
| + return; |
| + } |
| + } |
| + DoGetPhotoCapabilities(std::move(callback)); |
| } |
| void VideoCaptureDeviceAndroid::SetPhotoOptions( |
| mojom::PhotoSettingsPtr settings, |
| SetPhotoOptionsCallback callback) { |
| - DCHECK(thread_checker_.CalledOnValidThread()); |
| - JNIEnv* env = AttachCurrentThread(); |
| - // |width| and/or |height| are kept for the next TakePhoto()s. |
| - if (settings->has_width || settings->has_height) |
| - next_photo_resolution_.SetSize(0, 0); |
| - if (settings->has_width) { |
| - next_photo_resolution_.set_width( |
| - base::saturated_cast<int>(settings->width)); |
| - } |
| - if (settings->has_height) { |
| - next_photo_resolution_.set_height( |
| - base::saturated_cast<int>(settings->height)); |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| + { |
| + base::AutoLock lock(lock_); |
| + if (state_ != kConfigured) |
| + return; |
| + if (!got_first_frame_) { // We have to wait until we get the first frame. |
| + photo_requests_queue_.push_back( |
| + base::Bind(&VideoCaptureDeviceAndroid::DoSetPhotoOptions, |
| + weak_ptr_factory_.GetWeakPtr(), base::Passed(&settings), |
| + base::Passed(&callback))); |
| + return; |
| + } |
| } |
| - |
| - if (settings->has_zoom) |
| - Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom); |
| - callback.Run(true); |
| + DoSetPhotoOptions(std::move(settings), std::move(callback)); |
| } |
| void VideoCaptureDeviceAndroid::OnFrameAvailable( |
| @@ -222,7 +196,7 @@ void VideoCaptureDeviceAndroid::OnFrameAvailable( |
| jint rotation) { |
| { |
| base::AutoLock lock(lock_); |
| - if (state_ != kCapturing || !client_) |
| + if (state_ != kConfigured || !client_) |
| return; |
| } |
| @@ -234,11 +208,17 @@ void VideoCaptureDeviceAndroid::OnFrameAvailable( |
| } |
| const base::TimeTicks current_time = base::TimeTicks::Now(); |
| - if (!got_first_frame_) { |
| - // Set aside one frame allowance for fluctuation. |
| - expected_next_frame_time_ = current_time - frame_interval_; |
| - first_ref_time_ = current_time; |
| - got_first_frame_ = true; |
| + { |
| + base::AutoLock lock(lock_); |
| + if (!got_first_frame_) { |
| + // Set aside one frame allowance for fluctuation. |
| + expected_next_frame_time_ = current_time - frame_interval_; |
| + first_ref_time_ = current_time; |
| + got_first_frame_ = true; |
| + |
| + for (const auto& request : photo_requests_queue_) |
| + 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.
|
| + } |
| } |
| // Deliver the frame when it doesn't arrive too early. |
| @@ -271,16 +251,23 @@ void VideoCaptureDeviceAndroid::OnI420FrameAvailable(JNIEnv* env, |
| jint rotation) { |
| { |
| base::AutoLock lock(lock_); |
| - if (state_ != kCapturing || !client_) |
| + if (state_ != kConfigured || !client_) |
| return; |
| } |
| const base::TimeTicks current_time = base::TimeTicks::Now(); |
| - if (!got_first_frame_) { |
| - // Set aside one frame allowance for fluctuation. |
| - expected_next_frame_time_ = current_time - frame_interval_; |
| - first_ref_time_ = current_time; |
| - got_first_frame_ = true; |
| + { |
| + base::AutoLock lock(lock_); |
| + if (!got_first_frame_) { |
| + // Set aside one frame allowance for fluctuation. |
| + expected_next_frame_time_ = current_time - frame_interval_; |
| + first_ref_time_ = current_time; |
| + got_first_frame_ = true; |
| + |
| + for (const auto& request : photo_requests_queue_) |
| + main_task_runner_->PostTask(FROM_HERE, request); |
| + photo_requests_queue_.clear(); |
| + } |
| } |
| uint8_t* const y_src = |
| @@ -385,4 +372,102 @@ void VideoCaptureDeviceAndroid::SetErrorState( |
| } |
| } |
| +void VideoCaptureDeviceAndroid::DoTakePhoto(TakePhotoCallback callback) { |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| +#if DCHECK_IS_ON() |
| + { |
| + base::AutoLock lock(lock_); |
| + DCHECK_EQ(kConfigured, state_); |
| + DCHECK(got_first_frame_); |
| + } |
| +#endif |
| + JNIEnv* env = AttachCurrentThread(); |
| + |
| + // Make copy on the heap so we can pass the pointer through JNI. |
| + std::unique_ptr<TakePhotoCallback> heap_callback( |
| + new TakePhotoCallback(std::move(callback))); |
| + const intptr_t callback_id = reinterpret_cast<intptr_t>(heap_callback.get()); |
| + if (!Java_VideoCapture_takePhoto(env, j_capture_.obj(), callback_id, |
| + next_photo_resolution_.width(), |
| + next_photo_resolution_.height())) |
| + return; |
| + |
| + { |
| + base::AutoLock lock(photo_callbacks_lock_); |
| + photo_callbacks_.push_back(std::move(heap_callback)); |
| + } |
| +} |
| + |
| +void VideoCaptureDeviceAndroid::DoGetPhotoCapabilities( |
| + GetPhotoCapabilitiesCallback callback) { |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| +#if DCHECK_IS_ON() |
| + { |
| + base::AutoLock lock(lock_); |
| + DCHECK_EQ(kConfigured, state_); |
| + DCHECK(got_first_frame_); |
| + } |
| +#endif |
| + JNIEnv* env = AttachCurrentThread(); |
| + |
| + PhotoCapabilities caps( |
| + Java_VideoCapture_getPhotoCapabilities(env, j_capture_.obj())); |
| + |
| + // TODO(mcasas): Manual member copying sucks, consider adding typemapping from |
| + // PhotoCapabilities to mojom::PhotoCapabilitiesPtr, https://crbug.com/622002. |
| + mojom::PhotoCapabilitiesPtr photo_capabilities = |
| + mojom::PhotoCapabilities::New(); |
| + photo_capabilities->iso = mojom::Range::New(); |
| + photo_capabilities->iso->current = caps.getCurrentIso(); |
| + photo_capabilities->iso->max = caps.getMaxIso(); |
| + photo_capabilities->iso->min = caps.getMinIso(); |
| + photo_capabilities->height = mojom::Range::New(); |
| + photo_capabilities->height->current = caps.getCurrentHeight(); |
| + photo_capabilities->height->max = caps.getMaxHeight(); |
| + photo_capabilities->height->min = caps.getMinHeight(); |
| + photo_capabilities->width = mojom::Range::New(); |
| + photo_capabilities->width->current = caps.getCurrentWidth(); |
| + photo_capabilities->width->max = caps.getMaxWidth(); |
| + photo_capabilities->width->min = caps.getMinWidth(); |
| + photo_capabilities->zoom = mojom::Range::New(); |
| + photo_capabilities->zoom->current = caps.getCurrentZoom(); |
| + photo_capabilities->zoom->max = caps.getMaxZoom(); |
| + photo_capabilities->zoom->min = caps.getMinZoom(); |
| + photo_capabilities->focus_mode = caps.getAutoFocusInUse() |
| + ? mojom::FocusMode::AUTO |
| + : mojom::FocusMode::MANUAL; |
| + callback.Run(std::move(photo_capabilities)); |
| +} |
| + |
| +void VideoCaptureDeviceAndroid::DoSetPhotoOptions( |
| + mojom::PhotoSettingsPtr settings, |
| + SetPhotoOptionsCallback callback) { |
| + DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| +#if DCHECK_IS_ON() |
| + { |
| + base::AutoLock lock(lock_); |
| + DCHECK_EQ(kConfigured, state_); |
| + DCHECK(got_first_frame_); |
| + } |
| +#endif |
| + JNIEnv* env = AttachCurrentThread(); |
| + |
| + // |width| and/or |height| are kept for the next TakePhoto()s. |
| + if (settings->has_width || settings->has_height) |
| + next_photo_resolution_.SetSize(0, 0); |
| + if (settings->has_width) { |
| + next_photo_resolution_.set_width( |
| + base::saturated_cast<int>(settings->width)); |
| + } |
| + if (settings->has_height) { |
| + next_photo_resolution_.set_height( |
| + base::saturated_cast<int>(settings->height)); |
| + } |
| + |
| + if (settings->has_zoom) |
| + Java_VideoCapture_setZoom(env, j_capture_.obj(), settings->zoom); |
| + |
| + callback.Run(true); |
| +} |
| + |
| } // namespace media |