summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Blechmann <tim@klingt.org>2024-04-11 09:11:26 +0800
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2024-04-25 17:58:52 +0000
commit1c0716eceeaaf0a0217b5ffb40f502500742284e (patch)
tree68343fe3818a559cab0c9c85053124191eef2d8e
parentec5e7b49998fba64ca59b499a5ecab9506e308e1 (diff)
GStreamer: metadata - reduce complexity for metadata lookup
Instead of doing a linear search, we can do a binary search in a constexpr array. Reducing O(N) to O(log(N)). Pick-to: 6.5 Change-Id: I5bdc42bfc73dc9993e80c7352d64e54bbffe9a28 Reviewed-by: Artem Dyomin <artem.dyomin@qt.io> Reviewed-by: Alexey Edelev <alexey.edelev@qt.io> (cherry picked from commit f0dca46cdcc406ade7b06f765a64c8522bd9c84b) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/plugins/multimedia/gstreamer/CMakeLists.txt5
-rw-r--r--src/plugins/multimedia/gstreamer/common/qgstreamermetadata.cpp161
-rw-r--r--tests/auto/unit/multimedia/CMakeLists.txt4
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt15
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp29
-rw-r--r--tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h24
6 files changed, 185 insertions, 53 deletions
diff --git a/src/plugins/multimedia/gstreamer/CMakeLists.txt b/src/plugins/multimedia/gstreamer/CMakeLists.txt
index 91fca82a3..80fc1fce0 100644
--- a/src/plugins/multimedia/gstreamer/CMakeLists.txt
+++ b/src/plugins/multimedia/gstreamer/CMakeLists.txt
@@ -52,13 +52,14 @@ qt_internal_add_module(QGstreamerMediaPluginPrivate
)
qt_internal_extend_target(QGstreamerMediaPluginPrivate CONDITION QT_FEATURE_gstreamer_photography
- LIBRARIES
+ PUBLIC_LIBRARIES
GStreamer::Photography
)
qt_internal_extend_target(QGstreamerMediaPluginPrivate CONDITION QT_FEATURE_gstreamer_gl
- LIBRARIES
+ PUBLIC_LIBRARIES
GStreamer::Gl
+ LIBRARIES
EGL::EGL
)
diff --git a/src/plugins/multimedia/gstreamer/common/qgstreamermetadata.cpp b/src/plugins/multimedia/gstreamer/common/qgstreamermetadata.cpp
index 953acb56a..b02e3e40f 100644
--- a/src/plugins/multimedia/gstreamer/common/qgstreamermetadata.cpp
+++ b/src/plugins/multimedia/gstreamer/common/qgstreamermetadata.cpp
@@ -15,77 +15,135 @@
QT_BEGIN_NAMESPACE
-struct {
- const char *tag;
- QMediaMetaData::Key key;
-} gstTagToMetaDataKey[] = {
- { GST_TAG_TITLE, QMediaMetaData::Title },
- { GST_TAG_COMMENT, QMediaMetaData::Comment },
- { GST_TAG_DESCRIPTION, QMediaMetaData::Description },
- { GST_TAG_GENRE, QMediaMetaData::Genre },
- { GST_TAG_DATE_TIME, QMediaMetaData::Date },
- { GST_TAG_DATE, QMediaMetaData::Date },
+namespace {
- { GST_TAG_LANGUAGE_CODE, QMediaMetaData::Language },
+namespace MetadataLookupImpl {
- { GST_TAG_ORGANIZATION, QMediaMetaData::Publisher },
- { GST_TAG_COPYRIGHT, QMediaMetaData::Copyright },
+#ifdef __cpp_lib_constexpr_algorithms
+# define constexpr_lookup constexpr
+#else
+# define constexpr_lookup /*constexpr*/
+#endif
- // Media
- { GST_TAG_DURATION, QMediaMetaData::Duration },
+struct MetadataKeyValuePair
+{
+ const char *tag;
+ QMediaMetaData::Key key;
+};
- // Audio
- { GST_TAG_BITRATE, QMediaMetaData::AudioBitRate },
- { GST_TAG_AUDIO_CODEC, QMediaMetaData::AudioCodec },
+constexpr const char *toTag(const char *t)
+{
+ return t;
+}
+constexpr const char *toTag(const MetadataKeyValuePair &kv)
+{
+ return kv.tag;
+}
- // Music
- { GST_TAG_ALBUM, QMediaMetaData::AlbumTitle },
- { GST_TAG_ALBUM_ARTIST, QMediaMetaData::AlbumArtist },
- { GST_TAG_ARTIST, QMediaMetaData::ContributingArtist },
- { GST_TAG_TRACK_NUMBER, QMediaMetaData::TrackNumber },
+constexpr QMediaMetaData::Key toKey(QMediaMetaData::Key k)
+{
+ return k;
+}
+constexpr QMediaMetaData::Key toKey(const MetadataKeyValuePair &kv)
+{
+ return kv.key;
+}
- { GST_TAG_PREVIEW_IMAGE, QMediaMetaData::ThumbnailImage },
- { GST_TAG_IMAGE, QMediaMetaData::CoverArtImage },
+constexpr auto compareByKey = [](const auto &lhs, const auto &rhs) {
+ return toKey(lhs) < toKey(rhs);
+};
- // Image/Video
- { "resolution", QMediaMetaData::Resolution },
- { GST_TAG_IMAGE_ORIENTATION, QMediaMetaData::Orientation },
+constexpr auto compareByTag = [](const auto &lhs, const auto &rhs) {
+ return std::strcmp(toTag(lhs), toTag(rhs)) < 0;
+};
- // Video
- { GST_TAG_VIDEO_CODEC, QMediaMetaData::VideoCodec },
+constexpr_lookup auto makeLookupTable()
+{
+ std::array<MetadataKeyValuePair, 22> lookupTable{ {
+ { GST_TAG_TITLE, QMediaMetaData::Title },
+ { GST_TAG_COMMENT, QMediaMetaData::Comment },
+ { GST_TAG_DESCRIPTION, QMediaMetaData::Description },
+ { GST_TAG_GENRE, QMediaMetaData::Genre },
+ { GST_TAG_DATE_TIME, QMediaMetaData::Date },
+ { GST_TAG_DATE, QMediaMetaData::Date },
+
+ { GST_TAG_LANGUAGE_CODE, QMediaMetaData::Language },
+
+ { GST_TAG_ORGANIZATION, QMediaMetaData::Publisher },
+ { GST_TAG_COPYRIGHT, QMediaMetaData::Copyright },
+
+ // Media
+ { GST_TAG_DURATION, QMediaMetaData::Duration },
+
+ // Audio
+ { GST_TAG_BITRATE, QMediaMetaData::AudioBitRate },
+ { GST_TAG_AUDIO_CODEC, QMediaMetaData::AudioCodec },
+
+ // Music
+ { GST_TAG_ALBUM, QMediaMetaData::AlbumTitle },
+ { GST_TAG_ALBUM_ARTIST, QMediaMetaData::AlbumArtist },
+ { GST_TAG_ARTIST, QMediaMetaData::ContributingArtist },
+ { GST_TAG_TRACK_NUMBER, QMediaMetaData::TrackNumber },
+
+ { GST_TAG_PREVIEW_IMAGE, QMediaMetaData::ThumbnailImage },
+ { GST_TAG_IMAGE, QMediaMetaData::CoverArtImage },
+
+ // Image/Video
+ { "resolution", QMediaMetaData::Resolution },
+ { GST_TAG_IMAGE_ORIENTATION, QMediaMetaData::Orientation },
+
+ // Video
+ { GST_TAG_VIDEO_CODEC, QMediaMetaData::VideoCodec },
+
+ // Movie
+ { GST_TAG_PERFORMER, QMediaMetaData::LeadPerformer },
+ } };
+
+ std::sort(lookupTable.begin(), lookupTable.end(),
+ [](const MetadataKeyValuePair &lhs, const MetadataKeyValuePair &rhs) {
+ return std::string_view(lhs.tag) < std::string_view(rhs.tag);
+ });
+ return lookupTable;
+}
- // Movie
- { GST_TAG_PERFORMER, QMediaMetaData::LeadPerformer },
+constexpr_lookup auto gstTagToMetaDataKey = makeLookupTable();
+constexpr_lookup auto metaDataKeyToGstTag = [] {
+ auto array = gstTagToMetaDataKey;
+ std::sort(array.begin(), array.end(), compareByKey);
+ return array;
+}();
- { nullptr, QMediaMetaData::Title }
-};
+} // namespace MetadataLookupImpl
-static QMediaMetaData::Key tagToKey(const char *tag)
+QMediaMetaData::Key tagToKey(const char *tag)
{
- auto *map = gstTagToMetaDataKey;
- while (map->tag) {
- if (!strcmp(map->tag, tag))
- return map->key;
- ++map;
- }
+ if (tag == nullptr)
+ return QMediaMetaData::Key(-1);
+
+ using namespace MetadataLookupImpl;
+ auto foundIterator = std::lower_bound(gstTagToMetaDataKey.begin(), gstTagToMetaDataKey.end(),
+ tag, compareByTag);
+ if (std::strcmp(foundIterator->tag, tag) == 0)
+ return foundIterator->key;
+
return QMediaMetaData::Key(-1);
}
-static const char *keyToTag(QMediaMetaData::Key key)
+const char *keyToTag(QMediaMetaData::Key key)
{
- auto *map = gstTagToMetaDataKey;
- while (map->tag) {
- if (map->key == key)
- return map->tag;
- ++map;
- }
+ using namespace MetadataLookupImpl;
+ auto foundIterator = std::lower_bound(metaDataKeyToGstTag.begin(), metaDataKeyToGstTag.end(),
+ key, compareByKey);
+ if (foundIterator->key == key)
+ return foundIterator->tag;
+
return nullptr;
}
+#undef constexpr_lookup
+
//internal
-static void addTagToMap(const GstTagList *list,
- const gchar *tag,
- gpointer user_data)
+void addTagToMap(const GstTagList *list, const gchar *tag, gpointer user_data)
{
QMediaMetaData::Key key = tagToKey(tag);
if (key == QMediaMetaData::Key(-1))
@@ -187,6 +245,7 @@ static void addTagToMap(const GstTagList *list,
g_value_unset(&val);
}
+} // namespace
QGstreamerMetaData QGstreamerMetaData::fromGstTagList(const GstTagList *tags)
{
diff --git a/tests/auto/unit/multimedia/CMakeLists.txt b/tests/auto/unit/multimedia/CMakeLists.txt
index c6663a800..345c1679c 100644
--- a/tests/auto/unit/multimedia/CMakeLists.txt
+++ b/tests/auto/unit/multimedia/CMakeLists.txt
@@ -30,3 +30,7 @@ add_subdirectory(qmediadevices)
add_subdirectory(qerrorinfo)
add_subdirectory(qvideobuffers)
add_subdirectory(qwavedecoder)
+
+if (QT_FEATURE_gstreamer)
+ add_subdirectory(gstreamer_backend)
+endif()
diff --git a/tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt b/tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt
new file mode 100644
index 000000000..6d52d09e1
--- /dev/null
+++ b/tests/auto/unit/multimedia/gstreamer_backend/CMakeLists.txt
@@ -0,0 +1,15 @@
+# Copyright (C) 2024 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## tst_gstreamer_backend Test:
+#####################################################################
+
+qt_internal_add_test(tst_gstreamer_backend
+ SOURCES
+ tst_gstreamer_backend.cpp
+ tst_gstreamer_backend.h
+ LIBRARIES
+ Qt::MultimediaPrivate
+ Qt::QGstreamerMediaPluginPrivate
+)
diff --git a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp
new file mode 100644
index 000000000..3b4577ca2
--- /dev/null
+++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.cpp
@@ -0,0 +1,29 @@
+// 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 "tst_gstreamer_backend.h"
+
+#include <QtTest/QtTest>
+#include <QtQGstreamerMediaPlugin/private/qgstreamermetadata_p.h>
+#include <QtQGstreamerMediaPlugin/private/qgst_handle_types_p.h>
+
+QT_USE_NAMESPACE
+
+using namespace Qt::Literals;
+
+void tst_GStreamer::metadata_fromGstTagList()
+{
+ QGstTagListHandle tagList{
+ gst_tag_list_new_from_string(R"(taglist, title="My Video", comment="yada")"),
+ QGstTagListHandle::NeedsRef,
+ };
+
+ QGstreamerMetaData parsed = QGstreamerMetaData::fromGstTagList(tagList.get());
+
+ QCOMPARE(parsed.stringValue(QMediaMetaData::Title), u"My Video"_s);
+ QCOMPARE(parsed.stringValue(QMediaMetaData::Comment), u"yada"_s);
+}
+
+QTEST_GUILESS_MAIN(tst_GStreamer)
+
+#include "moc_tst_gstreamer_backend.cpp"
diff --git a/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h
new file mode 100644
index 000000000..5bac3a599
--- /dev/null
+++ b/tests/auto/unit/multimedia/gstreamer_backend/tst_gstreamer_backend.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TST_GSTREAMER_BACKEND_H
+#define TST_GSTREAMER_BACKEND_H
+
+#include <QtTest/QtTest>
+
+#include <QtQGstreamerMediaPlugin/private/qgstreamerintegration_p.h>
+
+QT_USE_NAMESPACE
+
+class tst_GStreamer : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void metadata_fromGstTagList();
+
+private:
+ QGstreamerIntegration integration;
+};
+
+#endif // TST_GSTREAMER_BACKEND_H