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

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

Powered by Google App Engine
This is Rietveld 408576698