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

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: handle error_msg in Notify 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),
wuchengli 2017/05/05 08:10:55 use std::move to reduce a copy
jcliang 2017/05/08 01:48:59 Done. The std::move() is added in VideoCaptureDevi
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 screen_observer_delegate_(
106 new ScreenObserverDelegate(this, 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);
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(
wuchengli 2017/05/05 08:10:55 What happens when AllocateAndStart, StopAndDeAlloc
jcliang 2017/05/08 01:48:59 Right...there's a tiny chance that the second open
134 const VideoCaptureParams& params,
135 std::unique_ptr<Client> client) {
136 DCHECK(capture_task_runner_->BelongsToCurrentThread());
137 // AllocateAndStart, StopAndDeAllocate, and creation / deletion of
138 // |camera_device_delegate_| all happen on |capture_task_runner_|. When
139 // StopAndDeAllocate is called, we either 1) reset |camera_device_delegate_|
140 // immediately if it's set, or 2) drop the on-going open process in
141 // CreateDeviceOnCaptureThread. In case 1, it safe; in case 2, the
142 // |camera_device_delegate_| is not set when StopAndDeAllocate is called, and
143 // wouldn't be set in CreateDeviceOnCaptureThread, either. So back-to-back
144 // AllocateAndStart, StopAndDeAllocate, and AllocateAndStart calls wouldn't
145 // hit this DCHECK.
146 DCHECK(!camera_device_delegate_);
147 int32_t camera_id = std::stoi(device_descriptor_.device_id);
148 camera_hal_delegate_->GetCameraInfo(
149 camera_id,
150 base::Bind(&VideoCaptureDeviceArcChromeOS::OnGotCameraInfo,
151 base::Unretained(this), params, base::Passed(&client)));
152 }
153
154 void VideoCaptureDeviceArcChromeOS::StopAndDeAllocate() {
155 DCHECK(capture_task_runner_->BelongsToCurrentThread());
156 stopping_ = true;
157 // StopAndDeAllocate is called only after AllocateAndStart is called. We have
158 // two cases here: |camera_device_delegate_| is either created, or being
159 // created. If |camera_device_delegate_| is already created then we simply
160 // close the camera device here; otherwise we defer to
161 // CreateDeviceOnCaptureThread to close the camera device right after camera
162 // HAL opens the camera device.
163 if (camera_device_delegate_) {
164 base::WaitableEvent closed(base::WaitableEvent::ResetPolicy::MANUAL,
165 base::WaitableEvent::InitialState::NOT_SIGNALED);
166 device_thread_.task_runner()->PostTask(
167 FROM_HERE,
168 base::Bind(&CameraDeviceDelegate::StopAndDeAllocate,
169 camera_device_delegate_, base::Unretained(&closed)));
170 closed.Wait();
171 camera_device_delegate_ = nullptr;
172 device_thread_.Stop();
173 stopping_ = false;
174 }
175 }
176
177 void VideoCaptureDeviceArcChromeOS::TakePhoto(TakePhotoCallback callback) {
178 DCHECK(capture_task_runner_->BelongsToCurrentThread());
179 DCHECK(camera_device_delegate_);
180 device_thread_.task_runner()->PostTask(
181 FROM_HERE, base::Bind(&CameraDeviceDelegate::TakePhoto,
182 camera_device_delegate_, base::Passed(&callback)));
183 }
184
185 void VideoCaptureDeviceArcChromeOS::GetPhotoCapabilities(
186 GetPhotoCapabilitiesCallback callback) {
187 DCHECK(capture_task_runner_->BelongsToCurrentThread());
188 device_thread_.task_runner()->PostTask(
189 FROM_HERE, base::Bind(&CameraDeviceDelegate::GetPhotoCapabilities,
190 camera_device_delegate_, base::Passed(&callback)));
191 }
192
193 void VideoCaptureDeviceArcChromeOS::SetPhotoOptions(
194 mojom::PhotoSettingsPtr settings,
195 SetPhotoOptionsCallback callback) {
196 DCHECK(capture_task_runner_->BelongsToCurrentThread());
197 device_thread_.task_runner()->PostTask(
198 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetPhotoOptions,
199 camera_device_delegate_, base::Passed(&settings),
200 base::Passed(&callback)));
201 }
202
203 void VideoCaptureDeviceArcChromeOS::OnGotCameraInfo(
204 const VideoCaptureParams& params,
205 std::unique_ptr<Client> client,
206 int32_t result,
207 arc::mojom::CameraInfoPtr camera_info) {
208 // This method runs on |module_task_runner_| of |camera_hal_delegate_|.
209 if (result) {
210 client->OnError(FROM_HERE, "Failed to get camera info");
211 return;
212 }
213 int32_t camera_id = std::stoi(device_descriptor_.device_id);
214 camera_hal_delegate_->OpenDevice(
215 camera_id,
216 base::Bind(&VideoCaptureDeviceArcChromeOS::OnOpenedDevice,
217 base::Unretained(this), params, base::Passed(&client),
218 base::Passed(&camera_info->static_camera_characteristics)));
219 }
220
221 void VideoCaptureDeviceArcChromeOS::OnOpenedDevice(
222 const VideoCaptureParams& params,
223 std::unique_ptr<Client> client,
224 arc::mojom::CameraMetadataPtr static_metadata,
225 int32_t result,
226 arc::mojom::Camera3DeviceOpsPtr device_ops) {
227 // This method runs on |module_task_runner_| of |camera_hal_delegate_|.
228 if (result) {
229 client->OnError(FROM_HERE, "Failed to open camera device");
230 return;
231 }
232 mojo::InterfacePtrInfo<arc::mojom::Camera3DeviceOps> device_ops_info =
233 device_ops.PassInterface();
234 capture_task_runner_->PostTask(
235 FROM_HERE,
236 base::Bind(&VideoCaptureDeviceArcChromeOS::CreateDeviceOnCaptureThread,
237 base::Unretained(this), params, base::Passed(&client),
238 base::Passed(&static_metadata), result,
239 base::Passed(&device_ops_info)));
240 }
241
242 void VideoCaptureDeviceArcChromeOS::CreateDeviceOnCaptureThread(
243 const VideoCaptureParams& params,
244 std::unique_ptr<Client> client,
245 arc::mojom::CameraMetadataPtr static_metadata,
246 int32_t result,
247 mojo::InterfacePtrInfo<arc::mojom::Camera3DeviceOps> device_ops_info) {
248 DCHECK(capture_task_runner_->BelongsToCurrentThread());
249
250 if (stopping_) {
251 // A StopAndDeAllocate call was made.
252 arc::mojom::Camera3DeviceOpsPtr device_ops;
253 device_ops.Bind(std::move(device_ops_info));
254 base::Callback<void(int32_t)> dont_care = base::Bind([](int32_t result) {});
255 // We don't need to worry about the return value of the Close mojo call here
256 // since the Camera3DeviceOps proxy will be terminated immediately. The next
257 // AllocateAndStart will create a new Camera3DeviceOps proxy.
258 device_ops->Close(dont_care);
259 stopping_ = false;
260 return;
261 }
262 device_thread_.Start();
263 camera_device_delegate_ = new CameraDeviceDelegate(
264 device_descriptor_, std::move(static_metadata),
265 std::move(device_ops_info), device_thread_.task_runner());
266 device_thread_.task_runner()->PostTask(
267 FROM_HERE,
268 base::Bind(&CameraDeviceDelegate::AllocateAndStart,
269 camera_device_delegate_, params, base::Passed(&client)));
270 }
271
272 void VideoCaptureDeviceArcChromeOS::SetRotation(int rotation) {
273 DCHECK(capture_task_runner_->BelongsToCurrentThread());
274 if (!rotates_with_device_) {
275 rotation = 0;
276 } else if (lens_facing_ == VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT) {
277 // Original frame when |rotation| = 0
278 // -----------------------
279 // | * |
280 // | * * |
281 // | * * |
282 // | ******* |
283 // | * * |
284 // | * * |
285 // -----------------------
286 //
287 // |rotation| = 90, this is what back camera sees
288 // -----------------------
289 // | ******** |
290 // | * **** |
291 // | * *** |
292 // | * *** |
293 // | * **** |
294 // | ******** |
295 // -----------------------
296 //
297 // |rotation| = 90, this is what front camera sees
298 // -----------------------
299 // | ******** |
300 // | **** * |
301 // | *** * |
302 // | *** * |
303 // | **** * |
304 // | ******** |
305 // -----------------------
306 //
307 // Therefore, for back camera, we need to rotate (360 - |rotation|).
308 rotation = (360 - rotation) % 360;
309 }
310 // Take into account camera orientation w.r.t. the display. External cameras
311 // would have camera_orientation_ as 0.
312 rotation = (rotation + camera_orientation_) % 360;
313 if (device_thread_.IsRunning()) {
314 device_thread_.task_runner()->PostTask(
315 FROM_HERE, base::Bind(&CameraDeviceDelegate::SetRotation,
316 camera_device_delegate_, rotation));
317 }
318 }
319
320 void VideoCaptureDeviceArcChromeOS::SetDisplayRotation(
321 const display::Display& display) {
322 DCHECK(capture_task_runner_->BelongsToCurrentThread());
323 if (display.IsInternal())
324 SetRotation(display.rotation() * 90);
325 }
326
327 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698