Chromium Code Reviews| 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(); | |
|
wuchengli
2017/05/18 04:26:14
check return value
jcliang
2017/05/22 13:54:13
Done.
| |
| 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))); | |
|
wuchengli
2017/05/18 04:26:14
|started| will be destroyed after timeout and |cam
jcliang
2017/05/22 13:54:14
These are removed after I moved the logic into Cam
| |
| 153 started.TimedWait(kEventWaitTimeoutMs); | |
|
wuchengli
2017/05/18 04:26:14
print a warning if it times out. Same for other Wa
| |
| 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))); | |
|
wuchengli
2017/05/18 04:26:14
|closed| may be destroyed when |camera_device_dele
| |
| 165 closed.TimedWait(kEventWaitTimeoutMs); | |
| 166 camera_device_delegate_ = nullptr; | |
| 167 } | |
| 168 device_thread_.Stop(); | |
|
wuchengli
2017/05/18 04:26:14
Do we need |closed| if Stop will return until all
| |
| 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) { | |
|
wuchengli
2017/05/18 04:26:14
Print an error log. Same for line 226.
jcliang
2017/05/22 13:54:13
Done.
| |
| 205 client->OnError(FROM_HERE, "Failed to get camera info"); | |
|
wuchengli
2017/05/18 04:26:14
started->Signal();
jcliang
2017/05/22 13:54:14
Done.
| |
| 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"); | |
|
wuchengli
2017/05/18 04:26:14
started->Signal();
jcliang
2017/05/22 13:54:14
Done.
| |
| 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 |