[WebRTC] Caching camera devices and their capabilities 57/313757/5 submit/tizen/20240701.160016
authorAdam Bujalski <a.bujalski@samsung.com>
Tue, 25 Jun 2024 15:16:47 +0000 (17:16 +0200)
committerBot Blink <blinkbot@samsung.com>
Mon, 1 Jul 2024 13:50:47 +0000 (13:50 +0000)
Currently call to `navigator.getUserMedia()` can last few seconds. This
is because during processing this call few times
`VideoCaptureDeviceFactoryTizenTv` is asked to list cameras and their
capabilities. Although first iteration is fast (~ 0.2s), each next
iteration can take more than one second.

Investigation revealed that most time is consumed by recreating
platform camera (`camera_create`).

To avoid such costly time operation this patch add caches for camera
capabilities and also adds cache keeping created camera device for
short time period, as there is high probability of using it by the
application.

Bug: https://jira-eu.sec.samsung.net/browse/VDGAME-524
Change-Id: I15618075be67c03fc472a0fdf52691b6bcec4c47
Signed-off-by: Adam Bujalski <a.bujalski@samsung.com>
media/capture/video/tizen/video_capture_device_factory_tizen_tv.cc
media/capture/video/tizen/video_capture_device_factory_tizen_tv.h
media/capture/video/tizen/video_capture_device_tizen_tv.cc
media/capture/video/tizen/video_capture_device_tizen_tv.h

index 0571b77e2e2ed28c8befa6af6536e697b5c8af76..37036aadde69aa71bd24e7b60a5a79df765b8dce 100644 (file)
@@ -4,8 +4,12 @@
 
 #include "media/capture/video/tizen/video_capture_device_factory_tizen_tv.h"
 
+#include <memory>
+#include <string>
+
 #include "base/functional/bind.h"
-#include "base/task/bind_post_task.h"
+#include "base/location.h"
+#include "base/time/time.h"
 #include "media/base/tizen/logger/media_logger.h"
 #include "media/base/video_types.h"
 #include "media/capture/video/tizen/camera_utils.h"
 
 namespace media {
 
+namespace {
+
+constexpr VideoCaptureError kCameraCreateError = VideoCaptureError::
+    kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested;
+
+}  // namespace
+
 VideoCaptureDeviceFactoryTizenTv::VideoCaptureDeviceFactoryTizenTv() {
-  weak_this_ = weak_factory_.GetWeakPtr();
   int err = camera_device_manager_initialize(&handle_);
   if (err != CAMERA_ERROR_NONE) {
     TIZEN_MEDIA_LOG(ERROR) << "Cannot initialize camera device manager: "
@@ -25,7 +35,9 @@ VideoCaptureDeviceFactoryTizenTv::VideoCaptureDeviceFactoryTizenTv() {
 }
 
 VideoCaptureDeviceFactoryTizenTv::~VideoCaptureDeviceFactoryTizenTv() {
-  weak_factory_.InvalidateWeakPtrs();
+  base::AutoLock lock(devices_lock_);
+  devices_cache_.clear();
+
   if (handle_) {
     camera_device_manager_deinitialize(handle_);
   }
@@ -35,6 +47,16 @@ VideoCaptureErrorOrDevice VideoCaptureDeviceFactoryTizenTv::CreateDevice(
     const VideoCaptureDeviceDescriptor& device_descriptor) {
   // Ensure that other thread won't try allocating camera device.
   base::AutoLock lock(devices_lock_);
+  auto cached_device_it = devices_cache_.find(device_descriptor);
+  if (cached_device_it != devices_cache_.end()) {
+    TIZEN_MEDIA_LOG(INFO) << "CreateDevice: "
+                          << device_descriptor.GetNameAndModel()
+                          << " found in cache.";
+    auto device = std::make_unique<VideoCaptureDeviceTizenTv>(
+        std::move(cached_device_it->second.camera));
+    devices_cache_.erase(cached_device_it);
+    return VideoCaptureErrorOrDevice(std::move(device));
+  }
 
   TIZEN_MEDIA_LOG(INFO) << "CreateDevice: "
                         << device_descriptor.GetNameAndModel();
@@ -42,9 +64,7 @@ VideoCaptureErrorOrDevice VideoCaptureDeviceFactoryTizenTv::CreateDevice(
   int err = camera_device_manager_get_device_list(handle_, &list);
   if (err != CAMERA_ERROR_NONE) {
     TIZEN_MEDIA_LOG(ERROR) << "Cannot get device list: " << err;
-    return VideoCaptureErrorOrDevice(
-        VideoCaptureError::
-            kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested);
+    return VideoCaptureErrorOrDevice(kCameraCreateError);
   }
 
   for (size_t i = 0; i < list.count; ++i) {
@@ -54,31 +74,17 @@ VideoCaptureErrorOrDevice VideoCaptureDeviceFactoryTizenTv::CreateDevice(
     }
 
     auto camera = Camera::Create(list.device[i].index, list.device[i].type);
-    supported_formats_cache_.emplace(list.device[i].index,
-                                     GetSupportedFormats(camera.get()));
-    auto destroy_cb = base::BindPostTaskToCurrentDefault(
-        base::BindOnce(&VideoCaptureDeviceFactoryTizenTv::OnDeviceReleased,
-                       weak_factory_.GetWeakPtr(), list.device[i].index));
+    auto it = supported_formats_cache_.find(device_descriptor);
+    if (it == supported_formats_cache_.end()) {
+      supported_formats_cache_.emplace(device_descriptor,
+                                       GetSupportedFormats(camera.get()));
+    }
     return VideoCaptureErrorOrDevice(
-        std::make_unique<VideoCaptureDeviceTizenTv>(std::move(camera),
-                                                    std::move(destroy_cb)));
+        std::make_unique<VideoCaptureDeviceTizenTv>(std::move(camera)));
   }
 
   TIZEN_MEDIA_LOG(WARNING) << "Requested device not found";
-  return VideoCaptureErrorOrDevice(
-      VideoCaptureError::
-          kVideoCaptureControllerInvalidOrUnsupportedVideoCaptureParametersRequested);
-}
-
-void VideoCaptureDeviceFactoryTizenTv::OnDeviceReleased(
-    camera_device_e device) {
-  base::AutoLock lock(devices_lock_);
-  auto it = supported_formats_cache_.find(device);
-  if (it == supported_formats_cache_.end()) {
-    TIZEN_MEDIA_LOG(WARNING) << "Cannot find released device";
-    return;
-  }
-  supported_formats_cache_.erase(it);
+  return VideoCaptureErrorOrDevice(kCameraCreateError);
 }
 
 std::vector<VideoCaptureDeviceInfo>
@@ -101,13 +107,16 @@ VideoCaptureDeviceFactoryTizenTv::GetDevices() {
   for (size_t i = 0; i < list.count; ++i) {
     std::string name(list.device[i].name);
     std::string id(list.device[i].id);
-    TIZEN_MEDIA_LOG(INFO) << "Name " << name << ", type " << list.device[i].type
-                          << ", index " << list.device[i].index << ", id "
-                          << id;
-
-    VideoCaptureDeviceInfo info(VideoCaptureDeviceDescriptor(name, id));
-    info.supported_formats =
-        GetSupportedFormats(list.device[i].index, list.device[i].type);
+    TIZEN_MEDIA_LOG(VERBOSE) << "Camera #" << i
+                             << ": name " << name
+                             << ", type " << list.device[i].type
+                             << ", index " << list.device[i].index
+                             << ", id " << id;
+
+    VideoCaptureDeviceDescriptor camera_descriptor(name, id);
+    VideoCaptureDeviceInfo info(camera_descriptor);
+    info.supported_formats = GetSupportedFormats(
+        camera_descriptor, list.device[i].index, list.device[i].type);
     if (info.supported_formats.empty()) {
       continue;
     }
@@ -144,11 +153,12 @@ VideoCaptureFormats VideoCaptureDeviceFactoryTizenTv::GetSupportedFormats(
 }
 
 VideoCaptureFormats VideoCaptureDeviceFactoryTizenTv::GetSupportedFormats(
+    const VideoCaptureDeviceDescriptor& device_descriptor,
     camera_device_e index,
     camera_device_type_e type) {
   // We cannot obtain camera again if it's already allocated, so
   // get cached formats.
-  auto cache_it = supported_formats_cache_.find(index);
+  auto cache_it = supported_formats_cache_.find(device_descriptor);
   if (cache_it != supported_formats_cache_.end()) {
     return cache_it->second;
   }
@@ -158,7 +168,23 @@ VideoCaptureFormats VideoCaptureDeviceFactoryTizenTv::GetSupportedFormats(
     TIZEN_MEDIA_LOG(INFO) << "Cannot create camera, skip that one.";
     return {};
   }
-  return GetSupportedFormats(camera.get());
+  auto supported_formats = GetSupportedFormats(camera.get());
+  supported_formats_cache_.emplace(device_descriptor, supported_formats);
+
+  auto retain_timer = std::make_unique<base::OneShotTimer>();
+  retain_timer->Start(
+      FROM_HERE, base::Seconds(2),
+      base::BindOnce(&VideoCaptureDeviceFactoryTizenTv::ReleaseCachedDevice,
+                     base::Unretained(this), device_descriptor));
+  devices_cache_[device_descriptor].camera = std::move(camera);
+  devices_cache_[device_descriptor].retain_timer = std::move(retain_timer);
+  return supported_formats;
+}
+
+void VideoCaptureDeviceFactoryTizenTv::ReleaseCachedDevice(
+    const VideoCaptureDeviceDescriptor& device_descriptor) {
+  base::AutoLock lock(devices_lock_);
+  devices_cache_.erase(device_descriptor);
 }
 
 void VideoCaptureDeviceFactoryTizenTv::GetDevicesInfo(
index 24b24918abeef53ba1b3649f03a962fb31eaf814..88af10f173f2a9ef2656fd23a5b07144dd977cb0 100644 (file)
@@ -5,15 +5,14 @@
 #ifndef MEDIA_CAPTURE_VIDEO_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_TV_H_
 #define MEDIA_CAPTURE_VIDEO_TIZEN_VIDEO_CAPTURE_DEVICE_FACTORY_TIZEN_TV_H_
 
-#include <map>
-
 #include <media/camera.h>
 #include <media/camera_internal.h>
 
-#include "base/memory/weak_ptr.h"
+#include <map>
+
 #include "base/synchronization/lock.h"
 #include "base/thread_annotations.h"
-#include "base/threading/thread.h"
+#include "base/timer/timer.h"
 #include "media/capture/video/tizen/camera.h"
 #include "media/capture/video/video_capture_device_factory.h"
 
@@ -31,22 +30,27 @@ class VideoCaptureDeviceFactoryTizenTv : public VideoCaptureDeviceFactory {
       VideoCaptureDeviceFactory::GetDevicesInfoCallback callback) override;
 
  private:
+  struct CameraDeviceHolder {
+    std::unique_ptr<Camera> camera;
+    std::unique_ptr<base::OneShotTimer> retain_timer;
+  };
+
   std::vector<VideoCaptureDeviceInfo> GetDevices();
-  VideoCaptureFormats GetSupportedFormats(camera_device_e index,
-                                          camera_device_type_e type)
-      EXCLUSIVE_LOCKS_REQUIRED(devices_lock_);
+  VideoCaptureFormats GetSupportedFormats(
+      const VideoCaptureDeviceDescriptor& device_descriptor,
+      camera_device_e index,
+      camera_device_type_e type) EXCLUSIVE_LOCKS_REQUIRED(devices_lock_);
   VideoCaptureFormats GetSupportedFormats(Camera* camera);
-
-  void OnDeviceReleased(camera_device_e device);
+  void ReleaseCachedDevice(
+      const VideoCaptureDeviceDescriptor& device_descriptor);
 
   camera_device_manager_h handle_ = nullptr;
 
   base::Lock devices_lock_;
-  std::unordered_map<camera_device_e, VideoCaptureFormats>
+  std::map<VideoCaptureDeviceDescriptor, VideoCaptureFormats>
       supported_formats_cache_ GUARDED_BY(devices_lock_);
-
-  base::WeakPtrFactory<VideoCaptureDeviceFactoryTizenTv> weak_factory_{this};
-  base::WeakPtr<VideoCaptureDeviceFactoryTizenTv> weak_this_;
+  std::map<VideoCaptureDeviceDescriptor, CameraDeviceHolder>
+      devices_cache_ GUARDED_BY(devices_lock_);
 };
 
 }  // namespace media
index 55e4dd5de0fcbaa1cc5acf197dcc85435b17fb05..0d638dd69e9617adf361ffaf6bfcbfc57afa5672 100644 (file)
@@ -627,21 +627,16 @@ void VideoCaptureDeviceTizenTv::Impl::OnDecodedFrame(RawFrame frame) {
 }
 
 VideoCaptureDeviceTizenTv::VideoCaptureDeviceTizenTv(
-    std::unique_ptr<Camera> camera,
-    base::OnceClosure destroy_cb)
+    std::unique_ptr<Camera> camera)
     : camera_thread_("camera_thread"),
-      camera_(std::move(camera)),
-      destroy_camera_cb_(std::move(destroy_cb)) {
+      camera_(std::move(camera)) {
   TIZEN_MEDIA_LOG(INFO);
   LOG_ASSERT(camera_);
-
   camera_thread_.Start();
 }
 
 VideoCaptureDeviceTizenTv::~VideoCaptureDeviceTizenTv() {
   camera_thread_.task_runner()->DeleteSoon(FROM_HERE, std::move(camera_));
-  camera_thread_.task_runner()->PostTask(FROM_HERE,
-                                         std::move(destroy_camera_cb_));
 }
 
 void VideoCaptureDeviceTizenTv::AllocateAndStart(
index 75f9ef2693696455fcb4295fc5b31aa61e7abc26..7b5a491b9b7396b98d5eb04ec078d8d799fd2eb4 100644 (file)
@@ -17,8 +17,7 @@ namespace media {
 
 class VideoCaptureDeviceTizenTv : public VideoCaptureDevice {
  public:
-  explicit VideoCaptureDeviceTizenTv(std::unique_ptr<Camera> camera,
-                                     base::OnceClosure destroy_cb);
+  explicit VideoCaptureDeviceTizenTv(std::unique_ptr<Camera> camera);
   ~VideoCaptureDeviceTizenTv() override;
 
   // VideoCaptureDevice implementation.
@@ -40,7 +39,6 @@ class VideoCaptureDeviceTizenTv : public VideoCaptureDevice {
   base::SequenceBound<Impl> impl_;
   base::Thread camera_thread_;
   std::unique_ptr<Camera> camera_;
-  base::OnceClosure destroy_camera_cb_;
 };
 
 }  // namespace media