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

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

Powered by Google App Engine
This is Rietveld 408576698