diff options
author | Tim Blechmann <tim@klingt.org> | 2024-04-11 09:11:26 +0800 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2024-04-25 17:58:52 +0000 |
commit | 1c0716eceeaaf0a0217b5ffb40f502500742284e (patch) | |
tree | 68343fe3818a559cab0c9c85053124191eef2d8e | |
parent | ec5e7b49998fba64ca59b499a5ecab9506e308e1 (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>
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 |