From 6f1945af48bf39c0d6483befb9a46a617ef5b288 Mon Sep 17 00:00:00 2001
From: Mohamed Chibani <mohamed.chibani@savoirfairelinux.com>
Date: Tue, 12 Apr 2022 15:40:45 -0400
Subject: [PATCH] SHM: Fix copy from shared memory to QVideoFrame

Frames in shared memory have no specific line alignment
(i.e. stride = width), as opposed to the QVideoFrame, so
the copy need to be done accordingly.

Gitlab: #721

Change-Id: Id6576e55c5742a4e99d603feb4bc78f4d2be1ff0
---
 src/videoprovider.cpp | 39 +++++++++++++++++++++++++++++++++++++--
 src/videoprovider.h   |  1 +
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/src/videoprovider.cpp b/src/videoprovider.cpp
index c3d4f0e0e..8c8319948 100644
--- a/src/videoprovider.cpp
+++ b/src/videoprovider.cpp
@@ -111,9 +111,11 @@ VideoProvider::onRendererStarted(const QString& id)
         if (it == framesObjects_.end()) {
             auto fo = std::make_unique<FrameObject>();
             fo->videoFrame = std::make_unique<QVideoFrame>(frameFormat);
+            qDebug() << "Create new QVideoFrame " << frameFormat.frameSize();
             framesObjects_.emplace(id, std::move(fo));
         } else {
             it->second->videoFrame.reset(new QVideoFrame(frameFormat));
+            qDebug() << "QVideoFrame reset to " << frameFormat.frameSize();
         }
     }
 
@@ -174,8 +176,10 @@ VideoProvider::onFrameUpdated(const QString& id)
             qWarning() << "QVideoFrame can't be mapped" << id;
             return;
         }
-        auto frame = avModel_.getRendererFrame(id);
-        std::memcpy(videoFrame->bits(0), frame.ptr, frame.size);
+        auto srcFrame = avModel_.getRendererFrame(id);
+        if (srcFrame.ptr != nullptr and srcFrame.size > 0) {
+            copyUnaligned(videoFrame, srcFrame);
+        }
     }
     if (videoFrame->isMapped()) {
         videoFrame->unmap();
@@ -206,3 +210,34 @@ VideoProvider::onRendererStopped(const QString& id)
     }
     it->second->videoFrame.reset();
 }
+
+void
+VideoProvider::copyUnaligned(QVideoFrame* dst, const video::Frame& src)
+{
+    // Copy from a frame residing in the shared memory.
+    // Frames in shared memory have no specific line alignment
+    // (i.e. stride = width), as opposed to QVideoFrame frames,
+    // so the copy need to be done accordingly.
+
+    // This helper only handles RGBA and BGRA pixel formats, so the
+    // following constraints must apply.
+    assert(dst->pixelFormat() == QVideoFrameFormat::Format_RGBA8888
+           or dst->pixelFormat() == QVideoFrameFormat::Format_BGRA8888);
+    assert(dst->planeCount() == 1);
+
+    const int BYTES_PER_PIXEL = 4;
+
+    // The provided source must be valid.
+    assert(src.ptr != nullptr and src.size > 0);
+    if (dst->width() * dst->height() * BYTES_PER_PIXEL != src.size) {
+        qCritical() << "Size mismatch. Actual " << src.size << " Expected "
+                    << dst->width() * dst->height() * BYTES_PER_PIXEL;
+        return;
+    }
+
+    for (int row = 0; row < dst->height(); row++) {
+        auto dstPtr = dst->bits(0) + row * dst->bytesPerLine(0);
+        auto srcPtr = src.ptr + row * dst->width() * BYTES_PER_PIXEL;
+        std::memcpy(dstPtr, srcPtr, dst->width() * BYTES_PER_PIXEL);
+    }
+}
diff --git a/src/videoprovider.h b/src/videoprovider.h
index 02d5a9b9b..f73bc6350 100644
--- a/src/videoprovider.h
+++ b/src/videoprovider.h
@@ -54,6 +54,7 @@ private Q_SLOTS:
     void onRendererStopped(const QString& id);
 
 private:
+    void copyUnaligned(QVideoFrame* dst, const video::Frame& src);
     AVModel& avModel_;
 
     struct FrameObject
-- 
GitLab