Add orientation support to VideoOutput.
authorMichael Goddard <michael.goddard@nokia.com>
Fri, 25 Nov 2011 05:25:22 +0000 (15:25 +1000)
committerQt by Nokia <qt-info@nokia.com>
Fri, 25 Nov 2011 07:30:55 +0000 (08:30 +0100)
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>
src/imports/multimedia/qdeclarativevideooutput.cpp
src/imports/multimedia/qdeclarativevideooutput_p.h
src/imports/multimedia/qsgvideonode.cpp
src/imports/multimedia/qsgvideonode_p.h

index 0d65becf371e2c3aa3c207ef98a33019661cb7ae..b7667fddc226206e04d775de9e2ef5ce054ed41f 100644 (file)
@@ -163,7 +163,8 @@ private:
 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);
@@ -290,6 +291,14 @@ void QDeclarativeVideoOutput::stop()
     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
 
@@ -322,7 +331,11 @@ void QDeclarativeVideoOutput::setFillMode(FillMode mode)
 
 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;
 
@@ -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 *)
 {
     QSGVideoNode *videoNode = static_cast<QSGVideoNode *>(oldNode);
@@ -396,7 +446,8 @@ QSGNode *QDeclarativeVideoOutput::updatePaintNode(QSGNode *oldNode, UpdatePaintN
         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;
 }
index 2c63fc9e467a50ff9869569a70a90d4fbc044bb8..6b990f72f433b553ff8f8de3e196a6b7764c2374 100644 (file)
@@ -65,6 +65,7 @@ class QDeclarativeVideoOutput : public QQuickItem
     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:
@@ -84,9 +85,13 @@ 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 *);
@@ -122,6 +127,7 @@ private:
     QSize m_nativeSize;
     QRectF m_boundingRect;
     QRectF m_sourceRect;
+    int m_orientation;
 
     QMutex m_frameMutex;
 };
index 712caff6533ab8c1c143f28c2d88d8e8eb21e21d..14d55c118bff80d42b23d8c7a37314c98fd15c15 100644 (file)
 #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);
 }
index 466b4566c35fce8369a385de86d3f49ae98a9ac1..45087dd0d23e6f17ecb1b74d7a6d4abe9f131fe3 100644 (file)
@@ -56,11 +56,12 @@ public:
     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 {