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>
QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) :
QQuickItem(parent),
m_sourceType(NoSource),
- m_fillMode(PreserveAspectFit)
+ m_fillMode(PreserveAspectFit),
+ m_orientation(0)
{
setFlag(ItemHasContents, true);
m_surface = new QSGVideoItemSurface(this);
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
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) {
m_nativeSize = size;
}
}
+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 *)
{
QSGVideoNode *videoNode = static_cast<QSGVideoNode *>(oldNode);
return 0;
_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);
return videoNode;
}
Q_DISABLE_COPY(QDeclarativeVideoOutput)
Q_PROPERTY(QObject* source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
+ Q_PROPERTY(int orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
Q_ENUMS(FillMode)
public:
FillMode fillMode() const;
void setFillMode(FillMode mode);
+ int orientation() const;
+ void setOrientation(int);
+
Q_SIGNALS:
void sourceChanged();
void fillModeChanged(QDeclarativeVideoOutput::FillMode);
+ void orientationChanged();
protected:
QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *);
QSize m_nativeSize;
QRectF m_boundingRect;
QRectF m_sourceRect;
+ int m_orientation;
QMutex m_frameMutex;
};
#include "qsgvideonode_p.h"
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;
m_rect = rect;
m_textureRect = textureRect;
+ m_orientation = orientation;
QSGGeometry *g = geometry();
- if (g == 0) {
+ if (g == 0)
g = new QSGGeometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4);
- QSGGeometry::updateTexturedRectGeometry(g, rect, textureRect);
- setGeometry(g);
- } else {
- QSGGeometry::updateTexturedRectGeometry(g, rect, textureRect);
+
+ 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, 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);
}
virtual void setCurrentFrame(const QVideoFrame &frame) = 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:
QRectF m_rect;
QRectF m_textureRect;
+ int m_orientation;
};
class QSGVideoNodeFactory {