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

Side by Side Diff: media/capture/video/chromeos/camera_hal_delegate.cc

Issue 2837273004: media: add video capture device for ARC++ camera HAL v3 (Closed)
Patch Set: address chfremer's comments Created 3 years, 6 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/camera_hal_delegate.h"
6
7 #include <fcntl.h>
8 #include <sys/uio.h>
9
10 #include <algorithm>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/bind_helpers.h"
15 #include "base/strings/string_piece.h"
16 #include "media/capture/video/chromeos/camera_metadata_utils.h"
17 #include "media/capture/video/chromeos/pixel_format_utils.h"
18 #include "media/capture/video/chromeos/video_capture_device_arc_chromeos.h"
19 #include "mojo/edk/embedder/embedder.h"
20 #include "mojo/edk/embedder/incoming_broker_client_invitation.h"
21 #include "mojo/edk/embedder/named_platform_handle.h"
22 #include "mojo/edk/embedder/named_platform_handle_utils.h"
23 #include "mojo/edk/embedder/platform_channel_pair.h"
24 #include "mojo/edk/embedder/platform_channel_utils_posix.h"
25 #include "mojo/edk/embedder/platform_handle_vector.h"
26
27 namespace media {
28
29 namespace {
30
31 const base::StringPiece kArcCamera3SocketPath("/var/run/camera/camera3.sock");
32
33 const base::TimeDelta kEventWaitTimeoutMs =
34 base::TimeDelta::FromMilliseconds(3000);
35
36 } // namespace
37
38 CameraHalDelegate::CameraHalDelegate(
39 scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner)
40 : builtin_camera_info_updated_(
41 base::WaitableEvent::ResetPolicy::MANUAL,
42 base::WaitableEvent::InitialState::NOT_SIGNALED),
43 num_builtin_cameras_(0),
44 ipc_task_runner_(std::move(ipc_task_runner)),
45 camera_module_callbacks_(this) {
46 DETACH_FROM_SEQUENCE(sequence_checker_);
47 }
48
49 CameraHalDelegate::~CameraHalDelegate() {}
50
51 bool CameraHalDelegate::StartCameraModuleIpc() {
52 // Non-blocking socket handle.
53 mojo::edk::ScopedPlatformHandle socket_handle = mojo::edk::CreateClientHandle(
54 mojo::edk::NamedPlatformHandle(kArcCamera3SocketPath));
55
56 // Set socket to blocking
57 int flags = HANDLE_EINTR(fcntl(socket_handle.get().handle, F_GETFL));
58 if (flags == -1) {
59 PLOG(ERROR) << "fcntl(F_GETFL) failed: ";
60 return false;
61 }
62 if (HANDLE_EINTR(fcntl(socket_handle.get().handle, F_SETFL,
63 flags & ~O_NONBLOCK)) == -1) {
64 PLOG(ERROR) << "fcntl(F_SETFL) failed: ";
65 return false;
66 }
67
68 const size_t kTokenSize = 32;
69 char token[kTokenSize] = {};
70 std::deque<mojo::edk::PlatformHandle> platform_handles;
71 ssize_t ret = mojo::edk::PlatformChannelRecvmsg(
72 socket_handle.get(), token, sizeof(token), &platform_handles, true);
73 if (ret == -1) {
74 PLOG(ERROR) << "PlatformChannelRecvmsg failed: ";
75 return false;
76 }
77 if (platform_handles.size() != 1) {
78 LOG(ERROR) << "Unexpected number of handles received, expected 1: "
79 << platform_handles.size();
80 return false;
81 }
82 mojo::edk::ScopedPlatformHandle parent_pipe(platform_handles.back());
83 platform_handles.pop_back();
84 if (!parent_pipe.is_valid()) {
85 LOG(ERROR) << "Invalid parent pipe";
86 return false;
87 }
88 std::unique_ptr<mojo::edk::IncomingBrokerClientInvitation> invitation =
89 mojo::edk::IncomingBrokerClientInvitation::Accept(
90 mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
91 std::move(parent_pipe)));
92 mojo::ScopedMessagePipeHandle child_pipe =
93 invitation->ExtractMessagePipe(token);
94 DCHECK(child_pipe.is_valid());
wuchengli 2017/06/09 07:43:54 return false if !child_pipe.is_valid()
jcliang 2017/06/09 08:34:37 Done.
95
96 camera_module_ =
97 mojo::MakeProxy(mojo::InterfacePtrInfo<arc::mojom::CameraModule>(
98 std::move(child_pipe), 0u),
99 ipc_task_runner_);
100
101 VLOG(1) << "Camera module IPC connection established";
102
103 return true;
104 }
105
106 void CameraHalDelegate::Reset() {
107 ipc_task_runner_->PostTask(
108 FROM_HERE,
109 base::Bind(&CameraHalDelegate::ResetMojoInterfaceOnModuleThread, this));
110 }
111
112 std::unique_ptr<VideoCaptureDevice> CameraHalDelegate::CreateDevice(
113 scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer,
114 const VideoCaptureDeviceDescriptor& device_descriptor) {
115 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
116 std::unique_ptr<VideoCaptureDevice> capture_device;
117 if (!UpdateBuiltInCameraInfo()) {
118 return capture_device;
119 }
120 if (camera_info_.find(device_descriptor.device_id) == camera_info_.end()) {
121 LOG(ERROR) << "Invalid camera device: " << device_descriptor.device_id;
122 return capture_device;
123 }
124 capture_device.reset(new VideoCaptureDeviceArcChromeOS(
125 std::move(task_runner_for_screen_observer), device_descriptor, this));
126 return capture_device;
127 }
128
129 void CameraHalDelegate::GetSupportedFormats(
130 const VideoCaptureDeviceDescriptor& device_descriptor,
131 VideoCaptureFormats* supported_formats) {
132 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
133
134 if (!UpdateBuiltInCameraInfo()) {
135 return;
136 }
137 std::string camera_id = device_descriptor.device_id;
138 if (camera_info_.find(camera_id) == camera_info_.end() ||
139 camera_info_[camera_id].is_null()) {
140 LOG(ERROR) << "Invalid camera_id: " << camera_id;
141 return;
142 }
143 const arc::mojom::CameraInfoPtr& camera_info = camera_info_[camera_id];
144
145 const arc::mojom::CameraMetadataEntryPtr* min_frame_durations =
146 GetMetadataEntry(camera_info->static_camera_characteristics,
147 arc::mojom::CameraMetadataTag::
148 ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
149 if (!min_frame_durations) {
150 LOG(ERROR)
151 << "Failed to get available min frame durations from camera info";
152 return;
153 }
154 // The min frame durations are stored as tuples of four int64s:
155 // (hal_pixel_format, width, height, ns) x n
156 const size_t kStreamFormatOffset = 0;
157 const size_t kStreamWidthOffset = 1;
158 const size_t kStreamHeightOffset = 2;
159 const size_t kStreamDurationOffset = 3;
160 const size_t kStreamDurationSize = 4;
161 int64_t* iter =
162 reinterpret_cast<int64_t*>((*min_frame_durations)->data.data());
163 for (size_t i = 0; i < (*min_frame_durations)->count;
164 i += kStreamDurationSize) {
165 int32_t format = static_cast<int32_t>(iter[kStreamFormatOffset]);
166 int32_t width = static_cast<int32_t>(iter[kStreamWidthOffset]);
167 int32_t height = static_cast<int32_t>(iter[kStreamHeightOffset]);
168 int64_t duration = iter[kStreamDurationOffset];
169 iter += kStreamDurationSize;
170
171 float max_fps = 1.0 * 1000000000LL / duration;
172
173 DVLOG(1) << "[" << std::hex << format << " " << std::dec << width << " "
174 << height << " " << duration << "]";
175 VideoPixelFormat cr_format =
176 PixFormatHalToChromium(static_cast<arc::mojom::HalPixelFormat>(format));
177 if (cr_format == PIXEL_FORMAT_UNKNOWN) {
178 continue;
179 }
180 VLOG(1) << "Supported format: " << width << "x" << height
181 << " fps=" << max_fps << " format=" << cr_format;
182 supported_formats->emplace_back(gfx::Size(width, height), max_fps,
183 cr_format);
184 }
185 }
186
187 void CameraHalDelegate::GetDeviceDescriptors(
188 VideoCaptureDeviceDescriptors* device_descriptors) {
189 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
190
191 if (!UpdateBuiltInCameraInfo()) {
192 return;
193 }
194 for (size_t id = 0; id < num_builtin_cameras_; ++id) {
195 VideoCaptureDeviceDescriptor desc;
196 std::string camera_id = std::to_string(id);
197 const arc::mojom::CameraInfoPtr& camera_info = camera_info_[camera_id];
198 if (!camera_info) {
199 continue;
200 }
201 desc.device_id = camera_id;
202 desc.capture_api = VideoCaptureApi::ANDROID_API2_LIMITED;
203 desc.transport_type = VideoCaptureTransportType::OTHER_TRANSPORT;
204 switch (camera_info->facing) {
205 case arc::mojom::CameraFacing::CAMERA_FACING_BACK:
206 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT;
207 desc.display_name = std::string("Back Camera");
208 break;
209 case arc::mojom::CameraFacing::CAMERA_FACING_FRONT:
210 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_USER;
211 desc.display_name = std::string("Front Camera");
212 break;
213 case arc::mojom::CameraFacing::CAMERA_FACING_EXTERNAL:
214 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_NONE;
215 desc.display_name = std::string("External Camera");
216 break;
217 // Mojo validates the input parameters for us so we don't need to worry
218 // about malformed values.
219 }
220 device_descriptors->push_back(desc);
221 }
222 // TODO(jcliang): Remove this after JS API supports query camera facing
223 // (http://crbug.com/543997).
224 std::sort(device_descriptors->begin(), device_descriptors->end());
225 }
226
227 void CameraHalDelegate::GetCameraInfo(int32_t camera_id,
228 const GetCameraInfoCallback& callback) {
229 // This method may be called on any thread. Currently this method is used by
230 // CameraDeviceDelegate to query camera info.
231 ipc_task_runner_->PostTask(
232 FROM_HERE, base::Bind(&CameraHalDelegate::GetCameraInfoOnModuleThread,
233 this, camera_id, callback));
234 }
235
236 void CameraHalDelegate::OpenDevice(
237 int32_t camera_id,
238 arc::mojom::Camera3DeviceOpsRequest device_ops_request,
239 const OpenDeviceCallback& callback) {
240 // This method may be called on any thread. Currently this method is used by
241 // CameraDeviceDelegate to open a camera device.
242 ipc_task_runner_->PostTask(
243 FROM_HERE,
244 base::Bind(&CameraHalDelegate::OpenDeviceOnModuleThread, this, camera_id,
245 base::Passed(&device_ops_request), callback));
246 }
247
248 void CameraHalDelegate::StartForTesting(arc::mojom::CameraModulePtrInfo info) {
249 camera_module_.Bind(std::move(info), ipc_task_runner_);
250 }
251
252 void CameraHalDelegate::ResetMojoInterfaceOnModuleThread() {
253 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
254 camera_module_.reset();
255 if (camera_module_callbacks_.is_bound()) {
256 camera_module_callbacks_.Close();
257 }
258 }
259
260 bool CameraHalDelegate::UpdateBuiltInCameraInfo() {
261 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
262 if (builtin_camera_info_updated_.IsSignaled()) {
263 return true;
264 }
265 // The built-in camera are static per specification of the Android camera HAL
266 // v3 specification. We only update the built-in camera info once.
267 ipc_task_runner_->PostTask(
268 FROM_HERE,
269 base::Bind(&CameraHalDelegate::UpdateBuiltInCameraInfoOnModuleThread,
270 this));
271 if (!builtin_camera_info_updated_.TimedWait(kEventWaitTimeoutMs)) {
272 LOG(ERROR) << "Timed out getting camera info";
273 return false;
274 }
275 return true;
276 }
277
278 void CameraHalDelegate::UpdateBuiltInCameraInfoOnModuleThread() {
279 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
280 camera_module_->GetNumberOfCameras(
281 base::Bind(&CameraHalDelegate::OnGotNumberOfCamerasOnModuleThread, this));
282 }
283
284 void CameraHalDelegate::OnGotNumberOfCamerasOnModuleThread(
285 int32_t num_cameras) {
286 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
287 if (num_cameras < 0) {
wuchengli 2017/06/09 07:43:54 <= 0 because it shouldn't happen. Printing it in l
jcliang 2017/06/09 08:34:37 Done.
288 builtin_camera_info_updated_.Signal();
289 LOG(ERROR) << "Failed to get number of cameras";
wuchengli 2017/06/09 07:43:54 print num_cameras
jcliang 2017/06/09 08:34:37 Done.
290 return;
291 }
292 VLOG(1) << "Number of built-in cameras: " << num_cameras;
293 num_builtin_cameras_ = num_cameras;
294 // Per camera HAL v3 specification SetCallbacks() should be called after the
295 // first time GetNumberOfCameras() is called, and before other CameraModule
296 // functions are called.
297 camera_module_->SetCallbacks(
298 camera_module_callbacks_.CreateInterfacePtrAndBind(),
299 base::Bind(&CameraHalDelegate::OnSetCallbacksOnModuleThread, this));
300 }
301
302 void CameraHalDelegate::OnSetCallbacksOnModuleThread(int32_t result) {
303 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
304 if (result) {
305 num_builtin_cameras_ = 0;
306 builtin_camera_info_updated_.Signal();
307 LOG(ERROR) << "Failed to set camera module callbacks: " << strerror(result);
308 return;
309 }
310 for (size_t camera_id = 0; camera_id < num_builtin_cameras_; ++camera_id) {
311 GetCameraInfoOnModuleThread(
312 camera_id, base::Bind(&CameraHalDelegate::OnGotCameraInfoOnModuleThread,
313 this, camera_id));
314 }
315 }
316
317 void CameraHalDelegate::GetCameraInfoOnModuleThread(
318 int32_t camera_id,
319 const GetCameraInfoCallback& callback) {
320 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
321 camera_module_->GetCameraInfo(camera_id, callback);
322 }
323
324 void CameraHalDelegate::OnGotCameraInfoOnModuleThread(
325 int32_t camera_id,
326 int32_t result,
327 arc::mojom::CameraInfoPtr camera_info) {
328 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
329 DVLOG(1) << "Got camera info of camera " << camera_id;
330 if (result) {
331 LOG(ERROR) << "Failed to get camera info. Camera id: " << camera_id;
332 }
333 // In case of error |camera_info| is empty.
334 camera_info_[std::to_string(camera_id)] = std::move(camera_info);
335 if (camera_info_.size() == num_builtin_cameras_) {
336 builtin_camera_info_updated_.Signal();
337 }
338 if (!builtin_camera_info_updated_.IsSignaled()) {
wuchengli 2017/06/09 07:43:54 These code can be removed.
jcliang 2017/06/09 08:34:37 Done.
339 // Make sure all the built-in camera info is set.
340 for (size_t id = 0; id < num_builtin_cameras_; ++id) {
341 if (camera_info_.find(std::to_string(id)) == camera_info_.end()) {
342 return;
343 }
344 }
345 }
346 }
347
348 void CameraHalDelegate::OpenDeviceOnModuleThread(
349 int32_t camera_id,
350 arc::mojom::Camera3DeviceOpsRequest device_ops_request,
351 const OpenDeviceCallback& callback) {
352 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
353 camera_module_->OpenDevice(camera_id, std::move(device_ops_request),
354 callback);
355 }
356
357 // CameraModuleCallbacks implementations.
358 void CameraHalDelegate::CameraDeviceStatusChange(
359 int32_t camera_id,
360 arc::mojom::CameraDeviceStatus new_status) {
361 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
362 // TODO(jcliang): Handle status change for external cameras.
363 }
364
365 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698