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

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

Issue 2837273004: media: add video capture device for ARC++ camera HAL v3 (Closed)
Patch Set: address wuchengli@'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_device_delegate.h"
6
7 #include <libdrm/drm_fourcc.h>
8
9 #include "media/capture/video/chromeos/camera_metadata_utils.h"
10 #include "mojo/edk/embedder/embedder.h"
11 #include "mojo/edk/embedder/scoped_platform_handle.h"
12 #include "third_party/libsync/include/sync/sync.h"
13
14 namespace media {
15
16 namespace {
17
18 struct SupportedFormat {
19 VideoPixelFormat chromium_format;
20 arc::mojom::HalPixelFormat hal_format;
21 uint32_t drm_format;
22 } const kSupportedFormats[] = {
23 // The Android camera HAL v3 has three types of mandatory pixel formats:
24 //
25 // 1. HAL_PIXEL_FORMAT_YCbCr_420_888 (YUV flexible format).
26 // 2. HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED (platform-specific format).
27 // 3. HAL_PIXEL_FORMAT_BLOB (for JPEG).
28 //
29 // We can't use HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED as it is highly
30 // platform specific and there is no way for Chrome to query the exact
31 // pixel layout of the implementation-defined buffer.
32 //
33 // On Android the framework requests the preview stream with the
34 // implementation-defined format, and as a result some camera HALs support
35 // only implementation-defined preview buffers. We should use the video
36 // capture stream in Chrome VCD as it is mandatory for the camera HAL to
37 // support YUV flexbile format video streams.
38 {PIXEL_FORMAT_I420,
39 arc::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_YCbCr_420_888,
40 DRM_FORMAT_YUV420},
41 // TODO(jcliang): Do not use IMPLEMENTATION_DEFINED formats at all as it is
42 // nearly impossible to get it right across all boards.
43 {PIXEL_FORMAT_NV12,
44 arc::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
45 DRM_FORMAT_NV12},
46 };
47
48 } // namespace
49
50 CameraDeviceDelegate::CameraDeviceDelegate(
51 VideoCaptureDeviceDescriptor device_descriptor,
52 arc::mojom::CameraMetadataPtr static_metadata,
53 mojo::InterfacePtrInfo<arc::mojom::Camera3DeviceOps> device_ops_info,
54 const scoped_refptr<base::SingleThreadTaskRunner> ipc_task_runner)
55 : device_descriptor_(device_descriptor),
56 static_metadata_(std::move(static_metadata)),
57 state_(kStopped),
58 closed_(nullptr),
59 rotation_(0),
60 device_ops_info_(std::move(device_ops_info)),
61 callback_ops_(this),
62 ipc_task_runner_(ipc_task_runner),
63 frame_number_(0),
64 partial_result_count_(1),
65 first_frame_shutter_time_(base::TimeTicks::Now()) {}
66
67 // static
68 VideoPixelFormat CameraDeviceDelegate::PixFormatHalToChromium(
69 arc::mojom::HalPixelFormat from) {
70 auto it =
71 std::find_if(std::begin(kSupportedFormats), std::end(kSupportedFormats),
72 [from](SupportedFormat f) { return f.hal_format == from; });
73 if (it == std::end(kSupportedFormats)) {
74 return PIXEL_FORMAT_UNKNOWN;
75 }
76 return it->chromium_format;
77 }
78
79 // static
80 uint32_t CameraDeviceDelegate::PixFormatChromiumToDrm(VideoPixelFormat from) {
81 auto it = std::find_if(
82 std::begin(kSupportedFormats), std::end(kSupportedFormats),
83 [from](SupportedFormat f) { return f.chromium_format == from; });
84 if (it == std::end(kSupportedFormats)) {
85 return 0;
86 }
87 return it->drm_format;
88 }
89
90 void CameraDeviceDelegate::AllocateAndStart(
91 const VideoCaptureParams& params,
92 std::unique_ptr<VideoCaptureDevice::Client> client) {
93 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
94 DCHECK(!client_);
95 DCHECK_EQ(state_, kStopped);
96 const arc::mojom::CameraMetadataEntryPtr* partial_count = GetMetadataEntry(
97 static_metadata_,
98 arc::mojom::CameraMetadataTag::ANDROID_REQUEST_PARTIAL_RESULT_COUNT);
99 // The partial result count metadata is optional. It defaults to 1 in case it
100 // is not set in the static metadata.
101 if (partial_count) {
102 partial_result_count_ =
103 *reinterpret_cast<int32_t*>((*partial_count)->data.data());
104 }
105
106 client_ = std::move(client);
107 device_ops_.Bind(std::move(device_ops_info_), ipc_task_runner_);
108 device_ops_.set_connection_error_handler(
109 base::Bind(&CameraDeviceDelegate::OnMojoConnectionError, this));
110 frame_number_ = 0;
111 partial_results_.clear();
112 first_frame_shutter_time_ = base::TimeTicks::Now();
113
114 // Set up context for preview stream.
115 arc::mojom::Camera3StreamPtr preview_stream =
116 arc::mojom::Camera3Stream::New();
117 preview_stream->id = static_cast<uint64_t>(
118 arc::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW);
119 preview_stream->stream_type =
120 arc::mojom::Camera3StreamType::CAMERA3_STREAM_OUTPUT;
121 preview_stream->width = params.requested_format.frame_size.width();
122 preview_stream->height = params.requested_format.frame_size.height();
123 // TODO(jcliang): We should not use implementation defined format here.
124 preview_stream->format =
125 arc::mojom::HalPixelFormat::HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
126 preview_stream->data_space = 0;
127 preview_stream->rotation =
128 arc::mojom::Camera3StreamRotation::CAMERA3_STREAM_ROTATION_0;
129
130 stream_context_.reset(new StreamContext);
131 stream_context_->params = params;
132 stream_context_->stream = std::move(preview_stream);
133
134 SetState(kStarting);
135 Initialize();
136 }
137
138 void CameraDeviceDelegate::StopAndDeAllocate(base::WaitableEvent* closed) {
139 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
140 // StopAndDeAllocate may be called at any state except kStopping.
141 DCHECK_NE(state_, kStopping);
142
143 if (!device_ops_.is_bound() || state_ == kStopped) {
144 // In case of Mojo connection error |device_ops_| and |callback_ops_| are
145 // unbound.
146 closed->Signal();
147 return;
148 }
149 closed_ = closed;
150 SetState(kStopping);
151 device_ops_->Close(base::Bind(&CameraDeviceDelegate::OnClosed, this));
152 }
153
154 void CameraDeviceDelegate::TakePhoto(
155 VideoCaptureDevice::TakePhotoCallback callback) {
156 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
157 // TODO(jcliang): Implement TakePhoto.
158 }
159
160 void CameraDeviceDelegate::GetPhotoCapabilities(
161 VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) {
162 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
163 // TODO(jcliang): Implement GetPhotoCapabilities.
164 }
165
166 void CameraDeviceDelegate::SetPhotoOptions(
167 mojom::PhotoSettingsPtr settings,
168 VideoCaptureDevice::SetPhotoOptionsCallback callback) {
169 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
170 // TODO(jcliang): Implement SetPhotoOptions.
171 }
172
173 void CameraDeviceDelegate::SetRotation(int rotation) {
174 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
175 DCHECK(rotation >= 0 && rotation < 360 && rotation % 90 == 0);
176 rotation_ = rotation;
177 }
178
179 void CameraDeviceDelegate::SetState(State state) {
180 state_ = state;
181 }
182
183 void CameraDeviceDelegate::SetErrorState(
184 const tracked_objects::Location& from_here,
185 const std::string& reason) {
186 state_ = kError;
187 LOG(ERROR) << reason;
188 client_->OnError(from_here, reason);
189 }
190
191 void CameraDeviceDelegate::ResetMojoInterface() {
192 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
193 device_ops_.reset();
194 if (callback_ops_.is_bound()) {
195 callback_ops_.Unbind();
196 }
197 }
198
199 void CameraDeviceDelegate::OnMojoConnectionError() {
200 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
201 if (state_ == kStopping) {
202 // When in stopping state the camera HAL adapter may terminate the Mojo
203 // channel before we do, in which case the OnClosed callback would not be
204 // called.
205 OnClosed(0);
206 } else {
207 // The Mojo channel terminated unexpectedly.
208 ResetMojoInterface();
209 SetState(kStopped);
210 SetErrorState(FROM_HERE, "Mojo connection error");
211 }
212 }
213
214 void CameraDeviceDelegate::OnClosed(int32_t result) {
215 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
216 DCHECK(closed_);
217 if (result) {
218 client_->OnLog(std::string("Failed to close device: ") +
219 std::string(strerror(result)));
220 }
221 ResetMojoInterface();
222 // Only after the Mojo channel is closed can we be sure that |stream_context_|
223 // is not accessed anymore.
224 stream_context_.reset();
225 client_.reset();
226 SetState(kStopped);
227 closed_->Signal();
228 closed_ = nullptr;
229 }
230
231 void CameraDeviceDelegate::Initialize() {
232 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
233 DCHECK_EQ(state_, kStarting);
234
235 device_ops_->Initialize(
236 callback_ops_.CreateInterfacePtrAndBind(),
237 base::Bind(&CameraDeviceDelegate::OnInitialized, this));
238 callback_ops_.set_connection_error_handler(
239 base::Bind(&CameraDeviceDelegate::OnMojoConnectionError, this));
240 }
241
242 void CameraDeviceDelegate::OnInitialized(int32_t result) {
243 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
244 DCHECK(state_ == kStarting || state_ == kStopping);
245
246 if (state_ == kStopping) {
247 return;
248 }
249 if (result) {
250 SetErrorState(FROM_HERE, std::string("Failed to initialize camera device") +
251 std::to_string(result));
252 return;
253 }
254 SetState(kInitialized);
255 ConfigureStreams();
256 }
257
258 void CameraDeviceDelegate::ConfigureStreams() {
259 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
260 DCHECK(state_ == kInitialized);
261
262 arc::mojom::Camera3StreamConfigurationPtr stream_config =
263 arc::mojom::Camera3StreamConfiguration::New();
264 stream_config->streams.push_back(stream_context_->stream.Clone());
265 stream_config->operation_mode = arc::mojom::Camera3StreamConfigurationMode::
266 CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE;
267 device_ops_->ConfigureStreams(
268 std::move(stream_config),
269 base::Bind(&CameraDeviceDelegate::OnConfiguredStreams, this));
270 }
271
272 void CameraDeviceDelegate::OnConfiguredStreams(
273 int32_t result,
274 arc::mojom::Camera3StreamConfigurationPtr updated_config) {
275 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
276 DCHECK(state_ == kInitialized || state_ == kStopping);
277
278 if (state_ == kStopping) {
279 return;
280 }
281 if (result) {
282 SetErrorState(FROM_HERE, std::string("Failed to configure streams") +
283 std::to_string(result));
284 return;
285 }
286 if (!updated_config || updated_config->streams.size() != 1) {
287 SetErrorState(FROM_HERE,
288 std::string("Wrong number of streams configured") +
289 std::to_string(updated_config->streams.size()));
290 return;
291 }
292 auto& updated_stream = updated_config->streams[0];
293 // TODO(jcliang): Determine the best format from metadata.
294 VideoCaptureFormat capture_format = stream_context_->params.requested_format;
295 capture_format.pixel_format = PIXEL_FORMAT_NV12;
296 stream_context_->capture_format = capture_format;
297 stream_context_->stream->usage = updated_stream->usage;
298 stream_context_->stream->max_buffers = updated_stream->max_buffers;
299
300 VLOG(2) << "Stream " << updated_stream->id
301 << " configured: usage=" << updated_stream->usage
302 << " max_buffers=" << updated_stream->max_buffers;
303
304 // Allocate buffers.
305 size_t num_buffers = stream_context_->stream->max_buffers;
306 stream_context_->buffers.resize(num_buffers);
307 for (size_t j = 0; j < num_buffers; ++j) {
308 const VideoCaptureFormat frame_format(
309 gfx::Size(stream_context_->stream->width,
310 stream_context_->stream->height),
311 0.0, stream_context_->capture_format.pixel_format);
312 std::unique_ptr<base::SharedMemory> buffer(new base::SharedMemory());
313 base::SharedMemoryCreateOptions options;
314 options.size = frame_format.ImageAllocationSize();
315 options.share_read_only = false;
316 bool ret = buffer->Create(options);
317 if (!ret) {
318 SetErrorState(FROM_HERE, "Failed to create SharedMemory buffer");
319 return;
320 }
321 ret = buffer->Map(buffer->requested_size());
322 if (!ret) {
323 SetErrorState(FROM_HERE, "Failed to map SharedMemory buffer");
324 return;
325 }
326 stream_context_->buffers[j] = std::move(buffer);
327 stream_context_->free_buffers.push(j);
328 }
329 VLOG(2) << "Allocated " << stream_context_->stream->max_buffers << " buffers";
330 ConstructDefaultRequestSettings();
331 client_->OnStarted();
332 }
333
334 void CameraDeviceDelegate::ConstructDefaultRequestSettings() {
335 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
336 DCHECK(stream_context_);
337
338 device_ops_->ConstructDefaultRequestSettings(
339 arc::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW,
340 base::Bind(&CameraDeviceDelegate::OnConstructedDefaultRequestSettings,
341 this));
342 }
343
344 void CameraDeviceDelegate::OnConstructedDefaultRequestSettings(
345 arc::mojom::CameraMetadataPtr settings) {
346 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
347
348 if (state_ == kStopping) {
349 return;
350 }
351 DCHECK(stream_context_);
352 stream_context_->request_settings = std::move(settings);
353 SetState(kStreamConfigured);
354 StartCapture();
355 }
356
357 void CameraDeviceDelegate::StartCapture() {
358 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
359 DCHECK(state_ == kStreamConfigured);
360
361 if (state_ == kStopping) {
362 return;
363 }
364 DCHECK(stream_context_);
365 DCHECK(!stream_context_->request_settings.is_null());
366 SetState(kCapturing);
367 RegisterBuffer();
368 }
369
370 void CameraDeviceDelegate::RegisterBuffer() {
371 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
372 DCHECK(state_ == kCapturing || state_ == kStopping);
373
374 if (state_ == kStopping) {
375 return;
376 }
377 DCHECK(stream_context_);
378 if (stream_context_->free_buffers.empty()) {
379 return;
380 }
381
382 size_t buffer_id = stream_context_->free_buffers.front();
383 stream_context_->free_buffers.pop();
384 const base::SharedMemory* buffer = stream_context_->buffers[buffer_id].get();
385
386 VideoPixelFormat buffer_format = stream_context_->capture_format.pixel_format;
387 uint32_t drm_format = PixFormatChromiumToDrm(buffer_format);
388 if (!drm_format) {
389 SetErrorState(FROM_HERE, std::string("Unsupported video pixel format") +
390 VideoPixelFormatToString(buffer_format));
391 return;
392 }
393 arc::mojom::HalPixelFormat hal_pixel_format = stream_context_->stream->format;
394
395 size_t num_planes = VideoFrame::NumPlanes(buffer_format);
396 std::vector<mojo::ScopedHandle> fds(num_planes);
397 std::vector<uint32_t> strides(num_planes);
398 std::vector<uint32_t> offsets(num_planes);
399 const VideoCaptureParams& params = stream_context_->params;
400 for (size_t i = 0; i < num_planes; ++i) {
401 base::SharedMemoryHandle shm_handle = buffer->handle();
402 // Wrap the platform handle.
403 MojoHandle wrapped_handle;
404 MojoResult result = mojo::edk::CreatePlatformHandleWrapper(
405 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(
406 base::SharedMemory::DuplicateHandle(shm_handle).fd)),
407 &wrapped_handle);
408 if (result != MOJO_RESULT_OK) {
409 SetErrorState(FROM_HERE, "Failed to wrap shared memory handle");
410 return;
411 }
412 fds[i].reset(mojo::Handle(wrapped_handle));
413 strides[i] = VideoFrame::RowBytes(
414 i, buffer_format, params.requested_format.frame_size.width());
415 if (!i) {
416 offsets[i] = 0;
417 } else {
418 offsets[i] = offsets[i - 1] +
419 VideoFrame::PlaneSize(buffer_format, i - 1,
420 params.requested_format.frame_size)
421 .GetArea();
422 }
423 }
424 device_ops_->RegisterBuffer(
425 buffer_id, arc::mojom::Camera3DeviceOps::BufferType::SHM, std::move(fds),
426 drm_format, hal_pixel_format, stream_context_->stream->width,
427 stream_context_->stream->height, std::move(strides), std::move(offsets),
428 base::Bind(&CameraDeviceDelegate::OnRegisteredBuffer, this, buffer_id));
429 VLOG(2) << "Registered buffer " << buffer_id;
430 }
431
432 void CameraDeviceDelegate::OnRegisteredBuffer(size_t buffer_id,
433 int32_t result) {
434 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
435 DCHECK(state_ == kCapturing || state_ == kStopping);
436
437 if (state_ == kStopping) {
438 return;
439 }
440 if (result) {
441 SetErrorState(FROM_HERE, std::string("Failed to register buffer: ") +
442 std::to_string(result));
443 return;
444 }
445 ProcessCaptureRequest(buffer_id);
446 }
447
448 void CameraDeviceDelegate::ProcessCaptureRequest(size_t buffer_id) {
449 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
450 DCHECK(state_ == kCapturing || state_ == kStopping);
451 DCHECK(stream_context_);
452
453 arc::mojom::Camera3StreamBufferPtr buffer =
454 arc::mojom::Camera3StreamBuffer::New();
455 buffer->stream_id = static_cast<uint64_t>(
456 arc::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW);
457 buffer->buffer_id = buffer_id;
458 buffer->status = arc::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_OK;
459
460 arc::mojom::Camera3CaptureRequestPtr request =
461 arc::mojom::Camera3CaptureRequest::New();
462 request->frame_number = frame_number_;
463 request->settings = stream_context_->request_settings.Clone();
464 request->output_buffers.push_back(std::move(buffer));
465
466 device_ops_->ProcessCaptureRequest(
467 std::move(request),
468 base::Bind(&CameraDeviceDelegate::OnProcessedCaptureRequest, this));
469 VLOG(2) << "Requested capture for frame " << frame_number_ << " with buffer "
470 << buffer_id;
471 frame_number_++;
472 // In case |frame_number_| wraps around, we start at 1 to avoid resetting
473 // |first_frame_shutter_time_|.
474 if (!frame_number_) {
475 frame_number_++;
476 }
477 }
478
479 void CameraDeviceDelegate::OnProcessedCaptureRequest(int32_t result) {
480 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
481 DCHECK(state_ == kCapturing || state_ == kStopping);
482
483 if (state_ == kStopping) {
484 return;
485 }
486 if (result) {
487 SetErrorState(FROM_HERE, std::string("Process capture request failed") +
488 std::to_string(result));
489 return;
490 }
491 RegisterBuffer();
492 }
493
494 void CameraDeviceDelegate::ProcessCaptureResult(
495 arc::mojom::Camera3CaptureResultPtr result) {
496 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
497
498 uint32_t frame_number = result->frame_number;
499 // A new partial result may be created in either ProcessCaptureResult or
500 // Notify.
501 CaptureResult& partial_result = partial_results_[frame_number];
502 if (result->output_buffers) {
503 if (result->output_buffers->size() != 1) {
504 SetErrorState(
505 FROM_HERE,
506 std::string("Incorrect number of output buffers received: ") +
507 std::to_string(result->output_buffers->size()));
508 return;
509 }
510 arc::mojom::Camera3StreamBufferPtr& stream_buffer =
511 result->output_buffers.value()[0];
512 VLOG(2) << "Received capture result for frame " << frame_number
513 << " stream_id: " << stream_buffer->stream_id;
514 // The camera HAL v3 API specifies that only one capture result can carry
515 // the result buffer for any given frame number.
516 if (!partial_result.buffer.is_null()) {
517 SetErrorState(FROM_HERE,
518 std::string("Received multiple result buffers for frame ") +
519 std::to_string(frame_number));
520 return;
521 } else {
522 partial_result.buffer = std::move(stream_buffer);
523 }
524 }
525
526 // |result->partial_result| is set to 0 if the capture result contains only
527 // the result buffer handles and no result metadata.
528 if (result->partial_result) {
529 uint32_t result_id = result->partial_result;
530 if (result_id > partial_result_count_) {
531 SetErrorState(FROM_HERE, std::string("Invalid partial_result id: ") +
532 std::to_string(result_id));
533 return;
534 }
535 if (partial_result.partial_metadata_received.find(result_id) !=
536 partial_result.partial_metadata_received.end()) {
537 SetErrorState(FROM_HERE,
538 std::string("Received duplicated partial metadata: ") +
539 std::to_string(result_id));
540 return;
541 }
542 partial_result.partial_metadata_received.insert(result_id);
543 MergeMetadata(&partial_result.metadata, result->result);
544 }
545
546 if (partial_result.partial_metadata_received.size() ==
547 partial_result_count_ &&
548 !partial_result.buffer.is_null()) {
549 // We can only submit the result buffer after we receive the shutter time.
550 if (partial_result.reference_time != base::TimeTicks()) {
551 SubmitCaptureResult(frame_number);
552 }
553 }
554 }
555
556 void CameraDeviceDelegate::Notify(arc::mojom::Camera3NotifyMsgPtr message) {
557 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
558
559 if (message->type == arc::mojom::Camera3MsgType::CAMERA3_MSG_ERROR) {
560 uint32_t frame_number = message->message->get_error()->frame_number;
561 uint64_t error_stream_id = message->message->get_error()->error_stream_id;
562 arc::mojom::Camera3ErrorMsgCode error_code =
563 message->message->get_error()->error_code;
564 switch (error_code) {
565 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_DEVICE:
566 // Fatal error and no more frames will be produced by the device.
567 SetErrorState(FROM_HERE, "Fatal device error");
568 break;
569 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_REQUEST: {
570 // An error has occurred in processing the request; the request
571 // specified by |frame_number| has been dropped by the camera device.
572 // Subsequent requests are unaffected.
573 //
574 // The HAL will call ProcessCaptureResult with the buffers' state set to
575 // STATUS_ERROR. The content of the buffers will be dropped and the
576 // buffers will be reused in SubmitCaptureResult.
577 std::string warning_msg =
578 std::string(
579 "An error occurred while processing request for frame ") +
580 std::to_string(frame_number);
581 LOG(WARNING) << warning_msg;
582 client_->OnLog(warning_msg);
583 break;
584 }
585 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_RESULT: {
586 // An error has occurred in producing the output metadata buffer for a
587 // result; the output metadata will not be available for the frame
588 // specified by |frame_number|. Subsequent requests are unaffected.
589 std::string warning_msg =
590 std::string(
591 "An error occurred while producing result "
592 "metadata for frame ") +
593 std::to_string(frame_number);
594 LOG(WARNING) << warning_msg;
595 client_->OnLog(warning_msg);
596 // The result metadata will not be complete so we don't need to wait for
597 // partial results on frame |frame_number|.
598 partial_results_[frame_number].partial_metadata_received.clear();
599 for (uint32_t i = 0; i < partial_result_count_; ++i) {
600 partial_results_[frame_number].partial_metadata_received.insert(i);
601 }
602 break;
603 }
604 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_BUFFER:
605 // An error has occurred in placing the output buffer into a stream for
606 // a request. |frame_number| specifies the request for which the buffer
607 // was dropped, and |error_stream_id| specifies the stream that dropped
608 // the buffer.
609 //
610 // The HAL will call ProcessCaptureResult with the buffer's state set to
611 // STATUS_ERROR. The content of the buffer will be dropped and the
612 // buffer will be reused in SubmitCaptureResult.
613 client_->OnLog(
614 std::string(
615 "An error occurred while filling output buffer of stream ") +
616 std::to_string(error_stream_id) + std::string(" in frame ") +
617 std::to_string(frame_number));
618 break;
619 default:
620 // To eliminate the warning for not handling CAMERA3_MSG_NUM_ERRORS
621 break;
622 }
623 } else { // arc::mojom::Camera3MsgType::CAMERA3_MSG_SHUTTER
624 uint32_t frame_number = message->message->get_shutter()->frame_number;
625 uint64_t shutter_time = message->message->get_shutter()->timestamp;
626 // A new partial result may be created in either ProcessCaptureResult or
627 // Notify.
628 VLOG(2) << "Received shutter time for frame " << frame_number;
629 if (!shutter_time) {
630 SetErrorState(FROM_HERE, std::string("Received invalid shutter time: ") +
631 std::to_string(shutter_time));
632 return;
633 }
634 CaptureResult& partial_result = partial_results_[frame_number];
635 // Shutter timestamp is in ns.
636 base::TimeTicks reference_time =
637 base::TimeTicks::FromInternalValue(shutter_time / 1000);
638 partial_result.reference_time = reference_time;
639 if (!frame_number) {
640 // Record the shutter time of the first frame for calculating the
641 // timestamp.
642 first_frame_shutter_time_ = reference_time;
643 }
644 partial_result.timestamp = reference_time - first_frame_shutter_time_;
645 if (partial_result.partial_metadata_received.size() ==
646 partial_result_count_ &&
647 !partial_result.buffer.is_null()) {
648 SubmitCaptureResult(frame_number);
649 }
650 }
651 }
652
653 void CameraDeviceDelegate::SubmitCaptureResult(uint32_t frame_number) {
654 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
655
656 if (partial_results_.begin()->first != frame_number) {
657 SetErrorState(FROM_HERE, "Received out-of-order frames from HAL");
658 return;
659 }
660
661 VLOG(2) << "Submit capture result of frame " << frame_number;
662 CaptureResult& partial_result = partial_results_[frame_number];
663 DCHECK_EQ(partial_result.partial_metadata_received.size(),
664 partial_result_count_);
665 DCHECK(partial_result.buffer);
666 uint32_t buffer_id = partial_result.buffer->buffer_id;
667
668 // Wait on release fence before delivering the result buffer to client.
669 if (partial_result.buffer->release_fence.is_valid()) {
670 const int kSyncWaitTimeoutMs = 1000;
671 mojo::edk::ScopedPlatformHandle fence;
672 MojoResult result = mojo::edk::PassWrappedPlatformHandle(
673 partial_result.buffer->release_fence.release().value(), &fence);
674 if (result != MOJO_RESULT_OK) {
675 SetErrorState(FROM_HERE, "Failed to unwrap release fence fd");
676 return;
677 }
678 if (!sync_wait(fence.get().handle, kSyncWaitTimeoutMs)) {
679 SetErrorState(FROM_HERE, "Sync wait on release fence timed out");
680 return;
681 }
682 }
683
684 // Deliver the captured data to client and then re-queue the buffer.
685 if (partial_result.buffer->status !=
686 arc::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR) {
687 const base::SharedMemory* shm_buffer =
688 stream_context_->buffers[buffer_id].get();
689 client_->OnIncomingCapturedData(
690 reinterpret_cast<uint8_t*>(shm_buffer->memory()),
691 shm_buffer->mapped_size(), stream_context_->capture_format, rotation_,
692 partial_result.reference_time, partial_result.timestamp);
693 }
694 stream_context_->free_buffers.push(buffer_id);
695 partial_results_.erase(frame_number);
696 RegisterBuffer();
697 }
698
699 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698