fixup! [M120 Migration] Notify media device state to webbrowser
[platform/framework/web/chromium-efl.git] / components / capture_mode / camera_video_frame_handler.cc
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.
4
5 #include "components/capture_mode/camera_video_frame_handler.h"
6
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"
32
33 namespace capture_mode {
34
35 namespace {
36
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;
41
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;
47
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;
54
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;
60
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;
65
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;
71
72 gfx::BufferUsage GetBufferUsage() {
73   return g_force_use_gpu_memory_buffer_for_test ? kGpuMemoryBufferUsageForTest
74                                                 : kGpuMemoryBufferUsage;
75 }
76
77 gfx::BufferFormat GetBufferFormat() {
78   return g_force_use_gpu_memory_buffer_for_test ? kGpuMemoryBufferFormatForTest
79                                                 : kGpuMemoryBufferFormat;
80 }
81
82 viz::SharedImageFormat GetSharedImageFormat() {
83   return g_force_use_gpu_memory_buffer_for_test
84              ? viz::SinglePlaneFormat::kBGRA_8888
85              : viz::MultiPlaneFormat::kNV12;
86 }
87
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) {
92   DCHECK(params);
93
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);
99     return;
100   }
101
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;
106 }
107 #endif
108
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();
114 }
115
116 // Whether to use per-plane sampling rather than external sampling.
117 bool UsePerPlaneSampling() {
118   return base::FeatureList::IsEnabled(
119       media::kMultiPlaneVideoCaptureSharedImages);
120 }
121
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);
129   } else {
130     planes.push_back(gfx::BufferPlane::DEFAULT);
131   }
132   return planes;
133 }
134
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);
141 }
142
143 bool IsFatalError(media::VideoCaptureError error) {
144   switch (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:
154       return true;
155     default:
156       return false;
157   }
158 }
159
160 // -----------------------------------------------------------------------------
161 // SharedMemoryBufferHandleHolder:
162
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 {
167  public:
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());
174 #endif
175   }
176   SharedMemoryBufferHandleHolder(const SharedMemoryBufferHandleHolder&) =
177       delete;
178   SharedMemoryBufferHandleHolder& operator=(
179       const SharedMemoryBufferHandleHolder&) = delete;
180   ~SharedMemoryBufferHandleHolder() override = default;
181
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)) {
188       return {};
189     }
190
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);
197
198     return frame;
199   }
200
201  private:
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
204   // otherwise.
205   bool MaybeUpdateMapping(size_t new_mapping_size) {
206     if (mapping_.IsValid()) {
207       // TODO(https://crbug.com/1316812): What guarantees that this DCHECK will
208       // hold?
209       DCHECK_EQ(mapping_.size(), new_mapping_size);
210       return true;
211     }
212
213     mapping_ = region_.Map();
214     return mapping_.IsValid();
215   }
216
217   // The held shared memory region associated with this object.
218   base::UnsafeSharedMemoryRegion region_;
219
220   // Shared memory mapping associated with the held `region_`.
221   base::WritableSharedMemoryMapping mapping_;
222 };
223
224 // -----------------------------------------------------------------------------
225 // GpuMemoryBufferHandleHolder:
226
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 {
231  public:
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),
238         context_provider_(
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);
245   }
246
247   GpuMemoryBufferHandleHolder(const GpuMemoryBufferHandleHolder&) = delete;
248   GpuMemoryBufferHandleHolder& operator=(const GpuMemoryBufferHandleHolder&) =
249       delete;
250
251   ~GpuMemoryBufferHandleHolder() override {
252     if (!context_provider_) {
253       return;
254     }
255
256     context_provider_->RemoveObserver(this);
257
258     gpu::SharedImageInterface* shared_image_interface =
259         context_provider_->SharedImageInterface();
260     DCHECK(shared_image_interface);
261
262     for (const auto& mb : mailboxes_) {
263       if (mb.IsZero() || !mb.IsSharedImage()) {
264         continue;
265       }
266       shared_image_interface->DestroySharedImage(release_sync_token_, mb);
267     }
268   }
269
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.";
275       return {};
276     }
277
278     const auto& frame_info = buffer->frame_info;
279     if (!MaybeCreateSharedImages(frame_info)) {
280       LOG(ERROR) << "Failed to initialize GpuMemoryBufferHandleHolder.";
281       return {};
282     }
283
284     return WrapMailboxesInVideoFrame(frame_info);
285   }
286
287   // viz::ContextLostObserver:
288   void OnContextLost() override {
289     DCHECK(context_provider_);
290     context_provider_->RemoveObserver(this);
291
292     // Clear the mailboxes so that we can recreate the shared images.
293     should_create_shared_images_ = true;
294     for (auto& mb : mailboxes_) {
295       mb.SetZero();
296     }
297     release_sync_token_ = gpu::SyncToken();
298
299     context_provider_ =
300         context_factory_->SharedMainThreadRasterContextProvider();
301     if (context_provider_) {
302       context_provider_->AddObserver(this);
303       buffer_texture_target_ = CalculateBufferTextureTarget(
304           context_provider_->ContextCapabilities());
305     }
306   }
307
308  private:
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,
321           base::DoNothing());
322     }
323
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,
328         base::DoNothing());
329   }
330
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_);
340
341     if (!should_create_shared_images_) {
342       return true;
343     }
344
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
349     // called).
350     std::unique_ptr<gfx::GpuMemoryBuffer> gmb =
351         CreateGpuMemoryBufferFromHandle(frame_info->coded_size);
352
353     if (!gmb) {
354       LOG(ERROR) << "Failed to create a GpuMemoryBuffer.";
355       return false;
356     }
357
358     gpu::SharedImageInterface* shared_image_interface =
359         context_provider_->SharedImageInterface();
360     DCHECK(shared_image_interface);
361
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();
369       }
370 #endif
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();
378     } else {
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");
386       }
387     }
388
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();
392
393     should_create_shared_images_ = false;
394     return true;
395   }
396
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_);
402
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";
408       return {};
409     }
410
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);
414
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_);
422     }
423     mailbox_holder_sync_token_.Clear();
424
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);
431
432     if (!frame) {
433       LOG(ERROR) << "Failed to create a video frame.";
434       return frame;
435     }
436
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);
444       } else {
445         frame->set_shared_image_format_type(
446             media::SharedImageFormatType::kSharedImageFormat);
447       }
448     }
449
450     if (frame_info->color_space.IsValid()) {
451       frame->set_color_space(frame_info->color_space);
452     }
453     frame->metadata().allow_overlay = true;
454     frame->metadata().read_lock_fences_enabled = true;
455     frame->metadata().MergeMetadataFrom(frame_info->metadata);
456
457     return frame;
458   }
459
460   // Called when the video frame is destroyed.
461   void OnMailboxReleased(const gpu::SyncToken& release_sync_token) {
462     release_sync_token_ = release_sync_token;
463   }
464
465   // The held GPU buffer handle associated with this object.
466   const gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle_;
467
468   // The buffer planes for each we need to create a shared image and store it in
469   // `mailboxes_`.
470   const std::vector<gfx::BufferPlane> buffer_planes_;
471
472   const raw_ptr<ui::ContextFactory> context_factory_;
473
474   // Used to create a GPU memory buffer from its handle.
475   gpu::GpuMemoryBufferSupport gpu_memory_buffer_support_;
476
477   scoped_refptr<viz::RasterContextProvider> context_provider_;
478
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_;
483
484   // Contains the shared images of the video frame planes created from the GPU
485   // memory buffer.
486   std::vector<gpu::Mailbox> mailboxes_{media::VideoFrame::kMaxPlanes};
487
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_;
491
492   // The release sync token of the above `mailboxes_`.
493   gpu::SyncToken release_sync_token_;
494
495   bool should_create_shared_images_ = true;
496
497   base::WeakPtrFactory<GpuMemoryBufferHandleHolder> weak_ptr_factory_{this};
498 };
499
500 // Notifies the passed `VideoFrameAccessHandler` that the handler is done using
501 // the buffer.
502 void OnFrameGone(
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);
507 }
508
509 }  // namespace
510
511 // -----------------------------------------------------------------------------
512 // BufferHandleHolder:
513
514 BufferHandleHolder::~BufferHandleHolder() = default;
515
516 // static
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));
523   }
524
525   DCHECK(buffer_handle->is_gpu_memory_buffer_handle());
526   return std::make_unique<GpuMemoryBufferHandleHolder>(std::move(buffer_handle),
527                                                        context_factory);
528 }
529
530 // -----------------------------------------------------------------------------
531 // CameraVideoFrameHandler:
532
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_);
540
541   camera_video_source_remote_.set_disconnect_handler(
542       base::BindOnce(&CameraVideoFrameHandler::OnFatalErrorOrDisconnection,
543                      base::Unretained(this)));
544
545   media::VideoCaptureParams capture_params;
546   capture_params.requested_format = capture_format;
547 #if BUILDFLAG(IS_CHROMEOS)
548   AdjustParamsForCurrentConfig(&capture_params);
549 #endif
550
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
557       // if any.
558       /*force_reopen_with_new_settings=*/false,
559       camera_video_stream_subsciption_remote_.BindNewPipeAndPassReceiver(),
560       base::BindOnce(
561           [](video_capture::mojom::CreatePushSubscriptionResultCodePtr
562                  result_code,
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());
567             }
568           }));
569 }
570
571 CameraVideoFrameHandler::~CameraVideoFrameHandler() = default;
572
573 void CameraVideoFrameHandler::StartHandlingFrames(Delegate* delegate) {
574   CHECK(delegate);
575   CHECK(camera_video_stream_subsciption_remote_);
576   delegate_ = delegate;
577   active_ = true;
578   camera_video_stream_subsciption_remote_->Activate();
579 }
580
581 void CameraVideoFrameHandler::Close(base::OnceClosure close_complete_callback) {
582   active_ = false;
583   // `delegate_` might be freed any time after this point, so nullify it to
584   // reflect that.
585   delegate_ = nullptr;
586   camera_video_stream_subsciption_remote_->Close(
587       std::move(close_complete_callback));
588 }
589
590 void CameraVideoFrameHandler::OnCaptureConfigurationChanged() {}
591
592 void CameraVideoFrameHandler::OnNewBuffer(
593     int buffer_id,
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()));
598   DCHECK(pair.second);
599 }
600
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());
607 }
608
609 void CameraVideoFrameHandler::OnFrameReadyInBuffer(
610     video_capture::mojom::ReadyFrameInBufferPtr buffer) {
611   CHECK(video_frame_access_handler_remote_);
612
613   const int buffer_id = buffer->buffer_id;
614
615   if (!active_) {
616     video_frame_access_handler_remote_->OnFinishedConsumingBuffer(buffer_id);
617     return;
618   }
619   // `delegate_` should still exist if the handler is active.
620   CHECK(delegate_);
621
622   const auto& iter = buffer_map_.find(buffer_id);
623   CHECK(iter != buffer_map_.end());
624
625   const auto& buffer_handle_holder = iter->second;
626   scoped_refptr<media::VideoFrame> frame =
627       buffer_handle_holder->OnFrameReadyInBuffer(std::move(buffer));
628   if (!frame) {
629     video_frame_access_handler_remote_->OnFinishedConsumingBuffer(buffer_id);
630     return;
631   }
632
633   frame->AddDestructionObserver(base::BindOnce(
634       &OnFrameGone, video_frame_access_handler_remote_, buffer_id));
635
636   delegate_->OnCameraVideoFrame(std::move(frame));
637 }
638
639 void CameraVideoFrameHandler::OnBufferRetired(int buffer_id) {
640   DCHECK(buffer_map_.contains(buffer_id));
641   buffer_map_.erase(buffer_id);
642 }
643
644 void CameraVideoFrameHandler::OnError(media::VideoCaptureError error) {
645   LOG(ERROR) << "Recieved error: " << static_cast<int>(error);
646   if (IsFatalError(error)) {
647     OnFatalErrorOrDisconnection();
648   }
649 }
650
651 void CameraVideoFrameHandler::OnFrameDropped(
652     media::VideoCaptureFrameDropReason reason) {
653   DLOG(ERROR) << "A camera video frame was dropped due to: "
654               << static_cast<int>(reason);
655 }
656
657 void CameraVideoFrameHandler::OnNewSubCaptureTargetVersion(
658     uint32_t sub_capture_target_version) {}
659
660 void CameraVideoFrameHandler::OnFrameWithEmptyRegionCapture() {}
661
662 void CameraVideoFrameHandler::OnLog(const std::string& message) {
663   DVLOG(1) << message;
664 }
665
666 void CameraVideoFrameHandler::OnStarted() {}
667
668 void CameraVideoFrameHandler::OnStartedUsingGpuDecode() {}
669
670 void CameraVideoFrameHandler::OnStopped() {}
671
672 // static
673 void CameraVideoFrameHandler::SetForceUseGpuMemoryBufferForTest(bool value) {
674   g_force_use_gpu_memory_buffer_for_test = value;
675 }
676
677 void CameraVideoFrameHandler::OnVideoFrameGone(int buffer_id) {
678   CHECK(video_frame_access_handler_remote_);
679   video_frame_access_handler_remote_->OnFinishedConsumingBuffer(buffer_id);
680 }
681
682 void CameraVideoFrameHandler::OnFatalErrorOrDisconnection() {
683   active_ = false;
684   buffer_map_.clear();
685   weak_ptr_factory_.InvalidateWeakPtrs();
686   video_frame_handler_receiver_.reset();
687   camera_video_source_remote_.reset();
688   camera_video_stream_subsciption_remote_.reset();
689
690   if (delegate_) {
691     delegate_->OnFatalErrorOrDisconnection();
692     // Caution as the delegate may choose to delete `this` after the above call.
693   }
694 }
695
696 }  // namespace capture_mode