mirror of
https://github.com/wang-bin/QtAV.git
synced 2026-10-18 21:21:29 +08:00
346 lines
8.9 KiB
C++
346 lines
8.9 KiB
C++
/******************************************************************************
|
|
QtAV: Multimedia framework based on Qt and FFmpeg
|
|
Copyright (C) 2012-2017 Wang Bin <wbsecg1@gmail.com>
|
|
|
|
* This file is part of QtAV
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library 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
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
******************************************************************************/
|
|
|
|
#include "QtAVWidgets/GraphicsItemRenderer.h"
|
|
#include "QtAV/private/QPainterRenderer_p.h"
|
|
#include "QtAV/FilterContext.h"
|
|
#if !defined QT_NO_OPENGL && (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) || defined(QT_OPENGL_LIB))
|
|
#define QTAV_HAVE_OPENGL 1
|
|
#else
|
|
#define QTAV_HAVE_OPENGL 0
|
|
#endif
|
|
#if QTAV_HAVE(OPENGL)
|
|
#include "QtAV/OpenGLVideo.h"
|
|
#else
|
|
typedef float GLfloat;
|
|
#endif
|
|
#include <QMatrix4x4>
|
|
#include <QGraphicsScene>
|
|
#include <QtGui/QPainter>
|
|
#include <QEvent>
|
|
#include <QKeyEvent>
|
|
#include <QGraphicsSceneEvent>
|
|
#include <QtCore/QCoreApplication>
|
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
|
#include <QtGui/QSurface>
|
|
#endif
|
|
|
|
namespace QtAV {
|
|
|
|
class GraphicsItemRendererPrivate : public QPainterRendererPrivate
|
|
{
|
|
public:
|
|
GraphicsItemRendererPrivate()
|
|
: frame_changed(false)
|
|
, opengl(false)
|
|
{}
|
|
virtual ~GraphicsItemRendererPrivate(){}
|
|
void setupAspectRatio() {
|
|
matrix.setToIdentity();
|
|
matrix.scale((GLfloat)out_rect.width()/(GLfloat)renderer_width, (GLfloat)out_rect.height()/(GLfloat)renderer_height, 1);
|
|
if (rotation())
|
|
matrix.rotate(rotation(), 0, 0, 1); // Z axis
|
|
}
|
|
// return true if opengl is enabled and context is ready. may called by non-rendering thread
|
|
bool checkGL() {
|
|
#if QTAV_HAVE(OPENGL)
|
|
if (!opengl) {
|
|
glv.setOpenGLContext(0); // it's for Qt4. may not in rendering thread
|
|
return false;
|
|
}
|
|
if (!glv.openGLContext()) {
|
|
//qWarning("no opengl context! set current");
|
|
// null if not called from renderering thread;
|
|
QOpenGLContext *ctx = const_cast<QOpenGLContext*>(QOpenGLContext::currentContext());
|
|
if (!ctx)
|
|
return false;
|
|
glv.setOpenGLContext(ctx);
|
|
}
|
|
return true;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool frame_changed;
|
|
bool opengl;
|
|
#if QTAV_HAVE(OPENGL)
|
|
OpenGLVideo glv;
|
|
#endif
|
|
QMatrix4x4 matrix;
|
|
};
|
|
|
|
VideoRendererId GraphicsItemRenderer::id() const
|
|
{
|
|
return VideoRendererId_GraphicsItem;
|
|
}
|
|
|
|
GraphicsItemRenderer::GraphicsItemRenderer(QGraphicsItem * parent)
|
|
:GraphicsWidget(parent),QPainterRenderer(*new GraphicsItemRendererPrivate())
|
|
{
|
|
setFlag(ItemIsFocusable); //receive key events
|
|
//setAcceptHoverEvents(true);
|
|
#if CONFIG_GRAPHICSWIDGET
|
|
setFocusPolicy(Qt::ClickFocus); //for widget
|
|
#endif //CONFIG_GRAPHICSWIDGET
|
|
}
|
|
|
|
GraphicsItemRenderer::GraphicsItemRenderer(GraphicsItemRendererPrivate &d, QGraphicsItem *parent)
|
|
:GraphicsWidget(parent),QPainterRenderer(d)
|
|
{
|
|
setFlag(ItemIsFocusable); //receive key events
|
|
//setAcceptHoverEvents(true);
|
|
#if CONFIG_GRAPHICSWIDGET
|
|
setFocusPolicy(Qt::ClickFocus); //for widget
|
|
#endif //CONFIG_GRAPHICSWIDGET
|
|
}
|
|
|
|
bool GraphicsItemRenderer::isSupported(VideoFormat::PixelFormat pixfmt) const
|
|
{
|
|
if (isOpenGL())
|
|
return true;
|
|
return QPainterRenderer::isSupported(pixfmt);
|
|
}
|
|
|
|
bool GraphicsItemRenderer::receiveFrame(const VideoFrame& frame)
|
|
{
|
|
#if QTAV_HAVE(OPENGL)
|
|
DPTR_D(GraphicsItemRenderer);
|
|
if (isOpenGL()) {
|
|
d.video_frame = frame;
|
|
d.frame_changed = true;
|
|
} else
|
|
#endif
|
|
{
|
|
preparePixmap(frame);
|
|
}
|
|
// moved to event
|
|
// scene()->update(sceneBoundingRect()); //TODO: thread?
|
|
QCoreApplication::postEvent(this, new QEvent(QEvent::User));
|
|
//update(); //does not cause an immediate paint. my not redraw.
|
|
return true;
|
|
}
|
|
|
|
QRectF GraphicsItemRenderer::boundingRect() const
|
|
{
|
|
return QRectF(0, 0, rendererWidth(), rendererHeight());
|
|
}
|
|
|
|
bool GraphicsItemRenderer::isOpenGL() const
|
|
{
|
|
#if QTAV_HAVE(OPENGL)
|
|
return d_func().opengl;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
void GraphicsItemRenderer::setOpenGL(bool o)
|
|
{
|
|
DPTR_D(GraphicsItemRenderer);
|
|
if (d.opengl == o)
|
|
return;
|
|
d.opengl = o;
|
|
Q_EMIT openGLChanged();
|
|
}
|
|
|
|
OpenGLVideo* GraphicsItemRenderer::opengl() const
|
|
{
|
|
#if QTAV_HAVE(OPENGL)
|
|
return const_cast<OpenGLVideo*>(&d_func().glv);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
void GraphicsItemRenderer::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
|
{
|
|
Q_UNUSED(option);
|
|
Q_UNUSED(widget);
|
|
DPTR_D(GraphicsItemRenderer);
|
|
d.painter = painter;
|
|
QPainterFilterContext *ctx = static_cast<QPainterFilterContext*>(d.filter_context);
|
|
if (ctx) {
|
|
ctx->painter = d.painter;
|
|
} else {
|
|
qWarning("FilterContext not available!");
|
|
}
|
|
// save painter state, switch to native opengl painting
|
|
painter->save();
|
|
painter->beginNativePainting();
|
|
|
|
handlePaintEvent();
|
|
|
|
// end native painting, restore state
|
|
painter->endNativePainting();
|
|
painter->restore();
|
|
|
|
d.painter = 0; //painter may be not available outside this function
|
|
if (ctx)
|
|
ctx->painter = 0;
|
|
}
|
|
|
|
void GraphicsItemRenderer::drawBackground()
|
|
{
|
|
DPTR_D(GraphicsItemRenderer);
|
|
#if QTAV_HAVE(OPENGL)
|
|
if (d.checkGL()) {
|
|
// d.glv.fill(QColor(0, 0, 0)); //FIXME: fill boundingRect
|
|
return;
|
|
} else
|
|
#endif
|
|
{
|
|
QPainterRenderer::drawBackground();
|
|
}
|
|
}
|
|
|
|
void GraphicsItemRenderer::drawFrame()
|
|
{
|
|
DPTR_D(GraphicsItemRenderer);
|
|
if (!d.painter)
|
|
return;
|
|
#if QTAV_HAVE(OPENGL)
|
|
if (d.checkGL()) {
|
|
if (d.frame_changed) {
|
|
d.glv.setCurrentFrame(d.video_frame);
|
|
d.frame_changed = false;
|
|
}
|
|
d.glv.render(boundingRect(), realROI(), d.matrix*sceneTransform());
|
|
return;
|
|
}
|
|
#endif
|
|
QPainterRenderer::drawFrame();
|
|
}
|
|
|
|
|
|
void GraphicsItemRenderer::onSetOutAspectRatio(qreal ratio)
|
|
{
|
|
Q_UNUSED(ratio);
|
|
DPTR_D(GraphicsItemRenderer);
|
|
d.setupAspectRatio();
|
|
}
|
|
|
|
bool GraphicsItemRenderer::onSetOrientation(int value)
|
|
{
|
|
Q_UNUSED(value);
|
|
d_func().setupAspectRatio();
|
|
update(); //TODO: thread?
|
|
return true;
|
|
}
|
|
|
|
void GraphicsItemRenderer::onSetOutAspectRatioMode(OutAspectRatioMode mode)
|
|
{
|
|
Q_UNUSED(mode);
|
|
DPTR_D(GraphicsItemRenderer);
|
|
d.setupAspectRatio();
|
|
}
|
|
|
|
bool GraphicsItemRenderer::onSetBrightness(qreal b)
|
|
{
|
|
if (!isOpenGL())
|
|
return false;
|
|
Q_UNUSED(b);
|
|
#if QTAV_HAVE(OPENGL)
|
|
d_func().glv.setBrightness(b);
|
|
update();
|
|
return true;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool GraphicsItemRenderer::onSetContrast(qreal c)
|
|
{
|
|
if (!isOpenGL())
|
|
return false;
|
|
Q_UNUSED(c);
|
|
#if QTAV_HAVE(OPENGL)
|
|
d_func().glv.setContrast(c);
|
|
update();
|
|
return true;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool GraphicsItemRenderer::onSetHue(qreal h)
|
|
{
|
|
if (!isOpenGL())
|
|
return false;
|
|
Q_UNUSED(h);
|
|
#if QTAV_HAVE(OPENGL)
|
|
d_func().glv.setHue(h);
|
|
update();
|
|
return true;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
bool GraphicsItemRenderer::onSetSaturation(qreal s)
|
|
{
|
|
if (!isOpenGL())
|
|
return false;
|
|
Q_UNUSED(s);
|
|
#if QTAV_HAVE(OPENGL)
|
|
d_func().glv.setSaturation(s);
|
|
update();
|
|
return true;
|
|
#endif
|
|
return false;
|
|
}
|
|
//GraphicsWidget will lose focus forever if focus out. Why?
|
|
|
|
#if CONFIG_GRAPHICSWIDGET
|
|
bool GraphicsItemRenderer::event(QEvent *event)
|
|
{
|
|
if (event->type() == QEvent::User) {
|
|
scene()->update(sceneBoundingRect());
|
|
}
|
|
else {
|
|
setFocus(); //WHY: Force focus
|
|
QEvent::Type type = event->type();
|
|
qDebug("GraphicsItemRenderer event type = %d", type);
|
|
if (type == QEvent::KeyPress) {
|
|
qDebug("KeyPress Event. key=%d", static_cast<QKeyEvent*>(event)->key());
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
#else
|
|
bool GraphicsItemRenderer::event(QEvent *event)
|
|
{
|
|
if (event->type() != QEvent::User)
|
|
return GraphicsWidget::event(event);
|
|
scene()->update(sceneBoundingRect());
|
|
return true;
|
|
}
|
|
/*simply passes event to QGraphicsWidget::event(). you should not have to
|
|
*reimplement sceneEvent() in a subclass of QGraphicsWidget.
|
|
*/
|
|
/*
|
|
bool GraphicsItemRenderer::sceneEvent(QEvent *event)
|
|
{
|
|
QEvent::Type type = event->type();
|
|
qDebug("sceneEvent type = %d", type);
|
|
if (type == QEvent::KeyPress) {
|
|
qDebug("KeyPress Event. key=%d", static_cast<QKeyEvent*>(event)->key());
|
|
}
|
|
return true;
|
|
}
|
|
*/
|
|
#endif //!CONFIG_GRAPHICSWIDGET
|
|
} //namespace QtAV
|