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

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 wuchengli's and chfremer's comments 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/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 const 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_(module_task_runner),
chfremer 2017/05/26 17:40:57 For passing scoped_refptr<>, I believe it is now r
jcliang 2017/05/31 14:58:06 Done.
45 camera_module_callbacks_(this) {
46 DETACH_FROM_SEQUENCE(sequence_checker_);
47 }
48
49 CameraHalDelegate::~CameraHalDelegate() {
50 base::WaitableEvent interface_closed(
51 base::WaitableEvent::ResetPolicy::MANUAL,
52 base::WaitableEvent::InitialState::NOT_SIGNALED);
53 module_task_runner_->PostTask(
54 FROM_HERE,
55 base::Bind(&CameraHalDelegate::ResetMojoInterfaceOnModuleThread,
56 base::Unretained(this), base::Unretained(&interface_closed)));
57 interface_closed.Wait();
58 }
59
60 bool CameraHalDelegate::StartCameraModuleIpc() {
61 // Non-blocking socket handle.
62 mojo::edk::ScopedPlatformHandle socket_handle = mojo::edk::CreateClientHandle(
63 mojo::edk::NamedPlatformHandle(kArcCamera3SocketPath));
64
65 // Set socket to blocking
66 int flags = HANDLE_EINTR(fcntl(socket_handle.get().handle, F_GETFL));
67 if (flags == -1) {
68 PLOG(ERROR) << "fcntl(F_GETFL) failed: ";
69 return false;
70 }
71 if (HANDLE_EINTR(fcntl(socket_handle.get().handle, F_SETFL,
72 flags & ~O_NONBLOCK)) == -1) {
73 PLOG(ERROR) << "fcntl(F_SETFL) failed: ";
74 return false;
75 }
76
77 const size_t kTokenSize = 32;
78 char token[kTokenSize] = {};
79 std::deque<mojo::edk::PlatformHandle> platform_handles;
80 ssize_t ret = mojo::edk::PlatformChannelRecvmsg(
81 socket_handle.get(), token, sizeof(token), &platform_handles, true);
82 if (ret == -1) {
83 PLOG(ERROR) << "PlatformChannelRecvmsg failed: ";
84 return false;
85 }
86 if (platform_handles.size() != 1) {
87 LOG(ERROR) << "Unexpected number of handles received, expected 1: "
88 << platform_handles.size();
89 return false;
90 }
91 mojo::edk::ScopedPlatformHandle parent_pipe(platform_handles.back());
92 platform_handles.pop_back();
93 if (!parent_pipe.is_valid()) {
94 LOG(ERROR) << "Invalid parent pipe";
95 return false;
96 }
97 std::unique_ptr<mojo::edk::IncomingBrokerClientInvitation> invitation =
98 mojo::edk::IncomingBrokerClientInvitation::Accept(
99 mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
100 std::move(parent_pipe)));
101 mojo::ScopedMessagePipeHandle child_pipe =
102 invitation->ExtractMessagePipe(token);
103 DCHECK(child_pipe.is_valid());
104
105 camera_module_ =
106 mojo::MakeProxy(mojo::InterfacePtrInfo<arc::mojom::CameraModule>(
107 std::move(child_pipe), 0u),
108 module_task_runner_);
109
110 VLOG(1) << "Camera module IPC connection established";
111
112 return true;
113 }
chfremer 2017/05/26 17:40:57 The contents of the above method look reasonable,
jcliang 2017/05/31 14:58:06 I believe this is the common flow to establish a l
yzshen1 2017/06/02 15:15:22 +rockot who knows this the best.
114
115 std::unique_ptr<VideoCaptureDevice> CameraHalDelegate::CreateDevice(
116 const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
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 ui_task_runner, 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 // FIXME(jcliang): Remove this after the camera HAL has set the min frame
149 // durations for all formats.
150 supported_formats->emplace_back(gfx::Size(1280, 720), 60.0,
151 PIXEL_FORMAT_NV12);
152
153 const arc::mojom::CameraMetadataEntryPtr* min_frame_durations =
154 GetMetadataEntry(camera_info->static_camera_characteristics,
155 arc::mojom::CameraMetadataTag::
156 ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
157 if (!min_frame_durations) {
158 LOG(ERROR)
159 << "Failed to get available min frame durations from camera info";
160 return;
161 }
162 // The min frame durations are stored as tuples of four int64s:
163 // (hal_pixel_format, width, height, ns) x n
164 const size_t kStreamFormatOffset = 0;
165 const size_t kStreamWidthOffset = 1;
166 const size_t kStreamHeightOffset = 2;
167 const size_t kStreamDurationOffset = 3;
168 const size_t kStreamDurationSize = 4;
169 int64_t* iter =
170 reinterpret_cast<int64_t*>((*min_frame_durations)->data.data());
171 for (size_t i = 0; i < (*min_frame_durations)->count / sizeof(int64_t); ++i) {
172 int32_t format = static_cast<int32_t>(iter[kStreamFormatOffset]);
173 int32_t width = static_cast<int32_t>(iter[kStreamWidthOffset]);
174 int32_t height = static_cast<int32_t>(iter[kStreamHeightOffset]);
175 int64_t duration = iter[kStreamDurationOffset];
176 iter += kStreamDurationSize;
177
178 float max_fps = 1.0 * 1000000000LL / duration;
179
180 DVLOG(1) << "[" << std::hex << format << " " << std::dec << width << " "
181 << height << " " << duration << "]";
182 VideoPixelFormat cr_format =
183 PixFormatHalToChromium(static_cast<arc::mojom::HalPixelFormat>(format));
184 if (cr_format == PIXEL_FORMAT_UNKNOWN) {
185 continue;
186 }
187 VLOG(1) << "Supported format: " << width << "x" << height
188 << " fps=" << max_fps << " format=" << cr_format;
189 supported_formats->emplace_back(gfx::Size(width, height), max_fps,
190 cr_format);
191 }
192 }
193
194 void CameraHalDelegate::GetDeviceDescriptors(
195 VideoCaptureDeviceDescriptors* device_descriptors) {
196 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
197
198 if (!UpdateBuiltInCameraInfo()) {
199 return;
200 }
201 for (size_t id = 0; id < num_builtin_cameras_; ++id) {
202 VideoCaptureDeviceDescriptor desc;
203 std::string camera_id = std::to_string(id);
204 const arc::mojom::CameraInfoPtr& camera_info = camera_info_[camera_id];
205 if (!camera_info) {
206 continue;
207 }
208 desc.device_id = camera_id;
209 desc.capture_api = VideoCaptureApi::ANDROID_API2_LIMITED;
210 desc.transport_type = VideoCaptureTransportType::OTHER_TRANSPORT;
211 switch (camera_info->facing) {
212 case arc::mojom::CameraFacing::CAMERA_FACING_BACK:
213 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_ENVIRONMENT;
214 desc.display_name = std::string("Back Camera");
215 break;
216 case arc::mojom::CameraFacing::CAMERA_FACING_FRONT:
217 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_USER;
218 desc.display_name = std::string("Front Camera");
219 break;
220 case arc::mojom::CameraFacing::CAMERA_FACING_EXTERNAL:
221 desc.facing = VideoFacingMode::MEDIA_VIDEO_FACING_NONE;
222 desc.display_name = std::string("External Camera");
223 break;
224 // Mojo validates the input parameters for us so we don't need to worry
225 // about malformed values.
226 }
227 device_descriptors->push_back(desc);
228 }
229 // TODO(jcliang): Remove this after JS API supports query camera facing
230 // (http://crbug.com/543997).
231 std::sort(device_descriptors->begin(), device_descriptors->end());
232 }
233
234 void CameraHalDelegate::GetCameraInfo(int32_t camera_id,
235 const GetCameraInfoCallback& callback) {
236 // This method may be called on any thread. Currently this method is used by
237 // CameraDeviceDelegate to query camera info.
238 module_task_runner_->PostTask(
239 FROM_HERE, base::Bind(&CameraHalDelegate::GetCameraInfoOnModuleThread,
240 this, camera_id, callback));
241 }
242
243 void CameraHalDelegate::OpenDevice(int32_t camera_id,
244 const OpenDeviceCallback& callback) {
245 // This method may be called on any thread. Currently this method is used by
246 // CameraDeviceDelegate to open a camera device.
247 module_task_runner_->PostTask(
248 FROM_HERE, base::Bind(&CameraHalDelegate::OpenDeviceOnModuleThread, this,
249 camera_id, callback));
250 }
251
252 void CameraHalDelegate::StartForTesting(arc::mojom::CameraModulePtrInfo info) {
253 camera_module_.Bind(std::move(info), module_task_runner_);
254 }
255
256 void CameraHalDelegate::ResetMojoInterfaceOnModuleThread(
257 base::WaitableEvent* interface_closed) {
258 DCHECK(module_task_runner_->BelongsToCurrentThread());
259 camera_module_.reset();
260 if (camera_module_callbacks_.is_bound()) {
261 camera_module_callbacks_.Unbind();
262 }
263 interface_closed->Signal();
264 }
265
266 bool CameraHalDelegate::UpdateBuiltInCameraInfo() {
267 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
268 if (builtin_camera_info_updated_.IsSignaled()) {
269 return true;
270 }
271 // The built-in camera are static per specification of the Android camera HAL
272 // v3 specification. We only update the built-in camera info once.
273 module_task_runner_->PostTask(
274 FROM_HERE,
275 base::Bind(&CameraHalDelegate::UpdateBuiltInCameraInfoOnModuleThread,
276 this));
277 if (!builtin_camera_info_updated_.TimedWait(kEventWaitTimeoutMs)) {
278 LOG(ERROR) << "Timed out getting camera info";
279 return false;
280 }
281 return true;
282 }
283
284 void CameraHalDelegate::UpdateBuiltInCameraInfoOnModuleThread() {
285 DCHECK(module_task_runner_->BelongsToCurrentThread());
286 camera_module_->GetNumberOfCameras(
287 base::Bind(&CameraHalDelegate::OnGotNumberOfCamerasOnModuleThread, this));
288 }
289
290 void CameraHalDelegate::OnGotNumberOfCamerasOnModuleThread(
291 int32_t num_cameras) {
292 DCHECK(module_task_runner_->BelongsToCurrentThread());
293 if (num_cameras < 0) {
294 builtin_camera_info_updated_.Signal();
295 LOG(ERROR) << "Failed to get number of cameras";
296 return;
297 }
298 VLOG(1) << "Number of built-in cameras: " << num_cameras;
299 num_builtin_cameras_ = num_cameras;
300 // Per camera HAL v3 specification SetCallbacks() should be called after the
301 // first time GetNumberOfCameras() is called, and before other CameraModule
302 // functions are called.
303 camera_module_->SetCallbacks(
304 camera_module_callbacks_.CreateInterfacePtrAndBind(),
305 base::Bind(&CameraHalDelegate::OnSetCallbacksOnModuleThread, this));
306 }
307
308 void CameraHalDelegate::OnSetCallbacksOnModuleThread(int32_t result) {
309 DCHECK(module_task_runner_->BelongsToCurrentThread());
310 if (result) {
311 num_builtin_cameras_ = 0;
312 builtin_camera_info_updated_.Signal();
313 LOG(ERROR) << "Failed to set camera module callbacks: " << strerror(result);
314 return;
315 }
316 for (size_t camera_id = 0; camera_id < num_builtin_cameras_; ++camera_id) {
317 GetCameraInfoOnModuleThread(
318 camera_id, base::Bind(&CameraHalDelegate::OnGotCameraInfoOnModuleThread,
319 this, camera_id));
320 }
321 }
322
323 void CameraHalDelegate::GetCameraInfoOnModuleThread(
324 int32_t camera_id,
325 const GetCameraInfoCallback& callback) {
326 DCHECK(module_task_runner_->BelongsToCurrentThread());
327 camera_module_->GetCameraInfo(camera_id, callback);
328 }
329
330 void CameraHalDelegate::OnGotCameraInfoOnModuleThread(
331 int32_t camera_id,
332 int32_t result,
333 arc::mojom::CameraInfoPtr camera_info) {
334 DCHECK(module_task_runner_->BelongsToCurrentThread());
335 DVLOG(1) << "Got camera info of camera " << camera_id;
336 if (result) {
337 LOG(ERROR) << "Failed to get camera info. Camera id: " << camera_id;
338 }
339 // In case of error |camera_info| is empty.
340 camera_info_[std::to_string(camera_id)] = std::move(camera_info);
341 if (camera_info_.size() == num_builtin_cameras_) {
342 builtin_camera_info_updated_.Signal();
343 }
344 if (!builtin_camera_info_updated_.IsSignaled()) {
345 // Make sure all the built-in camera info is set.
346 for (size_t id = 0; id < num_builtin_cameras_; ++id) {
347 if (camera_info_.find(std::to_string(id)) == camera_info_.end()) {
348 return;
349 }
350 }
351 }
352 }
353
354 void CameraHalDelegate::OpenDeviceOnModuleThread(
355 int32_t camera_id,
356 const OpenDeviceCallback& callback) {
357 DCHECK(module_task_runner_->BelongsToCurrentThread());
358 camera_module_->OpenDevice(camera_id, callback);
359 }
360
361 // CameraModuleCallbacks implementations.
362 void CameraHalDelegate::CameraDeviceStatusChange(
363 int32_t camera_id,
364 arc::mojom::CameraDeviceStatus new_status) {
365 DCHECK(module_task_runner_->BelongsToCurrentThread());
366 // TODO(jcliang): Handle status change for external cameras.
367 }
368
369 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698