| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "media/capture/video/chromeos/video_capture_device_arc_chromeos.h" |
| 6 |
| 7 #include "media/capture/video/chromeos/camera_device_delegate.h" |
| 8 #include "media/capture/video/chromeos/camera_hal_delegate.h" |
| 9 #include "ui/display/display.h" |
| 10 #include "ui/display/display_observer.h" |
| 11 #include "ui/display/screen.h" |
| 12 |
| 13 namespace media { |
| 14 |
| 15 namespace { |
| 16 |
| 17 const base::TimeDelta kEventWaitTimeoutMs = |
| 18 base::TimeDelta::FromMilliseconds(3000); |
| 19 |
| 20 } // namespace |
| 21 |
| 22 // This is a delegate class used to transfer Display change events from the UI |
| 23 // thread to the media thread. |
| 24 class VideoCaptureDeviceArcChromeOS::ScreenObserverDelegate |
| 25 : public display::DisplayObserver, |
| 26 public base::RefCountedThreadSafe<ScreenObserverDelegate> { |
| 27 public: |
| 28 // It is safe to use the raw pointer |capture_device| as |
| 29 // VideoCaptureDeviceArcChromeOS owns the ScreenObserverDelegate instance and |
| 30 // we make sure the VideoCaptureDeviceArcChromeOS instance outlives the |
| 31 // ScreenObserverDelegate instance. |
| 32 ScreenObserverDelegate( |
| 33 VideoCaptureDeviceArcChromeOS* capture_device, |
| 34 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
| 35 : capture_device_(capture_device), |
| 36 ui_task_runner_(ui_task_runner), |
| 37 capture_task_runner_(base::ThreadTaskRunnerHandle::Get()) { |
| 38 ui_task_runner_->PostTask( |
| 39 FROM_HERE, |
| 40 base::Bind(&ScreenObserverDelegate::AddObserverOnUIThread, this)); |
| 41 } |
| 42 |
| 43 void RemoveObserver() { |
| 44 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 45 capture_device_ = nullptr; |
| 46 ui_task_runner_->PostTask( |
| 47 FROM_HERE, |
| 48 base::Bind(&ScreenObserverDelegate::RemoveObserverOnUIThread, this)); |
| 49 } |
| 50 |
| 51 private: |
| 52 friend class base::RefCountedThreadSafe<ScreenObserverDelegate>; |
| 53 |
| 54 ~ScreenObserverDelegate() override { DCHECK(!capture_device_); } |
| 55 |
| 56 void OnDisplayAdded(const display::Display& /*new_display*/) override {} |
| 57 void OnDisplayRemoved(const display::Display& /*old_display*/) override {} |
| 58 void OnDisplayMetricsChanged(const display::Display& display, |
| 59 uint32_t metrics) override { |
| 60 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 61 if (!(metrics & DISPLAY_METRIC_ROTATION)) |
| 62 return; |
| 63 SendDisplayRotation(display); |
| 64 } |
| 65 |
| 66 void AddObserverOnUIThread() { |
| 67 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 68 display::Screen* screen = display::Screen::GetScreen(); |
| 69 if (screen) { |
| 70 screen->AddObserver(this); |
| 71 SendDisplayRotation(screen->GetPrimaryDisplay()); |
| 72 } |
| 73 } |
| 74 |
| 75 void RemoveObserverOnUIThread() { |
| 76 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 77 display::Screen* screen = display::Screen::GetScreen(); |
| 78 if (screen) |
| 79 screen->RemoveObserver(this); |
| 80 } |
| 81 |
| 82 // Post the screen rotation change from the UI thread to capture thread |
| 83 void SendDisplayRotation(const display::Display& display) { |
| 84 DCHECK(ui_task_runner_->BelongsToCurrentThread()); |
| 85 capture_task_runner_->PostTask( |
| 86 FROM_HERE, |
| 87 base::Bind(&ScreenObserverDelegate::SendDisplayRotationOnCaptureThread, |
| 88 this, display)); |
| 89 } |
| 90 |
| 91 void SendDisplayRotationOnCaptureThread(const display::Display& display) { |
| 92 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 93 if (capture_device_) |
| 94 capture_device_->SetDisplayRotation(display); |
| 95 } |
| 96 |
| 97 VideoCaptureDeviceArcChromeOS* capture_device_; |
| 98 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; |
| 99 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_; |
| 100 DISALLOW_IMPLICIT_CONSTRUCTORS(ScreenObserverDelegate); |
| 101 }; |
| 102 |
| 103 VideoCaptureDeviceArcChromeOS::VideoCaptureDeviceArcChromeOS( |
| 104 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| 105 const VideoCaptureDeviceDescriptor& device_descriptor, |
| 106 scoped_refptr<CameraHalDelegate> camera_hal_delegate) |
| 107 : device_descriptor_(device_descriptor), |
| 108 camera_hal_delegate_(camera_hal_delegate), |
| 109 capture_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 110 device_thread_("CameraDeviceThread"), |
| 111 screen_observer_delegate_( |
| 112 new ScreenObserverDelegate(this, std::move(ui_task_runner))), |
| 113 lens_facing_(device_descriptor.facing), |
| 114 camera_orientation_(0), |
| 115 // External cameras have lens_facing as MEDIA_VIDEO_FACING_NONE. |
| 116 // We don't want to rotate the frame even if the device rotates. |
| 117 rotates_with_device_(lens_facing_ != |
| 118 VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {} |
| 119 |
| 120 VideoCaptureDeviceArcChromeOS::~VideoCaptureDeviceArcChromeOS() { |
| 121 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 122 DCHECK(!device_thread_.IsRunning()); |
| 123 screen_observer_delegate_->RemoveObserver(); |
| 124 } |
| 125 |
| 126 // static |
| 127 VideoPixelFormat VideoCaptureDeviceArcChromeOS::PixFormatHalToChromium( |
| 128 arc::mojom::HalPixelFormat from) { |
| 129 return CameraDeviceDelegate::PixFormatHalToChromium(from); |
| 130 } |
| 131 |
| 132 // static |
| 133 uint32_t VideoCaptureDeviceArcChromeOS::PixFormatChromiumToDrm( |
| 134 VideoPixelFormat from) { |
| 135 return CameraDeviceDelegate::PixFormatChromiumToDrm(from); |
| 136 } |
| 137 |
| 138 // VideoCaptureDevice implementation. |
| 139 void VideoCaptureDeviceArcChromeOS::AllocateAndStart( |
| 140 const VideoCaptureParams& params, |
| 141 std::unique_ptr<Client> client) { |
| 142 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 143 DCHECK(!camera_device_delegate_); |
| 144 base::WaitableEvent started(base::WaitableEvent::ResetPolicy::MANUAL, |
| 145 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 146 int32_t camera_id = std::stoi(device_descriptor_.device_id); |
| 147 device_thread_.Start(); |
| 148 // We need to get the static camera metadata of the camera deivce first. |
| 149 camera_hal_delegate_->GetCameraInfo( |
| 150 camera_id, base::Bind(&VideoCaptureDeviceArcChromeOS::OnGotCameraInfo, |
| 151 base::Unretained(this), params, |
| 152 base::Passed(&client), base::Unretained(&started))); |
| 153 started.TimedWait(kEventWaitTimeoutMs); |
| 154 } |
| 155 |
| 156 void VideoCaptureDeviceArcChromeOS::StopAndDeAllocate() { |
| 157 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 158 if (camera_device_delegate_) { |
| 159 base::WaitableEvent closed(base::WaitableEvent::ResetPolicy::MANUAL, |
| 160 base::WaitableEvent::InitialState::NOT_SIGNALED); |
| 161 device_thread_.task_runner()->PostTask( |
| 162 FROM_HERE, |
| 163 base::Bind(&CameraDeviceDelegate::StopAndDeAllocate, |
| 164 camera_device_delegate_, base::Unretained(&closed))); |
| 165 closed.TimedWait(kEventWaitTimeoutMs); |
| 166 camera_device_delegate_ = nullptr; |
| 167 } |
| 168 device_thread_.Stop(); |
| 169 } |
| 170 |
| 171 void VideoCaptureDeviceArcChromeOS::TakePhoto(TakePhotoCallback callback) { |
| 172 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 173 DCHECK(camera_device_delegate_); |
| 174 device_thread_.task_runner()->PostTask( |
| 175 FROM_HERE, base::Bind(&CameraDeviceDelegate::TakePhoto, |
| 176 camera_device_delegate_, base::Passed(&callback))); |
| 177 } |
| 178 |
| 179 void VideoCaptureDeviceArcChromeOS::GetPhotoCapabilities( |
| 180 GetPhotoCapabilitiesCallback callback) { |
| 181 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 182 device_thread_.task_runner()->PostTask( |
| 183 FROM_HERE, base::Bind(&CameraDeviceDelegate::GetPhotoCapabilities, |
| 184 camera_device_delegate_, base::Passed(&callback))); |
| 185 } |
| 186 |
| 187 void VideoCaptureDeviceArcChromeOS::SetPhotoOptions( |
| 188 mojom::PhotoSettingsPtr settings, |
| 189 SetPhotoOptionsCallback callback) { |
| 190 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 191 device_thread_.task_runner()->PostTask( |
| 192 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetPhotoOptions, |
| 193 camera_device_delegate_, base::Passed(&settings), |
| 194 base::Passed(&callback))); |
| 195 } |
| 196 |
| 197 void VideoCaptureDeviceArcChromeOS::OnGotCameraInfo( |
| 198 const VideoCaptureParams& params, |
| 199 std::unique_ptr<Client> client, |
| 200 base::WaitableEvent* started, |
| 201 int32_t result, |
| 202 arc::mojom::CameraInfoPtr camera_info) { |
| 203 // This method runs on |module_task_runner_| of |camera_hal_delegate_|. |
| 204 if (result) { |
| 205 client->OnError(FROM_HERE, "Failed to get camera info"); |
| 206 return; |
| 207 } |
| 208 int32_t camera_id = std::stoi(device_descriptor_.device_id); |
| 209 camera_hal_delegate_->OpenDevice( |
| 210 camera_id, |
| 211 base::Bind(&VideoCaptureDeviceArcChromeOS::OnOpenedDevice, |
| 212 base::Unretained(this), params, base::Passed(&client), |
| 213 base::Unretained(started), |
| 214 base::Passed(&camera_info->static_camera_characteristics))); |
| 215 } |
| 216 |
| 217 void VideoCaptureDeviceArcChromeOS::OnOpenedDevice( |
| 218 const VideoCaptureParams& params, |
| 219 std::unique_ptr<Client> client, |
| 220 base::WaitableEvent* started, |
| 221 arc::mojom::CameraMetadataPtr static_metadata, |
| 222 int32_t result, |
| 223 arc::mojom::Camera3DeviceOpsPtr device_ops) { |
| 224 // This method runs on |module_task_runner_| of |camera_hal_delegate_|. |
| 225 if (result) { |
| 226 client->OnError(FROM_HERE, "Failed to open camera device"); |
| 227 return; |
| 228 } |
| 229 mojo::InterfacePtrInfo<arc::mojom::Camera3DeviceOps> device_ops_info = |
| 230 device_ops.PassInterface(); |
| 231 camera_device_delegate_ = new CameraDeviceDelegate( |
| 232 device_descriptor_, std::move(static_metadata), |
| 233 std::move(device_ops_info), device_thread_.task_runner()); |
| 234 device_thread_.task_runner()->PostTask( |
| 235 FROM_HERE, |
| 236 base::Bind(&CameraDeviceDelegate::AllocateAndStart, |
| 237 camera_device_delegate_, params, base::Passed(&client))); |
| 238 started->Signal(); |
| 239 } |
| 240 |
| 241 void VideoCaptureDeviceArcChromeOS::SetRotation(int rotation) { |
| 242 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 243 if (!rotates_with_device_) { |
| 244 rotation = 0; |
| 245 } else if (lens_facing_ == VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) { |
| 246 // Original frame when |rotation| = 0 |
| 247 // ----------------------- |
| 248 // | * | |
| 249 // | * * | |
| 250 // | * * | |
| 251 // | ******* | |
| 252 // | * * | |
| 253 // | * * | |
| 254 // ----------------------- |
| 255 // |
| 256 // |rotation| = 90, this is what back camera sees |
| 257 // ----------------------- |
| 258 // | ******** | |
| 259 // | * **** | |
| 260 // | * *** | |
| 261 // | * *** | |
| 262 // | * **** | |
| 263 // | ******** | |
| 264 // ----------------------- |
| 265 // |
| 266 // |rotation| = 90, this is what front camera sees |
| 267 // ----------------------- |
| 268 // | ******** | |
| 269 // | **** * | |
| 270 // | *** * | |
| 271 // | *** * | |
| 272 // | **** * | |
| 273 // | ******** | |
| 274 // ----------------------- |
| 275 // |
| 276 // Therefore, for back camera, we need to rotate (360 - |rotation|). |
| 277 rotation = (360 - rotation) % 360; |
| 278 } |
| 279 // Take into account camera orientation w.r.t. the display. External cameras |
| 280 // would have camera_orientation_ as 0. |
| 281 rotation = (rotation + camera_orientation_) % 360; |
| 282 if (device_thread_.IsRunning()) { |
| 283 device_thread_.task_runner()->PostTask( |
| 284 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetRotation, |
| 285 camera_device_delegate_, rotation)); |
| 286 } |
| 287 } |
| 288 |
| 289 void VideoCaptureDeviceArcChromeOS::SetDisplayRotation( |
| 290 const display::Display& display) { |
| 291 DCHECK(capture_task_runner_->BelongsToCurrentThread()); |
| 292 if (display.IsInternal()) |
| 293 SetRotation(display.rotation() * 90); |
| 294 } |
| 295 |
| 296 } // namespace media |
| OLD | NEW |