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

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: update ConfigureStreams mojo interface 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 }
wuchengli 2017/05/17 03:40:12 Clear stream_context_ here. Document why we should
jcliang 2017/05/17 07:32:10 Done.
221 ResetMojoInterface();
222 client_.reset();
223 SetState(kStopped);
224 closed_->Signal();
225 closed_ = nullptr;
226 }
227
228 void CameraDeviceDelegate::Initialize() {
229 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
230 DCHECK_EQ(state_, kStarting);
231
232 device_ops_->Initialize(
233 callback_ops_.CreateInterfacePtrAndBind(),
234 base::Bind(&CameraDeviceDelegate::OnInitialized, this));
235 callback_ops_.set_connection_error_handler(
236 base::Bind(&CameraDeviceDelegate::OnMojoConnectionError, this));
237 }
238
239 void CameraDeviceDelegate::OnInitialized(int32_t result) {
240 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
241 DCHECK(state_ == kStarting || state_ == kStopping);
242
243 if (state_ == kStopping) {
244 return;
245 }
246 if (result) {
247 SetErrorState(FROM_HERE, "Failed to initialize camera device");
248 return;
249 }
250 SetState(kInitialized);
251 ConfigureStreams();
252 }
253
254 void CameraDeviceDelegate::ConfigureStreams() {
255 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
256 DCHECK(state_ == kInitialized || state_ == kStopping);
wuchengli 2017/05/17 03:40:12 remove state_ == kStopping
jcliang 2017/05/17 07:32:09 Done.
257
258 arc::mojom::Camera3StreamConfigurationPtr stream_config =
259 arc::mojom::Camera3StreamConfiguration::New();
260 stream_config->streams.push_back(stream_context_->stream.Clone());
261 stream_config->operation_mode = arc::mojom::Camera3StreamConfigurationMode::
262 CAMERA3_STREAM_CONFIGURATION_NORMAL_MODE;
263 device_ops_->ConfigureStreams(
264 std::move(stream_config),
265 base::Bind(&CameraDeviceDelegate::OnConfiguredStreams, this));
266 }
267
268 void CameraDeviceDelegate::OnConfiguredStreams(
269 int32_t result,
270 arc::mojom::Camera3StreamConfigurationPtr updated_config) {
271 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
272 DCHECK(state_ == kInitialized || state_ == kStopping);
273
274 if (state_ == kStopping) {
275 return;
276 }
277 if (result) {
278 SetErrorState(FROM_HERE, "Failed to configure streams");
279 return;
280 }
281 if (!updated_config || updated_config->streams.size() != 1) {
282 SetErrorState(FROM_HERE, "Wrong number of streams configured");
wuchengli 2017/05/17 03:40:13 print updated_config->streams.size()
jcliang 2017/05/17 07:32:10 Done.
283 return;
284 }
285 auto& updated_stream = updated_config->streams[0];
286 // TODO(jcliang): Determine the best format from metadata.
287 VideoCaptureFormat capture_format = stream_context_->params.requested_format;
288 capture_format.pixel_format = PIXEL_FORMAT_NV12;
289 stream_context_->capture_format = capture_format;
290 stream_context_->stream->usage = updated_stream->usage;
291 stream_context_->stream->max_buffers = updated_stream->max_buffers;
292
293 VLOG(2) << "Stream " << updated_stream->id
294 << " configured: usage=" << updated_stream->usage
295 << " max_buffers=" << updated_stream->max_buffers;
296
297 // Allocate buffers.
298 size_t num_buffers = stream_context_->stream->max_buffers;
299 stream_context_->buffers.resize(num_buffers);
300 for (size_t j = 0; j < num_buffers; ++j) {
301 const VideoCaptureFormat frame_format(
302 gfx::Size(stream_context_->stream->width,
303 stream_context_->stream->height),
304 0.0, stream_context_->capture_format.pixel_format);
305 std::unique_ptr<base::SharedMemory> buffer(new base::SharedMemory());
306 base::SharedMemoryCreateOptions options;
307 options.size = frame_format.ImageAllocationSize();
308 options.share_read_only = false;
309 buffer->Create(options);
wuchengli 2017/05/17 03:40:12 check return value and print error. Same for buffe
jcliang 2017/05/17 07:32:10 Done.
310 buffer->Map(buffer->requested_size());
311 stream_context_->buffers[j] = std::move(buffer);
312 stream_context_->free_buffers.push(j);
313 }
314 VLOG(2) << "Allocated " << stream_context_->stream->max_buffers << " buffers";
315 ConstructDefaultRequestSettings();
316 client_->OnStarted();
317 }
318
319 void CameraDeviceDelegate::ConstructDefaultRequestSettings() {
320 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
321 DCHECK(stream_context_);
322
323 device_ops_->ConstructDefaultRequestSettings(
324 arc::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW,
325 base::Bind(&CameraDeviceDelegate::OnConstructedDefaultRequestSettings,
326 this));
327 }
328
329 void CameraDeviceDelegate::OnConstructedDefaultRequestSettings(
330 arc::mojom::CameraMetadataPtr settings) {
331 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
332
333 if (state_ == kStopping) {
334 return;
335 }
336 DCHECK(stream_context_);
337 stream_context_->request_settings = std::move(settings);
338 SetState(kStreamConfigured);
339 StartCapture();
340 }
341
342 void CameraDeviceDelegate::StartCapture() {
343 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
344 // We may get here when either after the streams are configured, or when we
345 // start still capture while the preview capture is running.
wuchengli 2017/05/17 03:40:13 This comment can be removed because we don't suppo
jcliang 2017/05/17 07:32:10 Done.
346 DCHECK(state_ == kStreamConfigured || state_ == kCapturing ||
wuchengli 2017/05/17 03:40:13 remove state_ == kCapturing
jcliang 2017/05/17 07:32:09 Done.
347 state_ == kStopping);
348
349 if (state_ == kStopping) {
350 return;
351 }
352 DCHECK(stream_context_);
353 DCHECK(!stream_context_->request_settings.is_null());
354 SetState(kCapturing);
355 RegisterBuffer();
356 }
357
358 void CameraDeviceDelegate::RegisterBuffer() {
359 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
360 DCHECK(state_ == kCapturing || state_ == kStopping);
361
362 if (state_ == kStopping) {
363 return;
364 }
365 DCHECK(stream_context_);
366 if (stream_context_->free_buffers.empty()) {
367 return;
368 }
369
370 const VideoCaptureParams& params = stream_context_->params;
371 const arc::mojom::Camera3StreamPtr& stream = stream_context_->stream;
372 size_t buffer_id = stream_context_->free_buffers.front();
373 stream_context_->free_buffers.pop();
374 const base::SharedMemory* buffer = stream_context_->buffers[buffer_id].get();
375
376 VideoPixelFormat buffer_format = stream_context_->capture_format.pixel_format;
377 uint32_t drm_format = PixFormatChromiumToDrm(buffer_format);
378 if (!drm_format) {
379 SetErrorState(FROM_HERE, "Unsupported video pixel format");
wuchengli 2017/05/17 03:40:12 print buffer_format
jcliang 2017/05/17 07:32:09 Done.
380 return;
381 }
382 arc::mojom::HalPixelFormat hal_pixel_format = stream->format;
383
384 size_t num_planes = VideoFrame::NumPlanes(buffer_format);
385 std::vector<mojo::ScopedHandle> fds(num_planes);
386 std::vector<uint32_t> strides(num_planes);
387 std::vector<uint32_t> offsets(num_planes);
388 for (size_t i = 0; i < num_planes; ++i) {
389 base::SharedMemoryHandle shm_handle = buffer->handle();
390 // Wrap the platform handle.
391 MojoHandle wrapped_handle;
392 MojoResult result = mojo::edk::CreatePlatformHandleWrapper(
393 mojo::edk::ScopedPlatformHandle(mojo::edk::PlatformHandle(
394 base::SharedMemory::DuplicateHandle(shm_handle).fd)),
395 &wrapped_handle);
396 if (result != MOJO_RESULT_OK) {
397 SetErrorState(FROM_HERE, "Failed to wrap shared memory handle");
398 return;
399 }
400 fds[i].reset(mojo::Handle(wrapped_handle));
401 strides[i] = VideoFrame::RowBytes(i, buffer_format, stream->width);
wuchengli 2017/05/17 03:40:13 Use params.requested_format.frame_size.width to be
jcliang 2017/05/17 07:32:10 Done.
402 if (!i) {
403 offsets[i] = 0;
404 } else {
405 offsets[i] = offsets[i - 1] +
406 VideoFrame::PlaneSize(buffer_format, i,
wuchengli 2017/05/17 03:40:13 i-1
jcliang 2017/05/17 07:32:10 Done.
407 params.requested_format.frame_size)
408 .GetArea();
409 }
410 }
411 device_ops_->RegisterBuffer(
412 buffer_id, arc::mojom::Camera3DeviceOps::BufferType::SHM, std::move(fds),
413 drm_format, hal_pixel_format, stream_context_->stream->width,
414 stream_context_->stream->height, std::move(strides), std::move(offsets),
415 base::Bind(&CameraDeviceDelegate::OnRegisteredBuffer, this, buffer_id));
416 VLOG(2) << "Registered buffer " << buffer_id;
417 }
418
419 void CameraDeviceDelegate::OnRegisteredBuffer(size_t buffer_index,
wuchengli 2017/05/17 03:40:13 s/buffer_index/buffer_id/
jcliang 2017/05/17 07:32:09 Done.
420 int32_t result) {
421 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
422 DCHECK(state_ == kCapturing || state_ == kStopping);
423
424 if (state_ == kStopping) {
425 return;
426 }
427 if (result) {
428 SetErrorState(FROM_HERE, "Failed to register buffer");
wuchengli 2017/05/17 03:40:13 print result. Same for other IPC result if it cont
jcliang 2017/05/17 07:32:10 Done.
429 return;
430 }
431 ProcessCaptureRequest(buffer_index);
432 }
433
434 void CameraDeviceDelegate::ProcessCaptureRequest(size_t buffer_index) {
wuchengli 2017/05/17 03:40:13 s/buffer_index/buffer_id/
jcliang 2017/05/17 07:32:10 Done.
435 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
436 DCHECK(state_ == kCapturing || state_ == kStopping);
437 DCHECK(stream_context_);
438
439 arc::mojom::Camera3StreamBufferPtr buffer =
440 arc::mojom::Camera3StreamBuffer::New();
441 buffer->stream_id = static_cast<uint64_t>(
442 arc::mojom::Camera3RequestTemplate::CAMERA3_TEMPLATE_PREVIEW);
443 buffer->buffer_id = buffer_index;
444 buffer->status = arc::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_OK;
445
446 arc::mojom::Camera3CaptureRequestPtr request =
447 arc::mojom::Camera3CaptureRequest::New();
448 request->frame_number = frame_number_;
449 request->settings = stream_context_->request_settings.Clone();
450 request->output_buffers.push_back(std::move(buffer));
451
452 device_ops_->ProcessCaptureRequest(
453 std::move(request),
454 base::Bind(&CameraDeviceDelegate::OnProcessedCaptureRequest, this));
455 VLOG(2) << "Requested capture for frame " << frame_number_ << " with buffer "
456 << buffer_index;
457 frame_number_++;
wuchengli 2017/05/17 03:40:12 Handle wraparound. Start with 1 so the initial tim
jcliang 2017/05/17 07:32:10 Done.
458 }
459
460 void CameraDeviceDelegate::OnProcessedCaptureRequest(int32_t result) {
461 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
462 DCHECK(state_ == kCapturing || state_ == kStopping);
463
464 if (state_ == kStopping) {
465 return;
466 }
467 if (result) {
468 SetErrorState(FROM_HERE, "Process capture request failed");
469 return;
470 }
471 RegisterBuffer();
472 }
473
474 void CameraDeviceDelegate::ProcessCaptureResult(
475 arc::mojom::Camera3CaptureResultPtr result) {
476 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
477
478 uint32_t frame_number = result->frame_number;
479 // A new partial result may be created in either ProcessCaptureResult or
480 // Notify.
481 CaptureResult& partial_result = partial_results_[frame_number];
482 if (result->output_buffers.has_value()) {
483 if (result->output_buffers->size() != 1) {
484 client_->OnError(FROM_HERE,
wuchengli 2017/05/17 03:40:13 Use SetErrorState
jcliang 2017/05/17 07:32:10 Done.
485 "Incorrect number of output buffers received");
wuchengli 2017/05/17 03:40:13 print output_buffers->size()
jcliang 2017/05/17 07:32:10 Done.
486 return;
487 }
488 arc::mojom::Camera3StreamBufferPtr& stream_buffer =
489 result->output_buffers.value()[0];
490 VLOG(2) << "Received capture result for frame " << frame_number
491 << " stream_id: " << stream_buffer->stream_id;
492 // The camera HAL v3 API specifies that only one capture result can carry
493 // the result buffer for any given frame number.
494 if (!partial_result.buffer.is_null()) {
wuchengli 2017/05/17 03:40:12 Use SetErrorState so the preview will be stopped a
jcliang 2017/05/17 07:32:10 Done.
495 LOG(ERROR) << "Received multiple result buffers for frame "
496 << frame_number;
497 } else {
498 partial_result.buffer = std::move(stream_buffer);
499 }
500 }
501
502 // |result->partial_result| is set to 0 if the capture result contains only
503 // the result buffer handles and no result metadata.
504 if (result->partial_result) {
505 partial_result.partial_stage = result->partial_result;
wuchengli 2017/05/17 03:40:13 Check Android API if partial_result is increasing.
jcliang 2017/05/17 07:32:10 Per camera HALv3 API it's not required for partial
506 MergeMetadata(&partial_result.metadata, result->result);
507 }
508
509 if (partial_result.partial_stage == partial_result_count_ &&
wuchengli 2017/05/17 03:40:13 Let's do some error checking because HAL will defi
jcliang 2017/05/17 07:32:10 Done.
510 !partial_result.buffer.is_null()) {
511 // We can only submit the result buffer after we receive the shutter time.
512 if (partial_result.reference_time != base::TimeTicks()) {
513 SubmitCaptureResult(frame_number);
514 }
515 }
516 }
517
518 void CameraDeviceDelegate::Notify(arc::mojom::Camera3NotifyMsgPtr message) {
519 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
520
521 if (message->type == arc::mojom::Camera3MsgType::CAMERA3_MSG_ERROR) {
522 uint32_t frame_number = message->message->get_error()->frame_number;
523 uint64_t error_stream_id = message->message->get_error()->error_stream_id;
524 arc::mojom::Camera3ErrorMsgCode error_code =
525 message->message->get_error()->error_code;
526 switch (error_code) {
527 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_DEVICE:
528 // Fatal error and no more frames will be produced by the device.
529 SetErrorState(FROM_HERE, "Fatal device error");
530 break;
531 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_REQUEST:
532 // An error has occurred in processing the request; the request
533 // specified by |frame_number| has been dropped by the camera device.
534 // Subsequent requests are unaffected.
535 //
536 // The HAL will call ProcessCaptureResult with the buffers' state set to
537 // STATUS_ERROR. The content of the buffers will be dropped and the
538 // buffers will be reused in SubmitCaptureResult.
wuchengli 2017/05/17 03:40:13 Make this this is printed because this shouldn't h
jcliang 2017/05/17 07:32:10 Done.
539 client_->OnLog(
540 std::string(
541 "An error occurred while processing request for frame ") +
542 std::to_string(frame_number));
543 break;
544 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_RESULT:
545 // An error has occurred in producing the output metadata buffer for a
546 // result; the output metadata will not be available for the frame
547 // specified by |frame_number|. Subsequent requests are unaffected.
548 client_->OnLog(std::string("An error occurred while producing result "
549 "metadata for frame ") +
550 std::to_string(frame_number));
551 // The result metadata will not be complete so we don't need to wait for
552 // partial results on frame |frame_number|.
553 partial_results_[frame_number].partial_stage = partial_result_count_;
554 break;
555 case arc::mojom::Camera3ErrorMsgCode::CAMERA3_MSG_ERROR_BUFFER:
556 // An error has occurred in placing the output buffer into a stream for
557 // a request. |frame_number| specifies the request for which the buffer
558 // was dropped, and |error_stream_id| specifies the stream that dropped
559 // the buffer.
560 //
561 // The HAL will call ProcessCaptureResult with the buffer's state set to
562 // STATUS_ERROR. The content of the buffer will be dropped and the
563 // buffer will be reused in SubmitCaptureResult.
564 client_->OnLog(
565 std::string(
566 "An error occurred while filling output buffer of stream ") +
567 std::to_string(error_stream_id) + std::string(" in frame ") +
568 std::to_string(frame_number));
569 break;
570 default:
571 // To eliminate the warning for not handling CAMERA3_MSG_NUM_ERRORS
572 break;
573 }
574 } else { // arc::mojom::Camera3MsgType::CAMERA3_MSG_SHUTTER
575 uint32_t frame_number = message->message->get_shutter()->frame_number;
576 uint64_t shutter_time = message->message->get_shutter()->timestamp;
wuchengli 2017/05/17 03:40:12 Check if the timestamp is not 0. Otherwise, previe
jcliang 2017/05/17 07:32:10 Done.
577 // A new partial result may be created in either ProcessCaptureResult or
578 // Notify.
579 VLOG(2) << "Received shutter time for frame " << frame_number;
580 CaptureResult& partial_result = partial_results_[frame_number];
581 // Shutter timestamp is in ns.
582 base::TimeTicks reference_time =
583 base::TimeTicks::FromInternalValue(shutter_time / 1000);
584 partial_result.reference_time = reference_time;
585 if (!frame_number) {
586 // Record the shutter time of the first frame for calculating the
587 // timestamp.
588 first_frame_shutter_time_ = reference_time;
589 partial_result.timestamp = base::TimeDelta::FromMicroseconds(0);
590 } else {
591 partial_result.timestamp = reference_time - first_frame_shutter_time_;
wuchengli 2017/05/17 03:40:13 This can be extracted. reference_time - first_fra
jcliang 2017/05/17 07:32:10 Done.
592 }
593 if (partial_result.partial_stage == partial_result_count_ &&
594 !partial_result.buffer.is_null()) {
595 SubmitCaptureResult(frame_number);
596 }
597 }
598 }
599
600 void CameraDeviceDelegate::SubmitCaptureResult(uint32_t frame_number) {
601 DCHECK(ipc_task_runner_->BelongsToCurrentThread());
602
603 if (partial_results_.begin()->first != frame_number) {
604 SetErrorState(FROM_HERE, "Received out-of-order frames from HAL");
605 return;
606 }
607
608 VLOG(2) << "Submit capture result of frame " << frame_number;
609 CaptureResult& partial_result = partial_results_[frame_number];
610 DCHECK_EQ(partial_result.partial_stage, partial_result_count_);
611 DCHECK(partial_result.buffer);
612 uint32_t buffer_id = partial_result.buffer->buffer_id;
613
614 // Wait on release fence before delivering the result buffer to client.
615 if (partial_result.buffer->release_fence.is_valid()) {
616 const int kSyncWaitTimeoutMs = 1000;
617 mojo::edk::ScopedPlatformHandle fence;
618 MojoResult result = mojo::edk::PassWrappedPlatformHandle(
619 partial_result.buffer->release_fence.release().value(), &fence);
620 if (result != MOJO_RESULT_OK) {
621 SetErrorState(FROM_HERE, "Failed to unwrap release fence fd");
622 return;
623 }
624 if (!sync_wait(fence.get().handle, kSyncWaitTimeoutMs)) {
625 SetErrorState(FROM_HERE, "Sync wait on release fence timed out");
626 return;
627 }
628 }
629
630 // Deliver the captured data to client and then re-queue the buffer.
631 if (partial_result.buffer->status !=
632 arc::mojom::Camera3BufferStatus::CAMERA3_BUFFER_STATUS_ERROR) {
633 const base::SharedMemory* shm_buffer =
634 stream_context_->buffers[buffer_id].get();
635 client_->OnIncomingCapturedData(
636 reinterpret_cast<uint8_t*>(shm_buffer->memory()),
637 shm_buffer->mapped_size(), stream_context_->capture_format, rotation_,
638 partial_result.reference_time, partial_result.timestamp);
639 }
640 stream_context_->free_buffers.push(buffer_id);
641 ipc_task_runner_->PostTask(
wuchengli 2017/05/17 03:40:13 Call RegisterBuffer directly because it's the same
jcliang 2017/05/17 07:32:10 Done.
642 FROM_HERE, base::Bind(&CameraDeviceDelegate::RegisterBuffer, this));
643 partial_results_.erase(frame_number);
644 }
645
646 } // namespace media
OLDNEW
« no previous file with comments | « media/capture/video/chromeos/camera_device_delegate.h ('k') | media/capture/video/chromeos/camera_hal_delegate.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698