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

Unified Diff: media/capture/video/chromeos/video_capture_device_arc_chromeos.cc

Issue 2837273004: media: add video capture device for ARC++ camera HAL v3 (Closed)
Patch Set: Created 3 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: media/capture/video/chromeos/video_capture_device_arc_chromeos.cc
diff --git a/media/capture/video/chromeos/video_capture_device_arc_chromeos.cc b/media/capture/video/chromeos/video_capture_device_arc_chromeos.cc
new file mode 100644
index 0000000000000000000000000000000000000000..53d4a8515e8d185d3dc5a5a45d64e9c7a6663d7e
--- /dev/null
+++ b/media/capture/video/chromeos/video_capture_device_arc_chromeos.cc
@@ -0,0 +1,324 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/video/chromeos/video_capture_device_arc_chromeos.h"
+
+#include "media/capture/video/chromeos/camera_device_delegate.h"
+#include "media/capture/video/chromeos/camera_hal_delegate.h"
+#include "ui/display/display.h"
+#include "ui/display/display_observer.h"
+#include "ui/display/screen.h"
+
+namespace media {
+
+using namespace arc::mojom;
+
+// This is a delegate class used to transfer Display change events from the UI
+// thread to the media thread.
+class VideoCaptureDeviceArcChromeOS::ScreenObserverDelegate
chfremer 2017/04/26 21:13:05 Please add comment explaining why the raw pointer
jcliang 2017/04/27 07:07:56 Done.
+ : public display::DisplayObserver,
+ public base::RefCountedThreadSafe<ScreenObserverDelegate> {
+ public:
+ ScreenObserverDelegate(
+ VideoCaptureDeviceArcChromeOS* capture_device,
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
+ : capture_device_(capture_device),
+ ui_task_runner_(ui_task_runner),
+ capture_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ScreenObserverDelegate::AddObserverOnUIThread, this));
+ }
+
+ void RemoveObserver() {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ capture_device_ = nullptr;
+ ui_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ScreenObserverDelegate::RemoveObserverOnUIThread, this));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<ScreenObserverDelegate>;
+
+ ~ScreenObserverDelegate() override { DCHECK(!capture_device_); }
+
+ void OnDisplayAdded(const display::Display& /*new_display*/) override {}
+ void OnDisplayRemoved(const display::Display& /*old_display*/) override {}
+ void OnDisplayMetricsChanged(const display::Display& display,
+ uint32_t metrics) override {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ if (!(metrics & DISPLAY_METRIC_ROTATION))
+ return;
+ SendDisplayRotation(display);
+ }
+
+ void AddObserverOnUIThread() {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ display::Screen* screen = display::Screen::GetScreen();
+ if (screen) {
+ screen->AddObserver(this);
+ SendDisplayRotation(screen->GetPrimaryDisplay());
+ }
+ }
+
+ void RemoveObserverOnUIThread() {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ display::Screen* screen = display::Screen::GetScreen();
+ if (screen)
+ screen->RemoveObserver(this);
+ }
+
+ // Post the screen rotation change from the UI thread to capture thread
+ void SendDisplayRotation(const display::Display& display) {
+ DCHECK(ui_task_runner_->BelongsToCurrentThread());
+ capture_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&ScreenObserverDelegate::SendDisplayRotationOnCaptureThread,
+ this, display));
+ }
+
+ void SendDisplayRotationOnCaptureThread(const display::Display& display) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ if (capture_device_)
+ capture_device_->SetDisplayRotation(display);
+ }
+
+ VideoCaptureDeviceArcChromeOS* capture_device_;
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ScreenObserverDelegate);
+};
+
+VideoCaptureDeviceArcChromeOS::VideoCaptureDeviceArcChromeOS(
+ scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
+ const VideoCaptureDeviceDescriptor& device_descriptor,
+ scoped_refptr<CameraHalDelegate> camera_hal_delegate)
+ : device_descriptor_(device_descriptor),
+ camera_hal_delegate_(camera_hal_delegate),
+ capture_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ device_thread_("CameraDeviceThread"),
+ starting_(false),
+ stopping_(false),
+ // TODO(jcliang): Determine |lens_facing_| and |camera_orientation_| from
+ // static characteristics. We should probably defer the
+ // initialization of |screen_observer_delegate_| until
+ // after we get the static characteristics in
+ // OnGotCameraInfo.
+ screen_observer_delegate_(
+ new ScreenObserverDelegate(this, ui_task_runner)),
+ lens_facing_(VideoFacingMode::MEDIA_VIDEO_FACING_USER),
+ camera_orientation_(0),
+ // External cameras have lens_facing as MEDIA_VIDEO_FACING_NONE.
+ // We don't want to rotate the frame even if the device rotates.
+ rotates_with_device_(lens_facing_ !=
+ VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {}
+
+VideoCaptureDeviceArcChromeOS::~VideoCaptureDeviceArcChromeOS() {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ DCHECK(!device_thread_.IsRunning());
+ screen_observer_delegate_->RemoveObserver();
+}
+
+// static
+VideoPixelFormat VideoCaptureDeviceArcChromeOS::PixFormatHalToChromium(
+ HalPixelFormat from) {
+ return CameraDeviceDelegate::PixFormatHalToChromium(from);
+}
+
+// static
+uint32_t VideoCaptureDeviceArcChromeOS::PixFormatChromiumToDrm(
+ VideoPixelFormat from) {
+ return CameraDeviceDelegate::PixFormatChromiumToDrm(from);
+}
+
+// VideoCaptureDevice implementation.
+void VideoCaptureDeviceArcChromeOS::AllocateAndStart(
+ const VideoCaptureParams& params,
+ std::unique_ptr<Client> client) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ DCHECK(!camera_device_delegate_);
chfremer 2017/04/26 21:13:05 Would we be hitting this when a client calls Alloc
jcliang 2017/04/27 07:07:56 It wouldn't hit this DCHECK. I'll add some comment
+ starting_ = true;
+ int32_t camera_id = std::stoi(device_descriptor_.device_id);
+ camera_hal_delegate_->GetCameraInfo(
+ camera_id,
+ base::Bind(&VideoCaptureDeviceArcChromeOS::OnGotCameraInfo,
+ base::Unretained(this), params, base::Passed(&client)));
+}
+
+void VideoCaptureDeviceArcChromeOS::StopAndDeAllocate() {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ stopping_ = true;
+ // StopAndDeAllocate is called only after AllocateAndStart. We have two cases
+ // here: |camera_device_delegate_| is either created, or being created. If
+ // |camera_device_delegate_| is already created then we simply close the
+ // camera device here; otherwise we defer to CreateDeviceOnCaptureThread to
+ // close the camera device right after camera HAL has opened the camera
+ // device.
+ if (camera_device_delegate_) {
+ base::WaitableEvent closed(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ device_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&CameraDeviceDelegate::StopAndDeAllocate,
+ camera_device_delegate_, base::Unretained(&closed)));
+ closed.Wait();
+ camera_device_delegate_ = nullptr;
+ device_thread_.Stop();
+ stopping_ = false;
+ }
+}
+
+void VideoCaptureDeviceArcChromeOS::TakePhoto(TakePhotoCallback callback) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ DCHECK(camera_device_delegate_);
+ device_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&CameraDeviceDelegate::TakePhoto,
+ camera_device_delegate_, base::Passed(&callback)));
+}
+
+void VideoCaptureDeviceArcChromeOS::GetPhotoCapabilities(
+ GetPhotoCapabilitiesCallback callback) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ device_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&CameraDeviceDelegate::GetPhotoCapabilities,
+ camera_device_delegate_, base::Passed(&callback)));
+}
+
+void VideoCaptureDeviceArcChromeOS::OnGotCameraInfo(
+ const VideoCaptureParams& params,
+ std::unique_ptr<Client> client,
+ int32_t result,
+ CameraInfoPtr camera_info) {
+ // This method runs on |module_task_runner_| of |camera_hal_delegate_|.
+ if (result) {
+ client->OnError(FROM_HERE, "Failed to get camera info");
+ return;
+ }
+ int32_t camera_id = std::stoi(device_descriptor_.device_id);
+ camera_hal_delegate_->OpenDevice(
+ camera_id,
+ base::Bind(&VideoCaptureDeviceArcChromeOS::OnOpenedDevice,
+ base::Unretained(this), params, base::Passed(&client),
+ base::Passed(&camera_info->static_camera_characteristics)));
+}
+
+void VideoCaptureDeviceArcChromeOS::OnOpenedDevice(
+ const VideoCaptureParams& params,
+ std::unique_ptr<Client> client,
+ CameraMetadataPtr static_metadata,
+ int32_t result,
+ Camera3DeviceOpsPtr device_ops) {
+ // This method runs on |module_task_runner_| of |camera_hal_delegate_|.
+ if (result) {
+ client->OnError(FROM_HERE, "Failed to open camera device");
+ return;
+ }
+ mojo::InterfacePtrInfo<Camera3DeviceOps> device_ops_info =
+ device_ops.PassInterface();
+ capture_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&VideoCaptureDeviceArcChromeOS::CreateDeviceOnCaptureThread,
+ base::Unretained(this), params, base::Passed(&client),
+ base::Passed(&static_metadata), result,
+ base::Passed(&device_ops_info)));
+}
+
+void VideoCaptureDeviceArcChromeOS::CreateDeviceOnCaptureThread(
+ const VideoCaptureParams& params,
+ std::unique_ptr<Client> client,
+ CameraMetadataPtr static_metadata,
+ int32_t result,
+ mojo::InterfacePtrInfo<Camera3DeviceOps> device_ops_info) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+
+ starting_ = false;
+ if (stopping_) {
+ // A StopAndDeAllocate call was made.
+ Camera3DeviceOpsPtr device_ops;
+ device_ops.Bind(std::move(device_ops_info));
+ base::Callback<void(int32_t)> dont_care = base::Bind([](int32_t result) {});
+ // We don't need to worry about the return value of the Close mojo call here
+ // since the Camera3DeviceOps proxy will be terminated immediately. The next
+ // AllocateAndStart will create a new Camera3DeviceOps proxy.
+ device_ops->Close(dont_care);
+ stopping_ = false;
+ return;
+ }
+ device_thread_.Start();
+ camera_device_delegate_ = new CameraDeviceDelegate(
+ device_descriptor_, std::move(static_metadata),
+ std::move(device_ops_info), device_thread_.task_runner());
+ device_thread_.task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&CameraDeviceDelegate::AllocateAndStart,
+ camera_device_delegate_, params, base::Passed(&client)));
+}
+
+void VideoCaptureDeviceArcChromeOS::SetPhotoOptions(
+ mojom::PhotoSettingsPtr settings,
+ SetPhotoOptionsCallback callback) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ device_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&CameraDeviceDelegate::SetPhotoOptions,
+ camera_device_delegate_, base::Passed(&settings),
+ base::Passed(&callback)));
+}
+
+void VideoCaptureDeviceArcChromeOS::SetRotation(int rotation) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ if (!rotates_with_device_) {
+ rotation = 0;
+ } else if (lens_facing_ == VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) {
+ // Original frame when |rotation| = 0
+ // -----------------------
+ // | * |
+ // | * * |
+ // | * * |
+ // | ******* |
+ // | * * |
+ // | * * |
+ // -----------------------
+ //
+ // |rotation| = 90, this is what back camera sees
+ // -----------------------
+ // | ******** |
+ // | * **** |
+ // | * *** |
+ // | * *** |
+ // | * **** |
+ // | ******** |
+ // -----------------------
+ //
+ // |rotation| = 90, this is what front camera sees
+ // -----------------------
+ // | ******** |
+ // | **** * |
+ // | *** * |
+ // | *** * |
+ // | **** * |
+ // | ******** |
+ // -----------------------
+ //
+ // Therefore, for back camera, we need to rotate (360 - |rotation|).
+ rotation = (360 - rotation) % 360;
+ }
+ // Take into account camera orientation w.r.t. the display. External cameras
+ // would have camera_orientation_ as 0.
+ rotation = (rotation + camera_orientation_) % 360;
+ if (device_thread_.IsRunning()) {
+ device_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(&CameraDeviceDelegate::SetRotation,
+ camera_device_delegate_, rotation));
+ }
+}
+
+void VideoCaptureDeviceArcChromeOS::SetDisplayRotation(
+ const display::Display& display) {
+ DCHECK(capture_task_runner_->BelongsToCurrentThread());
+ if (display.IsInternal())
+ SetRotation(display.rotation() * 90);
+}
+
+} // namespace media

Powered by Google App Engine
This is Rietveld 408576698