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 "base/threading/platform_thread.h" | |
| 8 #include "media/capture/video/chromeos/camera_device_delegate.h" | |
| 9 #include "media/capture/video/chromeos/camera_hal_delegate.h" | |
| 10 #include "ui/display/display.h" | |
| 11 #include "ui/display/display_observer.h" | |
| 12 #include "ui/display/screen.h" | |
| 13 | |
| 14 namespace media { | |
| 15 | |
| 16 // This is a delegate class used to transfer Display change events from the UI | |
| 17 // thread to the media thread. | |
|
chfremer
2017/05/24 23:36:43
What is "the media thread"?
jcliang
2017/05/25 14:23:47
I believe it's the media capture thread on which t
chfremer
2017/05/25 17:13:07
Oh, I see. In that case, can we please avoid dupli
jcliang
2017/05/26 04:33:33
Agreed. I've extracted the common codes to display
| |
| 18 class VideoCaptureDeviceArcChromeOS::ScreenObserverDelegate | |
| 19 : public display::DisplayObserver, | |
| 20 public base::RefCountedThreadSafe<ScreenObserverDelegate> { | |
| 21 public: | |
| 22 // It is safe to use the raw pointer |capture_device| as | |
| 23 // VideoCaptureDeviceArcChromeOS owns the ScreenObserverDelegate instance and | |
| 24 // we make sure the VideoCaptureDeviceArcChromeOS instance outlives the | |
| 25 // ScreenObserverDelegate instance. | |
|
chfremer
2017/05/24 23:36:43
I am not convinced that this is accurate.
Looking
jcliang
2017/05/25 14:23:47
Yes you are correct. I've updated the comments.
| |
| 26 ScreenObserverDelegate( | |
| 27 VideoCaptureDeviceArcChromeOS* capture_device, | |
| 28 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | |
| 29 : capture_device_(capture_device), | |
| 30 ui_task_runner_(ui_task_runner), | |
| 31 capture_task_runner_(base::ThreadTaskRunnerHandle::Get()) { | |
| 32 ui_task_runner_->PostTask( | |
| 33 FROM_HERE, | |
| 34 base::Bind(&ScreenObserverDelegate::AddObserverOnUIThread, this)); | |
| 35 } | |
| 36 | |
| 37 void RemoveObserver() { | |
| 38 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 39 capture_device_ = nullptr; | |
| 40 ui_task_runner_->PostTask( | |
| 41 FROM_HERE, | |
| 42 base::Bind(&ScreenObserverDelegate::RemoveObserverOnUIThread, this)); | |
| 43 } | |
| 44 | |
| 45 private: | |
| 46 friend class base::RefCountedThreadSafe<ScreenObserverDelegate>; | |
| 47 | |
| 48 ~ScreenObserverDelegate() override { DCHECK(!capture_device_); } | |
| 49 | |
| 50 void OnDisplayAdded(const display::Display& /*new_display*/) override {} | |
| 51 void OnDisplayRemoved(const display::Display& /*old_display*/) override {} | |
| 52 void OnDisplayMetricsChanged(const display::Display& display, | |
| 53 uint32_t metrics) override { | |
| 54 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 55 if (!(metrics & DISPLAY_METRIC_ROTATION)) | |
| 56 return; | |
| 57 SendDisplayRotation(display); | |
| 58 } | |
| 59 | |
| 60 void AddObserverOnUIThread() { | |
| 61 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 62 display::Screen* screen = display::Screen::GetScreen(); | |
|
chfremer
2017/05/24 23:36:43
When I see a dependency on a global like this, I g
jcliang
2017/05/25 14:23:47
I agree having direct dependency on ScreenObserver
chfremer
2017/05/25 17:13:07
Sounds good. Agreed that VideoCaptureDeviceArcChro
| |
| 63 if (screen) { | |
| 64 screen->AddObserver(this); | |
| 65 SendDisplayRotation(screen->GetPrimaryDisplay()); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 void RemoveObserverOnUIThread() { | |
| 70 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 71 display::Screen* screen = display::Screen::GetScreen(); | |
| 72 if (screen) | |
| 73 screen->RemoveObserver(this); | |
| 74 } | |
| 75 | |
| 76 // Post the screen rotation change from the UI thread to capture thread | |
| 77 void SendDisplayRotation(const display::Display& display) { | |
| 78 DCHECK(ui_task_runner_->BelongsToCurrentThread()); | |
| 79 capture_task_runner_->PostTask( | |
| 80 FROM_HERE, | |
| 81 base::Bind(&ScreenObserverDelegate::SendDisplayRotationOnCaptureThread, | |
| 82 this, display)); | |
| 83 } | |
| 84 | |
| 85 void SendDisplayRotationOnCaptureThread(const display::Display& display) { | |
| 86 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 87 if (capture_device_) | |
| 88 capture_device_->SetDisplayRotation(display); | |
| 89 } | |
| 90 | |
| 91 VideoCaptureDeviceArcChromeOS* capture_device_; | |
| 92 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | |
| 93 scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_; | |
| 94 DISALLOW_IMPLICIT_CONSTRUCTORS(ScreenObserverDelegate); | |
| 95 }; | |
| 96 | |
| 97 VideoCaptureDeviceArcChromeOS::VideoCaptureDeviceArcChromeOS( | |
| 98 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, | |
| 99 const VideoCaptureDeviceDescriptor& device_descriptor, | |
| 100 scoped_refptr<CameraHalDelegate> camera_hal_delegate) | |
| 101 : device_descriptor_(device_descriptor), | |
| 102 camera_hal_delegate_(camera_hal_delegate), | |
| 103 capture_task_runner_(base::ThreadTaskRunnerHandle::Get()), | |
| 104 device_thread_("CameraDeviceThread"), | |
| 105 screen_observer_delegate_( | |
| 106 new ScreenObserverDelegate(this, std::move(ui_task_runner))), | |
| 107 lens_facing_(device_descriptor.facing), | |
| 108 camera_orientation_(0), | |
| 109 // External cameras have lens_facing as MEDIA_VIDEO_FACING_NONE. | |
| 110 // We don't want to rotate the frame even if the device rotates. | |
| 111 rotates_with_device_(lens_facing_ != | |
| 112 VideoFacingMode::MEDIA_VIDEO_FACING_NONE) {} | |
| 113 | |
| 114 VideoCaptureDeviceArcChromeOS::~VideoCaptureDeviceArcChromeOS() { | |
| 115 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 116 DCHECK(!device_thread_.IsRunning()); | |
| 117 screen_observer_delegate_->RemoveObserver(); | |
| 118 } | |
| 119 | |
| 120 // static | |
| 121 VideoPixelFormat VideoCaptureDeviceArcChromeOS::PixFormatHalToChromium( | |
| 122 arc::mojom::HalPixelFormat from) { | |
| 123 return CameraDeviceDelegate::PixFormatHalToChromium(from); | |
|
chfremer
2017/05/24 23:36:43
nit: Since these are public static both here and i
jcliang
2017/05/25 14:23:47
Done. Moved to pixel_format_utils.h/.cc
| |
| 124 } | |
| 125 | |
| 126 // static | |
| 127 uint32_t VideoCaptureDeviceArcChromeOS::PixFormatChromiumToDrm( | |
| 128 VideoPixelFormat from) { | |
| 129 return CameraDeviceDelegate::PixFormatChromiumToDrm(from); | |
| 130 } | |
| 131 | |
| 132 // VideoCaptureDevice implementation. | |
| 133 void VideoCaptureDeviceArcChromeOS::AllocateAndStart( | |
| 134 const VideoCaptureParams& params, | |
| 135 std::unique_ptr<Client> client) { | |
| 136 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 137 DCHECK(!camera_device_delegate_); | |
| 138 | |
| 139 if (!device_thread_.Start()) { | |
| 140 std::string error_msg = "Failed to start device thread"; | |
| 141 LOG(ERROR) << error_msg; | |
| 142 client->OnError(FROM_HERE, error_msg); | |
| 143 return; | |
| 144 } | |
| 145 camera_device_delegate_ = new CameraDeviceDelegate( | |
| 146 device_descriptor_, camera_hal_delegate_, device_thread_.task_runner()); | |
| 147 device_thread_.task_runner()->PostTask( | |
| 148 FROM_HERE, | |
| 149 base::Bind(&CameraDeviceDelegate::AllocateAndStart, | |
| 150 camera_device_delegate_, params, base::Passed(&client))); | |
| 151 } | |
| 152 | |
| 153 void VideoCaptureDeviceArcChromeOS::StopAndDeAllocate() { | |
| 154 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 155 | |
|
wuchengli
2017/05/23 02:56:02
if (!camera_device_delegate_)
return;
In case d
jcliang
2017/05/25 14:23:47
Done.
| |
| 156 DCHECK(camera_device_delegate_); | |
| 157 device_thread_.task_runner()->PostTask( | |
| 158 FROM_HERE, base::Bind(&CameraDeviceDelegate::StopAndDeAllocate, | |
| 159 camera_device_delegate_)); | |
| 160 // Wait until all other references to |camera_device_delegate_| are dropped to | |
| 161 // make sure all the IPC calls are done. | |
| 162 base::TimeTicks wait_until = | |
| 163 base::TimeTicks() + base::TimeDelta::FromSeconds(3); | |
| 164 while (!camera_device_delegate_->HasOneRef()) { | |
|
wuchengli
2017/05/23 02:56:02
Note to myself: need to think about this code.
chfremer
2017/05/24 23:36:43
I also have a strange feeling about this spinning
wuchengli
2017/05/25 07:59:06
Ricky. You can consider to move device_thread_ to
jcliang
2017/05/25 14:23:47
I'll look into it, but it'll likely be a sizable r
| |
| 165 if (base::TimeTicks() >= wait_until) { | |
| 166 LOG(ERROR) << "Timed out waiting capture device to stop"; | |
| 167 break; | |
| 168 } | |
| 169 base::PlatformThread::YieldCurrentThread(); | |
| 170 } | |
| 171 device_thread_.Stop(); | |
| 172 camera_device_delegate_ = nullptr; | |
| 173 } | |
| 174 | |
| 175 void VideoCaptureDeviceArcChromeOS::TakePhoto(TakePhotoCallback callback) { | |
| 176 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 177 DCHECK(camera_device_delegate_); | |
| 178 device_thread_.task_runner()->PostTask( | |
| 179 FROM_HERE, base::Bind(&CameraDeviceDelegate::TakePhoto, | |
| 180 camera_device_delegate_, base::Passed(&callback))); | |
| 181 } | |
| 182 | |
| 183 void VideoCaptureDeviceArcChromeOS::GetPhotoCapabilities( | |
| 184 GetPhotoCapabilitiesCallback callback) { | |
| 185 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 186 device_thread_.task_runner()->PostTask( | |
| 187 FROM_HERE, base::Bind(&CameraDeviceDelegate::GetPhotoCapabilities, | |
| 188 camera_device_delegate_, base::Passed(&callback))); | |
| 189 } | |
| 190 | |
| 191 void VideoCaptureDeviceArcChromeOS::SetPhotoOptions( | |
| 192 mojom::PhotoSettingsPtr settings, | |
| 193 SetPhotoOptionsCallback callback) { | |
| 194 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 195 device_thread_.task_runner()->PostTask( | |
| 196 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetPhotoOptions, | |
| 197 camera_device_delegate_, base::Passed(&settings), | |
| 198 base::Passed(&callback))); | |
| 199 } | |
| 200 | |
| 201 void VideoCaptureDeviceArcChromeOS::SetRotation(int rotation) { | |
| 202 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 203 if (!rotates_with_device_) { | |
| 204 rotation = 0; | |
| 205 } else if (lens_facing_ == VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) { | |
| 206 // Original frame when |rotation| = 0 | |
| 207 // ----------------------- | |
| 208 // | * | | |
| 209 // | * * | | |
| 210 // | * * | | |
| 211 // | ******* | | |
| 212 // | * * | | |
| 213 // | * * | | |
| 214 // ----------------------- | |
| 215 // | |
| 216 // |rotation| = 90, this is what back camera sees | |
| 217 // ----------------------- | |
| 218 // | ******** | | |
| 219 // | * **** | | |
| 220 // | * *** | | |
| 221 // | * *** | | |
| 222 // | * **** | | |
| 223 // | ******** | | |
| 224 // ----------------------- | |
| 225 // | |
| 226 // |rotation| = 90, this is what front camera sees | |
| 227 // ----------------------- | |
| 228 // | ******** | | |
| 229 // | **** * | | |
| 230 // | *** * | | |
| 231 // | *** * | | |
| 232 // | **** * | | |
| 233 // | ******** | | |
| 234 // ----------------------- | |
| 235 // | |
| 236 // Therefore, for back camera, we need to rotate (360 - |rotation|). | |
| 237 rotation = (360 - rotation) % 360; | |
| 238 } | |
| 239 // Take into account camera orientation w.r.t. the display. External cameras | |
| 240 // would have camera_orientation_ as 0. | |
| 241 rotation = (rotation + camera_orientation_) % 360; | |
| 242 if (device_thread_.IsRunning()) { | |
|
chfremer
2017/05/24 23:36:42
This check seems to indicate that rotation events
jcliang
2017/05/25 14:23:47
Oh yes! We should preserve the rotation informatio
| |
| 243 device_thread_.task_runner()->PostTask( | |
| 244 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetRotation, | |
| 245 camera_device_delegate_, rotation)); | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 void VideoCaptureDeviceArcChromeOS::SetDisplayRotation( | |
| 250 const display::Display& display) { | |
| 251 DCHECK(capture_task_runner_->BelongsToCurrentThread()); | |
| 252 if (display.IsInternal()) | |
| 253 SetRotation(display.rotation() * 90); | |
| 254 } | |
| 255 | |
| 256 } // namespace media | |
| OLD | NEW |