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

Side by Side 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: address wuchengli@'s comments Created 3 years, 7 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 unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698