diff --git a/src/imports/multimedia/qdeclarativevideooutput.cpp b/src/imports/multimedia/qdeclarativevideooutput.cpp index 1b4b9cd5bab1f5981d5355ab9da1a5f2dd3cae58..653d45b6d28a9e9969e8450b017c49e7c8e24072 100644 --- a/src/imports/multimedia/qdeclarativevideooutput.cpp +++ b/src/imports/multimedia/qdeclarativevideooutput.cpp @@ -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); } /*! diff --git a/src/imports/multimedia/qdeclarativevideooutput_backend_p.h b/src/imports/multimedia/qdeclarativevideooutput_backend_p.h index 7f2284bb41e76a0381b5556623e83fbdede6f47e..f731b77f1fcd98b6fde9e8c1eb10fb58d906b750 100644 --- a/src/imports/multimedia/qdeclarativevideooutput_backend_p.h +++ b/src/imports/multimedia/qdeclarativevideooutput_backend_p.h @@ -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; diff --git a/src/imports/multimedia/qdeclarativevideooutput_render.cpp b/src/imports/multimedia/qdeclarativevideooutput_render.cpp index e9bcf4b26da90496ba49df5333e08fb853f849b4..96b979bc5680d0a8cad9d5fd70ca7afe8bdc90be 100644 --- a/src/imports/multimedia/qdeclarativevideooutput_render.cpp +++ b/src/imports/multimedia/qdeclarativevideooutput_render.cpp @@ -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; diff --git a/src/imports/multimedia/qdeclarativevideooutput_render_p.h b/src/imports/multimedia/qdeclarativevideooutput_render_p.h index 2a706b3396a3265c8ab62bc2fae95890faa348ff..3682c15a6b9ec70ad6da21818d91f76c2862b493 100644 --- a/src/imports/multimedia/qdeclarativevideooutput_render_p.h +++ b/src/imports/multimedia/qdeclarativevideooutput_render_p.h @@ -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; diff --git a/src/imports/multimedia/qdeclarativevideooutput_window.cpp b/src/imports/multimedia/qdeclarativevideooutput_window.cpp index 527c08908a12866e6253d2c49ab8485b5ff23c97..2da63c1075f838f20ad38f33c76765d2bbbb24c3 100644 --- a/src/imports/multimedia/qdeclarativevideooutput_window.cpp +++ b/src/imports/multimedia/qdeclarativevideooutput_window.cpp @@ -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 diff --git a/src/imports/multimedia/qdeclarativevideooutput_window_p.h b/src/imports/multimedia/qdeclarativevideooutput_window_p.h index f09b08c4210825b4862869959e876b98448f827e..eb7b35b859d9d098b1d2cc426d32d17cb654880f 100644 --- a/src/imports/multimedia/qdeclarativevideooutput_window_p.h +++ b/src/imports/multimedia/qdeclarativevideooutput_window_p.h @@ -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;