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 using namespace arc::mojom; | |
| 16 | |
| 17 // This is a delegate class used to transfer Display change events from the UI | |
| 18 // thread to the media thread. | |
| 19 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.
| |
| 20 : public display::DisplayObserver, | |
| 21 public base::RefCountedThreadSafe<ScreenObserverDelegate> { | |
| 22 public: | |
| 23 ScreenObserverDelegate( | |
| 24 VideoCaptureDeviceArcChromeOS* capture_device, | |
| 25 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | |
| 26 : capture_device_(capture_device), | |
| 27 ui_task_runner_(ui_task_runner), | |
| 28 capture_task_runner_(base::ThreadTaskRunnerHandle::Get()) { | |
| 29 ui_task_runner_->PostTask( | |
| 30 FROM_HERE, | |
| 31 base::Bind(&ScreenObserverDelegate::AddObserverOnUIThread, this)); | |
| 32 } | |
| 33 | |
| 34 void RemoveObserver() { | |
| 35 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 36 capture_device_ = nullptr; | |
| 37 ui_task_runner_->PostTask( | |
| 38 FROM_HERE, | |
| 39 base::Bind(&ScreenObserverDelegate::RemoveObserverOnUIThread, this)); | |
| 40 } | |
| 41 | |
| 42 private: | |
| 43 friend class base::RefCountedThreadSafe<ScreenObserverDelegate>; | |
| 44 | |
| 45 ~ScreenObserverDelegate() override { DCHECK(!capture_device_); } | |
| 46 | |
| 47 void OnDisplayAdded(const display::Display& /*new_display*/) override {} | |
| 48 void OnDisplayRemoved(const display::Display& /*old_display*/) override {} | |
| 49 void OnDisplayMetricsChanged(const display::Display& display, | |
| 50 uint32_t metrics) override { | |
| 51 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 52 if (!(metrics & DISPLAY_METRIC_ROTATION)) | |
| 53 return; | |
| 54 SendDisplayRotation(display); | |
| 55 } | |
| 56 | |
| 57 void AddObserverOnUIThread() { | |
| 58 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 59 display::Screen* screen = display::Screen::GetScreen(); | |
| 60 if (screen) { | |
| 61 screen->AddObserver(this); | |
| 62 SendDisplayRotation(screen->GetPrimaryDisplay()); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 void RemoveObserverOnUIThread() { | |
| 67 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 68 display::Screen* screen = display::Screen::GetScreen(); | |
| 69 if (screen) | |
| 70 screen->RemoveObserver(this); | |
| 71 } | |
| 72 | |
| 73 // Post the screen rotation change from the UI thread to capture thread | |
| 74 void SendDisplayRotation(const display::Display& display) { | |
| 75 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 76 capture_task_runner_->PostTask( | |
| 77 FROM_HERE, | |
| 78 base::Bind(&ScreenObserverDelegate::SendDisplayRotationOnCaptureThread, | |
| 79 this, display)); | |
| 80 } | |
| 81 | |
| 82 void SendDisplayRotationOnCaptureThread(const display::Display& display) { | |
| 83 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 84 if (capture_device_) | |
| 85 capture_device_->SetDisplayRotation(display); | |
| 86 } | |
| 87 | |
| 88 VideoCaptureDeviceArcChromeOS* capture_device_; | |
| 89 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | |
| 90 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_; | |
| 91 DISALLOW_IMPLICIT_CONSTRUCTORS(ScreenObserverDelegate); | |
| 92 }; | |
| 93 | |
| 94 VideoCaptureDeviceArcChromeOS::VideoCaptureDeviceArcChromeOS( | |
| 95 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, | |
| 96 const VideoCaptureDeviceDescriptor& device_descriptor, | |
| 97 scoped_refptr<CameraHalDelegate> camera_hal_delegate) | |
| 98 : device_descriptor_(device_descriptor), | |
| 99 camera_hal_delegate_(camera_hal_delegate), | |
| 100 capture_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 101 device_thread_("CameraDeviceThread"), | |
| 102 starting_(false), | |
| 103 stopping_(false), | |
| 104 // TODO(jcliang): Determine |lens_facing_| and |camera_orientation_| from | |
| 105 // static characteristics. We should probably defer the | |
| 106 // initialization of |screen_observer_delegate_| until | |
| 107 // after we get the static characteristics in | |
| 108 // OnGotCameraInfo. | |
| 109 screen_observer_delegate_( | |
| 110 new ScreenObserverDelegate(this, ui_task_runner)), | |
| 111 lens_facing_(VideoFacingMode::MEDIA_VIDEO_FACING_USER), | |
| 112 camera_orientation_(0), | |
| 113 // External cameras have lens_facing as MEDIA_VIDEO_FACING_NONE. | |
| 114 // We don't want to rotate the frame even if the device rotates. | |
| 115 rotates_with_device_(lens_facing_ != | |
| 116 VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {} | |
| 117 | |
| 118 VideoCaptureDeviceArcChromeOS::~VideoCaptureDeviceArcChromeOS() { | |
| 119 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 120 DCHECK(!device_thread_.IsRunning()); | |
| 121 screen_observer_delegate_->RemoveObserver(); | |
| 122 } | |
| 123 | |
| 124 // static | |
| 125 VideoPixelFormat VideoCaptureDeviceArcChromeOS::PixFormatHalToChromium( | |
| 126 HalPixelFormat from) { | |
| 127 return CameraDeviceDelegate::PixFormatHalToChromium(from); | |
| 128 } | |
| 129 | |
| 130 // static | |
| 131 uint32_t VideoCaptureDeviceArcChromeOS::PixFormatChromiumToDrm( | |
| 132 VideoPixelFormat from) { | |
| 133 return CameraDeviceDelegate::PixFormatChromiumToDrm(from); | |
| 134 } | |
| 135 | |
| 136 // VideoCaptureDevice implementation. | |
| 137 void VideoCaptureDeviceArcChromeOS::AllocateAndStart( | |
| 138 const VideoCaptureParams& params, | |
| 139 std::unique_ptr<Client> client) { | |
| 140 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 141 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
| |
| 142 starting_ = true; | |
| 143 int32_t camera_id = std::stoi(device_descriptor_.device_id); | |
| 144 camera_hal_delegate_->GetCameraInfo( | |
| 145 camera_id, | |
| 146 base::Bind(&VideoCaptureDeviceArcChromeOS::OnGotCameraInfo, | |
| 147 base::Unretained(this), params, base::Passed(&client))); | |
| 148 } | |
| 149 | |
| 150 void VideoCaptureDeviceArcChromeOS::StopAndDeAllocate() { | |
| 151 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 152 stopping_ = true; | |
| 153 // StopAndDeAllocate is called only after AllocateAndStart. We have two cases | |
| 154 // here: |camera_device_delegate_| is either created, or being created. If | |
| 155 // |camera_device_delegate_| is already created then we simply close the | |
| 156 // camera device here; otherwise we defer to CreateDeviceOnCaptureThread to | |
| 157 // close the camera device right after camera HAL has opened the camera | |
| 158 // device. | |
| 159 if (camera_device_delegate_) { | |
| 160 base::WaitableEvent closed(base::WaitableEvent::ResetPolicy::MANUAL, | |
| 161 base::WaitableEvent::InitialState::NOT_SIGNALED); | |
| 162 device_thread_.task_runner()->PostTask( | |
| 163 FROM_HERE, | |
| 164 base::Bind(&CameraDeviceDelegate::StopAndDeAllocate, | |
| 165 camera_device_delegate_, base::Unretained(&closed))); | |
| 166 closed.Wait(); | |
| 167 camera_device_delegate_ = nullptr; | |
| 168 device_thread_.Stop(); | |
| 169 stopping_ = false; | |
| 170 } | |
| 171 } | |
| 172 | |
| 173 void VideoCaptureDeviceArcChromeOS::TakePhoto(TakePhotoCallback callback) { | |
| 174 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 175 DCHECK(camera_device_delegate_); | |
| 176 device_thread_.task_runner()->PostTask( | |
| 177 FROM_HERE, base::Bind(&CameraDeviceDelegate::TakePhoto, | |
| 178 camera_device_delegate_, base::Passed(&callback))); | |
| 179 } | |
| 180 | |
| 181 void VideoCaptureDeviceArcChromeOS::GetPhotoCapabilities( | |
| 182 GetPhotoCapabilitiesCallback callback) { | |
| 183 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 184 device_thread_.task_runner()->PostTask( | |
| 185 FROM_HERE, base::Bind(&CameraDeviceDelegate::GetPhotoCapabilities, | |
| 186 camera_device_delegate_, base::Passed(&callback))); | |
| 187 } | |
| 188 | |
| 189 void VideoCaptureDeviceArcChromeOS::OnGotCameraInfo( | |
| 190 const VideoCaptureParams& params, | |
| 191 std::unique_ptr<Client> client, | |
| 192 int32_t result, | |
| 193 CameraInfoPtr camera_info) { | |
| 194 // This method runs on |module_task_runner_| of |camera_hal_delegate_|. | |
| 195 if (result) { | |
| 196 client->OnError(FROM_HERE, "Failed to get camera info"); | |
| 197 return; | |
| 198 } | |
| 199 int32_t camera_id = std::stoi(device_descriptor_.device_id); | |
| 200 camera_hal_delegate_->OpenDevice( | |
| 201 camera_id, | |
| 202 base::Bind(&VideoCaptureDeviceArcChromeOS::OnOpenedDevice, | |
| 203 base::Unretained(this), params, base::Passed(&client), | |
| 204 base::Passed(&camera_info->static_camera_characteristics))); | |
| 205 } | |
| 206 | |
| 207 void VideoCaptureDeviceArcChromeOS::OnOpenedDevice( | |
| 208 const VideoCaptureParams& params, | |
| 209 std::unique_ptr<Client> client, | |
| 210 CameraMetadataPtr static_metadata, | |
| 211 int32_t result, | |
| 212 Camera3DeviceOpsPtr device_ops) { | |
| 213 // This method runs on |module_task_runner_| of |camera_hal_delegate_|. | |
| 214 if (result) { | |
| 215 client->OnError(FROM_HERE, "Failed to open camera device"); | |
| 216 return; | |
| 217 } | |
| 218 mojo::InterfacePtrInfo<Camera3DeviceOps> device_ops_info = | |
| 219 device_ops.PassInterface(); | |
| 220 capture_task_runner_->PostTask( | |
| 221 FROM_HERE, | |
| 222 base::Bind(&VideoCaptureDeviceArcChromeOS::CreateDeviceOnCaptureThread, | |
| 223 base::Unretained(this), params, base::Passed(&client), | |
| 224 base::Passed(&static_metadata), result, | |
| 225 base::Passed(&device_ops_info))); | |
| 226 } | |
| 227 | |
| 228 void VideoCaptureDeviceArcChromeOS::CreateDeviceOnCaptureThread( | |
| 229 const VideoCaptureParams& params, | |
| 230 std::unique_ptr<Client> client, | |
| 231 CameraMetadataPtr static_metadata, | |
| 232 int32_t result, | |
| 233 mojo::InterfacePtrInfo<Camera3DeviceOps> device_ops_info) { | |
| 234 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 235 | |
| 236 starting_ = false; | |
| 237 if (stopping_) { | |
| 238 // A StopAndDeAllocate call was made. | |
| 239 Camera3DeviceOpsPtr device_ops; | |
| 240 device_ops.Bind(std::move(device_ops_info)); | |
| 241 base::Callback<void(int32_t)> dont_care = base::Bind([](int32_t result) {}); | |
| 242 // We don't need to worry about the return value of the Close mojo call here | |
| 243 // since the Camera3DeviceOps proxy will be terminated immediately. The next | |
| 244 // AllocateAndStart will create a new Camera3DeviceOps proxy. | |
| 245 device_ops->Close(dont_care); | |
| 246 stopping_ = false; | |
| 247 return; | |
| 248 } | |
| 249 device_thread_.Start(); | |
| 250 camera_device_delegate_ = new CameraDeviceDelegate( | |
| 251 device_descriptor_, std::move(static_metadata), | |
| 252 std::move(device_ops_info), device_thread_.task_runner()); | |
| 253 device_thread_.task_runner()->PostTask( | |
| 254 FROM_HERE, | |
| 255 base::Bind(&CameraDeviceDelegate::AllocateAndStart, | |
| 256 camera_device_delegate_, params, base::Passed(&client))); | |
| 257 } | |
| 258 | |
| 259 void VideoCaptureDeviceArcChromeOS::SetPhotoOptions( | |
| 260 mojom::PhotoSettingsPtr settings, | |
| 261 SetPhotoOptionsCallback callback) { | |
| 262 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 263 device_thread_.task_runner()->PostTask( | |
| 264 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetPhotoOptions, | |
| 265 camera_device_delegate_, base::Passed(&settings), | |
| 266 base::Passed(&callback))); | |
| 267 } | |
| 268 | |
| 269 void VideoCaptureDeviceArcChromeOS::SetRotation(int rotation) { | |
| 270 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 271 if (!rotates_with_device_) { | |
| 272 rotation = 0; | |
| 273 } else if (lens_facing_ == VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) { | |
| 274 // Original frame when |rotation| = 0 | |
| 275 // ----------------------- | |
| 276 // | * | | |
| 277 // | * * | | |
| 278 // | * * | | |
| 279 // | ******* | | |
| 280 // | * * | | |
| 281 // | * * | | |
| 282 // ----------------------- | |
| 283 // | |
| 284 // |rotation| = 90, this is what back camera sees | |
| 285 // ----------------------- | |
| 286 // | ******** | | |
| 287 // | * **** | | |
| 288 // | * *** | | |
| 289 // | * *** | | |
| 290 // | * **** | | |
| 291 // | ******** | | |
| 292 // ----------------------- | |
| 293 // | |
| 294 // |rotation| = 90, this is what front camera sees | |
| 295 // ----------------------- | |
| 296 // | ******** | | |
| 297 // | **** * | | |
| 298 // | *** * | | |
| 299 // | *** * | | |
| 300 // | **** * | | |
| 301 // | ******** | | |
| 302 // ----------------------- | |
| 303 // | |
| 304 // Therefore, for back camera, we need to rotate (360 - |rotation|). | |
| 305 rotation = (360 - rotation) % 360; | |
| 306 } | |
| 307 // Take into account camera orientation w.r.t. the display. External cameras | |
| 308 // would have camera_orientation_ as 0. | |
| 309 rotation = (rotation + camera_orientation_) % 360; | |
| 310 if (device_thread_.IsRunning()) { | |
| 311 device_thread_.task_runner()->PostTask( | |
| 312 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetRotation, | |
| 313 camera_device_delegate_, rotation)); | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 void VideoCaptureDeviceArcChromeOS::SetDisplayRotation( | |
| 318 const display::Display& display) { | |
| 319 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 320 if (display.IsInternal()) | |
| 321 SetRotation(display.rotation() * 90); | |
| 322 } | |
| 323 | |
| 324 } // namespace media | |
| OLD | NEW |