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

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

Powered by Google App Engine
This is Rietveld 408576698