diff --git a/src/plugins/screencast/outputscreencastsource.cpp b/src/plugins/screencast/outputscreencastsource.cpp index 0c0706a2a0..ac853171da 100644 --- a/src/plugins/screencast/outputscreencastsource.cpp +++ b/src/plugins/screencast/outputscreencastsource.cpp @@ -44,11 +44,11 @@ QSize OutputScreenCastSource::textureSize() const return m_output->pixelSize(); } -void OutputScreenCastSource::render(QImage *image) +void OutputScreenCastSource::render(spa_data *spa, spa_video_format format) { const std::shared_ptr outputTexture = Compositor::self()->scene()->textureForOutput(m_output); if (outputTexture) { - grabTexture(outputTexture.get(), image); + grabTexture(outputTexture.get(), spa, format); } } diff --git a/src/plugins/screencast/outputscreencastsource.h b/src/plugins/screencast/outputscreencastsource.h index 81bf511b18..1e12eba200 100644 --- a/src/plugins/screencast/outputscreencastsource.h +++ b/src/plugins/screencast/outputscreencastsource.h @@ -27,7 +27,7 @@ public: quint32 drmFormat() const override; void render(GLFramebuffer *target) override; - void render(QImage *image) override; + void render(spa_data *spa, spa_video_format format) override; std::chrono::nanoseconds clock() const override; private: diff --git a/src/plugins/screencast/regionscreencastsource.cpp b/src/plugins/screencast/regionscreencastsource.cpp index daeb69d7cb..8b747f57a6 100644 --- a/src/plugins/screencast/regionscreencastsource.cpp +++ b/src/plugins/screencast/regionscreencastsource.cpp @@ -110,10 +110,10 @@ void RegionScreenCastSource::render(GLFramebuffer *target) GLFramebuffer::popFramebuffer(); } -void RegionScreenCastSource::render(QImage *image) +void RegionScreenCastSource::render(spa_data *spa, spa_video_format format) { ensureTexture(); - grabTexture(m_renderedTexture.get(), image); + grabTexture(m_renderedTexture.get(), spa, format); } } diff --git a/src/plugins/screencast/regionscreencastsource.h b/src/plugins/screencast/regionscreencastsource.h index 09ea033248..560c5d64dc 100644 --- a/src/plugins/screencast/regionscreencastsource.h +++ b/src/plugins/screencast/regionscreencastsource.h @@ -28,7 +28,7 @@ public: QSize textureSize() const override; void render(GLFramebuffer *target) override; - void render(QImage *image) override; + void render(spa_data *spa, spa_video_format format) override; std::chrono::nanoseconds clock() const override; QRect region() const diff --git a/src/plugins/screencast/screencastsource.h b/src/plugins/screencast/screencastsource.h index 81d78762c9..6dcafc84c2 100644 --- a/src/plugins/screencast/screencastsource.h +++ b/src/plugins/screencast/screencastsource.h @@ -7,6 +7,8 @@ #pragma once #include +#include +#include namespace KWin { @@ -25,7 +27,7 @@ public: virtual QSize textureSize() const = 0; virtual void render(GLFramebuffer *target) = 0; - virtual void render(QImage *image) = 0; + virtual void render(spa_data *spa, spa_video_format format) = 0; virtual std::chrono::nanoseconds clock() const = 0; Q_SIGNALS: diff --git a/src/plugins/screencast/screencaststream.cpp b/src/plugins/screencast/screencaststream.cpp index fad5114c06..b79c422bd6 100644 --- a/src/plugins/screencast/screencaststream.cpp +++ b/src/plugins/screencast/screencaststream.cpp @@ -450,20 +450,20 @@ void ScreenCastStream::recordFrame(const QRegion &_damagedRegion) const int bpp = data && !hasAlpha ? 3 : 4; const uint stride = SPA_ROUND_UP_N(size.width() * bpp, 4); - QImage dest(data, size.width(), size.height(), stride, hasAlpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGB888); - if (dest.sizeInBytes() > spa_data->maxsize) { + if ((stride * size.height()) > spa_data->maxsize) { qCDebug(KWIN_SCREENCAST) << "Failed to record frame: frame is too big"; pw_stream_queue_buffer(pwStream, buffer); return; } - spa_data->chunk->size = dest.sizeInBytes(); - spa_data->chunk->stride = dest.bytesPerLine(); + spa_data->chunk->stride = stride; + spa_data->chunk->size = stride * size.height(); - m_source->render(&dest); + m_source->render(spa_data, videoFormat.format); auto cursor = Cursors::self()->currentCursor(); if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Embedded && exclusiveContains(m_cursor.viewport, cursor->pos())) { + QImage dest(data, size.width(), size.height(), stride, hasAlpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGB888); QPainter painter(&dest); const auto position = (cursor->pos() - m_cursor.viewport.topLeft() - cursor->hotspot()) * m_cursor.scale; painter.drawImage(QRect{position.toPoint(), cursor->image().size()}, cursor->image()); diff --git a/src/plugins/screencast/screencastutils.h b/src/plugins/screencast/screencastutils.h index 55efb604fc..f20ec322c8 100644 --- a/src/plugins/screencast/screencastutils.h +++ b/src/plugins/screencast/screencastutils.h @@ -8,6 +8,8 @@ #include "kwinglplatform.h" #include "kwingltexture.h" +#include +#include namespace KWin { @@ -25,28 +27,29 @@ static void mirrorVertically(uchar *data, int height, int stride) } } -static GLenum closestGLType(const QImage &image) +static GLenum closestGLType(spa_video_format format) { - switch (image.format()) { - case QImage::Format_RGB888: + switch (format) { + case SPA_VIDEO_FORMAT_RGB: return GL_RGB; - case QImage::Format_BGR888: + case SPA_VIDEO_FORMAT_BGR: return GL_BGR; - case QImage::Format_RGB32: - case QImage::Format_RGBX8888: - case QImage::Format_RGBA8888: - case QImage::Format_RGBA8888_Premultiplied: + case SPA_VIDEO_FORMAT_RGBx: + case SPA_VIDEO_FORMAT_RGBA: return GL_RGBA; + case SPA_VIDEO_FORMAT_BGRA: + case SPA_VIDEO_FORMAT_BGRx: + return GL_BGRA; default: - qDebug() << "unknown format" << image.format(); + qDebug() << "unknown format" << format; return GL_RGBA; } } -static void grabTexture(GLTexture *texture, QImage *image) +static void grabTexture(GLTexture *texture, spa_data *spa, spa_video_format format) { const bool invert = !texture->isYInverted(); - Q_ASSERT(texture->size() == image->size()); + const QSize size = texture->size(); bool isGLES = GLPlatform::instance()->isGLES(); bool invertNeeded = isGLES ^ invert; const bool invertNeededAndSupported = invertNeeded && GLPlatform::instance()->supports(PackInvert); @@ -58,11 +61,11 @@ static void grabTexture(GLTexture *texture, QImage *image) texture->bind(); if (GLPlatform::instance()->isGLES()) { - glReadPixels(0, 0, image->width(), image->height(), closestGLType(*image), GL_UNSIGNED_BYTE, (GLvoid *)image->bits()); + glReadPixels(0, 0, size.width(), size.height(), closestGLType(format), GL_UNSIGNED_BYTE, spa->data); } else if (GLPlatform::instance()->glVersion() >= kVersionNumber(4, 5)) { - glGetTextureImage(texture->texture(), 0, closestGLType(*image), GL_UNSIGNED_BYTE, image->sizeInBytes(), image->bits()); + glGetTextureImage(texture->texture(), 0, closestGLType(format), GL_UNSIGNED_BYTE, spa->chunk->size, spa->data); } else { - glGetTexImage(texture->target(), 0, closestGLType(*image), GL_UNSIGNED_BYTE, image->bits()); + glGetTexImage(texture->target(), 0, closestGLType(format), GL_UNSIGNED_BYTE, spa->data); } if (invertNeededAndSupported) { @@ -70,7 +73,7 @@ static void grabTexture(GLTexture *texture, QImage *image) glPixelStorei(GL_PACK_INVERT_MESA, prev); } } else if (invertNeeded) { - mirrorVertically(image->bits(), image->height(), image->bytesPerLine()); + mirrorVertically(static_cast(spa->data), size.height(), spa->chunk->stride); } } diff --git a/src/plugins/screencast/windowscreencastsource.cpp b/src/plugins/screencast/windowscreencastsource.cpp index 3c247a3c92..fe651ce854 100644 --- a/src/plugins/screencast/windowscreencastsource.cpp +++ b/src/plugins/screencast/windowscreencastsource.cpp @@ -46,13 +46,13 @@ QSize WindowScreenCastSource::textureSize() const return m_window->clientGeometry().size().toSize(); } -void WindowScreenCastSource::render(QImage *image) +void WindowScreenCastSource::render(spa_data *spa, spa_video_format format) { GLTexture offscreenTexture(hasAlphaChannel() ? GL_RGBA8 : GL_RGB8, textureSize()); GLFramebuffer offscreenTarget(&offscreenTexture); render(&offscreenTarget); - grabTexture(&offscreenTexture, image); + grabTexture(&offscreenTexture, spa, format); } void WindowScreenCastSource::render(GLFramebuffer *target) diff --git a/src/plugins/screencast/windowscreencastsource.h b/src/plugins/screencast/windowscreencastsource.h index 69cd989d53..4efb7850a3 100644 --- a/src/plugins/screencast/windowscreencastsource.h +++ b/src/plugins/screencast/windowscreencastsource.h @@ -27,7 +27,7 @@ public: QSize textureSize() const override; void render(GLFramebuffer *target) override; - void render(QImage *image) override; + void render(spa_data *spa, spa_video_format format) override; std::chrono::nanoseconds clock() const override; private: