From 36649887e8ba8841b45522a772cf83b5c5130fca Mon Sep 17 00:00:00 2001 From: Fabian Bumberger Date: Fri, 21 Mar 2014 16:02:48 +0100 Subject: QNX: Remove most of the CPU overhead for video rendering This patch uses the GL_OES_EGL_image extension to create a OpenGL Texture handle for a libscreen pixmap. If the extension is not available it uses the "old" technique as fallback where the image data is copied into a QImage. This reduces the CPU load by more than 70% and allows HD videos to be played jitter-free. Task-number: QTBUG-37752 Change-Id: I4cad22c39390e4cf9eb5be5f0bfe446544a11b9e Reviewed-by: Bernd Weimer Reviewed-by: Sean Harmer --- .../mmrendererplayervideorenderercontrol.cpp | 81 ++++++++++++++++++++-- .../mmrendererplayervideorenderercontrol.h | 4 +- 2 files changed, 79 insertions(+), 6 deletions(-) (limited to 'src/plugins/qnx/mediaplayer') diff --git a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp index 0abdfec49..b9fe95026 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include @@ -59,7 +60,7 @@ MmRendererPlayerVideoRendererControl::MmRendererPlayerVideoRendererControl(QObje , m_context(0) , m_videoId(-1) { - connect(m_windowGrabber, SIGNAL(frameGrabbed(QImage)), SLOT(frameGrabbed(QImage))); + connect(m_windowGrabber, SIGNAL(frameGrabbed(QImage, int)), SLOT(frameGrabbed(QImage, int))); } MmRendererPlayerVideoRendererControl::~MmRendererPlayerVideoRendererControl() @@ -75,6 +76,10 @@ QAbstractVideoSurface *MmRendererPlayerVideoRendererControl::surface() const void MmRendererPlayerVideoRendererControl::setSurface(QAbstractVideoSurface *surface) { m_surface = QPointer(surface); + if (QOpenGLContext::currentContext()) + m_windowGrabber->checkForEglImageExtension(); + else + m_surface->setProperty("_q_GLThreadCallback", QVariant::fromValue(this)); } void MmRendererPlayerVideoRendererControl::attachDisplay(mmr_context_t *context) @@ -139,20 +144,86 @@ void MmRendererPlayerVideoRendererControl::resume() m_windowGrabber->resume(); } -void MmRendererPlayerVideoRendererControl::frameGrabbed(const QImage &frame) +class BBTextureBuffer : public QAbstractVideoBuffer +{ +public: + BBTextureBuffer(int handle) : + QAbstractVideoBuffer(QAbstractVideoBuffer::GLTextureHandle) + { + m_handle = handle; + } + MapMode mapMode() const { + return QAbstractVideoBuffer::ReadWrite; + } + void unmap() { + + } + uchar *map(MapMode mode, int * numBytes, int * bytesPerLine) { + Q_UNUSED(mode); + Q_UNUSED(numBytes); + Q_UNUSED(bytesPerLine); + return 0; + } + QVariant handle() const { + return m_handle; + } +private: + int m_handle; +}; + +void MmRendererPlayerVideoRendererControl::frameGrabbed(const QImage &frame, int handle) { if (m_surface) { if (!m_surface->isActive()) { - m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + if (m_windowGrabber->eglImageSupported()) { + if (QOpenGLContext::currentContext()) + m_windowGrabber->createEglImages(); + else + m_surface->setProperty("_q_GLThreadCallback", QVariant::fromValue(this)); + + m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_BGR32, + QAbstractVideoBuffer::GLTextureHandle)); + } else { + m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + } } else { if (m_surface->surfaceFormat().frameSize() != frame.size()) { + QAbstractVideoBuffer::HandleType type = m_surface->surfaceFormat().handleType(); m_surface->stop(); - m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + if (type != QAbstractVideoBuffer::NoHandle) { + m_surface->setProperty("_q_GLThreadCallback", QVariant::fromValue(this)); + m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_BGR32, + QAbstractVideoBuffer::GLTextureHandle)); + } else { + m_surface->start(QVideoSurfaceFormat(frame.size(), QVideoFrame::Format_ARGB32)); + } } } - m_surface->present(frame.copy()); + // Depending on the support of EGL images on the current platform we either pass a texture + // handle or a copy of the image data + if (m_surface->surfaceFormat().handleType() != QAbstractVideoBuffer::NoHandle) { + if (m_windowGrabber->eglImagesInitialized() && + m_surface->property("_q_GLThreadCallback") != 0) + m_surface->setProperty("_q_GLThreadCallback", 0); + + + BBTextureBuffer *textBuffer = new BBTextureBuffer(handle); + QVideoFrame actualFrame(textBuffer, frame.size(), QVideoFrame::Format_BGR32); + m_surface->present(actualFrame); + } else { + m_surface->present(frame.copy()); + } } } +void MmRendererPlayerVideoRendererControl::customEvent(QEvent *e) +{ + // This is running in the render thread (OpenGL enabled) + if (e->type() == QEvent::User) + m_windowGrabber->checkForEglImageExtension(); + else if (e->type() == QEvent::User + 1) + m_windowGrabber->createEglImages(); +} + QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h index 4e271ad5d..5624b464e 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrendererplayervideorenderercontrol.h @@ -67,8 +67,10 @@ public: void pause(); void resume(); + void customEvent(QEvent *) Q_DECL_OVERRIDE; + private Q_SLOTS: - void frameGrabbed(const QImage &frame); + void frameGrabbed(const QImage &frame, int); private: QPointer m_surface; -- cgit v1.2.3