From d8e18d9add1ad664c6c2eddeb5a37e87b9676d29 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Sun, 15 Jan 2012 20:14:29 +0200 Subject: qtvideosink: Rename GstQtVideoSinkSurface to QtVideoSinkDelegate --- elements/gstqtvideosink/CMakeLists.txt | 2 +- elements/gstqtvideosink/gstqtvideosink.cpp | 2 +- elements/gstqtvideosink/gstqtvideosinkbase.cpp | 6 +- elements/gstqtvideosink/gstqtvideosinkbase.h | 4 +- elements/gstqtvideosink/gstqtvideosinksurface.cpp | 475 ---------------------- elements/gstqtvideosink/gstqtvideosinksurface.h | 169 -------- elements/gstqtvideosink/gstqwidgetvideosink.cpp | 2 +- elements/gstqtvideosink/qtvideosinkdelegate.cpp | 473 +++++++++++++++++++++ elements/gstqtvideosink/qtvideosinkdelegate.h | 169 ++++++++ 9 files changed, 650 insertions(+), 652 deletions(-) delete mode 100644 elements/gstqtvideosink/gstqtvideosinksurface.cpp delete mode 100644 elements/gstqtvideosink/gstqtvideosinksurface.h create mode 100644 elements/gstqtvideosink/qtvideosinkdelegate.cpp create mode 100644 elements/gstqtvideosink/qtvideosinkdelegate.h diff --git a/elements/gstqtvideosink/CMakeLists.txt b/elements/gstqtvideosink/CMakeLists.txt index be03077..f21e51c 100644 --- a/elements/gstqtvideosink/CMakeLists.txt +++ b/elements/gstqtvideosink/CMakeLists.txt @@ -12,7 +12,7 @@ set(GstQtVideoSink_SRCS gstqtvideosink.cpp gstqwidgetvideosink.cpp gstqtvideosinkplugin.cpp - gstqtvideosinksurface.cpp + qtvideosinkdelegate.cpp ${CMAKE_CURRENT_BINARY_DIR}/gstqtvideosinkmarshal.c ) diff --git a/elements/gstqtvideosink/gstqtvideosink.cpp b/elements/gstqtvideosink/gstqtvideosink.cpp index d990249..ffb3b2a 100644 --- a/elements/gstqtvideosink/gstqtvideosink.cpp +++ b/elements/gstqtvideosink/gstqtvideosink.cpp @@ -25,7 +25,7 @@ #include "gstqtvideosink.h" #include "gstqtvideosinkmarshal.h" -#include "gstqtvideosinksurface.h" +#include "qtvideosinkdelegate.h" //------------------------------ diff --git a/elements/gstqtvideosink/gstqtvideosinkbase.cpp b/elements/gstqtvideosink/gstqtvideosinkbase.cpp index cfb9707..385c333 100644 --- a/elements/gstqtvideosink/gstqtvideosinkbase.cpp +++ b/elements/gstqtvideosink/gstqtvideosinkbase.cpp @@ -16,7 +16,7 @@ */ #include "gstqtvideosinkbase.h" -#include "gstqtvideosinksurface.h" +#include "qtvideosinkdelegate.h" #include @@ -132,7 +132,7 @@ void GstQtVideoSinkBase::init(GTypeInstance *instance, gpointer g_class) GstQtVideoSinkBase *sink = GST_QT_VIDEO_SINK_BASE(instance); Q_UNUSED(g_class); - sink->surface = new GstQtVideoSinkSurface(sink); + sink->surface = new QtVideoSinkDelegate(sink); sink->formatDirty = true; } @@ -221,7 +221,7 @@ GstFlowReturn GstQtVideoSinkBase::show_frame(GstVideoSink *video_sink, GstBuffer "Format dirty: %d", buffer, (int)sink->formatDirty); QCoreApplication::postEvent(sink->surface, - new GstQtVideoSinkSurface::BufferEvent(buffer, sink->formatDirty)); + new QtVideoSinkDelegate::BufferEvent(buffer, sink->formatDirty)); sink->formatDirty = false; return GST_FLOW_OK; diff --git a/elements/gstqtvideosink/gstqtvideosinkbase.h b/elements/gstqtvideosink/gstqtvideosinkbase.h index bb0cc0e..e90cce0 100644 --- a/elements/gstqtvideosink/gstqtvideosinkbase.h +++ b/elements/gstqtvideosink/gstqtvideosinkbase.h @@ -31,7 +31,7 @@ #define GST_QT_VIDEO_SINK_BASE_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_QT_VIDEO_SINK_BASE, GstQtVideoSinkBaseClass)) -class GstQtVideoSinkSurface; +class QtVideoSinkDelegate; struct GstQtVideoSinkBase { @@ -66,7 +66,7 @@ private: static GstFlowReturn show_frame(GstVideoSink *sink, GstBuffer *buffer); public: - GstQtVideoSinkSurface *surface; + QtVideoSinkDelegate *surface; private: bool formatDirty; diff --git a/elements/gstqtvideosink/gstqtvideosinksurface.cpp b/elements/gstqtvideosink/gstqtvideosinksurface.cpp deleted file mode 100644 index b6f4a3c..0000000 --- a/elements/gstqtvideosink/gstqtvideosinksurface.cpp +++ /dev/null @@ -1,475 +0,0 @@ -/* - Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - Copyright (C) 2011 Collabora Ltd. - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 2.1 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#include "gstqtvideosinksurface.h" -#include "genericsurfacepainter.h" -#include "openglsurfacepainter.h" - -#include -#include -#include - -#define QSIZE_FORMAT "(%d x %d)" -#define QSIZE_FORMAT_ARGS(size) \ - size.width(), size.height() -#define QRECTF_FORMAT "(x: %f, y: %f, w: %f, h: %f)" -#define QRECTF_FORMAT_ARGS(rect) \ - (float) rect.x(), (float) rect.y(), (float) rect.width(), (float) rect.height() - - -GstQtVideoSinkSurface::GstQtVideoSinkSurface(GstQtVideoSinkBase *sink, QObject *parent) - : QObject(parent) - , m_painter(0) -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL - , m_glContext(0) - , m_supportedShaderTypes(NoShaders) -#endif - , m_colorsDirty(true) - , m_brightness(0) - , m_contrast(0) - , m_hue(0) - , m_saturation(0) - , m_forceAspectRatioDirty(true) - , m_forceAspectRatio(false) - , m_formatDirty(true) - , m_isActive(false) - , m_buffer(NULL) - , m_sink(sink) -{ -} - -GstQtVideoSinkSurface::~GstQtVideoSinkSurface() -{ - Q_ASSERT(!isActive()); - destroyPainter(); -} - -//------------------------------------- - -QSet GstQtVideoSinkSurface::supportedPixelFormats() const -{ - QSet result; -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL - if (m_glContext) - result = OpenGLSurfacePainter::supportedPixelFormats(); - else -#endif - result = GenericSurfacePainter::supportedPixelFormats(); - - return result; -} - -bool GstQtVideoSinkSurface::isActive() const -{ - QReadLocker l(&m_isActiveLock); - return m_isActive; -} - -void GstQtVideoSinkSurface::setActive(bool active) -{ - GST_INFO_OBJECT(m_sink, active ? "Activating" : "Deactivating"); - - QWriteLocker l(&m_isActiveLock); - m_isActive = active; - if (!active) { - QCoreApplication::postEvent(this, new DeactivateEvent()); - } -} - -//------------------------------------- - -int GstQtVideoSinkSurface::brightness() const -{ - QReadLocker l(&m_colorsLock); - return m_brightness; -} - -void GstQtVideoSinkSurface::setBrightness(int brightness) -{ - QWriteLocker l(&m_colorsLock); - m_brightness = brightness; - m_colorsDirty = true; -} - -int GstQtVideoSinkSurface::contrast() const -{ - QReadLocker l(&m_colorsLock); - return m_contrast; -} - -void GstQtVideoSinkSurface::setContrast(int contrast) -{ - QWriteLocker l(&m_colorsLock); - m_contrast = contrast; - m_colorsDirty = true; -} - -int GstQtVideoSinkSurface::hue() const -{ - QReadLocker l(&m_colorsLock); - return m_hue; -} - -void GstQtVideoSinkSurface::setHue(int hue) -{ - QWriteLocker l(&m_colorsLock); - m_hue = hue; - m_colorsDirty = true; -} - -int GstQtVideoSinkSurface::saturation() const -{ - QReadLocker l(&m_colorsLock); - return m_saturation; -} - -void GstQtVideoSinkSurface::setSaturation(int saturation) -{ - QWriteLocker l(&m_colorsLock); - m_saturation = saturation; - m_colorsDirty = true; -} - -//------------------------------------- - -bool GstQtVideoSinkSurface::forceAspectRatio() const -{ - QReadLocker l(&m_forceAspectRatioLock); - return m_forceAspectRatio; -} - -void GstQtVideoSinkSurface::setForceAspectRatio(bool force) -{ - QWriteLocker l(&m_forceAspectRatioLock); - if (m_forceAspectRatio != force) { - m_forceAspectRatio = force; - m_forceAspectRatioDirty = true; - } -} - -//------------------------------------- - -/* Modified version of gst_video_sink_center_rect */ -static QRectF centerRect(const QRectF & src, const QRectF & dst) -{ - QRectF result; - qreal srcRatio = src.width() / src.height(); - qreal dstRatio = dst.width() / dst.height(); - - if (srcRatio > dstRatio) { - result.setWidth(dst.width()); - result.setHeight(dst.width() / srcRatio); - result.moveTop((dst.height() - result.height()) / 2); - } else if (srcRatio < dstRatio) { - result.setWidth(dst.height() * srcRatio); - result.setHeight(dst.height()); - result.moveLeft((dst.width() - result.width()) / 2); - } else { - result = dst; - } - - return result; -} - -void GstQtVideoSinkSurface::paint(QPainter *painter, qreal x, qreal y, qreal width, qreal height) -{ - GST_TRACE_OBJECT(m_sink, "paint called"); - - QRectF targetArea(x, y, width, height); - - if (!m_buffer) { - painter->fillRect(targetArea, Qt::black); - } else { - m_glContext->makeCurrent(); - - BufferFormat format = m_formatDirty ? - BufferFormat::fromCaps(GST_BUFFER_CAPS(m_buffer)) : m_bufferFormat; - - //recalculate the video area if needed - QReadLocker forceAspectRatioLocker(&m_forceAspectRatioLock); - if (targetArea != m_areas.targetArea - || (m_formatDirty && (format.frameSize() != m_bufferFormat.frameSize() - || format.pixelAspectRatio() != m_bufferFormat.pixelAspectRatio())) - || m_forceAspectRatioDirty) - { - m_areas.targetArea = targetArea; - m_forceAspectRatioDirty = false; - - if (m_forceAspectRatio) { - qreal aspectRatio = (qreal) format.pixelAspectRatio().numerator / format.pixelAspectRatio().denominator; - qreal aspectRatioInv = (qreal) format.pixelAspectRatio().denominator / format.pixelAspectRatio().numerator; - - QRectF srcRect(QPointF(0,0), QSizeF(format.frameSize().width() * aspectRatio, - format.frameSize().height() * aspectRatioInv)); - QRectF destRect(QPointF(0,0), m_areas.targetArea.size()); - - m_areas.videoArea = centerRect(srcRect, destRect); - - if (m_areas.videoArea == m_areas.targetArea) { - m_areas.blackArea1 = m_areas.blackArea2 = QRectF(); - } else { - m_areas.blackArea1 = QRectF( - m_areas.targetArea.left(), - m_areas.targetArea.top(), - m_areas.videoArea.left() == m_areas.targetArea.left() ? - m_areas.targetArea.width() : m_areas.videoArea.left() - m_areas.targetArea.left(), - m_areas.videoArea.top() == m_areas.targetArea.top() ? - m_areas.targetArea.height() : m_areas.videoArea.top() - m_areas.targetArea.top() - ); - - m_areas.blackArea2 = QRectF( - m_areas.videoArea.right() == m_areas.targetArea.right() ? - m_areas.targetArea.left() : m_areas.videoArea.right() + 1, - m_areas.videoArea.bottom() == m_areas.targetArea.bottom() ? - m_areas.targetArea.top() : m_areas.videoArea.bottom() + 1, - m_areas.videoArea.right() == m_areas.targetArea.right() ? - m_areas.targetArea.width() : m_areas.targetArea.right() - m_areas.videoArea.right(), - m_areas.videoArea.bottom() == m_areas.targetArea.bottom() ? - m_areas.targetArea.height() : m_areas.targetArea.bottom() - m_areas.videoArea.bottom() - ); - } - } else { - m_areas.videoArea = m_areas.targetArea; - m_areas.blackArea1 = m_areas.blackArea2 = QRectF(); - } - - GST_LOG_OBJECT(m_sink, - "Recalculated paint areas: " - "Frame size: " QSIZE_FORMAT ", " - "target area: " QRECTF_FORMAT ", " - "video area: " QRECTF_FORMAT ", " - "black1: " QRECTF_FORMAT ", " - "black2: " QRECTF_FORMAT, - QSIZE_FORMAT_ARGS(format.frameSize()), - QRECTF_FORMAT_ARGS(m_areas.targetArea), - QRECTF_FORMAT_ARGS(m_areas.videoArea), - QRECTF_FORMAT_ARGS(m_areas.blackArea1), - QRECTF_FORMAT_ARGS(m_areas.blackArea2) - ); - } - forceAspectRatioLocker.unlock(); - - if (m_formatDirty /* || m_clipRectDirty */) { - //TODO add properties for modifying clipRect - m_clipRect = QRectF(QPointF(0,0), format.frameSize()); - } - - //if either pixelFormat or frameSize have changed, we need to reset the painter - //and/or change painter, in case the current one does not handle the requested format - if ((m_formatDirty && (format.videoFormat() != m_bufferFormat.videoFormat() - || format.colorMatrix() != m_bufferFormat.colorMatrix() - || format.frameSize() != m_bufferFormat.frameSize())) - || !m_painter) - { - changePainter(format); - - m_bufferFormat = format; - m_formatDirty = false; - - //make sure to update the colors after changing painter - m_colorsDirty = true; - } - - if (G_LIKELY(m_painter)) { - QReadLocker colorsLocker(&m_colorsLock); - if (m_colorsDirty) { - m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation); - m_colorsDirty = false; - } - colorsLocker.unlock(); - - m_painter->paint(m_buffer->data, m_bufferFormat, m_clipRect, painter, m_areas); - } - } -} - -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL - -QGLContext *GstQtVideoSinkSurface::glContext() const -{ - return m_glContext; -} - -void GstQtVideoSinkSurface::setGLContext(QGLContext *context) -{ - GST_LOG_OBJECT(m_sink, "Setting GL context. context=%p m_glContext=%p m_painter=%p", - context, m_glContext, m_painter); - - if (m_glContext == context) - return; - - m_glContext = context; - - m_supportedShaderTypes = NoShaders; - - if (m_glContext) { - m_glContext->makeCurrent(); - - const QByteArray extensions(reinterpret_cast(glGetString(GL_EXTENSIONS))); - GST_LOG_OBJECT(m_sink, "Available GL extensions: %s", extensions.constData()); - -#ifndef QT_OPENGL_ES - if (extensions.contains("ARB_fragment_program")) - m_supportedShaderTypes |= FragmentProgramShader; -#endif - -#ifndef QT_OPENGL_ES_2 - if (QGLShaderProgram::hasOpenGLShaderPrograms(m_glContext) - && extensions.contains("ARB_shader_objects")) -#endif - m_supportedShaderTypes |= GlslShader; - - } - - GST_LOG_OBJECT(m_sink, "Done setting GL context. m_shaderTypes=%x", (int) m_supportedShaderTypes); -} - -#endif - -enum PainterType { Glsl, ArbFp, Generic }; - -void GstQtVideoSinkSurface::changePainter(const BufferFormat & format) -{ - if (m_painter) { - m_painter->cleanup(); - if (!m_painter->supportsFormat(format.videoFormat())) { - delete m_painter; - m_painter = 0; - } - } - - QStack possiblePainters; - if (GenericSurfacePainter::supportedPixelFormats().contains(format.videoFormat())) { - possiblePainters.push(Generic); - } - -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL -# ifndef QT_OPENGL_ES - if (m_supportedShaderTypes & GstQtVideoSinkSurface::FragmentProgramShader - && ArbFpSurfacePainter::supportedPixelFormats().contains(format.videoFormat())) { - possiblePainters.push(ArbFp); - } -# endif - - if (m_supportedShaderTypes & GstQtVideoSinkSurface::GlslShader - && GlslSurfacePainter::supportedPixelFormats().contains(format.videoFormat())) { - possiblePainters.push(Glsl); - } -#endif - - while (!possiblePainters.isEmpty()) { - if (!m_painter) { - PainterType type = possiblePainters.pop(); - switch(type) { -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL - case Glsl: - GST_LOG_OBJECT(m_sink, "Creating GLSL painter"); - m_painter = new GlslSurfacePainter; - break; -# ifndef QT_OPENGL_ES - case ArbFp: - GST_LOG_OBJECT(m_sink, "Creating ARB Fragment Shader painter"); - m_painter = new ArbFpSurfacePainter; - break; -# endif -#endif - case Generic: - GST_LOG_OBJECT(m_sink, "Creating Generic painter"); - m_painter = new GenericSurfacePainter; - break; - default: - Q_ASSERT(false); - } - } - - try { - m_painter->init(format); - return; - } catch (const QString & error) { - GST_ELEMENT_WARNING(m_sink, RESOURCE, FAILED, - ("Failed to start painter"), ("%s", error.toUtf8().constData())); - delete m_painter; - m_painter = 0; - } - } - - GST_ELEMENT_ERROR(m_sink, RESOURCE, FAILED, - ("Failed to create a painter for the given format"), (NULL)); -} - -void GstQtVideoSinkSurface::destroyPainter() -{ - GST_LOG_OBJECT(m_sink, "Destroying painter"); - - delete m_painter; - m_painter = 0; -} - -bool GstQtVideoSinkSurface::event(QEvent *event) -{ - switch((int) event->type()) { - case BufferEventType: - { - BufferEvent *bufEvent = dynamic_cast(event); - Q_ASSERT(bufEvent); - - GST_TRACE_OBJECT(m_sink, "Received buffer %"GST_PTR_FORMAT, bufEvent->buffer); - - if (m_buffer) { - //free the previous buffer - gst_buffer_unref(m_buffer); - m_buffer = NULL; - } - - if (isActive()) { - //schedule this frame for rendering - m_buffer = bufEvent->buffer; - if (bufEvent->formatDirty) { - m_formatDirty = true; - } - GstQtVideoSinkBase::emit_update(m_sink); - } else { - //not active, drop the frame - gst_buffer_unref(bufEvent->buffer); - } - - return true; - } - case DeactivateEventType: - { - GST_LOG_OBJECT(m_sink, "Received deactivate event"); - - if (m_buffer) { - gst_buffer_unref(m_buffer); - m_buffer = NULL; - } - - if (m_painter) { - m_painter->cleanup(); - destroyPainter(); - } - - GstQtVideoSinkBase::emit_update(m_sink); - - return true; - } - default: - return QObject::event(event); - } -} - -#include "gstqtvideosinksurface.moc" diff --git a/elements/gstqtvideosink/gstqtvideosinksurface.h b/elements/gstqtvideosink/gstqtvideosinksurface.h deleted file mode 100644 index ee3b74e..0000000 --- a/elements/gstqtvideosink/gstqtvideosinksurface.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). - Copyright (C) 2011 Collabora Ltd. - - This library is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License version 2.1 - as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . -*/ - -#ifndef GST_QT_VIDEO_SINK_SURFACE_H -#define GST_QT_VIDEO_SINK_SURFACE_H - -#include "gstqtvideosinkbase.h" -#include "bufferformat.h" -#include "abstractsurfacepainter.h" - -#include -#include -#include -#include - -class QGLContext; - - -class GstQtVideoSinkSurface : public QObject -{ - Q_OBJECT -public: - enum EventType { - BufferEventType = QEvent::User, - DeactivateEventType - }; - - //------------------------------------- - - class BufferEvent : public QEvent - { - public: - inline BufferEvent(GstBuffer *buf, bool formatDirty) - : QEvent(static_cast(BufferEventType)), - buffer(gst_buffer_ref(buf)), - formatDirty(formatDirty) - { - } - - GstBuffer *buffer; - bool formatDirty; - }; - - //------------------------------------- - - class DeactivateEvent : public QEvent - { - public: - inline DeactivateEvent() - : QEvent(static_cast(DeactivateEventType)) - { - } - }; - - //------------------------------------- - - explicit GstQtVideoSinkSurface(GstQtVideoSinkBase *sink, QObject *parent = 0); - ~GstQtVideoSinkSurface(); - - // API for GstQtVideoSink - - QSet supportedPixelFormats() const; - - bool isActive() const; - void setActive(bool playing); - - // GstColorBalance interface - - int brightness() const; - void setBrightness(int brightness); - - int contrast() const; - void setContrast(int contrast); - - int hue() const; - void setHue(int hue); - - int saturation() const; - void setSaturation(int saturation); - - // force-aspect-ratio property - - bool forceAspectRatio() const; - void setForceAspectRatio(bool force); - - // glcontext property - -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL - QGLContext *glContext() const; - void setGLContext(QGLContext *context); - - enum ShaderType - { - NoShaders = 0x00, - FragmentProgramShader = 0x01, - GlslShader = 0x02 - }; - - Q_DECLARE_FLAGS(ShaderTypes, ShaderType) -#endif - - // paint action signal - - void paint(QPainter *painter, qreal x, qreal y, qreal width, qreal height); - -protected: - bool event(QEvent *event); - -private: - void changePainter(const BufferFormat & format); - void destroyPainter(); - - - AbstractSurfacePainter *m_painter; - -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL - QGLContext *m_glContext; - ShaderTypes m_supportedShaderTypes; - ShaderType m_shaderType; -#endif - - // colorbalance interface properties - mutable QReadWriteLock m_colorsLock; - bool m_colorsDirty; - int m_brightness; - int m_contrast; - int m_hue; - int m_saturation; - - // force-aspect-ratio property - mutable QReadWriteLock m_forceAspectRatioLock; - bool m_forceAspectRatioDirty; - bool m_forceAspectRatio; - - // format caching - bool m_formatDirty; - BufferFormat m_bufferFormat; - PaintAreas m_areas; - QRectF m_clipRect; - - // whether the sink is active (PAUSED or PLAYING) - mutable QReadWriteLock m_isActiveLock; - bool m_isActive; - - // the buffer to be drawn next - GstBuffer *m_buffer; - - GstQtVideoSinkBase *m_sink; -}; - -#ifndef GST_QT_VIDEO_SINK_NO_OPENGL -Q_DECLARE_OPERATORS_FOR_FLAGS(GstQtVideoSinkSurface::ShaderTypes) -#endif - -#endif // GST_QT_VIDEO_SINK_SURFACE_H diff --git a/elements/gstqtvideosink/gstqwidgetvideosink.cpp b/elements/gstqtvideosink/gstqwidgetvideosink.cpp index 6e5fafd..ed04569 100644 --- a/elements/gstqtvideosink/gstqwidgetvideosink.cpp +++ b/elements/gstqtvideosink/gstqwidgetvideosink.cpp @@ -37,7 +37,7 @@ */ #include "gstqwidgetvideosink.h" -#include "gstqtvideosinksurface.h" +#include "qtvideosinkdelegate.h" #include #include #include diff --git a/elements/gstqtvideosink/qtvideosinkdelegate.cpp b/elements/gstqtvideosink/qtvideosinkdelegate.cpp new file mode 100644 index 0000000..0dc6011 --- /dev/null +++ b/elements/gstqtvideosink/qtvideosinkdelegate.cpp @@ -0,0 +1,473 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + Copyright (C) 2011 Collabora Ltd. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "qtvideosinkdelegate.h" +#include "genericsurfacepainter.h" +#include "openglsurfacepainter.h" + +#include +#include +#include + +#define QSIZE_FORMAT "(%d x %d)" +#define QSIZE_FORMAT_ARGS(size) \ + size.width(), size.height() +#define QRECTF_FORMAT "(x: %f, y: %f, w: %f, h: %f)" +#define QRECTF_FORMAT_ARGS(rect) \ + (float) rect.x(), (float) rect.y(), (float) rect.width(), (float) rect.height() + + +QtVideoSinkDelegate::QtVideoSinkDelegate(GstQtVideoSinkBase *sink, QObject *parent) + : QObject(parent) + , m_painter(0) +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL + , m_glContext(0) + , m_supportedShaderTypes(NoShaders) +#endif + , m_colorsDirty(true) + , m_brightness(0) + , m_contrast(0) + , m_hue(0) + , m_saturation(0) + , m_forceAspectRatioDirty(true) + , m_forceAspectRatio(false) + , m_formatDirty(true) + , m_isActive(false) + , m_buffer(NULL) + , m_sink(sink) +{ +} + +QtVideoSinkDelegate::~QtVideoSinkDelegate() +{ + Q_ASSERT(!isActive()); + destroyPainter(); +} + +//------------------------------------- + +QSet QtVideoSinkDelegate::supportedPixelFormats() const +{ + QSet result; +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL + if (m_glContext) + result = OpenGLSurfacePainter::supportedPixelFormats(); + else +#endif + result = GenericSurfacePainter::supportedPixelFormats(); + + return result; +} + +bool QtVideoSinkDelegate::isActive() const +{ + QReadLocker l(&m_isActiveLock); + return m_isActive; +} + +void QtVideoSinkDelegate::setActive(bool active) +{ + GST_INFO_OBJECT(m_sink, active ? "Activating" : "Deactivating"); + + QWriteLocker l(&m_isActiveLock); + m_isActive = active; + if (!active) { + QCoreApplication::postEvent(this, new DeactivateEvent()); + } +} + +//------------------------------------- + +int QtVideoSinkDelegate::brightness() const +{ + QReadLocker l(&m_colorsLock); + return m_brightness; +} + +void QtVideoSinkDelegate::setBrightness(int brightness) +{ + QWriteLocker l(&m_colorsLock); + m_brightness = brightness; + m_colorsDirty = true; +} + +int QtVideoSinkDelegate::contrast() const +{ + QReadLocker l(&m_colorsLock); + return m_contrast; +} + +void QtVideoSinkDelegate::setContrast(int contrast) +{ + QWriteLocker l(&m_colorsLock); + m_contrast = contrast; + m_colorsDirty = true; +} + +int QtVideoSinkDelegate::hue() const +{ + QReadLocker l(&m_colorsLock); + return m_hue; +} + +void QtVideoSinkDelegate::setHue(int hue) +{ + QWriteLocker l(&m_colorsLock); + m_hue = hue; + m_colorsDirty = true; +} + +int QtVideoSinkDelegate::saturation() const +{ + QReadLocker l(&m_colorsLock); + return m_saturation; +} + +void QtVideoSinkDelegate::setSaturation(int saturation) +{ + QWriteLocker l(&m_colorsLock); + m_saturation = saturation; + m_colorsDirty = true; +} + +//------------------------------------- + +bool QtVideoSinkDelegate::forceAspectRatio() const +{ + QReadLocker l(&m_forceAspectRatioLock); + return m_forceAspectRatio; +} + +void QtVideoSinkDelegate::setForceAspectRatio(bool force) +{ + QWriteLocker l(&m_forceAspectRatioLock); + if (m_forceAspectRatio != force) { + m_forceAspectRatio = force; + m_forceAspectRatioDirty = true; + } +} + +//------------------------------------- + +/* Modified version of gst_video_sink_center_rect */ +static QRectF centerRect(const QRectF & src, const QRectF & dst) +{ + QRectF result; + qreal srcRatio = src.width() / src.height(); + qreal dstRatio = dst.width() / dst.height(); + + if (srcRatio > dstRatio) { + result.setWidth(dst.width()); + result.setHeight(dst.width() / srcRatio); + result.moveTop((dst.height() - result.height()) / 2); + } else if (srcRatio < dstRatio) { + result.setWidth(dst.height() * srcRatio); + result.setHeight(dst.height()); + result.moveLeft((dst.width() - result.width()) / 2); + } else { + result = dst; + } + + return result; +} + +void QtVideoSinkDelegate::paint(QPainter *painter, qreal x, qreal y, qreal width, qreal height) +{ + GST_TRACE_OBJECT(m_sink, "paint called"); + + QRectF targetArea(x, y, width, height); + + if (!m_buffer) { + painter->fillRect(targetArea, Qt::black); + } else { + m_glContext->makeCurrent(); + + BufferFormat format = m_formatDirty ? + BufferFormat::fromCaps(GST_BUFFER_CAPS(m_buffer)) : m_bufferFormat; + + //recalculate the video area if needed + QReadLocker forceAspectRatioLocker(&m_forceAspectRatioLock); + if (targetArea != m_areas.targetArea + || (m_formatDirty && (format.frameSize() != m_bufferFormat.frameSize() + || format.pixelAspectRatio() != m_bufferFormat.pixelAspectRatio())) + || m_forceAspectRatioDirty) + { + m_areas.targetArea = targetArea; + m_forceAspectRatioDirty = false; + + if (m_forceAspectRatio) { + qreal aspectRatio = (qreal) format.pixelAspectRatio().numerator / format.pixelAspectRatio().denominator; + qreal aspectRatioInv = (qreal) format.pixelAspectRatio().denominator / format.pixelAspectRatio().numerator; + + QRectF srcRect(QPointF(0,0), QSizeF(format.frameSize().width() * aspectRatio, + format.frameSize().height() * aspectRatioInv)); + QRectF destRect(QPointF(0,0), m_areas.targetArea.size()); + + m_areas.videoArea = centerRect(srcRect, destRect); + + if (m_areas.videoArea == m_areas.targetArea) { + m_areas.blackArea1 = m_areas.blackArea2 = QRectF(); + } else { + m_areas.blackArea1 = QRectF( + m_areas.targetArea.left(), + m_areas.targetArea.top(), + m_areas.videoArea.left() == m_areas.targetArea.left() ? + m_areas.targetArea.width() : m_areas.videoArea.left() - m_areas.targetArea.left(), + m_areas.videoArea.top() == m_areas.targetArea.top() ? + m_areas.targetArea.height() : m_areas.videoArea.top() - m_areas.targetArea.top() + ); + + m_areas.blackArea2 = QRectF( + m_areas.videoArea.right() == m_areas.targetArea.right() ? + m_areas.targetArea.left() : m_areas.videoArea.right() + 1, + m_areas.videoArea.bottom() == m_areas.targetArea.bottom() ? + m_areas.targetArea.top() : m_areas.videoArea.bottom() + 1, + m_areas.videoArea.right() == m_areas.targetArea.right() ? + m_areas.targetArea.width() : m_areas.targetArea.right() - m_areas.videoArea.right(), + m_areas.videoArea.bottom() == m_areas.targetArea.bottom() ? + m_areas.targetArea.height() : m_areas.targetArea.bottom() - m_areas.videoArea.bottom() + ); + } + } else { + m_areas.videoArea = m_areas.targetArea; + m_areas.blackArea1 = m_areas.blackArea2 = QRectF(); + } + + GST_LOG_OBJECT(m_sink, + "Recalculated paint areas: " + "Frame size: " QSIZE_FORMAT ", " + "target area: " QRECTF_FORMAT ", " + "video area: " QRECTF_FORMAT ", " + "black1: " QRECTF_FORMAT ", " + "black2: " QRECTF_FORMAT, + QSIZE_FORMAT_ARGS(format.frameSize()), + QRECTF_FORMAT_ARGS(m_areas.targetArea), + QRECTF_FORMAT_ARGS(m_areas.videoArea), + QRECTF_FORMAT_ARGS(m_areas.blackArea1), + QRECTF_FORMAT_ARGS(m_areas.blackArea2) + ); + } + forceAspectRatioLocker.unlock(); + + if (m_formatDirty /* || m_clipRectDirty */) { + //TODO add properties for modifying clipRect + m_clipRect = QRectF(QPointF(0,0), format.frameSize()); + } + + //if either pixelFormat or frameSize have changed, we need to reset the painter + //and/or change painter, in case the current one does not handle the requested format + if ((m_formatDirty && (format.videoFormat() != m_bufferFormat.videoFormat() + || format.colorMatrix() != m_bufferFormat.colorMatrix() + || format.frameSize() != m_bufferFormat.frameSize())) + || !m_painter) + { + changePainter(format); + + m_bufferFormat = format; + m_formatDirty = false; + + //make sure to update the colors after changing painter + m_colorsDirty = true; + } + + if (G_LIKELY(m_painter)) { + QReadLocker colorsLocker(&m_colorsLock); + if (m_colorsDirty) { + m_painter->updateColors(m_brightness, m_contrast, m_hue, m_saturation); + m_colorsDirty = false; + } + colorsLocker.unlock(); + + m_painter->paint(m_buffer->data, m_bufferFormat, m_clipRect, painter, m_areas); + } + } +} + +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL + +QGLContext *QtVideoSinkDelegate::glContext() const +{ + return m_glContext; +} + +void QtVideoSinkDelegate::setGLContext(QGLContext *context) +{ + GST_LOG_OBJECT(m_sink, "Setting GL context. context=%p m_glContext=%p m_painter=%p", + context, m_glContext, m_painter); + + if (m_glContext == context) + return; + + m_glContext = context; + + m_supportedShaderTypes = NoShaders; + + if (m_glContext) { + m_glContext->makeCurrent(); + + const QByteArray extensions(reinterpret_cast(glGetString(GL_EXTENSIONS))); + GST_LOG_OBJECT(m_sink, "Available GL extensions: %s", extensions.constData()); + +#ifndef QT_OPENGL_ES + if (extensions.contains("ARB_fragment_program")) + m_supportedShaderTypes |= FragmentProgramShader; +#endif + +#ifndef QT_OPENGL_ES_2 + if (QGLShaderProgram::hasOpenGLShaderPrograms(m_glContext) + && extensions.contains("ARB_shader_objects")) +#endif + m_supportedShaderTypes |= GlslShader; + + } + + GST_LOG_OBJECT(m_sink, "Done setting GL context. m_shaderTypes=%x", (int) m_supportedShaderTypes); +} + +#endif + +enum PainterType { Glsl, ArbFp, Generic }; + +void QtVideoSinkDelegate::changePainter(const BufferFormat & format) +{ + if (m_painter) { + m_painter->cleanup(); + if (!m_painter->supportsFormat(format.videoFormat())) { + delete m_painter; + m_painter = 0; + } + } + + QStack possiblePainters; + if (GenericSurfacePainter::supportedPixelFormats().contains(format.videoFormat())) { + possiblePainters.push(Generic); + } + +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL +# ifndef QT_OPENGL_ES + if (m_supportedShaderTypes & QtVideoSinkDelegate::FragmentProgramShader + && ArbFpSurfacePainter::supportedPixelFormats().contains(format.videoFormat())) { + possiblePainters.push(ArbFp); + } +# endif + + if (m_supportedShaderTypes & QtVideoSinkDelegate::GlslShader + && GlslSurfacePainter::supportedPixelFormats().contains(format.videoFormat())) { + possiblePainters.push(Glsl); + } +#endif + + while (!possiblePainters.isEmpty()) { + if (!m_painter) { + PainterType type = possiblePainters.pop(); + switch(type) { +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL + case Glsl: + GST_LOG_OBJECT(m_sink, "Creating GLSL painter"); + m_painter = new GlslSurfacePainter; + break; +# ifndef QT_OPENGL_ES + case ArbFp: + GST_LOG_OBJECT(m_sink, "Creating ARB Fragment Shader painter"); + m_painter = new ArbFpSurfacePainter; + break; +# endif +#endif + case Generic: + GST_LOG_OBJECT(m_sink, "Creating Generic painter"); + m_painter = new GenericSurfacePainter; + break; + default: + Q_ASSERT(false); + } + } + + try { + m_painter->init(format); + return; + } catch (const QString & error) { + GST_ELEMENT_WARNING(m_sink, RESOURCE, FAILED, + ("Failed to start painter"), ("%s", error.toUtf8().constData())); + delete m_painter; + m_painter = 0; + } + } + + GST_ELEMENT_ERROR(m_sink, RESOURCE, FAILED, + ("Failed to create a painter for the given format"), (NULL)); +} + +void QtVideoSinkDelegate::destroyPainter() +{ + GST_LOG_OBJECT(m_sink, "Destroying painter"); + + delete m_painter; + m_painter = 0; +} + +bool QtVideoSinkDelegate::event(QEvent *event) +{ + switch((int) event->type()) { + case BufferEventType: + { + BufferEvent *bufEvent = dynamic_cast(event); + Q_ASSERT(bufEvent); + + GST_TRACE_OBJECT(m_sink, "Received buffer %"GST_PTR_FORMAT, bufEvent->buffer); + + if (m_buffer) { + //free the previous buffer + gst_buffer_unref(m_buffer); + m_buffer = NULL; + } + + if (isActive()) { + //schedule this frame for rendering + m_buffer = bufEvent->buffer; + if (bufEvent->formatDirty) { + m_formatDirty = true; + } + GstQtVideoSinkBase::emit_update(m_sink); + } else { + //not active, drop the frame + gst_buffer_unref(bufEvent->buffer); + } + + return true; + } + case DeactivateEventType: + { + GST_LOG_OBJECT(m_sink, "Received deactivate event"); + + if (m_buffer) { + gst_buffer_unref(m_buffer); + m_buffer = NULL; + } + + if (m_painter) { + m_painter->cleanup(); + destroyPainter(); + } + + GstQtVideoSinkBase::emit_update(m_sink); + + return true; + } + default: + return QObject::event(event); + } +} diff --git a/elements/gstqtvideosink/qtvideosinkdelegate.h b/elements/gstqtvideosink/qtvideosinkdelegate.h new file mode 100644 index 0000000..9bb361a --- /dev/null +++ b/elements/gstqtvideosink/qtvideosinkdelegate.h @@ -0,0 +1,169 @@ +/* + Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + Copyright (C) 2011 Collabora Ltd. + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License version 2.1 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef QT_VIDEO_SINK_DELEGATE_H +#define QT_VIDEO_SINK_DELEGATE_H + +#include "gstqtvideosinkbase.h" +#include "bufferformat.h" +#include "abstractsurfacepainter.h" + +#include +#include +#include +#include + +class QGLContext; + + +class QtVideoSinkDelegate : public QObject +{ + Q_OBJECT +public: + enum EventType { + BufferEventType = QEvent::User, + DeactivateEventType + }; + + //------------------------------------- + + class BufferEvent : public QEvent + { + public: + inline BufferEvent(GstBuffer *buf, bool formatDirty) + : QEvent(static_cast(BufferEventType)), + buffer(gst_buffer_ref(buf)), + formatDirty(formatDirty) + { + } + + GstBuffer *buffer; + bool formatDirty; + }; + + //------------------------------------- + + class DeactivateEvent : public QEvent + { + public: + inline DeactivateEvent() + : QEvent(static_cast(DeactivateEventType)) + { + } + }; + + //------------------------------------- + + explicit QtVideoSinkDelegate(GstQtVideoSinkBase *sink, QObject *parent = 0); + ~QtVideoSinkDelegate(); + + // API for GstQtVideoSink + + QSet supportedPixelFormats() const; + + bool isActive() const; + void setActive(bool playing); + + // GstColorBalance interface + + int brightness() const; + void setBrightness(int brightness); + + int contrast() const; + void setContrast(int contrast); + + int hue() const; + void setHue(int hue); + + int saturation() const; + void setSaturation(int saturation); + + // force-aspect-ratio property + + bool forceAspectRatio() const; + void setForceAspectRatio(bool force); + + // glcontext property + +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL + QGLContext *glContext() const; + void setGLContext(QGLContext *context); + + enum ShaderType + { + NoShaders = 0x00, + FragmentProgramShader = 0x01, + GlslShader = 0x02 + }; + + Q_DECLARE_FLAGS(ShaderTypes, ShaderType) +#endif + + // paint action signal + + void paint(QPainter *painter, qreal x, qreal y, qreal width, qreal height); + +protected: + bool event(QEvent *event); + +private: + void changePainter(const BufferFormat & format); + void destroyPainter(); + + + AbstractSurfacePainter *m_painter; + +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL + QGLContext *m_glContext; + ShaderTypes m_supportedShaderTypes; + ShaderType m_shaderType; +#endif + + // colorbalance interface properties + mutable QReadWriteLock m_colorsLock; + bool m_colorsDirty; + int m_brightness; + int m_contrast; + int m_hue; + int m_saturation; + + // force-aspect-ratio property + mutable QReadWriteLock m_forceAspectRatioLock; + bool m_forceAspectRatioDirty; + bool m_forceAspectRatio; + + // format caching + bool m_formatDirty; + BufferFormat m_bufferFormat; + PaintAreas m_areas; + QRectF m_clipRect; + + // whether the sink is active (PAUSED or PLAYING) + mutable QReadWriteLock m_isActiveLock; + bool m_isActive; + + // the buffer to be drawn next + GstBuffer *m_buffer; + + GstQtVideoSinkBase *m_sink; +}; + +#ifndef GST_QT_VIDEO_SINK_NO_OPENGL +Q_DECLARE_OPERATORS_FOR_FLAGS(QtVideoSinkDelegate::ShaderTypes) +#endif + +#endif // QT_VIDEO_SINK_DELEGATE_H -- cgit v1.2.3