From 1d9aab3c80603d24df5cc692e958834b50e4f8fb Mon Sep 17 00:00:00 2001 From: Artem Dyomin Date: Tue, 2 Jan 2024 15:14:32 +0100 Subject: Add unit tests for basic video buffers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch adds unit tests for QImageVideoBuffer and QMemoryVideoBuffer. As those behave the same in most cases, the added test suite contains parametric test cases for both. Pick-to: 6.5 Change-Id: I51cbbf9bcc5f3ad06cfee7777c439791579bcf34 Reviewed-by: Jøger Hansegård Reviewed-by: Lars Knoll (cherry picked from commit 716c094fb40641b23bc0c006f639e68019551fd8) Reviewed-by: Qt Cherry-pick Bot (cherry picked from commit 6b6ea0d42704db8f5fd5910dbe0e5959ec0c09e4) --- tests/auto/unit/multimedia/CMakeLists.txt | 1 + .../unit/multimedia/qvideobuffers/CMakeLists.txt | 10 + .../multimedia/qvideobuffers/tst_qvideobuffers.cpp | 223 +++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt create mode 100644 tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp diff --git a/tests/auto/unit/multimedia/CMakeLists.txt b/tests/auto/unit/multimedia/CMakeLists.txt index 467934920..c8fa299ab 100644 --- a/tests/auto/unit/multimedia/CMakeLists.txt +++ b/tests/auto/unit/multimedia/CMakeLists.txt @@ -27,3 +27,4 @@ add_subdirectory(qscreencapture) add_subdirectory(qvideotexturehelper) add_subdirectory(qmediadevices) add_subdirectory(qerrorinfo) +add_subdirectory(qvideobuffers) diff --git a/tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt b/tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt new file mode 100644 index 000000000..765d02c96 --- /dev/null +++ b/tests/auto/unit/multimedia/qvideobuffers/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_test(tst_qvideobuffers + SOURCES + tst_qvideobuffers.cpp + LIBRARIES + Qt::Multimedia + Qt::MultimediaPrivate +) diff --git a/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp b/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp new file mode 100644 index 000000000..cbbfea91e --- /dev/null +++ b/tests/auto/unit/multimedia/qvideobuffers/tst_qvideobuffers.cpp @@ -0,0 +1,223 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include + +#include +#include + +using BufferPtr = std::shared_ptr; +using MapModes = std::vector; + +static const MapModes validMapModes = { QVideoFrame::ReadOnly, QVideoFrame::WriteOnly, QVideoFrame::ReadWrite }; + +class tst_QVideoBuffers : public QObject +{ + Q_OBJECT + +public: + tst_QVideoBuffers() {} +public slots: + void initTestCase(); + +private slots: + void map_changesMappedStateAndReturnsProperMappings_whenBufferIsNotMapped_data(); + void map_changesMappedStateAndReturnsProperMappings_whenBufferIsNotMapped(); + + void mapWithNotMappedMode_doesNothing_data(); + void mapWithNotMappedMode_doesNothing(); + + void map_doesNothing_whenBufferIsMapped_data(); + void map_doesNothing_whenBufferIsMapped(); + + void mapMemoryBufferWithReadOnly_doesntDetachArray(); + + void mapMemoryBufferWithWriteModes_detachsArray_data(); + void mapMemoryBufferWithWriteModes_detachsArray(); + + void underlyingByteArray_returnsCorrectValueForPlanes(); + + void unmap_resetsMappedState_whenBufferIsMapped_data(); + void unmap_resetsMappedState_whenBufferIsMapped(); + +private: + QString mapModeToString(QVideoFrame::MapMode mapMode) const + { + switch (mapMode) { + case QVideoFrame::NotMapped: + return QLatin1String("NotMapped"); + case QVideoFrame::ReadOnly: + return QLatin1String("ReadOnly"); + case QVideoFrame::WriteOnly: + return QLatin1String("WriteOnly"); + case QVideoFrame::ReadWrite: + return QLatin1String("ReadWrite"); + default: + return QLatin1String("Unknown"); + } + } + + void generateImageAndMemoryBuffersWithAllModes(const MapModes& modes = validMapModes) const + { + QTest::addColumn("buffer"); + QTest::addColumn("mapMode"); + + for (auto mode : modes) { + QTest::newRow(QString("ImageBuffer, %1").arg(mapModeToString(mode)).toUtf8().constData()) + << createImageBuffer() << mode; + QTest::newRow(QString("MemoryBuffer, %1").arg(mapModeToString(mode)).toUtf8().constData()) + << createMemoryBuffer() << mode; + } + } + + BufferPtr createImageBuffer() const + { + return std::make_shared(m_image); + } + + BufferPtr createMemoryBuffer() const + { + return std::make_shared(m_byteArray, m_byteArray.size() / m_image.height()); + } + + QImage m_image = { QSize(5, 4), QImage::Format_RGBA8888 }; + QByteArray m_byteArray; +}; + + +void tst_QVideoBuffers::initTestCase() +{ + m_image.fill(Qt::gray); + m_image.setPixelColor(0, 0, Qt::green); + m_image.setPixelColor(m_image.width() - 1, 0, Qt::blue); + m_image.setPixelColor(0, m_image.height() - 1, Qt::red); + + m_byteArray.assign(m_image.constBits(), m_image.constBits() + m_image.sizeInBytes()); +} + +void tst_QVideoBuffers::map_changesMappedStateAndReturnsProperMappings_whenBufferIsNotMapped_data() +{ + generateImageAndMemoryBuffersWithAllModes(); +} + +void tst_QVideoBuffers::map_changesMappedStateAndReturnsProperMappings_whenBufferIsNotMapped() +{ + QFETCH(BufferPtr, buffer); + QFETCH(QVideoFrame::MapMode, mapMode); + + auto mappedData = buffer->map(mapMode); + + QCOMPARE(buffer->mapMode(), mapMode); + + QCOMPARE(mappedData.nPlanes, 1); + QVERIFY(mappedData.data[0]); + QCOMPARE(mappedData.size[0], 80); + QCOMPARE(mappedData.bytesPerLine[0], 20); + + const auto data = reinterpret_cast(mappedData.data[0]); + QCOMPARE(QByteArray(data, mappedData.size[0]), m_byteArray); +} + +void tst_QVideoBuffers::mapWithNotMappedMode_doesNothing_data() +{ + generateImageAndMemoryBuffersWithAllModes(); +} + +void tst_QVideoBuffers::mapWithNotMappedMode_doesNothing() +{ + QFETCH(BufferPtr, buffer); + QFETCH(QVideoFrame::MapMode, mapMode); + + buffer->map(mapMode); + + buffer->map(QVideoFrame::NotMapped); + + QCOMPARE(buffer->mapMode(), mapMode); +} + +void tst_QVideoBuffers::map_doesNothing_whenBufferIsMapped_data() +{ + generateImageAndMemoryBuffersWithAllModes(); +} + +void tst_QVideoBuffers::map_doesNothing_whenBufferIsMapped() +{ + QFETCH(BufferPtr, buffer); + QFETCH(QVideoFrame::MapMode, mapMode); + + buffer->map(mapMode); + auto mappedData = buffer->map(QVideoFrame::ReadOnly); + QCOMPARE(mappedData.nPlanes, 0); + QCOMPARE(buffer->mapMode(), mapMode); +} + +void tst_QVideoBuffers::mapMemoryBufferWithReadOnly_doesntDetachArray() +{ + auto buffer = createMemoryBuffer(); + auto underlyingArray = buffer->underlyingByteArray(0); + + auto mappedData = buffer->map(QVideoFrame::ReadOnly); + QCOMPARE(mappedData.nPlanes, 1); + QCOMPARE(mappedData.data[0], reinterpret_cast(underlyingArray.constData())); + QCOMPARE(mappedData.data[0], reinterpret_cast(m_byteArray.constData())); +} + +void tst_QVideoBuffers::mapMemoryBufferWithWriteModes_detachsArray_data() +{ + QTest::addColumn("mapMode"); + + QTest::newRow(mapModeToString(QVideoFrame::WriteOnly).toUtf8().constData()) << QVideoFrame::WriteOnly; + QTest::newRow(mapModeToString(QVideoFrame::WriteOnly).toUtf8().constData()) << QVideoFrame::WriteOnly; +} + +void tst_QVideoBuffers::mapMemoryBufferWithWriteModes_detachsArray() +{ + QFETCH(QVideoFrame::MapMode, mapMode); + + auto buffer = createMemoryBuffer(); + auto underlyingArray = buffer->underlyingByteArray(0); + + auto mappedData = buffer->map(mapMode); + QCOMPARE(mappedData.nPlanes, 1); + QCOMPARE_NE(mappedData.data[0], reinterpret_cast(underlyingArray.constData())); +} + +void tst_QVideoBuffers::underlyingByteArray_returnsCorrectValueForPlanes() +{ + auto buffer = createMemoryBuffer(); + + QCOMPARE(buffer->underlyingByteArray(0).constData(), m_byteArray.constData()); + + QVERIFY(buffer->underlyingByteArray(-1).isNull()); + QVERIFY(buffer->underlyingByteArray(1).isNull()); + QVERIFY(buffer->underlyingByteArray(2).isNull()); +} + +void tst_QVideoBuffers::unmap_resetsMappedState_whenBufferIsMapped_data() +{ + generateImageAndMemoryBuffersWithAllModes(); +} + +void tst_QVideoBuffers::unmap_resetsMappedState_whenBufferIsMapped() +{ + QFETCH(BufferPtr, buffer); + QFETCH(QVideoFrame::MapMode, mapMode); + + buffer->map(mapMode); + + buffer->unmap(); + + QCOMPARE(buffer->mapMode(), QVideoFrame::NotMapped); + + // Check buffer is valid and it's possible to map again + auto mappedData = buffer->map(QVideoFrame::ReadOnly); + QCOMPARE(mappedData.nPlanes, 1); + QCOMPARE(buffer->mapMode(), QVideoFrame::ReadOnly); + + const auto data = reinterpret_cast(mappedData.data[0]); + QCOMPARE(QByteArray(data, mappedData.size[0]), m_byteArray); +} + +QTEST_APPLESS_MAIN(tst_QVideoBuffers); + +#include "tst_qvideobuffers.moc" -- cgit v1.2.3