1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/capture_mode/camera_video_frame_handler.h"
7 #include "base/check.h"
8 #include "base/functional/bind.h"
9 #include "base/logging.h"
10 #include "base/memory/shared_memory_mapping.h"
11 #include "base/memory/unsafe_shared_memory_region.h"
12 #include "base/system/sys_info.h"
13 #include "components/viz/common/gpu/context_lost_observer.h"
14 #include "components/viz/common/gpu/context_provider.h"
15 #include "gpu/command_buffer/client/client_shared_image.h"
16 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
17 #include "gpu/command_buffer/client/shared_image_interface.h"
18 #include "gpu/command_buffer/common/context_result.h"
19 #include "gpu/command_buffer/common/gpu_memory_buffer_support.h"
20 #include "gpu/command_buffer/common/shared_image_usage.h"
21 #include "gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.h"
22 #include "gpu/ipc/common/gpu_memory_buffer_support.h"
23 #include "media/base/media_switches.h"
24 #include "media/base/video_frame.h"
25 #include "media/base/video_types.h"
26 #include "media/capture/video_capture_types.h"
27 #include "mojo/public/cpp/system/buffer.h"
28 #include "ui/compositor/compositor.h"
29 #include "ui/gfx/buffer_types.h"
30 #include "ui/gfx/geometry/size.h"
31 #include "ui/gfx/gpu_memory_buffer.h"
33 namespace capture_mode {
37 // The `kGpuMemoryBuffer` type is requested only when running on an actual
38 // device. This allows force-requesting them when testing in which case
39 // SharedMemory GMBs are used.
40 bool g_force_use_gpu_memory_buffer_for_test = false;
42 // A constant flag that describes which APIs the shared image mailboxes created
43 // for the video frame will be used with.
44 constexpr uint32_t kSharedImageUsage =
45 gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_RASTER |
46 gpu::SHARED_IMAGE_USAGE_DISPLAY_READ | gpu::SHARED_IMAGE_USAGE_SCANOUT;
48 // The usage of the GpuMemoryBuffer that backs the video frames on an actual
49 // device (of type `NATIVE_PIXMAP`). The buffer is going to be presented on the
50 // screen for rendering, will be used as a texture, and can be read by CPU and
51 // potentially a video encode accelerator.
52 constexpr gfx::BufferUsage kGpuMemoryBufferUsage =
53 gfx::BufferUsage::SCANOUT_VEA_CPU_READ;
55 // The usage of the GpuMemoryBuffer that backs the video frames in unittests,
56 // since the type of that buffer will be `SHARED_MEMORY_BUFFER` which doesn't
57 // support the above on-device usage.
58 constexpr gfx::BufferUsage kGpuMemoryBufferUsageForTest =
59 gfx::BufferUsage::SCANOUT_CPU_READ_WRITE;
61 // The only supported video pixel format used on devices is `PIXEL_FORMAT_NV12`.
62 // This maps to a buffer format of `YUV_420_BIPLANAR`.
63 constexpr gfx::BufferFormat kGpuMemoryBufferFormat =
64 gfx::BufferFormat::YUV_420_BIPLANAR;
66 // In unittests, the video pixel format used is `PIXEL_FORMAT_ARGB`, since the
67 // video frames are painted and verified manually using Skia. The buffer format
68 // used for this is `BGRA_8888`.
69 constexpr gfx::BufferFormat kGpuMemoryBufferFormatForTest =
70 gfx::BufferFormat::BGRA_8888;
72 gfx::BufferUsage GetBufferUsage() {
73 return g_force_use_gpu_memory_buffer_for_test ? kGpuMemoryBufferUsageForTest
74 : kGpuMemoryBufferUsage;
77 gfx::BufferFormat GetBufferFormat() {
78 return g_force_use_gpu_memory_buffer_for_test ? kGpuMemoryBufferFormatForTest
79 : kGpuMemoryBufferFormat;
82 viz::SharedImageFormat GetSharedImageFormat() {
83 return g_force_use_gpu_memory_buffer_for_test
84 ? viz::SinglePlaneFormat::kBGRA_8888
85 : viz::MultiPlaneFormat::kNV12;
88 #if BUILDFLAG(IS_CHROMEOS)
89 // Adjusts the requested video capture `params` depending on whether we're
90 // running on an actual device or the linux-chromeos build.
91 void AdjustParamsForCurrentConfig(media::VideoCaptureParams* params) {
94 // The default params are good enough when running on linux-chromeos.
95 if (!base::SysInfo::IsRunningOnChromeOS() &&
96 !g_force_use_gpu_memory_buffer_for_test) {
97 DCHECK_EQ(params->buffer_type,
98 media::VideoCaptureBufferType::kSharedMemory);
102 // On an actual device, the camera HAL only supports NV12 pixel formats in a
103 // GPU memory buffer.
104 params->requested_format.pixel_format = media::PIXEL_FORMAT_NV12;
105 params->buffer_type = media::VideoCaptureBufferType::kGpuMemoryBuffer;
109 // Whether to use the SharedImageInterface entrypoint taking a SharedImageFormat
110 // to create multiplanar SharedImages via viz::MultiPlaneFormat rather than
111 // going through the legacy entrypoint for SI creation that passes a GMB.
112 bool CreateNonLegacyMultiPlaneSharedImage() {
113 return media::IsMultiPlaneFormatForHardwareVideoEnabled();
116 // Whether to use per-plane sampling rather than external sampling.
117 bool UsePerPlaneSampling() {
118 return base::FeatureList::IsEnabled(
119 media::kMultiPlaneVideoCaptureSharedImages);
122 // Creates and returns a list of the buffer planes for each we'll need to create
123 // a shared image and store it in `GpuMemoryBufferHandleHolder::mailboxes_`.
124 std::vector<gfx::BufferPlane> CreateGpuBufferPlanes() {
125 std::vector<gfx::BufferPlane> planes;
126 if (UsePerPlaneSampling() && !CreateNonLegacyMultiPlaneSharedImage()) {
127 planes.push_back(gfx::BufferPlane::Y);
128 planes.push_back(gfx::BufferPlane::UV);
130 planes.push_back(gfx::BufferPlane::DEFAULT);
135 // Returns the buffer texture target used to create a `MailboxHolder` according
136 // to our GPU buffer usage, buffer format, and the given `context_capabilities`.
137 uint32_t CalculateBufferTextureTarget(
138 const gpu::Capabilities& context_capabilities) {
139 return gpu::GetBufferTextureTarget(GetBufferUsage(), GetBufferFormat(),
140 context_capabilities);
143 bool IsFatalError(media::VideoCaptureError error) {
145 case media::VideoCaptureError::kCrosHalV3FailedToStartDeviceThread:
146 case media::VideoCaptureError::kCrosHalV3DeviceDelegateMojoConnectionError:
147 case media::VideoCaptureError::
148 kCrosHalV3DeviceDelegateFailedToOpenCameraDevice:
149 case media::VideoCaptureError::
150 kCrosHalV3DeviceDelegateFailedToInitializeCameraDevice:
151 case media::VideoCaptureError::
152 kCrosHalV3DeviceDelegateFailedToConfigureStreams:
153 case media::VideoCaptureError::kCrosHalV3BufferManagerFatalDeviceError:
160 // -----------------------------------------------------------------------------
161 // SharedMemoryBufferHandleHolder:
163 // Defines an implementation for a `BufferHandleHolder` that can extract a video
164 // frame that is backed by a `kSharedMemory` buffer type. This implementation is
165 // used only when running on a linux-chromeos build (a.k.a. the emulator).
166 class SharedMemoryBufferHandleHolder : public BufferHandleHolder {
168 explicit SharedMemoryBufferHandleHolder(
169 media::mojom::VideoBufferHandlePtr buffer_handle)
170 : region_(std::move(buffer_handle->get_unsafe_shmem_region())) {
171 DCHECK(buffer_handle->is_unsafe_shmem_region());
172 #if BUILDFLAG(IS_CHROMEOS)
173 DCHECK(!base::SysInfo::IsRunningOnChromeOS());
176 SharedMemoryBufferHandleHolder(const SharedMemoryBufferHandleHolder&) =
178 SharedMemoryBufferHandleHolder& operator=(
179 const SharedMemoryBufferHandleHolder&) = delete;
180 ~SharedMemoryBufferHandleHolder() override = default;
182 // BufferHandleHolder:
183 scoped_refptr<media::VideoFrame> OnFrameReadyInBuffer(
184 video_capture::mojom::ReadyFrameInBufferPtr buffer) override {
185 const size_t mapping_size = media::VideoFrame::AllocationSize(
186 buffer->frame_info->pixel_format, buffer->frame_info->coded_size);
187 if (!MaybeUpdateMapping(mapping_size)) {
191 auto& frame_info = buffer->frame_info;
192 auto frame = media::VideoFrame::WrapExternalData(
193 frame_info->pixel_format, frame_info->coded_size,
194 frame_info->visible_rect, frame_info->visible_rect.size(),
195 mapping_.GetMemoryAs<uint8_t>(), mapping_.size(),
196 frame_info->timestamp);
202 // Maps a new region with a size `new_mapping_size` bytes if no `mapping_` is
203 // available. Returns true if already mapped, or mapping is successful, false
205 bool MaybeUpdateMapping(size_t new_mapping_size) {
206 if (mapping_.IsValid()) {
207 // TODO(https://crbug.com/1316812): What guarantees that this DCHECK will
209 DCHECK_EQ(mapping_.size(), new_mapping_size);
213 mapping_ = region_.Map();
214 return mapping_.IsValid();
217 // The held shared memory region associated with this object.
218 base::UnsafeSharedMemoryRegion region_;
220 // Shared memory mapping associated with the held `region_`.
221 base::WritableSharedMemoryMapping mapping_;
224 // -----------------------------------------------------------------------------
225 // GpuMemoryBufferHandleHolder:
227 // Defines an implementation for a `BufferHandleHolder` that can extract a video
228 // frame that is backed by a `kGpuMemoryBuffer` buffer type.
229 class GpuMemoryBufferHandleHolder : public BufferHandleHolder,
230 public viz::ContextLostObserver {
232 GpuMemoryBufferHandleHolder(media::mojom::VideoBufferHandlePtr buffer_handle,
233 ui::ContextFactory* context_factory)
234 : gpu_memory_buffer_handle_(
235 std::move(buffer_handle->get_gpu_memory_buffer_handle())),
236 buffer_planes_(CreateGpuBufferPlanes()),
237 context_factory_(context_factory),
239 context_factory_->SharedMainThreadRasterContextProvider()),
240 buffer_texture_target_(CalculateBufferTextureTarget(
241 context_provider_->ContextCapabilities())) {
242 DCHECK(buffer_handle->is_gpu_memory_buffer_handle());
243 DCHECK(context_provider_);
244 context_provider_->AddObserver(this);
247 GpuMemoryBufferHandleHolder(const GpuMemoryBufferHandleHolder&) = delete;
248 GpuMemoryBufferHandleHolder& operator=(const GpuMemoryBufferHandleHolder&) =
251 ~GpuMemoryBufferHandleHolder() override {
252 if (!context_provider_) {
256 context_provider_->RemoveObserver(this);
258 gpu::SharedImageInterface* shared_image_interface =
259 context_provider_->SharedImageInterface();
260 DCHECK(shared_image_interface);
262 for (const auto& mb : mailboxes_) {
263 if (mb.IsZero() || !mb.IsSharedImage()) {
266 shared_image_interface->DestroySharedImage(release_sync_token_, mb);
270 // BufferHandleHolder:
271 scoped_refptr<media::VideoFrame> OnFrameReadyInBuffer(
272 video_capture::mojom::ReadyFrameInBufferPtr buffer) override {
273 if (!context_provider_) {
274 LOG(ERROR) << "GPU context lost.";
278 const auto& frame_info = buffer->frame_info;
279 if (!MaybeCreateSharedImages(frame_info)) {
280 LOG(ERROR) << "Failed to initialize GpuMemoryBufferHandleHolder.";
284 return WrapMailboxesInVideoFrame(frame_info);
287 // viz::ContextLostObserver:
288 void OnContextLost() override {
289 DCHECK(context_provider_);
290 context_provider_->RemoveObserver(this);
292 // Clear the mailboxes so that we can recreate the shared images.
293 should_create_shared_images_ = true;
294 for (auto& mb : mailboxes_) {
297 release_sync_token_ = gpu::SyncToken();
300 context_factory_->SharedMainThreadRasterContextProvider();
301 if (context_provider_) {
302 context_provider_->AddObserver(this);
303 buffer_texture_target_ = CalculateBufferTextureTarget(
304 context_provider_->ContextCapabilities());
309 // Creates and returns a new `GpuMemoryBuffer` from a cloned handle of our
310 // `gpu_memory_buffer_handle_`. The type of the buffer depends on the type of
311 // the handle and can only be either `NATIVE_PIXMAP` or
312 // `SHARED_MEMORY_BUFFER`.
313 std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBufferFromHandle(
314 const gfx::Size& size) {
315 const auto buffer_format = GetBufferFormat();
316 const auto buffer_usage = GetBufferUsage();
317 if (gpu_memory_buffer_handle_.type ==
318 gpu::GpuMemoryBufferSupport::GetNativeGpuMemoryBufferType()) {
319 return gpu_memory_buffer_support_.CreateGpuMemoryBufferImplFromHandle(
320 gpu_memory_buffer_handle_.Clone(), size, buffer_format, buffer_usage,
324 DCHECK_EQ(gpu_memory_buffer_handle_.type, gfx::SHARED_MEMORY_BUFFER);
325 DCHECK(g_force_use_gpu_memory_buffer_for_test);
326 return gpu::GpuMemoryBufferImplSharedMemory::CreateFromHandle(
327 gpu_memory_buffer_handle_.Clone(), size, buffer_format, buffer_usage,
331 // Initializes this holder by creating shared images and storing them in
332 // `mailboxes_`. These shared images are backed by a GpuMemoryBuffer whose
333 // handle is a clone of our `gpu_memory_buffer_handle_`. This operation should
334 // only be done the first ever time, or whenever the gpu context is lost.
335 // Returns true if shared images are already created or creation is
336 // successful. False otherwise.
337 bool MaybeCreateSharedImages(
338 const media::mojom::VideoFrameInfoPtr& frame_info) {
339 DCHECK(context_provider_);
341 if (!should_create_shared_images_) {
345 // We clone our handle `gpu_memory_buffer_handle_` and use the cloned handle
346 // to create a new GpuMemoryBuffer which will be used to create the shared
347 // images. This way, the lifetime of our `gpu_memory_buffer_handle_` remains
348 // tied to the lieftime of this object (i.e. until `OnBufferRetired()` is
350 std::unique_ptr<gfx::GpuMemoryBuffer> gmb =
351 CreateGpuMemoryBufferFromHandle(frame_info->coded_size);
354 LOG(ERROR) << "Failed to create a GpuMemoryBuffer.";
358 gpu::SharedImageInterface* shared_image_interface =
359 context_provider_->SharedImageInterface();
360 DCHECK(shared_image_interface);
362 if (CreateNonLegacyMultiPlaneSharedImage()) {
363 auto format = GetSharedImageFormat();
364 #if BUILDFLAG(IS_OZONE)
365 // If format is not multiplanar it must be used for testing.
366 CHECK(format.is_multi_plane() || g_force_use_gpu_memory_buffer_for_test);
367 if (!UsePerPlaneSampling() && format.is_multi_plane()) {
368 format.SetPrefersExternalSampler();
371 CHECK_EQ(buffer_planes_.size(), 1u);
372 auto client_shared_image = shared_image_interface->CreateSharedImage(
373 format, gmb->GetSize(), frame_info->color_space,
374 kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, kSharedImageUsage,
375 "CameraVideoFrame", gmb->CloneHandle());
376 CHECK(client_shared_image);
377 mailboxes_[0] = client_shared_image->mailbox();
379 gpu::GpuMemoryBufferManager* gmb_manager =
380 context_factory_->GetGpuMemoryBufferManager();
381 for (size_t plane = 0; plane < buffer_planes_.size(); ++plane) {
382 mailboxes_[plane] = shared_image_interface->CreateSharedImage(
383 gmb.get(), gmb_manager, buffer_planes_[plane],
384 frame_info->color_space, kTopLeft_GrSurfaceOrigin,
385 kPremul_SkAlphaType, kSharedImageUsage, "CameraVideoFrame");
389 // Since this is the first time we create the shared images in `mailboxes_`,
390 // we need to guarantee that the mailboxes are created before they're used.
391 mailbox_holder_sync_token_ = shared_image_interface->GenVerifiedSyncToken();
393 should_create_shared_images_ = false;
397 // Wraps the shared images in `mailboxes_` in a video frame and returns it if
398 // wrapping was successful, or an empty refptr otherwise.
399 scoped_refptr<media::VideoFrame> WrapMailboxesInVideoFrame(
400 const media::mojom::VideoFrameInfoPtr& frame_info) {
401 DCHECK(!should_create_shared_images_);
403 if (frame_info->pixel_format !=
404 media::VideoPixelFormat::PIXEL_FORMAT_NV12 &&
405 frame_info->pixel_format !=
406 media::VideoPixelFormat::PIXEL_FORMAT_ARGB) {
407 LOG(ERROR) << "Unsupported pixel format";
411 // The camera GpuMemoryBuffer is backed by a DMA-buff, and doesn't use a
412 // pre-mapped shared memory region.
413 DCHECK(!frame_info->is_premapped);
415 gpu::MailboxHolder mailbox_holder_array[media::VideoFrame::kMaxPlanes];
416 for (size_t plane = 0; plane < buffer_planes_.size(); ++plane) {
417 DCHECK(!mailboxes_[plane].IsZero());
418 DCHECK(mailboxes_[plane].IsSharedImage());
419 mailbox_holder_array[plane] =
420 gpu::MailboxHolder(mailboxes_[plane], mailbox_holder_sync_token_,
421 buffer_texture_target_);
423 mailbox_holder_sync_token_.Clear();
425 auto frame = media::VideoFrame::WrapNativeTextures(
426 frame_info->pixel_format, mailbox_holder_array,
427 base::BindOnce(&GpuMemoryBufferHandleHolder::OnMailboxReleased,
428 weak_ptr_factory_.GetWeakPtr()),
429 frame_info->coded_size, frame_info->visible_rect,
430 frame_info->visible_rect.size(), frame_info->timestamp);
433 LOG(ERROR) << "Failed to create a video frame.";
437 if (CreateNonLegacyMultiPlaneSharedImage()) {
438 auto format = GetSharedImageFormat();
439 // If format is not multiplanar it must be used for testing.
440 CHECK(format.is_multi_plane() || g_force_use_gpu_memory_buffer_for_test);
441 if (!UsePerPlaneSampling() && format.is_multi_plane()) {
442 frame->set_shared_image_format_type(
443 media::SharedImageFormatType::kSharedImageFormatExternalSampler);
445 frame->set_shared_image_format_type(
446 media::SharedImageFormatType::kSharedImageFormat);
450 if (frame_info->color_space.IsValid()) {
451 frame->set_color_space(frame_info->color_space);
453 frame->metadata().allow_overlay = true;
454 frame->metadata().read_lock_fences_enabled = true;
455 frame->metadata().MergeMetadataFrom(frame_info->metadata);
460 // Called when the video frame is destroyed.
461 void OnMailboxReleased(const gpu::SyncToken& release_sync_token) {
462 release_sync_token_ = release_sync_token;
465 // The held GPU buffer handle associated with this object.
466 const gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle_;
468 // The buffer planes for each we need to create a shared image and store it in
470 const std::vector<gfx::BufferPlane> buffer_planes_;
472 const raw_ptr<ui::ContextFactory> context_factory_;
474 // Used to create a GPU memory buffer from its handle.
475 gpu::GpuMemoryBufferSupport gpu_memory_buffer_support_;
477 scoped_refptr<viz::RasterContextProvider> context_provider_;
479 // The texture target we use to create a `MailboxHolder`. This value is
480 // calculated for out GPU buffer format, and GPU buffer usage, and the current
481 // capabilities of `context_provider_`.
482 uint32_t buffer_texture_target_;
484 // Contains the shared images of the video frame planes created from the GPU
486 std::vector<gpu::Mailbox> mailboxes_{media::VideoFrame::kMaxPlanes};
488 // The sync token used when creating a `MailboxHolder`. This will be a
489 // verified sync token the first time we wrap a video frame around a mailbox.
490 gpu::SyncToken mailbox_holder_sync_token_;
492 // The release sync token of the above `mailboxes_`.
493 gpu::SyncToken release_sync_token_;
495 bool should_create_shared_images_ = true;
497 base::WeakPtrFactory<GpuMemoryBufferHandleHolder> weak_ptr_factory_{this};
500 // Notifies the passed `VideoFrameAccessHandler` that the handler is done using
503 mojo::SharedRemote<video_capture::mojom::VideoFrameAccessHandler>
504 video_frame_access_handler_remote,
505 const int buffer_id) {
506 video_frame_access_handler_remote->OnFinishedConsumingBuffer(buffer_id);
511 // -----------------------------------------------------------------------------
512 // BufferHandleHolder:
514 BufferHandleHolder::~BufferHandleHolder() = default;
517 std::unique_ptr<BufferHandleHolder> BufferHandleHolder::Create(
518 media::mojom::VideoBufferHandlePtr buffer_handle,
519 ui::ContextFactory* context_factory) {
520 if (buffer_handle->is_unsafe_shmem_region()) {
521 return std::make_unique<SharedMemoryBufferHandleHolder>(
522 std::move(buffer_handle));
525 DCHECK(buffer_handle->is_gpu_memory_buffer_handle());
526 return std::make_unique<GpuMemoryBufferHandleHolder>(std::move(buffer_handle),
530 // -----------------------------------------------------------------------------
531 // CameraVideoFrameHandler:
533 CameraVideoFrameHandler::CameraVideoFrameHandler(
534 ui::ContextFactory* context_factory,
535 mojo::Remote<video_capture::mojom::VideoSource> camera_video_source,
536 const media::VideoCaptureFormat& capture_format)
537 : context_factory_(context_factory),
538 camera_video_source_remote_(std::move(camera_video_source)) {
539 CHECK(camera_video_source_remote_);
541 camera_video_source_remote_.set_disconnect_handler(
542 base::BindOnce(&CameraVideoFrameHandler::OnFatalErrorOrDisconnection,
543 base::Unretained(this)));
545 media::VideoCaptureParams capture_params;
546 capture_params.requested_format = capture_format;
547 #if BUILDFLAG(IS_CHROMEOS)
548 AdjustParamsForCurrentConfig(&capture_params);
551 camera_video_source_remote_->CreatePushSubscription(
552 video_frame_handler_receiver_.BindNewPipeAndPassRemote(), capture_params,
553 // The Camera app, or some other camera capture operation may already be
554 // running with certain settings. We don't want to reopen the camera
555 // device with our settings, since our requirements are usually low in
556 // terms of frame rate and size. So we'll use whatever settings available
558 /*force_reopen_with_new_settings=*/false,
559 camera_video_stream_subsciption_remote_.BindNewPipeAndPassReceiver(),
561 [](video_capture::mojom::CreatePushSubscriptionResultCodePtr
563 const media::VideoCaptureParams& actual_params) {
564 if (result_code->is_error_code()) {
565 LOG(ERROR) << "Error in creating push subscription: "
566 << static_cast<int>(result_code->get_error_code());
571 CameraVideoFrameHandler::~CameraVideoFrameHandler() = default;
573 void CameraVideoFrameHandler::StartHandlingFrames(Delegate* delegate) {
575 CHECK(camera_video_stream_subsciption_remote_);
576 delegate_ = delegate;
578 camera_video_stream_subsciption_remote_->Activate();
581 void CameraVideoFrameHandler::Close(base::OnceClosure close_complete_callback) {
583 // `delegate_` might be freed any time after this point, so nullify it to
586 camera_video_stream_subsciption_remote_->Close(
587 std::move(close_complete_callback));
590 void CameraVideoFrameHandler::OnCaptureConfigurationChanged() {}
592 void CameraVideoFrameHandler::OnNewBuffer(
594 media::mojom::VideoBufferHandlePtr buffer_handle) {
595 const auto pair = buffer_map_.emplace(
596 buffer_id, BufferHandleHolder::Create(std::move(buffer_handle),
597 context_factory_.get()));
601 void CameraVideoFrameHandler::OnFrameAccessHandlerReady(
602 mojo::PendingRemote<video_capture::mojom::VideoFrameAccessHandler>
603 pending_frame_access_handler) {
604 video_frame_access_handler_remote_.Bind(
605 std::move(pending_frame_access_handler),
606 base::SequencedTaskRunner::GetCurrentDefault());
609 void CameraVideoFrameHandler::OnFrameReadyInBuffer(
610 video_capture::mojom::ReadyFrameInBufferPtr buffer) {
611 CHECK(video_frame_access_handler_remote_);
613 const int buffer_id = buffer->buffer_id;
616 video_frame_access_handler_remote_->OnFinishedConsumingBuffer(buffer_id);
619 // `delegate_` should still exist if the handler is active.
622 const auto& iter = buffer_map_.find(buffer_id);
623 CHECK(iter != buffer_map_.end());
625 const auto& buffer_handle_holder = iter->second;
626 scoped_refptr<media::VideoFrame> frame =
627 buffer_handle_holder->OnFrameReadyInBuffer(std::move(buffer));
629 video_frame_access_handler_remote_->OnFinishedConsumingBuffer(buffer_id);
633 frame->AddDestructionObserver(base::BindOnce(
634 &OnFrameGone, video_frame_access_handler_remote_, buffer_id));
636 delegate_->OnCameraVideoFrame(std::move(frame));
639 void CameraVideoFrameHandler::OnBufferRetired(int buffer_id) {
640 DCHECK(buffer_map_.contains(buffer_id));
641 buffer_map_.erase(buffer_id);
644 void CameraVideoFrameHandler::OnError(media::VideoCaptureError error) {
645 LOG(ERROR) << "Recieved error: " << static_cast<int>(error);
646 if (IsFatalError(error)) {
647 OnFatalErrorOrDisconnection();
651 void CameraVideoFrameHandler::OnFrameDropped(
652 media::VideoCaptureFrameDropReason reason) {
653 DLOG(ERROR) << "A camera video frame was dropped due to: "
654 << static_cast<int>(reason);
657 void CameraVideoFrameHandler::OnNewSubCaptureTargetVersion(
658 uint32_t sub_capture_target_version) {}
660 void CameraVideoFrameHandler::OnFrameWithEmptyRegionCapture() {}
662 void CameraVideoFrameHandler::OnLog(const std::string& message) {
666 void CameraVideoFrameHandler::OnStarted() {}
668 void CameraVideoFrameHandler::OnStartedUsingGpuDecode() {}
670 void CameraVideoFrameHandler::OnStopped() {}
673 void CameraVideoFrameHandler::SetForceUseGpuMemoryBufferForTest(bool value) {
674 g_force_use_gpu_memory_buffer_for_test = value;
677 void CameraVideoFrameHandler::OnVideoFrameGone(int buffer_id) {
678 CHECK(video_frame_access_handler_remote_);
679 video_frame_access_handler_remote_->OnFinishedConsumingBuffer(buffer_id);
682 void CameraVideoFrameHandler::OnFatalErrorOrDisconnection() {
685 weak_ptr_factory_.InvalidateWeakPtrs();
686 video_frame_handler_receiver_.reset();
687 camera_video_source_remote_.reset();
688 camera_video_stream_subsciption_remote_.reset();
691 delegate_->OnFatalErrorOrDisconnection();
692 // Caution as the delegate may choose to delete `this` after the above call.
696 } // namespace capture_mode