From 33f089ef50deb19c15b094dde10f87814b7c48b0 Mon Sep 17 00:00:00 2001
From: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
Date: Wed, 11 Jan 2023 09:11:10 -0300
Subject: [PATCH] windows sharing: don't loose window if name changes

GitLab: https://git.jami.net/savoirfairelinux/jami-client-qt/-/issues/481

Change-Id: I1cea58c2c1a4c03df4488e3dd88d381fce659b77
---
 contrib/src/ffmpeg/windows-dxgi-support.patch | 61 +++++++++++--------
 src/media/video/video_input.cpp               | 47 ++++++++++++++
 src/media/video/video_input.h                 |  1 +
 3 files changed, 84 insertions(+), 25 deletions(-)

diff --git a/contrib/src/ffmpeg/windows-dxgi-support.patch b/contrib/src/ffmpeg/windows-dxgi-support.patch
index 4458c03156..b1c1e5096a 100644
--- a/contrib/src/ffmpeg/windows-dxgi-support.patch
+++ b/contrib/src/ffmpeg/windows-dxgi-support.patch
@@ -1,4 +1,4 @@
-From 9055aa8b78fcd8e913642ffe21759579283ae1bb Mon Sep 17 00:00:00 2001
+From 000d467635e4ef42d805fd4cc17efdb2f986ce5e Mon Sep 17 00:00:00 2001
 From: Aline Gondim Santos <aline.gondimsantos@savoirfairelinux.com>
 Date: Thu, 29 Dec 2022 12:59:19 -0300
 Subject: [PATCH] Add dxgi support
@@ -7,15 +7,15 @@ Subject: [PATCH] Add dxgi support
  configure                        |   1 +
  libavdevice/Makefile             |   4 +
  libavdevice/alldevices.c         |   1 +
- libavdevice/d3dHelpers.h         |  59 +++++++++
- libavdevice/direct3d11.interop.h |  51 ++++++++
- libavdevice/dxgigrab.cpp         | 218 +++++++++++++++++++++++++++++++
- libavdevice/dxgigrab.h           |  83 ++++++++++++
- libavdevice/dxgigrab_c.c         |  59 +++++++++
- libavdevice/dxgigrab_c.h         |  98 ++++++++++++++
- libavdevice/windows_capture.cpp  | 184 ++++++++++++++++++++++++++
- libavdevice/windows_capture.h    |  82 ++++++++++++
- 11 files changed, 840 insertions(+)
+ libavdevice/d3dHelpers.h         |  59 ++++++++
+ libavdevice/direct3d11.interop.h |  51 +++++++
+ libavdevice/dxgigrab.cpp         | 229 +++++++++++++++++++++++++++++++
+ libavdevice/dxgigrab.h           |  83 +++++++++++
+ libavdevice/dxgigrab_c.c         |  59 ++++++++
+ libavdevice/dxgigrab_c.h         |  98 +++++++++++++
+ libavdevice/windows_capture.cpp  | 184 +++++++++++++++++++++++++
+ libavdevice/windows_capture.h    |  82 +++++++++++
+ 11 files changed, 851 insertions(+)
  create mode 100644 libavdevice/d3dHelpers.h
  create mode 100644 libavdevice/direct3d11.interop.h
  create mode 100644 libavdevice/dxgigrab.cpp
@@ -194,10 +194,10 @@ index 0000000000..62c9b0843e
 +}
 diff --git a/libavdevice/dxgigrab.cpp b/libavdevice/dxgigrab.cpp
 new file mode 100644
-index 0000000000..365ba4f9aa
+index 0000000000..da16b026a5
 --- /dev/null
 +++ b/libavdevice/dxgigrab.cpp
-@@ -0,0 +1,218 @@
+@@ -0,0 +1,229 @@
 +/*
 + * DXGI video grab interface
 + *
@@ -262,16 +262,27 @@ index 0000000000..365ba4f9aa
 +    monitorData.rect.left = 0;
 +    monitorData.rect.bottom = 0;
 +    monitorData.rect.right = 0;
-+    const char *name     = NULL;
++    std::string name;
 +    AVStream   *st       = NULL;
 +
 +    if (!strncmp(s1->url, "title=", 6)) {
-+        name = s1->url + 6;
-+        s->hwnd = FindWindow(NULL, name);
 +        if (!s->hwnd) {
-+            av_log(s1, AV_LOG_ERROR,
-+                   "Can't find window '%s', aborting.\n", name);
-+            return AVERROR_EXTERNAL;
++            name = s1->url + 6;
++            int srcLength = (int) name.length();
++            int requiredSize = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), srcLength, nullptr, 0);
++            if (!requiredSize) {
++                return AVERROR_EXTERNAL;
++            }
++            std::wstring wName((size_t) requiredSize, 0);
++            if (!MultiByteToWideChar(CP_UTF8, 0, name.c_str(), srcLength, &(*wName.begin()), requiredSize)) {
++                return AVERROR_EXTERNAL;
++            }
++            s->hwnd = FindWindowW(NULL, &(*wName.begin()));
++            if (!s->hwnd) {
++                av_log(s1, AV_LOG_ERROR,
++                       "Can't find window '%s', aborting.\n", name.c_str());
++                return AVERROR_EXTERNAL;
++            }
 +        }
 +    } else {
 +        s->hwnd = NULL;
@@ -351,8 +362,8 @@ index 0000000000..365ba4f9aa
 +        x_internal->m_capture.reset(new WindowsCapture(m_device, windowItem, monitorData));
 +        x_internal->m_capture->StartCapture();
 +        x_internal->m_capture->checkNewFrameArrived();
-+        x_internal->m_capture->window = name ? name : "";
-+        x_internal->windowName = name ? name : "";
++        x_internal->m_capture->window = name;
++        x_internal->windowName = name;
 +    }
 +
 +    s->time_base   = av_inv_q(s->framerate);
@@ -676,7 +687,7 @@ index 0000000000..d624ca0683
 +#endif /* AVDEVICE_DXGI_C_H */
 diff --git a/libavdevice/windows_capture.cpp b/libavdevice/windows_capture.cpp
 new file mode 100644
-index 0000000000..9eaf8cf222
+index 0000000000..c6b29f1a1d
 --- /dev/null
 +++ b/libavdevice/windows_capture.cpp
 @@ -0,0 +1,184 @@
@@ -780,12 +791,12 @@ index 0000000000..9eaf8cf222
 +{
 +    std::lock_guard<std::mutex> lk(mtx_);
 +    if (!running_)
-+        return 0;
++        return false;
 +    auto shouldResize = false;
 +
 +    auto frame = m_framePool.TryGetNextFrame();
 +    if (!frame)
-+        return 0;
++        return false;
 +
 +    auto frameSurface = GetDXGIInterfaceFromObject<ID3D11Texture2D>(frame.Surface());
 +
@@ -793,7 +804,7 @@ index 0000000000..9eaf8cf222
 +    frameSurface->GetDesc(&desc);
 +    auto frameContentSize = frame.ContentSize();
 +    if (desc.Width <= 0 || desc.Height <= 0)
-+        return 0;
++        return false;
 +
 +    shouldResize = frameContentSize.Width != m_DeviceSize.Width || frameContentSize.Height != m_DeviceSize.Height;
 +
@@ -820,7 +831,7 @@ index 0000000000..9eaf8cf222
 +    // copy the texture to a staging resource
 +    m_d3dContext->CopyResource(texture, frameSurface.get());
 +
-+    return 1;
++    return true;
 +}
 +
 +int
diff --git a/src/media/video/video_input.cpp b/src/media/video/video_input.cpp
index d56c291b58..398bd302eb 100644
--- a/src/media/video/video_input.cpp
+++ b/src/media/video/video_input.cpp
@@ -261,6 +261,30 @@ VideoInput::configureFilePlayback(const std::string&,
     sink_->setFrameSize(decoder_->getWidth(), decoder_->getHeight());
 }
 
+#ifdef WIN32
+BOOL CALLBACK
+EnumWindowsProcMy(HWND hwnd, LPARAM lParam)
+{
+    std::pair<DWORD, std::string>* dataPair = reinterpret_cast<std::pair<DWORD, std::string>*>(lParam);
+    DWORD lpdwProcessId;
+    if (auto parent = GetWindow(hwnd, GW_OWNER))
+        GetWindowThreadProcessId(parent, &lpdwProcessId);
+    else
+        GetWindowThreadProcessId(hwnd, &lpdwProcessId);
+    int len = GetWindowTextLength(hwnd) + 1;
+    std::vector<wchar_t> buf(len);
+    GetWindowText(hwnd, &buf[0], len);
+
+    if (lpdwProcessId == dataPair->first) {
+        if (!IsWindowVisible(hwnd))
+            return TRUE;
+        dataPair->second = to_string(&buf[0]);
+        return FALSE;
+    }
+    return TRUE;
+}
+#endif
+
 void
 VideoInput::createDecoder()
 {
@@ -286,6 +310,23 @@ VideoInput::createDecoder()
 
     bool ready = false, restartSink = false;
     if ((decOpts_.format == "x11grab" || decOpts_.format == "dxgigrab") && !decOpts_.is_area) {
+#ifdef WIN32
+        // if window is not find, it might have changed its name
+        // in that case we must search for the parent process window
+        auto hwnd = FindWindow(NULL, to_wstring(decOpts_.name.substr(6)).c_str());
+        if (!hwnd) {
+            std::pair<DWORD, std::string> idName(wProcessId, {});
+            LPARAM lParam = reinterpret_cast<LPARAM>(&idName);
+            EnumWindows(EnumWindowsProcMy, lParam);
+            if (!idName.second.empty()) {
+                auto newTitle = "title=" + idName.second;
+                if (decOpts_.name != newTitle || decOpts_.input != newTitle) {
+                    decOpts_.name = newTitle;
+                    decOpts_.input = newTitle;
+                }
+            }
+        }
+#endif
         decOpts_.width = 0;
         decOpts_.height = 0;
     }
@@ -484,6 +525,12 @@ VideoInput::initWindowsGrab(const std::string& display)
     if (winIdPos != std::string::npos) {
         p.input = display.substr(winIdPos + windowIdStr.size()); // "TITLE";
         p.name  = display.substr(winIdPos + windowIdStr.size()); // "TITLE";
+
+        auto hwnd = FindWindow(NULL, to_wstring(p.name.substr(6)).c_str());
+        if (auto parent = GetWindow(hwnd, GW_OWNER))
+            GetWindowThreadProcessId(parent, &wProcessId);
+        else
+            GetWindowThreadProcessId(hwnd, &wProcessId);
         p.is_area = 0;
     } else {
         p.input = display.substr(1);
diff --git a/src/media/video/video_input.h b/src/media/video/video_input.h
index 570427ec9d..80422457da 100644
--- a/src/media/video/video_input.h
+++ b/src/media/video/video_input.h
@@ -137,6 +137,7 @@ private:
     bool initFile(std::string path);
 #ifdef WIN32
     bool initWindowsGrab(const std::string& display);
+    DWORD wProcessId;
 #endif
 
     bool isCapturing() const noexcept;
-- 
GitLab