VideoOutput: Take the surface's viewport into account
authorThomas McGuire <thomas.mcguire.qnx@kdab.com>
Thu, 25 Apr 2013 14:06:08 +0000 (16:06 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Tue, 7 May 2013 13:02:15 +0000 (15:02 +0200)
Task-Number: QTBUG-30410

Change-Id: I480ce0bcd7ec136e54b5bfc5fec0e901141b72d8
Reviewed-by: Josh Faust <jfaust@suitabletech.com>
Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
src/imports/multimedia/qdeclarativevideooutput.cpp
src/imports/multimedia/qdeclarativevideooutput_backend_p.h
src/imports/multimedia/qdeclarativevideooutput_render.cpp
src/imports/multimedia/qdeclarativevideooutput_render_p.h
src/imports/multimedia/qdeclarativevideooutput_window.cpp
src/imports/multimedia/qdeclarativevideooutput_window_p.h

index 1b4b9cd..653d45b 100644 (file)
@@ -436,13 +436,18 @@ QRectF QDeclarativeVideoOutput::contentRect() const
 
     This property holds the area of the source video
     content that is considered for rendering.  The
-    values are in source pixel coordinates.
+    values are in source pixel coordinates, adjusted for
+    the source's pixel aspect ratio.
 
     Note that typically the top left corner of this rectangle
     will be \c {0,0} while the width and height will be the
-    width and height of the input content.
+    width and height of the input content. Only when the video
+    source has a viewport set, these values will differ.
 
     The orientation setting does not affect this rectangle.
+
+    \sa QVideoSurfaceFormat::pixelAspectRatio()
+    \sa QVideoSurfaceFormat::viewport()
 */
 QRectF QDeclarativeVideoOutput::sourceRect() const
 {
@@ -451,7 +456,19 @@ QRectF QDeclarativeVideoOutput::sourceRect() const
     if (!qIsDefaultAspect(m_orientation)) {
         size.transpose();
     }
-    return QRectF(QPointF(), size); // XXX ignores viewport
+
+    // No backend? Just assume no viewport.
+    if (!m_nativeSize.isValid() || !m_backend) {
+        return QRectF(QPointF(), size);
+    }
+
+    // Take the viewport into account for the top left position.
+    // m_nativeSize is already adjusted to the viewport, as it originats
+    // from QVideoSurfaceFormat::sizeHint(), which includes pixel aspect
+    // ratio and viewport.
+    const QRectF viewport = m_backend->adjustedViewport();
+    Q_ASSERT(viewport.size() == size);
+    return QRectF(viewport.topLeft(), size);
 }
 
 /*!
index 7f2284b..f731b77 100644 (file)
@@ -74,6 +74,9 @@ public:
     virtual QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data) = 0;
     virtual QAbstractVideoSurface *videoSurface() const = 0;
 
+    // The viewport, adjusted for the pixel aspect ratio
+    virtual QRectF adjustedViewport() const = 0;
+
 protected:
     QDeclarativeVideoOutput *q;
     QPointer<QMediaService> m_service;
index e9bcf4b..96b979b 100644 (file)
@@ -133,30 +133,45 @@ QSize QDeclarativeVideoRendererBackend::nativeSize() const
 
 void QDeclarativeVideoRendererBackend::updateGeometry()
 {
+    const QRectF viewport = videoSurface()->surfaceFormat().viewport();
+    const QSizeF frameSize = videoSurface()->surfaceFormat().frameSize();
+    const QRectF normalizedViewport(viewport.x() / frameSize.width(),
+                                    viewport.y() / frameSize.height(),
+                                    viewport.width() / frameSize.width(),
+                                    viewport.height() / frameSize.height());
     const QRectF rect(0, 0, q->width(), q->height());
     if (nativeSize().isEmpty()) {
         m_renderedRect = rect;
-        m_sourceTextureRect = QRectF(0, 0, 1, 1);
+        m_sourceTextureRect = normalizedViewport;
     } else if (q->fillMode() == QDeclarativeVideoOutput::Stretch) {
         m_renderedRect = rect;
-        m_sourceTextureRect = QRectF(0, 0, 1, 1);
+        m_sourceTextureRect = normalizedViewport;
     } else if (q->fillMode() == QDeclarativeVideoOutput::PreserveAspectFit) {
-        m_sourceTextureRect = QRectF(0, 0, 1, 1);
+        m_sourceTextureRect = normalizedViewport;
         m_renderedRect = q->contentRect();
     } else if (q->fillMode() == QDeclarativeVideoOutput::PreserveAspectCrop) {
         m_renderedRect = rect;
         const qreal contentHeight = q->contentRect().height();
         const qreal contentWidth = q->contentRect().width();
+
+        // Calculate the size of the source rectangle without taking the viewport into account
+        const qreal relativeOffsetLeft = -q->contentRect().left() / contentWidth;
+        const qreal relativeOffsetTop = -q->contentRect().top() / contentHeight;
+        const qreal relativeWidth = rect.width() / contentWidth;
+        const qreal relativeHeight = rect.height() / contentHeight;
+
+        // Now take the viewport size into account
+        const qreal totalOffsetLeft = normalizedViewport.x() + relativeOffsetLeft * normalizedViewport.width();
+        const qreal totalOffsetTop = normalizedViewport.y() + relativeOffsetTop * normalizedViewport.height();
+        const qreal totalWidth = normalizedViewport.width() * relativeWidth;
+        const qreal totalHeight = normalizedViewport.height() * relativeHeight;
+
         if (qIsDefaultAspect(q->orientation())) {
-            m_sourceTextureRect = QRectF(-q->contentRect().left() / contentWidth,
-                                         -q->contentRect().top() / contentHeight,
-                                         rect.width() / contentWidth,
-                                         rect.height() / contentHeight);
+            m_sourceTextureRect = QRectF(totalOffsetLeft, totalOffsetTop,
+                                         totalWidth, totalHeight);
         } else {
-            m_sourceTextureRect = QRectF(-q->contentRect().top() / contentHeight,
-                                         -q->contentRect().left() / contentWidth,
-                                         rect.height() / contentHeight,
-                                         rect.width() / contentWidth);
+            m_sourceTextureRect = QRectF(totalOffsetTop, totalOffsetLeft,
+                                         totalHeight, totalWidth);
         }
     }
 }
@@ -223,6 +238,22 @@ QAbstractVideoSurface *QDeclarativeVideoRendererBackend::videoSurface() const
     return m_surface;
 }
 
+QRectF QDeclarativeVideoRendererBackend::adjustedViewport() const
+{
+    const QRectF viewport = m_surface->surfaceFormat().viewport();
+    const QSize pixelAspectRatio = m_surface->surfaceFormat().pixelAspectRatio();
+
+    if (pixelAspectRatio.height() != 0) {
+        const qreal ratio = pixelAspectRatio.width() / pixelAspectRatio.height();
+        QRectF result = viewport;
+        result.setX(result.x() * ratio);
+        result.setWidth(result.width() * ratio);
+        return result;
+    }
+
+    return viewport;
+}
+
 QOpenGLContext *QDeclarativeVideoRendererBackend::glContext() const
 {
     return m_glContext;
index 2a706b3..3682c15 100644 (file)
@@ -71,6 +71,7 @@ public:
     void updateGeometry();
     QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data);
     QAbstractVideoSurface *videoSurface() const;
+    QRectF adjustedViewport() const Q_DECL_OVERRIDE;
     QOpenGLContext *glContext() const;
 
     friend class QSGVideoItemSurface;
index 527c089..2da63c1 100644 (file)
@@ -143,4 +143,11 @@ QAbstractVideoSurface *QDeclarativeVideoWindowBackend::videoSurface() const
     return 0;
 }
 
+QRectF QDeclarativeVideoWindowBackend::adjustedViewport() const
+{
+    // No viewport supported by QVideoWindowControl, so make the viewport the same size
+    // as the source
+    return QRectF(QPointF(0, 0), nativeSize());
+}
+
 QT_END_NAMESPACE
index f09b08c..eb7b35b 100644 (file)
@@ -62,6 +62,7 @@ public:
     void updateGeometry();
     QSGNode *updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *data);
     QAbstractVideoSurface *videoSurface() const;
+    QRectF adjustedViewport() const Q_DECL_OVERRIDE;
 
 private:
     QPointer<QVideoWindowControl> m_videoWindowControl;