Add orientation support to VideoOutput.

Just uses an integer to represent the degrees rotation from standard.
Only supports multiples of 90 - other rotation can be done with
standard QML.

Change-Id: Id4013169c5d9da473b6e5be94ba341da21c2f2a3
Reviewed-by: Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com>
This commit is contained in:
Michael Goddard
2011-11-25 15:25:22 +10:00
committed by Qt by Nokia
parent 581564c990
commit be7cc17cbf
4 changed files with 126 additions and 11 deletions

View File

@@ -163,7 +163,8 @@ private:
QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) : QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) :
QQuickItem(parent), QQuickItem(parent),
m_sourceType(NoSource), m_sourceType(NoSource),
m_fillMode(PreserveAspectFit) m_fillMode(PreserveAspectFit),
m_orientation(0)
{ {
setFlag(ItemHasContents, true); setFlag(ItemHasContents, true);
m_surface = new QSGVideoItemSurface(this); m_surface = new QSGVideoItemSurface(this);
@@ -290,6 +291,14 @@ void QDeclarativeVideoOutput::stop()
present(QVideoFrame()); present(QVideoFrame());
} }
/*
* Helper - returns true if the given orientation has the same aspect as the default (e.g. 180*n)
*/
static inline bool qIsDefaultAspect(int o)
{
return (o % 180) == 0;
}
/*! /*!
\qmlproperty enumeration VideoOutput::fillMode \qmlproperty enumeration VideoOutput::fillMode
@@ -322,7 +331,11 @@ void QDeclarativeVideoOutput::setFillMode(FillMode mode)
void QDeclarativeVideoOutput::_q_updateNativeSize(const QVideoSurfaceFormat &format) void QDeclarativeVideoOutput::_q_updateNativeSize(const QVideoSurfaceFormat &format)
{ {
const QSize &size = format.sizeHint(); QSize size = format.sizeHint();
if (!qIsDefaultAspect(m_orientation)) {
size.transpose();
}
if (m_nativeSize != size) { if (m_nativeSize != size) {
m_nativeSize = size; m_nativeSize = size;
@@ -363,6 +376,43 @@ void QDeclarativeVideoOutput::_q_updateGeometry()
} }
} }
int QDeclarativeVideoOutput::orientation() const
{
return m_orientation;
}
void QDeclarativeVideoOutput::setOrientation(int orientation)
{
// Make sure it's a multiple of 90.
if (orientation % 90)
return;
// If the new orientation is the same effect
// as the old one, don't update the video node stuff
if ((m_orientation % 360) == (orientation % 360)) {
m_orientation = orientation;
emit orientationChanged();
return;
}
// Otherwise, a new orientation
// See if we need to change aspect ratio orientation too
bool oldAspect = qIsDefaultAspect(m_orientation);
bool newAspect = qIsDefaultAspect(orientation);
m_orientation = orientation;
if (oldAspect != newAspect) {
m_nativeSize.transpose();
setImplicitWidth(m_nativeSize.width());
setImplicitHeight(m_nativeSize.height());
}
update();
emit orientationChanged();
}
QSGNode *QDeclarativeVideoOutput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) QSGNode *QDeclarativeVideoOutput::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *)
{ {
QSGVideoNode *videoNode = static_cast<QSGVideoNode *>(oldNode); QSGVideoNode *videoNode = static_cast<QSGVideoNode *>(oldNode);
@@ -396,7 +446,8 @@ QSGNode *QDeclarativeVideoOutput::updatePaintNode(QSGNode *oldNode, UpdatePaintN
return 0; return 0;
_q_updateGeometry(); _q_updateGeometry();
videoNode->setTexturedRectGeometry(m_boundingRect, m_sourceRect); // Negative rotations need lots of %360
videoNode->setTexturedRectGeometry(m_boundingRect, m_sourceRect, (360 + (m_orientation % 360)) % 360);
videoNode->setCurrentFrame(m_frame); videoNode->setCurrentFrame(m_frame);
return videoNode; return videoNode;
} }

View File

@@ -65,6 +65,7 @@ class QDeclarativeVideoOutput : public QQuickItem
Q_DISABLE_COPY(QDeclarativeVideoOutput) Q_DISABLE_COPY(QDeclarativeVideoOutput)
Q_PROPERTY(QObject* source READ source WRITE setSource NOTIFY sourceChanged) Q_PROPERTY(QObject* source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
Q_PROPERTY(int orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
Q_ENUMS(FillMode) Q_ENUMS(FillMode)
public: public:
@@ -84,9 +85,13 @@ public:
FillMode fillMode() const; FillMode fillMode() const;
void setFillMode(FillMode mode); void setFillMode(FillMode mode);
int orientation() const;
void setOrientation(int);
Q_SIGNALS: Q_SIGNALS:
void sourceChanged(); void sourceChanged();
void fillModeChanged(QDeclarativeVideoOutput::FillMode); void fillModeChanged(QDeclarativeVideoOutput::FillMode);
void orientationChanged();
protected: protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *); QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
@@ -122,6 +127,7 @@ private:
QSize m_nativeSize; QSize m_nativeSize;
QRectF m_boundingRect; QRectF m_boundingRect;
QRectF m_sourceRect; QRectF m_sourceRect;
int m_orientation;
QMutex m_frameMutex; QMutex m_frameMutex;
}; };

View File

@@ -42,26 +42,83 @@
#include "qsgvideonode_p.h" #include "qsgvideonode_p.h"
QSGVideoNode::QSGVideoNode() QSGVideoNode::QSGVideoNode()
: m_orientation(-1)
{ {
} }
void QSGVideoNode::setTexturedRectGeometry(const QRectF &rect, const QRectF &textureRect) /* Helpers */
static inline void qSetGeom(QSGGeometry::TexturedPoint2D *v, const QPointF &p)
{ {
if (rect == m_rect && textureRect == m_textureRect) 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();
}
/* Update the vertices and texture coordinates. Orientation must be in {0,90,180,270} */
void QSGVideoNode::setTexturedRectGeometry(const QRectF &rect, const QRectF &textureRect, int orientation)
{
if (rect == m_rect && textureRect == m_textureRect && orientation == m_orientation)
return; return;
m_rect = rect; m_rect = rect;
m_textureRect = textureRect; m_textureRect = textureRect;
m_orientation = orientation;
QSGGeometry *g = geometry(); QSGGeometry *g = geometry();
if (g == 0) { if (g == 0)
g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4); g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
QSGGeometry::updateTexturedRectGeometry(g, rect, textureRect);
setGeometry(g); QSGGeometry::TexturedPoint2D *v = g->vertexDataAsTexturedPoint2D();
} else {
QSGGeometry::updateTexturedRectGeometry(g, rect, textureRect); // 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, textureRect.topLeft());
qSetTex(v + 1, textureRect.bottomLeft());
qSetTex(v + 2, textureRect.topRight());
qSetTex(v + 3, textureRect.bottomRight());
break;
case 90:
// tr, tl, br, bl
qSetTex(v + 0, textureRect.topRight());
qSetTex(v + 1, textureRect.topLeft());
qSetTex(v + 2, textureRect.bottomRight());
qSetTex(v + 3, textureRect.bottomLeft());
break;
case 180:
// br, tr, bl, tl
qSetTex(v + 0, textureRect.bottomRight());
qSetTex(v + 1, textureRect.topRight());
qSetTex(v + 2, textureRect.bottomLeft());
qSetTex(v + 3, textureRect.topLeft());
break;
case 270:
// bl, br, tl, tr
qSetTex(v + 0, textureRect.bottomLeft());
qSetTex(v + 1, textureRect.bottomRight());
qSetTex(v + 2, textureRect.topLeft());
qSetTex(v + 3, textureRect.topRight());
break;
} }
if (!geometry())
setGeometry(g);
markDirty(DirtyGeometry); markDirty(DirtyGeometry);
} }

View File

@@ -56,11 +56,12 @@ public:
virtual void setCurrentFrame(const QVideoFrame &frame) = 0; virtual void setCurrentFrame(const QVideoFrame &frame) = 0;
virtual QVideoFrame::PixelFormat pixelFormat() const = 0; virtual QVideoFrame::PixelFormat pixelFormat() const = 0;
void setTexturedRectGeometry(const QRectF &boundingRect, const QRectF &textureRect); void setTexturedRectGeometry(const QRectF &boundingRect, const QRectF &textureRect, int orientation);
private: private:
QRectF m_rect; QRectF m_rect;
QRectF m_textureRect; QRectF m_textureRect;
int m_orientation;
}; };
class QSGVideoNodeFactory { class QSGVideoNodeFactory {