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

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

Issue 2936373002: Revert of media: add video capture device for ARC++ camera HAL v3 (Closed)
Patch Set: 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 = base::checked_cast<int32_t>(iter[kStreamFormatOffset]);
169 int32_t width = base::checked_cast<int32_t>(iter[kStreamWidthOffset]);
170 int32_t height = base::checked_cast<int32_t>(iter[kStreamHeightOffset]);
171 int64_t duration = iter[kStreamDurationOffset];
172 iter += kStreamDurationSize;
173
174 if (duration <= 0) {
175 LOG(ERROR) << "Ignoring invalid frame duration: " << duration;
176 continue;
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 ipc_task_runner_->PostTask(
239 FROM_HERE, base::Bind(&CameraHalDelegate::GetCameraInfoOnIpcThread, this,
240 camera_id, callback));
241 }
242
243 void CameraHalDelegate::OpenDevice(
244 int32_t camera_id,
245 arc::mojom::Camera3DeviceOpsRequest device_ops_request,
246 const OpenDeviceCallback& callback) {
247 // This method may be called on any thread. Currently this method is used by
248 // CameraDeviceDelegate to open a camera device.
249 ipc_task_runner_->PostTask(
250 FROM_HERE,
251 base::Bind(&CameraHalDelegate::OpenDeviceOnIpcThread, this, camera_id,
252 base::Passed(&device_ops_request), callback));
253 }
254
255 void CameraHalDelegate::StartForTesting(arc::mojom::CameraModulePtrInfo info) {
256 camera_module_.Bind(std::move(info), ipc_task_runner_);
257 }
258
259 void CameraHalDelegate::ResetMojoInterfaceOnIpcThread() {
260 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
261 camera_module_.reset();
262 if (camera_module_callbacks_.is_bound()) {
263 camera_module_callbacks_.Close();
264 }
265 }
266
267 bool CameraHalDelegate::UpdateBuiltInCameraInfo() {
268 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
269 if (builtin_camera_info_updated_.IsSignaled()) {
270 return true;
271 }
272 // The built-in camera are static per specification of the Android camera HAL
273 // v3 specification. We only update the built-in camera info once.
274 ipc_task_runner_->PostTask(
275 FROM_HERE,
276 base::Bind(&CameraHalDelegate::UpdateBuiltInCameraInfoOnIpcThread, 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::UpdateBuiltInCameraInfoOnIpcThread() {
285 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
286 camera_module_->GetNumberOfCameras(
287 base::Bind(&CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread, this));
288 }
289
290 void CameraHalDelegate::OnGotNumberOfCamerasOnIpcThread(int32_t num_cameras) {
291 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
292 if (num_cameras <= 0) {
293 builtin_camera_info_updated_.Signal();
294 LOG(ERROR) << "Failed to get number of cameras: " << num_cameras;
295 return;
296 }
297 VLOG(1) << "Number of built-in cameras: " << num_cameras;
298 num_builtin_cameras_ = num_cameras;
299 // Per camera HAL v3 specification SetCallbacks() should be called after the
300 // first time GetNumberOfCameras() is called, and before other CameraModule
301 // functions are called.
302 arc::mojom::CameraModuleCallbacksPtr camera_module_callbacks_ptr;
303 arc::mojom::CameraModuleCallbacksRequest camera_module_callbacks_request =
304 mojo::MakeRequest(&camera_module_callbacks_ptr);
305 camera_module_callbacks_.Bind(std::move(camera_module_callbacks_request));
306 camera_module_->SetCallbacks(
307 std::move(camera_module_callbacks_ptr),
308 base::Bind(&CameraHalDelegate::OnSetCallbacksOnIpcThread, this));
309 }
310
311 void CameraHalDelegate::OnSetCallbacksOnIpcThread(int32_t result) {
312 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
313 if (result) {
314 num_builtin_cameras_ = 0;
315 builtin_camera_info_updated_.Signal();
316 LOG(ERROR) << "Failed to set camera module callbacks: " << strerror(result);
317 return;
318 }
319 for (size_t camera_id = 0; camera_id < num_builtin_cameras_; ++camera_id) {
320 GetCameraInfoOnIpcThread(
321 camera_id, base::Bind(&CameraHalDelegate::OnGotCameraInfoOnIpcThread,
322 this, camera_id));
323 }
324 }
325
326 void CameraHalDelegate::GetCameraInfoOnIpcThread(
327 int32_t camera_id,
328 const GetCameraInfoCallback& callback) {
329 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
330 camera_module_->GetCameraInfo(camera_id, callback);
331 }
332
333 void CameraHalDelegate::OnGotCameraInfoOnIpcThread(
334 int32_t camera_id,
335 int32_t result,
336 arc::mojom::CameraInfoPtr camera_info) {
337 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
338 DVLOG(1) << "Got camera info of camera " << camera_id;
339 if (result) {
340 LOG(ERROR) << "Failed to get camera info. Camera id: " << camera_id;
341 }
342 // In case of error |camera_info| is empty.
343 camera_info_[std::to_string(camera_id)] = std::move(camera_info);
344 if (camera_info_.size() == num_builtin_cameras_) {
345 builtin_camera_info_updated_.Signal();
346 }
347 }
348
349 void CameraHalDelegate::OpenDeviceOnIpcThread(
350 int32_t camera_id,
351 arc::mojom::Camera3DeviceOpsRequest device_ops_request,
352 const OpenDeviceCallback& callback) {
353 DCHECK(ipc_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(ipc_task_runner_->BelongsToCurrentThread());
363 // TODO(jcliang): Handle status change for external cameras.
364 NOTIMPLEMENTED() << "CameraDeviceStatusChange is not implemented";
365 }
366
367 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/chromeos/camera_hal_delegate.h ('k') | media/capture/video/chromeos/camera_hal_delegate_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698