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