From 1c1a7f8487ffebf91daa15ce9174cc882a26d947 Mon Sep 17 00:00:00 2001
From: agsantos <aline.gondimsantos@savoirfairelinux.com>
Date: Wed, 20 Oct 2021 17:25:13 -0400
Subject: [PATCH] screensharing: add framerate preference

GitLab: client-qt#514
Change-Id: Iaad758cd52dd0837b00ca520aa4da87929215fcb
---
 src/media/video/v4l2/video_device_impl.cpp    | 30 +++++++++++++++++++
 .../video/v4l2/video_device_monitor_impl.cpp  |  1 +
 src/media/video/video_device.h                |  1 +
 src/media/video/video_device_monitor.cpp      | 27 ++++++++++-------
 src/media/video/video_input.cpp               |  9 ++----
 .../video/winvideo/video_device_impl.cpp      | 26 ++++++++++++++++
 .../winvideo/video_device_monitor_impl.cpp    |  1 +
 7 files changed, 78 insertions(+), 17 deletions(-)

diff --git a/src/media/video/v4l2/video_device_impl.cpp b/src/media/video/v4l2/video_device_impl.cpp
index eeb4d0363a..2741282d02 100644
--- a/src/media/video/v4l2/video_device_impl.cpp
+++ b/src/media/video/v4l2/video_device_impl.cpp
@@ -441,6 +441,11 @@ VideoDeviceImpl::VideoDeviceImpl(const string& id, const std::string& path)
     , size_(-1, -1)
     , rate_(-1, 1, 0)
 {
+    if (id == DEVICE_DESKTOP) {
+        name = DEVICE_DESKTOP;
+        rate_.frame_rate = 30;
+        return;
+    }
     int fd = open(path.c_str(), O_RDWR);
     if (fd == -1)
         throw std::runtime_error("could not open device");
@@ -514,6 +519,8 @@ VideoV4l2Rate::libAvPixelformat() const
 vector<string>
 VideoDeviceImpl::getChannelList() const
 {
+    if (unique_id == DEVICE_DESKTOP)
+        return {"default"};
     vector<string> v;
     v.reserve(channels_.size());
     for (const auto& itr : channels_)
@@ -525,12 +532,26 @@ VideoDeviceImpl::getChannelList() const
 vector<VideoSize>
 VideoDeviceImpl::getSizeList(const string& channel) const
 {
+    if (unique_id == DEVICE_DESKTOP) {
+        return {VideoSize(0, 0)};
+    }
     return getChannel(channel).getSizeList();
 }
 
 vector<FrameRate>
 VideoDeviceImpl::getRateList(const string& channel, VideoSize size) const
 {
+    if (unique_id == DEVICE_DESKTOP) {
+        return {FrameRate(5),
+                FrameRate(10),
+                FrameRate(15),
+                FrameRate(20),
+                FrameRate(25),
+                FrameRate(30),
+                FrameRate(60),
+                FrameRate(120),
+                FrameRate(144)};
+    }
     return getChannel(channel).getSize(size).getRateList();
 }
 
@@ -552,6 +573,11 @@ VideoDeviceImpl::getDeviceParams() const
     params.name = name;
     params.unique_id = unique_id;
     params.input = path;
+    if (unique_id == DEVICE_DESKTOP) {
+        params.format = "x11grab";
+        params.framerate = rate_.frame_rate;
+        return params;
+    }
     params.format = "video4linux2";
     params.channel_name = channel_.name;
     params.channel = channel_.idx;
@@ -565,6 +591,10 @@ VideoDeviceImpl::getDeviceParams() const
 void
 VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
 {
+    if (unique_id == DEVICE_DESKTOP) {
+        rate_.frame_rate = params.framerate;
+        return;
+    }
     // Set preferences or fallback to defaults.
     channel_ = getChannel(params.channel_name);
     size_ = channel_.getSize({params.width, params.height});
diff --git a/src/media/video/v4l2/video_device_monitor_impl.cpp b/src/media/video/v4l2/video_device_monitor_impl.cpp
index 5e02b3d033..2d9daf6628 100644
--- a/src/media/video/v4l2/video_device_monitor_impl.cpp
+++ b/src/media/video/v4l2/video_device_monitor_impl.cpp
@@ -279,6 +279,7 @@ VideoDeviceMonitor::VideoDeviceMonitor()
     , monitorImpl_(new VideoDeviceMonitorImpl(this))
 {
     monitorImpl_->start();
+    addDevice(DEVICE_DESKTOP, {});
 }
 
 VideoDeviceMonitor::~VideoDeviceMonitor() {}
diff --git a/src/media/video/video_device.h b/src/media/video/video_device.h
index 46386af941..4f2dec6e05 100644
--- a/src/media/video/video_device.h
+++ b/src/media/video/video_device.h
@@ -44,6 +44,7 @@ namespace video {
 
 using VideoSize = std::pair<unsigned, unsigned>;
 using FrameRate = rational<double>;
+static constexpr const char DEVICE_DESKTOP[] = "desktop";
 
 class VideoDeviceImpl;
 
diff --git a/src/media/video/video_device_monitor.cpp b/src/media/video/video_device_monitor.cpp
index 75a291b1ce..8542bd69ed 100644
--- a/src/media/video/video_device_monitor.cpp
+++ b/src/media/video/video_device_monitor.cpp
@@ -53,7 +53,8 @@ VideoDeviceMonitor::getDeviceList() const
     vector<string> ids;
     ids.reserve(devices_.size());
     for (const auto& dev : devices_) {
-        ids.emplace_back(dev.getDeviceId());
+        if (dev.name != DEVICE_DESKTOP)
+            ids.emplace_back(dev.getDeviceId());
     }
     return ids;
 }
@@ -213,7 +214,7 @@ VideoDeviceMonitor::addDevice(const string& id,
         }
 
         // in case there is no default device on a fresh run
-        if (defaultDevice_.empty())
+        if (defaultDevice_.empty() && id != DEVICE_DESKTOP)
             defaultDevice_ = dev.getDeviceId();
 
         devices_.emplace_back(std::move(dev));
@@ -235,13 +236,13 @@ VideoDeviceMonitor::removeDevice(const string& id)
             return;
 
         devices_.erase(it);
-
         if (defaultDevice_.find(id) != std::string::npos) {
-            if (devices_.size() == 0) {
-                defaultDevice_.clear();
-            } else {
-                defaultDevice_ = devices_[0].getDeviceId();
-            }
+            defaultDevice_.clear();
+            for (const auto& dev : devices_)
+                if (dev.name != DEVICE_DESKTOP) {
+                    defaultDevice_ = dev.getDeviceId();
+                    break;
+                }
         }
     }
     notify();
@@ -310,12 +311,16 @@ VideoDeviceMonitor::unserialize(const YAML::Node& in)
 
     // Restore the default device if present, or select the first one
     const string prefId = preferences_.empty() ? "" : preferences_[0].unique_id;
-    const string firstId = devices_.empty() ? "" : devices_[0].getDeviceId();
     const auto devIter = findDeviceById(prefId);
-    if (devIter != devices_.end()) {
+    if (devIter != devices_.end() && prefId != DEVICE_DESKTOP) {
         defaultDevice_ = devIter->getDeviceId();
     } else {
-        defaultDevice_ = firstId;
+        defaultDevice_.clear();
+        for (const auto& dev : devices_)
+            if (dev.name != DEVICE_DESKTOP) {
+                defaultDevice_ = dev.getDeviceId();
+                break;
+            }
     }
 }
 
diff --git a/src/media/video/video_input.cpp b/src/media/video/video_input.cpp
index d91f1b6bcc..f4af013842 100644
--- a/src/media/video/video_input.cpp
+++ b/src/media/video/video_input.cpp
@@ -396,8 +396,7 @@ VideoInput::initX11(std::string display)
     size_t space = display.find(' ');
 
     clearOptions();
-    decOpts_.format = "x11grab";
-    decOpts_.framerate = 25;
+    decOpts_ = jami::getVideoDeviceMonitor().getDeviceParams(DEVICE_DESKTOP);
 
     if (space != std::string::npos) {
         std::istringstream iss(display.substr(space + 1));
@@ -428,7 +427,7 @@ VideoInput::initAVFoundation(const std::string& display)
     decOpts_.pixel_format = "nv12";
     decOpts_.name = "Capture screen 0";
     decOpts_.input = "Capture screen 0";
-    decOpts_.framerate = 30;
+    decOpts_.framerate = jami::getVideoDeviceMonitor().getDeviceParams(DEVICE_DESKTOP).framerate;
 
     if (space != std::string::npos) {
         std::istringstream iss(display.substr(space + 1));
@@ -449,9 +448,7 @@ VideoInput::initGdiGrab(const std::string& params)
 {
     size_t space = params.find(' ');
     clearOptions();
-    decOpts_.format = "gdigrab";
-    decOpts_.input = "desktop";
-    decOpts_.framerate = 30;
+    decOpts_ = jami::getVideoDeviceMonitor().getDeviceParams(DEVICE_DESKTOP);
 
     if (space != std::string::npos) {
         std::istringstream iss(params.substr(space + 1));
diff --git a/src/media/video/winvideo/video_device_impl.cpp b/src/media/video/winvideo/video_device_impl.cpp
index e244d40079..9af9dc8ce3 100644
--- a/src/media/video/winvideo/video_device_impl.cpp
+++ b/src/media/video/winvideo/video_device_impl.cpp
@@ -64,6 +64,7 @@ private:
     std::vector<VideoSize> sizeList_;
     std::map<VideoSize, std::vector<FrameRate>> rateList_;
     std::map<VideoSize, AM_MEDIA_TYPE*> capMap_;
+    FrameRate desktopFrameRate_ = {30};
 
     void fail(const std::string& error);
 };
@@ -79,6 +80,21 @@ VideoDeviceImpl::VideoDeviceImpl(const std::string& id)
 void
 VideoDeviceImpl::setup()
 {
+    if (id == DEVICE_DESKTOP) {
+        name = DEVICE_DESKTOP;
+        VideoSize size {0, 0};
+        sizeList_.emplace_back(size);
+        rateList_[size] = {FrameRate(5),
+                           FrameRate(10),
+                           FrameRate(15),
+                           FrameRate(20),
+                           FrameRate(25),
+                           FrameRate(30),
+                           FrameRate(60),
+                           FrameRate(120),
+                           FrameRate(144)};
+        return;
+    }
     HRESULT hr = CoCreateInstance(CLSID_CaptureGraphBuilder2,
                                   nullptr,
                                   CLSCTX_INPROC_SERVER,
@@ -264,6 +280,12 @@ VideoDeviceImpl::getDeviceParams() const
     params.name = name;
     params.unique_id = id;
     params.input = id;
+    if (id == DEVICE_DESKTOP) {
+        params.format = "gdigrab";
+        params.framerate = desktopFrameRate_;
+        return params;
+    }
+
     params.format = "dshow";
 
     AM_MEDIA_TYPE* pmt;
@@ -282,6 +304,10 @@ VideoDeviceImpl::getDeviceParams() const
 void
 VideoDeviceImpl::setDeviceParams(const DeviceParams& params)
 {
+    if (id == DEVICE_DESKTOP) {
+        desktopFrameRate_ = params.framerate;
+        return;
+    }
     if (params.width and params.height) {
         auto pmt = capMap_.at(std::make_pair(params.width, params.height));
         if (pmt != nullptr) {
diff --git a/src/media/video/winvideo/video_device_monitor_impl.cpp b/src/media/video/winvideo/video_device_monitor_impl.cpp
index c4abebbfdd..cc23a92b64 100644
--- a/src/media/video/winvideo/video_device_monitor_impl.cpp
+++ b/src/media/video/winvideo/video_device_monitor_impl.cpp
@@ -293,6 +293,7 @@ VideoDeviceMonitor::VideoDeviceMonitor()
     , monitorImpl_(new VideoDeviceMonitorImpl(this))
 {
     monitorImpl_->start();
+    addDevice(DEVICE_DESKTOP, {});
 }
 
 VideoDeviceMonitor::~VideoDeviceMonitor() {}
-- 
GitLab