mirror of
https://github.com/wang-bin/QtAV.git
synced 2026-10-18 21:21:29 +08:00
203 lines
6.8 KiB
C++
203 lines
6.8 KiB
C++
/******************************************************************************
|
|
QtAV: Media play library based on Qt and FFmpeg
|
|
Copyright (C) 2014-2015 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 "QmlAV/SGVideoNode.h"
|
|
#include "QtAV/VideoShader.h"
|
|
#include "QtAV/VideoFrame.h"
|
|
#include <QtCore/QScopedPointer>
|
|
#include <QtGui/QOpenGLFunctions>
|
|
#include <QtQuick/QSGMaterialShader>
|
|
|
|
// all in QSGRenderThread
|
|
namespace QtAV {
|
|
|
|
class SGVideoMaterialShader : public QSGMaterialShader
|
|
{
|
|
public:
|
|
SGVideoMaterialShader(VideoShader* s) :
|
|
QSGMaterialShader()
|
|
, m_shader(s)
|
|
{}
|
|
virtual void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial);
|
|
virtual char const *const *attributeNames() const { return m_shader->attributeNames();}
|
|
protected:
|
|
virtual const char *vertexShader() const { return m_shader->vertexShader();}
|
|
virtual const char *fragmentShader() const { return m_shader->fragmentShader();}
|
|
virtual void initialize() { m_shader->initialize(program());}
|
|
|
|
int textureLocationCount() const { return m_shader->textureLocationCount();}
|
|
int textureLocation(int index) const { return m_shader->textureLocation(index);}
|
|
int matrixLocation() const { return m_shader->matrixLocation();}
|
|
int colorMatrixLocation() const { return m_shader->colorMatrixLocation();}
|
|
int opacityLocation() const { return m_shader->opacityLocation();}
|
|
private:
|
|
QScopedPointer<VideoShader> m_shader;
|
|
};
|
|
|
|
class SGVideoMaterial : public QSGMaterial
|
|
{
|
|
public:
|
|
SGVideoMaterial() : QSGMaterial(), m_opacity(1.0) {}
|
|
|
|
virtual QSGMaterialType *type() const {
|
|
return reinterpret_cast<QSGMaterialType*>((quintptr)m_material.type());
|
|
}
|
|
|
|
virtual QSGMaterialShader *createShader() const {
|
|
return new SGVideoMaterialShader(m_material.createShader());
|
|
}
|
|
|
|
virtual int compare(const QSGMaterial *other) const {
|
|
Q_ASSERT(other && type() == other->type());
|
|
const SGVideoMaterial *m = static_cast<const SGVideoMaterial*>(other);
|
|
return m_material.compare(&m->m_material);
|
|
}
|
|
/*
|
|
void updateBlending() {
|
|
setFlag(Blending, m_material.hasAlpha() || !qFuzzyCompare(m_opacity, qreal(1.0)));
|
|
}
|
|
*/
|
|
void setCurrentFrame(const VideoFrame &frame) {
|
|
m_material.setCurrentFrame(frame);
|
|
setFlag(Blending, m_material.hasAlpha());
|
|
}
|
|
|
|
VideoMaterial* videoMaterial() { return &m_material;}
|
|
qreal m_opacity;
|
|
VideoMaterial m_material;
|
|
};
|
|
|
|
void SGVideoMaterialShader::updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
|
|
{
|
|
Q_UNUSED(oldMaterial);
|
|
SGVideoMaterial *mat = static_cast<SGVideoMaterial *>(newMaterial);
|
|
if (!m_shader->update(&mat->m_material)) //material not ready. e.g. video item have not got a frame
|
|
return;
|
|
//mat->updateBlending();
|
|
if (state.isOpacityDirty()) {
|
|
mat->m_opacity = state.opacity();
|
|
program()->setUniformValue(opacityLocation(), GLfloat(mat->m_opacity));
|
|
}
|
|
if (state.isMatrixDirty())
|
|
program()->setUniformValue(matrixLocation(), state.combinedMatrix());
|
|
}
|
|
|
|
|
|
SGVideoNode::SGVideoNode()
|
|
: QSGGeometryNode()
|
|
, m_material(new SGVideoMaterial())
|
|
, m_validWidth(1.0)
|
|
{
|
|
setFlag(QSGNode::OwnsGeometry);
|
|
setFlag(QSGNode::OwnsMaterial);
|
|
setMaterial(m_material);
|
|
}
|
|
|
|
SGVideoNode::~SGVideoNode() {}
|
|
|
|
void SGVideoNode::setCurrentFrame(const VideoFrame &frame)
|
|
{
|
|
m_material->setCurrentFrame(frame);
|
|
markDirty(DirtyMaterial);
|
|
}
|
|
|
|
/* Helpers */
|
|
static inline void qSetGeom(QSGGeometry::TexturedPoint2D *v, const QPointF &p)
|
|
{
|
|
v->x = p.x();
|
|
v->y = p.y();
|
|
}
|
|
|
|
static inline void qSetTex(QSGGeometry::TexturedPoint2D *v, const QPointF &p)
|
|
{
|
|
v->tx = p.x();
|
|
v->ty = p.y();
|
|
}
|
|
|
|
void SGVideoNode::setTexturedRectGeometry(const QRectF &rect, const QRectF &textureRect, int orientation)
|
|
{
|
|
if (m_validWidth == m_material->videoMaterial()->validTextureWidth()
|
|
&& rect == m_rect && textureRect == m_textureRect && orientation == m_orientation)
|
|
return;
|
|
|
|
m_validWidth = m_material->videoMaterial()->validTextureWidth();
|
|
m_rect = rect;
|
|
m_textureRect = textureRect;
|
|
m_orientation = orientation;
|
|
QRectF validTexRect = m_material->videoMaterial()->normalizedROI(textureRect);
|
|
//qDebug() << ">>>>>>>valid: " << m_validWidth << " roi: " << validTexRect;
|
|
QSGGeometry *g = geometry();
|
|
|
|
if (g == 0)
|
|
g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
|
|
|
|
QSGGeometry::TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();
|
|
|
|
// Set geometry first
|
|
qSetGeom(v + 0, rect.topLeft());
|
|
qSetGeom(v + 1, rect.bottomLeft());
|
|
qSetGeom(v + 2, rect.topRight());
|
|
qSetGeom(v + 3, rect.bottomRight());
|
|
|
|
// and then texture coordinates
|
|
switch (orientation) {
|
|
default:
|
|
// tl, bl, tr, br
|
|
qSetTex(v + 0, validTexRect.topLeft());
|
|
qSetTex(v + 1, validTexRect.bottomLeft());
|
|
qSetTex(v + 2, validTexRect.topRight());
|
|
qSetTex(v + 3, validTexRect.bottomRight());
|
|
break;
|
|
|
|
case 90:
|
|
// tr, tl, br, bl
|
|
qSetTex(v + 0, validTexRect.topRight());
|
|
qSetTex(v + 1, validTexRect.topLeft());
|
|
qSetTex(v + 2, validTexRect.bottomRight());
|
|
qSetTex(v + 3, validTexRect.bottomLeft());
|
|
break;
|
|
|
|
case 180:
|
|
// br, tr, bl, tl
|
|
qSetTex(v + 0, validTexRect.bottomRight());
|
|
qSetTex(v + 1, validTexRect.topRight());
|
|
qSetTex(v + 2, validTexRect.bottomLeft());
|
|
qSetTex(v + 3, validTexRect.topLeft());
|
|
break;
|
|
|
|
case 270:
|
|
// bl, br, tl, tr
|
|
qSetTex(v + 0, validTexRect.bottomLeft());
|
|
qSetTex(v + 1, validTexRect.bottomRight());
|
|
qSetTex(v + 2, validTexRect.topLeft());
|
|
qSetTex(v + 3, validTexRect.topRight());
|
|
break;
|
|
}
|
|
|
|
if (!geometry())
|
|
setGeometry(g);
|
|
|
|
markDirty(DirtyGeometry);
|
|
}
|
|
|
|
} //namespace QtAV
|