summaryrefslogtreecommitdiffstats
path: root/tests/auto/integration/qdeclarativevideooutput
diff options
context:
space:
mode:
authorMichael Goddard <michael.goddard@nokia.com>2012-01-20 15:51:22 +1000
committerQt by Nokia <qt-info@nokia.com>2012-01-27 07:35:06 +0100
commitbad94a532996339da23906764521447803f24b16 (patch)
tree414f02bb075b3ab54b310e1027100639f6a9570d /tests/auto/integration/qdeclarativevideooutput
parent3b00730ecaeb4f780b897c3f0683c1d449e7c6c7 (diff)
Add a rendered and content rectangle properties to VideoOutput QML.
So you can align controls with an edge of the rendered area. There's also some convenience functions for mapping source to and from destination coordinates. Also tweaked the updateGeometry function to bail out if no input parameters have changed, rather than doing some more boring maths. Added a unit test for a lot of the class, too. Change-Id: I943bb45e4e56356247d5d6deb5d446222edcb7ca Reviewed-by: Dmytro Poplavskiy <dmytro.poplavskiy@nokia.com>
Diffstat (limited to 'tests/auto/integration/qdeclarativevideooutput')
-rw-r--r--tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro13
-rw-r--r--tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp692
2 files changed, 705 insertions, 0 deletions
diff --git a/tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro b/tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro
new file mode 100644
index 000000000..140eecb7d
--- /dev/null
+++ b/tests/auto/integration/qdeclarativevideooutput/qdeclarativevideooutput.pro
@@ -0,0 +1,13 @@
+CONFIG += testcase
+TARGET = tst_qdeclarativevideooutput
+
+QT += multimedia-private declarative testlib quick
+CONFIG += no_private_qt_headers_warning
+
+OTHER_FILES += \
+ ../../../../src/imports/multimedia/qdeclarativevideooutput_p.h
+
+SOURCES += \
+ tst_qdeclarativevideooutput.cpp
+
+INCLUDEPATH += ../../../../src/imports/multimedia
diff --git a/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp
new file mode 100644
index 000000000..029a64eee
--- /dev/null
+++ b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp
@@ -0,0 +1,692 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//TESTED_COMPONENT=plugins/declarative/multimedia
+
+#include <QtTest/QtTest>
+
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+
+#include "qdeclarativevideooutput_p.h"
+
+#include <qabstractvideosurface.h>
+#include <qvideorenderercontrol.h>
+
+#include <qmediaobject.h>
+
+class SurfaceHolder : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QAbstractVideoSurface *videoSurface READ videoSurface WRITE setVideoSurface)
+public:
+ SurfaceHolder(QObject *parent)
+ : QObject(parent)
+ , m_surface(0)
+ {
+ }
+
+ QAbstractVideoSurface *videoSurface() const
+ {
+ return m_surface;
+ }
+ void setVideoSurface(QAbstractVideoSurface *surface)
+ {
+ m_surface = surface;
+ }
+
+ void presentDummyFrame(const QSize &size);
+
+private:
+ QAbstractVideoSurface *m_surface;
+
+};
+
+// Starts the surface and puts a frame
+void SurfaceHolder::presentDummyFrame(const QSize &size)
+{
+ if (m_surface && m_surface->supportedPixelFormats().count() > 0) {
+ QVideoFrame::PixelFormat pixelFormat = m_surface->supportedPixelFormats().value(0);
+ QVideoSurfaceFormat format(size, pixelFormat);
+ QVideoFrame frame(size.width() * size.height() * 4, size, size.width() * 4, pixelFormat);
+
+ if (!m_surface->isActive())
+ m_surface->start(format);
+ m_surface->present(frame);
+
+ // Have to spin an event loop or two for the surfaceFormatChanged() signal
+ qApp->processEvents();
+ }
+}
+
+class tst_QDeclarativeVideoOutput : public QObject
+{
+ Q_OBJECT
+public:
+ tst_QDeclarativeVideoOutput()
+ : m_mappingComponent(0)
+ , m_mappingOutput(0)
+ , m_mappingSurface(0)
+ {
+ qRegisterMetaType<QDeclarativeVideoOutput::FillMode>();
+ }
+
+ ~tst_QDeclarativeVideoOutput()
+ {
+ delete m_mappingOutput;
+ delete m_mappingSurface;
+ delete m_mappingComponent;
+ }
+
+public slots:
+ void initTestCase();
+
+private slots:
+ void fillMode();
+ void orientation();
+ void surfaceSource();
+ void sourceRect();
+
+ void contentRect();
+ void contentRect_data();
+
+ void mappingPoint();
+ void mappingPoint_data();
+ void mappingRect();
+ void mappingRect_data();
+
+private:
+ QDeclarativeEngine m_engine;
+ QByteArray m_plainQML;
+
+ // Variables used for the mapping test
+ QDeclarativeComponent *m_mappingComponent;
+ QObject *m_mappingOutput;
+ SurfaceHolder *m_mappingSurface;
+
+ void updateOutputGeometry(QObject *output);
+
+ QRectF invokeR2R(QObject *object, const char *signature, const QRectF &rect);
+ QPointF invokeP2P(QObject *object, const char *signature, const QPointF &point);
+};
+
+void tst_QDeclarativeVideoOutput::initTestCase()
+{
+ m_plainQML = \
+ "import QtQuick 2.0\n" \
+ "import QtMultimedia 5.0\n" \
+ "VideoOutput {" \
+ " width: 150;" \
+ " height: 100;" \
+ "}";
+
+ // We initialize the mapping vars here
+ m_mappingComponent = new QDeclarativeComponent(&m_engine);
+ m_mappingComponent->setData(m_plainQML, QUrl());
+ m_mappingSurface = new SurfaceHolder(this);
+
+ m_mappingOutput = m_mappingComponent->create();
+ QVERIFY(m_mappingOutput != 0);
+
+ m_mappingOutput->setProperty("source", QVariant::fromValue(static_cast<QObject*>(m_mappingSurface)));
+
+ m_mappingSurface->presentDummyFrame(QSize(200,100)); // this should start m_surface
+ updateOutputGeometry(m_mappingOutput);
+}
+
+Q_DECLARE_METATYPE(QDeclarativeVideoOutput::FillMode)
+
+void tst_QDeclarativeVideoOutput::fillMode()
+{
+ QDeclarativeComponent component(&m_engine);
+ component.setData(m_plainQML, QUrl());
+
+ QObject *videoOutput = component.create();
+ QVERIFY(videoOutput != 0);
+
+ QSignalSpy propSpy(videoOutput, SIGNAL(fillModeChanged(QDeclarativeVideoOutput::FillMode)));
+
+ // Default is preserveaspectfit
+ QCOMPARE(videoOutput->property("fillMode").value<QDeclarativeVideoOutput::FillMode>(), QDeclarativeVideoOutput::PreserveAspectFit);
+ QCOMPARE(propSpy.count(), 0);
+
+ videoOutput->setProperty("fillMode", QVariant(int(QDeclarativeVideoOutput::PreserveAspectCrop)));
+ QCOMPARE(videoOutput->property("fillMode").value<QDeclarativeVideoOutput::FillMode>(), QDeclarativeVideoOutput::PreserveAspectCrop);
+ QCOMPARE(propSpy.count(), 1);
+
+ videoOutput->setProperty("fillMode", QVariant(int(QDeclarativeVideoOutput::Stretch)));
+ QCOMPARE(videoOutput->property("fillMode").value<QDeclarativeVideoOutput::FillMode>(), QDeclarativeVideoOutput::Stretch);
+ QCOMPARE(propSpy.count(), 2);
+
+ videoOutput->setProperty("fillMode", QVariant(int(QDeclarativeVideoOutput::Stretch)));
+ QCOMPARE(videoOutput->property("fillMode").value<QDeclarativeVideoOutput::FillMode>(), QDeclarativeVideoOutput::Stretch);
+ QCOMPARE(propSpy.count(), 2);
+
+ delete videoOutput;
+}
+
+void tst_QDeclarativeVideoOutput::orientation()
+{
+ QDeclarativeComponent component(&m_engine);
+ component.setData(m_plainQML, QUrl());
+
+ QObject *videoOutput = component.create();
+ QVERIFY(videoOutput != 0);
+
+ QSignalSpy propSpy(videoOutput, SIGNAL(orientationChanged()));
+
+ // Default orientation is 0
+ QCOMPARE(videoOutput->property("orientation").toInt(), 0);
+ QCOMPARE(propSpy.count(), 0);
+
+ videoOutput->setProperty("orientation", QVariant(90));
+ QCOMPARE(videoOutput->property("orientation").toInt(), 90);
+ QCOMPARE(propSpy.count(), 1);
+
+ videoOutput->setProperty("orientation", QVariant(180));
+ QCOMPARE(videoOutput->property("orientation").toInt(), 180);
+ QCOMPARE(propSpy.count(), 2);
+
+ videoOutput->setProperty("orientation", QVariant(270));
+ QCOMPARE(videoOutput->property("orientation").toInt(), 270);
+ QCOMPARE(propSpy.count(), 3);
+
+ videoOutput->setProperty("orientation", QVariant(360));
+ QCOMPARE(videoOutput->property("orientation").toInt(), 360);
+ QCOMPARE(propSpy.count(), 4);
+
+ // More than 360 should be fine
+ videoOutput->setProperty("orientation", QVariant(540));
+ QCOMPARE(videoOutput->property("orientation").toInt(), 540);
+ QCOMPARE(propSpy.count(), 5);
+
+ // Negative should be fine
+ videoOutput->setProperty("orientation", QVariant(-180));
+ QCOMPARE(videoOutput->property("orientation").toInt(), -180);
+ QCOMPARE(propSpy.count(), 6);
+
+ // Same value should not reemit
+ videoOutput->setProperty("orientation", QVariant(-180));
+ QCOMPARE(videoOutput->property("orientation").toInt(), -180);
+ QCOMPARE(propSpy.count(), 6);
+
+ // Non multiples of 90 should not work
+ videoOutput->setProperty("orientation", QVariant(-1));
+ QCOMPARE(videoOutput->property("orientation").toInt(), -180);
+ QCOMPARE(propSpy.count(), 6);
+
+ delete videoOutput;
+}
+
+void tst_QDeclarativeVideoOutput::surfaceSource()
+{
+ QDeclarativeComponent component(&m_engine);
+ component.setData(m_plainQML, QUrl());
+
+ QObject *videoOutput = component.create();
+ QVERIFY(videoOutput != 0);
+
+ SurfaceHolder holder(this);
+
+ QCOMPARE(holder.videoSurface(), static_cast<QAbstractVideoSurface*>(0));
+
+ videoOutput->setProperty("source", QVariant::fromValue(static_cast<QObject*>(&holder)));
+
+ QVERIFY(holder.videoSurface() != 0);
+
+ // Now we could do things with the surface..
+ QList<QVideoFrame::PixelFormat> formats = holder.videoSurface()->supportedPixelFormats();
+ QVERIFY(formats.count() > 0);
+
+ // See if we can start and stop each pixel format (..)
+ foreach (QVideoFrame::PixelFormat format, formats) {
+ QVideoSurfaceFormat surfaceFormat(QSize(200,100), format);
+ QVERIFY(holder.videoSurface()->isFormatSupported(surfaceFormat)); // This does kind of depend on node factories
+
+ QVERIFY(holder.videoSurface()->start(surfaceFormat));
+ QVERIFY(holder.videoSurface()->surfaceFormat() == surfaceFormat);
+ QVERIFY(holder.videoSurface()->isActive());
+
+ holder.videoSurface()->stop();
+
+ QVERIFY(!holder.videoSurface()->isActive());
+ }
+
+ delete videoOutput;
+
+ // This should clear the surface
+ QEXPECT_FAIL("", "Surface not cleared on destruction", Continue);
+ QCOMPARE(holder.videoSurface(), static_cast<QAbstractVideoSurface*>(0));
+
+ // Also, creating two sources, setting them in order, and destroying the first
+ // should not zero holder.videoSurface()
+ videoOutput = component.create();
+ videoOutput->setProperty("source", QVariant::fromValue(static_cast<QObject*>(&holder)));
+
+ QAbstractVideoSurface *surface = holder.videoSurface();
+ QVERIFY(holder.videoSurface());
+
+ QObject *videoOutput2 = component.create();
+ QVERIFY(videoOutput2);
+ videoOutput2->setProperty("source", QVariant::fromValue(static_cast<QObject*>(&holder)));
+ QVERIFY(holder.videoSurface());
+ QVERIFY(holder.videoSurface() != surface); // Surface should have changed
+ surface = holder.videoSurface();
+
+ // Now delete first one
+ delete videoOutput;
+ QVERIFY(holder.videoSurface());
+ QVERIFY(holder.videoSurface() == surface); // Should not have changed surface
+
+ // Now create a second surface and assign it as the source
+ // The old surface holder should be zeroed
+ SurfaceHolder holder2(this);
+ videoOutput2->setProperty("source", QVariant::fromValue(static_cast<QObject*>(&holder2)));
+
+ QCOMPARE(holder.videoSurface(), static_cast<QAbstractVideoSurface*>(0));
+ QVERIFY(holder2.videoSurface() != 0);
+
+ // XXX May be worth adding tests that the surface activeChanged signals are sent appropriately
+ // to holder?
+
+ delete videoOutput2;
+}
+
+void tst_QDeclarativeVideoOutput::sourceRect()
+{
+ QDeclarativeComponent component(&m_engine);
+ component.setData(m_plainQML, QUrl());
+
+ QObject *videoOutput = component.create();
+ QVERIFY(videoOutput != 0);
+
+ SurfaceHolder holder(this);
+
+ QSignalSpy propSpy(videoOutput, SIGNAL(sourceRectChanged()));
+
+ videoOutput->setProperty("source", QVariant::fromValue(static_cast<QObject*>(&holder)));
+
+ QRectF invalid(0,0,-1,-1);
+
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), invalid);
+
+ holder.presentDummyFrame(QSize(200,100));
+
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+ QCOMPARE(propSpy.count(), 1);
+
+ // Another frame shouldn't cause a source rect change
+ holder.presentDummyFrame(QSize(200,100));
+ QCOMPARE(propSpy.count(), 1);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ // Changing orientation and stretch modes should not affect this
+ videoOutput->setProperty("orientation", QVariant(90));
+ updateOutputGeometry(videoOutput);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ videoOutput->setProperty("orientation", QVariant(180));
+ updateOutputGeometry(videoOutput);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ videoOutput->setProperty("orientation", QVariant(270));
+ updateOutputGeometry(videoOutput);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ videoOutput->setProperty("orientation", QVariant(-90));
+ updateOutputGeometry(videoOutput);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ videoOutput->setProperty("fillMode", QVariant(int(QDeclarativeVideoOutput::PreserveAspectCrop)));
+ updateOutputGeometry(videoOutput);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ videoOutput->setProperty("fillMode", QVariant(int(QDeclarativeVideoOutput::Stretch)));
+ updateOutputGeometry(videoOutput);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ videoOutput->setProperty("fillMode", QVariant(int(QDeclarativeVideoOutput::Stretch)));
+ updateOutputGeometry(videoOutput);
+ QCOMPARE(videoOutput->property("sourceRect").toRectF(), QRectF(0, 0, 200, 100));
+
+ delete videoOutput;
+}
+
+void tst_QDeclarativeVideoOutput::mappingPoint()
+{
+ QFETCH(QPointF, point);
+ QFETCH(int, orientation);
+ QFETCH(QDeclarativeVideoOutput::FillMode, fillMode);
+ QFETCH(QPointF, expected);
+
+ QVERIFY(m_mappingOutput);
+ m_mappingOutput->setProperty("orientation", QVariant(orientation));
+ m_mappingOutput->setProperty("fillMode", QVariant::fromValue(fillMode));
+
+ updateOutputGeometry(m_mappingOutput);
+
+ QPointF output = invokeP2P(m_mappingOutput, "mapPointToItem", point);
+ QPointF reverse = invokeP2P(m_mappingOutput, "mapPointToSource", output);
+
+ QCOMPARE(output, expected);
+ QCOMPARE(reverse, point);
+
+ // Now the normalized versions
+ // Source rectangle is 200x100
+ QPointF normal(point.x() / 200, point.y() / 100);
+
+ output = invokeP2P(m_mappingOutput, "mapNormalizedPointToItem", normal);
+ reverse = invokeP2P(m_mappingOutput, "mapPointToSourceNormalized", output);
+
+ QCOMPARE(output, expected);
+ QCOMPARE(reverse, normal);
+}
+
+void tst_QDeclarativeVideoOutput::mappingPoint_data()
+{
+ QTest::addColumn<QPointF>("point");
+ QTest::addColumn<int>("orientation");
+ QTest::addColumn<QDeclarativeVideoOutput::FillMode>("fillMode");
+ QTest::addColumn<QPointF>("expected");
+
+ QDeclarativeVideoOutput::FillMode stretch = QDeclarativeVideoOutput::Stretch;
+ QDeclarativeVideoOutput::FillMode fit = QDeclarativeVideoOutput::PreserveAspectFit;
+ QDeclarativeVideoOutput::FillMode crop = QDeclarativeVideoOutput::PreserveAspectCrop;
+
+ // First make sure the component has processed the frame
+ QCOMPARE(m_mappingOutput->property("sourceRect").toRectF(), QRectF(0,0,200,100));
+
+ // 200x100 -> 150,100 stretch, 150x75 fit @ 12.5f, 200x100 @-25,0 crop
+
+ // Corners, then the center, then a point in the middle somewhere
+ QTest::newRow("s0-0") << QPointF(0,0) << 0 << stretch << QPointF(0,0);
+ QTest::newRow("s1-0") << QPointF(200,0) << 0 << stretch << QPointF(150,0);
+ QTest::newRow("s2-0") << QPointF(0,100) << 0 << stretch << QPointF(0,100);
+ QTest::newRow("s3-0") << QPointF(200,100) << 0 << stretch << QPointF(150,100);
+ QTest::newRow("s4-0") << QPointF(100,50) << 0 << stretch << QPointF(75,50);
+ QTest::newRow("s5-0") << QPointF(40,80) << 0 << stretch << QPointF(30,80);
+
+ QTest::newRow("f0-0") << QPointF(0,0) << 0 << fit << QPointF(0,12.5f);
+ QTest::newRow("f1-0") << QPointF(200,0) << 0 << fit << QPointF(150,12.5f);
+ QTest::newRow("f2-0") << QPointF(0,100) << 0 << fit << QPointF(0,87.5f);
+ QTest::newRow("f3-0") << QPointF(200,100) << 0 << fit << QPointF(150,87.5f);
+ QTest::newRow("f4-0") << QPointF(100,50) << 0 << stretch << QPointF(75,50);
+ QTest::newRow("f5-0") << QPointF(40,80) << 0 << stretch << QPointF(30,80);
+
+ QTest::newRow("c0-0") << QPointF(0,0) << 0 << crop << QPointF(-25,0);
+ QTest::newRow("c1-0") << QPointF(200,0) << 0 << crop << QPointF(175,0);
+ QTest::newRow("c2-0") << QPointF(0,100) << 0 << crop << QPointF(-25,100);
+ QTest::newRow("c3-0") << QPointF(200,100) << 0 << crop << QPointF(175,100);
+ QTest::newRow("c4-0") << QPointF(100,50) << 0 << stretch << QPointF(75,50);
+ QTest::newRow("c5-0") << QPointF(40,80) << 0 << stretch << QPointF(30,80);
+
+ // 90 degrees (anti clockwise)
+ QTest::newRow("s0-90") << QPointF(0,0) << 90 << stretch << QPointF(0,100);
+ QTest::newRow("s1-90") << QPointF(200,0) << 90 << stretch << QPointF(0,0);
+ QTest::newRow("s2-90") << QPointF(0,100) << 90 << stretch << QPointF(150,100);
+ QTest::newRow("s3-90") << QPointF(200,100) << 90 << stretch << QPointF(150,0);
+ QTest::newRow("s4-90") << QPointF(100,50) << 90 << stretch << QPointF(75,50);
+ QTest::newRow("s5-90") << QPointF(40,80) << 90 << stretch << QPointF(120,80);
+
+ QTest::newRow("f0-90") << QPointF(0,0) << 90 << fit << QPointF(50,100);
+ QTest::newRow("f1-90") << QPointF(200,0) << 90 << fit << QPointF(50,0);
+ QTest::newRow("f2-90") << QPointF(0,100) << 90 << fit << QPointF(100,100);
+ QTest::newRow("f3-90") << QPointF(200,100) << 90 << fit << QPointF(100,0);
+ QTest::newRow("f4-90") << QPointF(100,50) << 90 << fit << QPointF(75,50);
+ QTest::newRow("f5-90") << QPointF(40,80) << 90 << fit << QPointF(90,80);
+
+ QTest::newRow("c0-90") << QPointF(0,0) << 90 << crop << QPointF(0,200);
+ QTest::newRow("c1-90") << QPointF(200,0) << 90 << crop << QPointF(0,-100);
+ QTest::newRow("c2-90") << QPointF(0,100) << 90 << crop << QPointF(150,200);
+ QTest::newRow("c3-90") << QPointF(200,100) << 90 << crop << QPointF(150,-100);
+ QTest::newRow("c4-90") << QPointF(100,50) << 90 << crop << QPointF(75,50);
+ QTest::newRow("c5-90") << QPointF(40,80) << 90 << crop << QPointF(120,140);
+
+ // 180
+ QTest::newRow("s0-180") << QPointF(0,0) << 180 << stretch << QPointF(150,100);
+ QTest::newRow("s1-180") << QPointF(200,0) << 180 << stretch << QPointF(0,100);
+ QTest::newRow("s2-180") << QPointF(0,100) << 180 << stretch << QPointF(150,0);
+ QTest::newRow("s3-180") << QPointF(200,100) << 180 << stretch << QPointF(0,0);
+ QTest::newRow("s4-180") << QPointF(100,50) << 180 << stretch << QPointF(75,50);
+ QTest::newRow("s5-180") << QPointF(40,80) << 180 << stretch << QPointF(120,20);
+
+ QTest::newRow("f0-180") << QPointF(0,0) << 180 << fit << QPointF(150,87.5f);
+ QTest::newRow("f1-180") << QPointF(200,0) << 180 << fit << QPointF(0,87.5f);
+ QTest::newRow("f2-180") << QPointF(0,100) << 180 << fit << QPointF(150,12.5f);
+ QTest::newRow("f3-180") << QPointF(200,100) << 180 << fit << QPointF(0,12.5f);
+ QTest::newRow("f4-180") << QPointF(100,50) << 180 << fit << QPointF(75,50);
+ QTest::newRow("f5-180") << QPointF(40,80) << 180 << fit << QPointF(120,27.5f);
+
+ QTest::newRow("c0-180") << QPointF(0,0) << 180 << crop << QPointF(175,100);
+ QTest::newRow("c1-180") << QPointF(200,0) << 180 << crop << QPointF(-25,100);
+ QTest::newRow("c2-180") << QPointF(0,100) << 180 << crop << QPointF(175,0);
+ QTest::newRow("c3-180") << QPointF(200,100) << 180 << crop << QPointF(-25,0);
+ QTest::newRow("c4-180") << QPointF(100,50) << 180 << crop << QPointF(75,50);
+ QTest::newRow("c5-180") << QPointF(40,80) << 180 << crop << QPointF(135,20);
+
+ // 270
+ QTest::newRow("s0-270") << QPointF(0,0) << 270 << stretch << QPointF(150,0);
+ QTest::newRow("s1-270") << QPointF(200,0) << 270 << stretch << QPointF(150,100);
+ QTest::newRow("s2-270") << QPointF(0,100) << 270 << stretch << QPointF(0,0);
+ QTest::newRow("s3-270") << QPointF(200,100) << 270 << stretch << QPointF(0,100);
+ QTest::newRow("s4-270") << QPointF(100,50) << 270 << stretch << QPointF(75,50);
+ QTest::newRow("s5-270") << QPointF(40,80) << 270 << stretch << QPointF(30,20);
+
+ QTest::newRow("f0-270") << QPointF(0,0) << 270 << fit << QPointF(100,0);
+ QTest::newRow("f1-270") << QPointF(200,0) << 270 << fit << QPointF(100,100);
+ QTest::newRow("f2-270") << QPointF(0,100) << 270 << fit << QPointF(50,0);
+ QTest::newRow("f3-270") << QPointF(200,100) << 270 << fit << QPointF(50,100);
+ QTest::newRow("f4-270") << QPointF(100,50) << 270 << fit << QPointF(75,50);
+ QTest::newRow("f5-270") << QPointF(40,80) << 270 << fit << QPointF(60,20);
+
+ QTest::newRow("c0-270") << QPointF(0,0) << 270 << crop << QPointF(150,-100);
+ QTest::newRow("c1-270") << QPointF(200,0) << 270 << crop << QPointF(150,200);
+ QTest::newRow("c2-270") << QPointF(0,100) << 270 << crop << QPointF(0,-100);
+ QTest::newRow("c3-270") << QPointF(200,100) << 270 << crop << QPointF(0,200);
+ QTest::newRow("c4-270") << QPointF(100,50) << 270 << crop << QPointF(75,50);
+ QTest::newRow("c5-270") << QPointF(40,80) << 270 << crop << QPointF(30,-40);
+}
+
+/* Test all rectangle mapping */
+void tst_QDeclarativeVideoOutput::mappingRect()
+{
+ QFETCH(QRectF, rect);
+ QFETCH(int, orientation);
+ QFETCH(QDeclarativeVideoOutput::FillMode, fillMode);
+ QFETCH(QRectF, expected);
+
+ QVERIFY(m_mappingOutput);
+ m_mappingOutput->setProperty("orientation", QVariant(orientation));
+ m_mappingOutput->setProperty("fillMode", QVariant::fromValue(fillMode));
+
+ updateOutputGeometry(m_mappingOutput);
+
+ QRectF output = invokeR2R(m_mappingOutput, "mapRectToItem", rect);
+ QRectF reverse = invokeR2R(m_mappingOutput, "mapRectToSource", output);
+
+ QCOMPARE(output, expected);
+ QCOMPARE(reverse, rect);
+
+ // Now the normalized versions
+ // Source rectangle is 200x100
+ QRectF normal(rect.x() / 200, rect.y() / 100, rect.width() / 200, rect.height() / 100);
+
+ output = invokeR2R(m_mappingOutput, "mapNormalizedRectToItem", normal);
+ reverse = invokeR2R(m_mappingOutput, "mapRectToSourceNormalized", output);
+
+ QCOMPARE(output, expected);
+ QCOMPARE(reverse, normal);
+}
+
+void tst_QDeclarativeVideoOutput::mappingRect_data()
+{
+ QTest::addColumn<QRectF>("rect");
+ QTest::addColumn<int>("orientation");
+ QTest::addColumn<QDeclarativeVideoOutput::FillMode>("fillMode");
+ QTest::addColumn<QRectF>("expected");
+
+ // First make sure the component has processed the frame
+ QCOMPARE(m_mappingOutput->property("sourceRect").toRectF(), QRectF(0,0,200,100));
+
+ QDeclarativeVideoOutput::FillMode stretch = QDeclarativeVideoOutput::Stretch;
+ QDeclarativeVideoOutput::FillMode fit = QDeclarativeVideoOutput::PreserveAspectFit;
+ QDeclarativeVideoOutput::FillMode crop = QDeclarativeVideoOutput::PreserveAspectCrop;
+
+ // Full rectangle mapping
+ // Stretch
+ QTest::newRow("s0") << QRectF(0,0, 200, 100) << 0 << stretch << QRectF(0,0,150,100);
+ QTest::newRow("s90") << QRectF(0,0, 200, 100) << 90 << stretch << QRectF(0,0,150,100);
+ QTest::newRow("s180") << QRectF(0,0, 200, 100) << 180 << stretch << QRectF(0,0,150,100);
+ QTest::newRow("s270") << QRectF(0,0, 200, 100) << 270 << stretch << QRectF(0,0,150,100);
+
+ // Fit
+ QTest::newRow("f0") << QRectF(0,0, 200, 100) << 0 << fit << QRectF(0,12.5f,150,75);
+ QTest::newRow("f90") << QRectF(0,0, 200, 100) << 90 << fit << QRectF(50,0,50,100);
+ QTest::newRow("f180") << QRectF(0,0, 200, 100) << 180 << fit << QRectF(0,12.5f,150,75);
+ QTest::newRow("f270") << QRectF(0,0, 200, 100) << 270 << fit << QRectF(50,0,50,100);
+
+ // Crop
+ QTest::newRow("c0") << QRectF(0,0, 200, 100) << 0 << crop << QRectF(-25,0,200,100);
+ QTest::newRow("c90") << QRectF(0,0, 200, 100) << 90 << crop << QRectF(0,-100,150,300);
+ QTest::newRow("c180") << QRectF(0,0, 200, 100) << 180 << crop << QRectF(-25,0,200,100);
+ QTest::newRow("c270") << QRectF(0,0, 200, 100) << 270 << crop << QRectF(0,-100,150,300);
+
+ // Partial rectangle mapping
+ // Stretch
+ // 50-130 in x (0.25 - 0.65), 25-50 (0.25 - 0.5) in y (out of 200, 100) -> 150x100
+ QTest::newRow("p-s0") << QRectF(50, 25, 80, 25) << 0 << stretch << QRectF(37.5f,25,60,25);
+ QTest::newRow("p-s90") << QRectF(50, 25, 80, 25) << 90 << stretch << QRectF(37.5f,35,37.5f,40);
+ QTest::newRow("p-s180") << QRectF(50, 25, 80, 25) << 180 << stretch << QRectF(52.5f,50,60,25);
+ QTest::newRow("p-s270") << QRectF(50, 25, 80, 25) << 270 << stretch << QRectF(75,25,37.5f,40);
+
+ // Fit
+ QTest::newRow("p-f0") << QRectF(50, 25, 80, 25) << 0 << fit << QRectF(37.5f,31.25f,60,18.75f);
+ QTest::newRow("p-f90") << QRectF(50, 25, 80, 25) << 90 << fit << QRectF(62.5f,35,12.5f,40);
+ QTest::newRow("p-f180") << QRectF(50, 25, 80, 25) << 180 << fit << QRectF(52.5f,50,60,18.75f);
+ QTest::newRow("p-f270") << QRectF(50, 25, 80, 25) << 270 << fit << QRectF(75,25,12.5f,40);
+
+ // Crop
+ QTest::newRow("p-c0") << QRectF(50, 25, 80, 25) << 0 << crop << QRectF(25,25,80,25);
+ QTest::newRow("p-c90") << QRectF(50, 25, 80, 25) << 90 << crop << QRectF(37.5f,5,37.5f,120);
+ QTest::newRow("p-c180") << QRectF(50, 25, 80, 25) << 180 << crop << QRectF(45,50,80,25);
+ QTest::newRow("p-c270") << QRectF(50, 25, 80, 25) << 270 << crop << QRectF(75,-25,37.5f,120);
+}
+
+void tst_QDeclarativeVideoOutput::updateOutputGeometry(QObject *output)
+{
+ // Since the object isn't visible, update() doesn't do anything
+ // so we manually force this
+ QMetaObject::invokeMethod(output, "_q_updateGeometry");
+}
+
+void tst_QDeclarativeVideoOutput::contentRect()
+{
+ QFETCH(int, orientation);
+ QFETCH(QDeclarativeVideoOutput::FillMode, fillMode);
+ QFETCH(QRectF, expected);
+
+ QVERIFY(m_mappingOutput);
+ m_mappingOutput->setProperty("orientation", QVariant(orientation));
+ m_mappingOutput->setProperty("fillMode", QVariant::fromValue(fillMode));
+
+ updateOutputGeometry(m_mappingOutput);
+
+ QRectF output = m_mappingOutput->property("contentRect").toRectF();
+ QCOMPARE(output, expected);
+}
+
+void tst_QDeclarativeVideoOutput::contentRect_data()
+{
+ QTest::addColumn<int>("orientation");
+ QTest::addColumn<QDeclarativeVideoOutput::FillMode>("fillMode");
+ QTest::addColumn<QRectF>("expected");
+
+ // First make sure the component has processed the frame
+ QCOMPARE(m_mappingOutput->property("sourceRect").toRectF(), QRectF(0,0,200,100));
+
+ QDeclarativeVideoOutput::FillMode stretch = QDeclarativeVideoOutput::Stretch;
+ QDeclarativeVideoOutput::FillMode fit = QDeclarativeVideoOutput::PreserveAspectFit;
+ QDeclarativeVideoOutput::FillMode crop = QDeclarativeVideoOutput::PreserveAspectCrop;
+
+ // Stretch just keeps the full render rect regardless of orientation
+ QTest::newRow("s0") << 0 << stretch << QRectF(0,0,150,100);
+ QTest::newRow("s90") << 90 << stretch << QRectF(0,0,150,100);
+ QTest::newRow("s180") << 180 << stretch << QRectF(0,0,150,100);
+ QTest::newRow("s270") << 270 << stretch << QRectF(0,0,150,100);
+
+ // Fit depends on orientation
+ // Source is 200x100, fitting in 150x100 -> 150x75
+ // or 100x200 -> 50x100
+ QTest::newRow("f0") << 0 << fit << QRectF(0,12.5f,150,75);
+ QTest::newRow("f90") << 90 << fit << QRectF(50,0,50,100);
+ QTest::newRow("f180") << 180 << fit << QRectF(0,12.5,150,75);
+ QTest::newRow("f270") << 270 << fit << QRectF(50,0,50,100);
+
+ // Crop also depends on orientation, may go outside render rect
+ // 200x100 -> -25,0 200x100
+ // 100x200 -> 0,-100 150x300
+ QTest::newRow("c0") << 0 << crop << QRectF(-25,0,200,100);
+ QTest::newRow("c90") << 90 << crop << QRectF(0,-100,150,300);
+ QTest::newRow("c180") << 180 << crop << QRectF(-25,0,200,100);
+ QTest::newRow("c270") << 270 << crop << QRectF(0,-100,150,300);
+}
+
+
+QRectF tst_QDeclarativeVideoOutput::invokeR2R(QObject *object, const char *signature, const QRectF &rect)
+{
+ QRectF r;
+ const QMetaObject *meta = object->metaObject();
+ meta->invokeMethod(object, signature, Q_RETURN_ARG(QRectF, r), Q_ARG(QRectF, rect));
+ return r;
+}
+
+QPointF tst_QDeclarativeVideoOutput::invokeP2P(QObject *object, const char *signature, const QPointF &point)
+{
+ QPointF p;
+ const QMetaObject *meta = object->metaObject();
+ meta->invokeMethod(object, signature, Q_RETURN_ARG(QPointF, p), Q_ARG(QPointF, point));
+ return p;
+}
+
+
+QTEST_MAIN(tst_QDeclarativeVideoOutput)
+
+#include "tst_qdeclarativevideooutput.moc"