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

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: set CL dependency 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 if (!child_pipe.is_valid()) {
95 LOG(ERROR) << "Invalid child pipe";
96 return false;
97 }
98
99 camera_module_ =
100 mojo::MakeProxy(mojo::InterfacePtrInfo<arc::mojom::CameraModule>(
101 std::move(child_pipe), 0u),
102 ipc_task_runner_);
103
104 VLOG(1) << "Camera module IPC connection established";
105
106 return true;
107 }
108
109 void CameraHalDelegate::Reset() {
110 ipc_task_runner_->PostTask(
111 FROM_HERE,
112 base::Bind(&CameraHalDelegate::ResetMojoInterfaceOnIpcThread, this));
113 }
114
115 std::unique_ptr<VideoCaptureDevice> CameraHalDelegate::CreateDevice(
116 scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_screen_observer,
117 const VideoCaptureDeviceDescriptor& device_descriptor) {
118 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
119 std::unique_ptr<VideoCaptureDevice> capture_device;
120 if (!UpdateBuiltInCameraInfo()) {
121 return capture_device;
122 }
123 if (camera_info_.find(device_descriptor.device_id) == camera_info_.end()) {
124 LOG(ERROR) << "Invalid camera device: " << device_descriptor.device_id;
125 return capture_device;
126 }
127 capture_device.reset(new VideoCaptureDeviceArcChromeOS(
128 std::move(task_runner_for_screen_observer), device_descriptor, this));
129 return capture_device;
130 }
131
132 void CameraHalDelegate::GetSupportedFormats(
133 const VideoCaptureDeviceDescriptor& device_descriptor,
134 VideoCaptureFormats* supported_formats) {
135 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
136
137 if (!UpdateBuiltInCameraInfo()) {
138 return;
139 }
140 std::string camera_id = device_descriptor.device_id;
141 if (camera_info_.find(camera_id) == camera_info_.end() ||
142 camera_info_[camera_id].is_null()) {
143 LOG(ERROR) << "Invalid camera_id: " << camera_id;
144 return;
145 }
146 const arc::mojom::CameraInfoPtr& camera_info = camera_info_[camera_id];
147
148 const arc::mojom::CameraMetadataEntryPtr* min_frame_durations =
149 GetMetadataEntry(camera_info->static_camera_characteristics,
150 arc::mojom::CameraMetadataTag::
151 ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
152 if (!min_frame_durations) {
153 LOG(ERROR)
154 << "Failed to get available min frame durations from camera info";
155 return;
156 }
157 // The min frame durations are stored as tuples of four int64s:
158 // (hal_pixel_format, width, height, ns) x n
159 const size_t kStreamFormatOffset = 0;
160 const size_t kStreamWidthOffset = 1;
161 const size_t kStreamHeightOffset = 2;
162 const size_t kStreamDurationOffset = 3;
163 const size_t kStreamDurationSize = 4;
164 int64_t* iter =
165 reinterpret_cast<int64_t*>((*min_frame_durations)->data.data());
166 for (size_t i = 0; i < (*min_frame_durations)->count;
167 i += kStreamDurationSize) {
168 int32_t format = static_cast<int32_t>(iter[kStreamFormatOffset]);
Pawel Osciak 2017/06/13 08:40:16 checked_cast ?
jcliang 2017/06/14 04:46:06 Done.
169 int32_t width = static_cast<int32_t>(iter[kStreamWidthOffset]);
170 int32_t height = static_cast<int32_t>(iter[kStreamHeightOffset]);
171 int64_t duration = iter[kStreamDurationOffset];
172 iter += kStreamDurationSize;
173
174 float max_fps = 1.0 * 1000000000LL / duration;
Pawel Osciak 2017/06/13 08:40:16 Should we check for duration != 0 ?
jcliang 2017/06/14 04:46:06 Done.
175
176 DVLOG(1) << "[" << std::hex << format << " " << std::dec << width << " "
177 << height << " " << duration << "]";
178 VideoPixelFormat cr_format =
179 PixFormatHalToChromium(static_cast<arc::mojom::HalPixelFormat>(format));
180 if (cr_format == PIXEL_FORMAT_UNKNOWN) {
181 continue;
182 }
183 VLOG(1) << "Supported format: " << width << "x" << height
184 << " fps=" << max_fps << " format=" << cr_format;
185 supported_formats->emplace_back(gfx::Size(width, height), max_fps,
186 cr_format);
187 }
188 }
189
190 void CameraHalDelegate::GetDeviceDescriptors(
191 VideoCaptureDeviceDescriptors* device_descriptors) {
192 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
193
194 if (!UpdateBuiltInCameraInfo()) {
195 return;
196 }
197 for (size_t id = 0; id < num_builtin_cameras_; ++id) {
198 VideoCaptureDeviceDescriptor desc;
199 std::string camera_id = std::to_string(id);
200 const arc::mojom::CameraInfoPtr& camera_info = camera_info_[camera_id];
201 if (!camera_info) {
202 continue;
203 }
204 desc.device_id = camera_id;
205 desc.capture_api = VideoCaptureApi::ANDROID_API2_LIMITED;
206 desc.transport_type = VideoCaptureTransportType::OTHER_TRANSPORT;
207 switch (camera_info->facing) {
208 case arc::mojom::CameraFacing::CAMERA_FACING_BACK:
209 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT;
210 desc.display_name = std::string("Back Camera");
211 break;
212 case arc::mojom::CameraFacing::CAMERA_FACING_FRONT:
213 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_USER;
214 desc.display_name = std::string("Front Camera");
215 break;
216 case arc::mojom::CameraFacing::CAMERA_FACING_EXTERNAL:
217 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_NONE;
218 desc.display_name = std::string("External Camera");
219 break;
220 // Mojo validates the input parameters for us so we don't need to worry
221 // about malformed values.
222 }
223 device_descriptors->push_back(desc);
224 }
225 // TODO(jcliang): Remove this after JS API supports query camera facing
226 // (http://crbug.com/543997).
227 std::sort(device_descriptors->begin(), device_descriptors->end());
228 }
229
230 void CameraHalDelegate::GetCameraInfo(int32_t camera_id,
231 const GetCameraInfoCallback& callback) {
232 // This method may be called on any thread. Currently this method is used by
233 // CameraDeviceDelegate to query camera info.
234 ipc_task_runner_->PostTask(
235 FROM_HERE, base::Bind(&CameraHalDelegate::GetCameraInfoOnIpcThread, this,
236 camera_id, callback));
237 }
238
239 void CameraHalDelegate::OpenDevice(
240 int32_t camera_id,
241 arc::mojom::Camera3DeviceOpsRequest device_ops_request,
242 const OpenDeviceCallback& callback) {
243 // This method may be called on any thread. Currently this method is used by
244 // CameraDeviceDelegate to open a camera device.
245 ipc_task_runner_->PostTask(
246 FROM_HERE,
247 base::Bind(&CameraHalDelegate::OpenDeviceOnIpcThread, this, camera_id,
248 base::Passed(&device_ops_request), callback));
249 }
250
251 void CameraHalDelegate::StartForTesting(arc::mojom::CameraModulePtrInfo info) {
252 camera_module_.Bind(std::move(info), ipc_task_runner_);
253 }
254
255 void CameraHalDelegate::ResetMojoInterfaceOnIpcThread() {
256 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
257 camera_module_.reset();
258 if (camera_module_callbacks_.is_bound()) {
259 camera_module_callbacks_.Close();
260 }
261 }
262
263 bool CameraHalDelegate::UpdateBuiltInCameraInfo() {
264 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
265 if (builtin_camera_info_updated_.IsSignaled()) {
266 return true;
267 }
268 // The built-in camera are static per specification of the Android camera HAL
269 // v3 specification. We only update the built-in camera info once.
270 ipc_task_runner_->PostTask(
271 FROM_HERE,
272 base::Bind(&CameraHalDelegate::UpdateBuiltInCameraInfoOnIpcThread, this));
273 if (!builtin_camera_info_updated_.TimedWait(kEventWaitTimeoutMs)) {
274 LOG(ERROR) << "Timed out getting camera info";
275 return false;
276 }
277 return true;
278 }
279
280 void CameraHalDelegate::UpdateBuiltInCameraInfoOnIpcThread() {
281 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
282 camera_module_->GetNumberOfCameras(
283 base::Bind(&CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread, this));
284 }
285
286 void CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread(int32_t num_cameras) {
287 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
288 if (num_cameras <= 0) {
289 builtin_camera_info_updated_.Signal();
290 LOG(ERROR) << "Failed to get number of cameras: " << num_cameras;
291 return;
292 }
293 VLOG(1) << "Number of built-in cameras: " << num_cameras;
294 num_builtin_cameras_ = num_cameras;
295 // Per camera HAL v3 specification SetCallbacks() should be called after the
296 // first time GetNumberOfCameras() is called, and before other CameraModule
297 // functions are called.
298 arc::mojom::CameraModuleCallbacksPtr camera_module_callbacks_ptr;
299 arc::mojom::CameraModuleCallbacksRequest camera_module_callbacks_request =
300 mojo::MakeRequest(&camera_module_callbacks_ptr);
301 camera_module_callbacks_.Bind(std::move(camera_module_callbacks_request));
302 camera_module_->SetCallbacks(
303 std::move(camera_module_callbacks_ptr),
304 base::Bind(&CameraHalDelegate::OnSetCallbacksOnIpcThread, this));
305 }
306
307 void CameraHalDelegate::OnSetCallbacksOnIpcThread(int32_t result) {
308 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
309 if (result) {
310 num_builtin_cameras_ = 0;
311 builtin_camera_info_updated_.Signal();
312 LOG(ERROR) << "Failed to set camera module callbacks: " << strerror(result);
313 return;
314 }
315 for (size_t camera_id = 0; camera_id < num_builtin_cameras_; ++camera_id) {
316 GetCameraInfoOnIpcThread(
317 camera_id, base::Bind(&CameraHalDelegate::OnGotCameraInfoOnIpcThread,
318 this, camera_id));
319 }
320 }
321
322 void CameraHalDelegate::GetCameraInfoOnIpcThread(
323 int32_t camera_id,
324 const GetCameraInfoCallback& callback) {
325 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
326 camera_module_->GetCameraInfo(camera_id, callback);
327 }
328
329 void CameraHalDelegate::OnGotCameraInfoOnIpcThread(
330 int32_t camera_id,
331 int32_t result,
332 arc::mojom::CameraInfoPtr camera_info) {
333 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
334 DVLOG(1) << "Got camera info of camera " << camera_id;
335 if (result) {
336 LOG(ERROR) << "Failed to get camera info. Camera id: " << camera_id;
337 }
338 // In case of error |camera_info| is empty.
339 camera_info_[std::to_string(camera_id)] = std::move(camera_info);
340 if (camera_info_.size() == num_builtin_cameras_) {
341 builtin_camera_info_updated_.Signal();
342 }
343 }
344
345 void CameraHalDelegate::OpenDeviceOnIpcThread(
346 int32_t camera_id,
347 arc::mojom::Camera3DeviceOpsRequest device_ops_request,
348 const OpenDeviceCallback& callback) {
349 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
350 camera_module_->OpenDevice(camera_id, std::move(device_ops_request),
351 callback);
352 }
353
354 // CameraModuleCallbacks implementations.
355 void CameraHalDelegate::CameraDeviceStatusChange(
356 int32_t camera_id,
357 arc::mojom::CameraDeviceStatus new_status) {
358 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
359 // TODO(jcliang): Handle status change for external cameras.
Pawel Osciak 2017/06/13 08:40:16 NOTIMPLEMENTED() ?
jcliang 2017/06/14 04:46:06 Done.
360 }
361
362 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698