| 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 a0596b5095c8699cd0b0e1ac3c5a01cee6341665..8df6ca9226053c4bc5c180c10ae00ddeee220222 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"
|
| @@ -34,12 +35,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();
|
| }
|
|
|
| @@ -56,7 +59,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)
|
| @@ -105,15 +108,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;
|
| }
|
|
|
| @@ -135,84 +138,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(
|
| @@ -223,7 +197,7 @@ void VideoCaptureDeviceAndroid::OnFrameAvailable(
|
| jint rotation) {
|
| {
|
| base::AutoLock lock(lock_);
|
| - if (state_ != kCapturing || !client_)
|
| + if (state_ != kConfigured || !client_)
|
| return;
|
| }
|
|
|
| @@ -235,11 +209,18 @@ 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);
|
| + photo_requests_queue_.clear();
|
| + }
|
| }
|
|
|
| // Deliver the frame when it doesn't arrive too early.
|
| @@ -272,16 +253,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 =
|
| @@ -386,4 +374,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
|
|
|