Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qgstreamermetadata.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <QDebug>
6#include <QtMultimedia/qmediametadata.h>
7#include <QtCore/qdatetime.h>
8#include <QtCore/qtimezone.h>
9
10#include <gst/gstversion.h>
11#include <qgstutils_p.h>
12#include <qlocale.h>
13
15
16struct {
17 const char *tag;
20 { GST_TAG_TITLE, QMediaMetaData::Title },
21 { GST_TAG_COMMENT, QMediaMetaData::Comment },
22 { GST_TAG_DESCRIPTION, QMediaMetaData::Description },
23 { GST_TAG_GENRE, QMediaMetaData::Genre },
24 { GST_TAG_DATE_TIME, QMediaMetaData::Date },
25 { GST_TAG_DATE, QMediaMetaData::Date },
26
27 { GST_TAG_LANGUAGE_CODE, QMediaMetaData::Language },
28
29 { GST_TAG_ORGANIZATION, QMediaMetaData::Publisher },
30 { GST_TAG_COPYRIGHT, QMediaMetaData::Copyright },
31
32 // Media
33 { GST_TAG_DURATION, QMediaMetaData::Duration },
34
35 // Audio
36 { GST_TAG_BITRATE, QMediaMetaData::AudioBitRate },
37 { GST_TAG_AUDIO_CODEC, QMediaMetaData::AudioCodec },
38
39 // Music
40 { GST_TAG_ALBUM, QMediaMetaData::AlbumTitle },
41 { GST_TAG_ALBUM_ARTIST, QMediaMetaData::AlbumArtist },
42 { GST_TAG_ARTIST, QMediaMetaData::ContributingArtist },
43 { GST_TAG_TRACK_NUMBER, QMediaMetaData::TrackNumber },
44
45 { GST_TAG_PREVIEW_IMAGE, QMediaMetaData::ThumbnailImage },
46 { GST_TAG_IMAGE, QMediaMetaData::CoverArtImage },
47
48 // Image/Video
49 { "resolution", QMediaMetaData::Resolution },
50 { GST_TAG_IMAGE_ORIENTATION, QMediaMetaData::Orientation },
51
52 // Video
53 { GST_TAG_VIDEO_CODEC, QMediaMetaData::VideoCodec },
54
55 // Movie
56 { GST_TAG_PERFORMER, QMediaMetaData::LeadPerformer },
57
58 { nullptr, QMediaMetaData::Title }
59};
60
61static QMediaMetaData::Key tagToKey(const char *tag)
62{
64 while (map->tag) {
65 if (!strcmp(map->tag, tag))
66 return map->key;
67 ++map;
68 }
69 return QMediaMetaData::Key(-1);
70}
71
72static const char *keyToTag(QMediaMetaData::Key key)
73{
75 while (map->tag) {
76 if (map->key == key)
77 return map->tag;
78 ++map;
79 }
80 return nullptr;
81}
82
83//internal
84static void addTagToMap(const GstTagList *list,
85 const gchar *tag,
86 gpointer user_data)
87{
89 if (key == QMediaMetaData::Key(-1))
90 return;
91
92 auto *map = reinterpret_cast<QHash<QMediaMetaData::Key, QVariant>* >(user_data);
93
94 GValue val;
95 val.g_type = 0;
96 gst_tag_list_copy_value(&val, list, tag);
97
98
99 switch( G_VALUE_TYPE(&val) ) {
100 case G_TYPE_STRING:
101 {
102 const gchar *str_value = g_value_get_string(&val);
105 break;
106 }
107 map->insert(key, QString::fromUtf8(str_value));
108 break;
109 }
110 case G_TYPE_INT:
111 map->insert(key, g_value_get_int(&val));
112 break;
113 case G_TYPE_UINT:
114 map->insert(key, g_value_get_uint(&val));
115 break;
116 case G_TYPE_LONG:
117 map->insert(key, qint64(g_value_get_long(&val)));
118 break;
119 case G_TYPE_BOOLEAN:
120 map->insert(key, g_value_get_boolean(&val));
121 break;
122 case G_TYPE_CHAR:
123 map->insert(key, g_value_get_schar(&val));
124 break;
125 case G_TYPE_DOUBLE:
126 map->insert(key, g_value_get_double(&val));
127 break;
128 default:
129 // GST_TYPE_DATE is a function, not a constant, so pull it out of the switch
130 if (G_VALUE_TYPE(&val) == G_TYPE_DATE) {
131 const GDate *date = (const GDate *)g_value_get_boxed(&val);
132 if (g_date_valid(date)) {
133 int year = g_date_get_year(date);
134 int month = g_date_get_month(date);
135 int day = g_date_get_day(date);
136 // don't insert if we already have a datetime.
137 if (!map->contains(key))
138 map->insert(key, QDateTime(QDate(year, month, day), QTime()));
139 }
140 } else if (G_VALUE_TYPE(&val) == GST_TYPE_DATE_TIME) {
141 const GstDateTime *dateTime = (const GstDateTime *)g_value_get_boxed(&val);
142 int year = gst_date_time_has_year(dateTime) ? gst_date_time_get_year(dateTime) : 0;
143 int month = gst_date_time_has_month(dateTime) ? gst_date_time_get_month(dateTime) : 0;
144 int day = gst_date_time_has_day(dateTime) ? gst_date_time_get_day(dateTime) : 0;
145 int hour = 0;
146 int minute = 0;
147 int second = 0;
148 float tz = 0;
149 if (gst_date_time_has_time(dateTime)) {
150 hour = gst_date_time_get_hour(dateTime);
151 minute = gst_date_time_get_minute(dateTime);
152 second = gst_date_time_get_second(dateTime);
153 tz = gst_date_time_get_time_zone_offset(dateTime);
154 }
155 QDateTime qDateTime(QDate(year, month, day), QTime(hour, minute, second),
156 QTimeZone(tz * 60 * 60));
157 map->insert(key, qDateTime);
158 } else if (G_VALUE_TYPE(&val) == GST_TYPE_SAMPLE) {
159 GstSample *sample = (GstSample *)g_value_get_boxed(&val);
160 GstCaps* caps = gst_sample_get_caps(sample);
161 if (caps && !gst_caps_is_empty(caps)) {
162 GstStructure *structure = gst_caps_get_structure(caps, 0);
163 const gchar *name = gst_structure_get_name(structure);
164 if (QByteArray(name).startsWith("image/")) {
165 GstBuffer *buffer = gst_sample_get_buffer(sample);
166 if (buffer) {
167 GstMapInfo info;
168 gst_buffer_map(buffer, &info, GST_MAP_READ);
170 gst_buffer_unmap(buffer, &info);
171 }
172 }
173 }
174 } else if (G_VALUE_TYPE(&val) == GST_TYPE_FRACTION) {
175 int nom = gst_value_get_fraction_numerator(&val);
176 int denom = gst_value_get_fraction_denominator(&val);
177
178 if (denom > 0) {
179 map->insert(key, double(nom)/denom);
180 }
181 }
182 break;
183 }
184
185 g_value_unset(&val);
186}
187
188
190{
192 gst_tag_list_foreach(tags, addTagToMap, &m.data);
193 return m;
194}
195
196
197void QGstreamerMetaData::setMetaData(GstElement *element) const
198{
199 if (!GST_IS_TAG_SETTER(element))
200 return;
201
202 gst_tag_setter_reset_tags(GST_TAG_SETTER(element));
203
204 for (auto it = data.cbegin(), end = data.cend(); it != end; ++it) {
205 const char *tagName = keyToTag(it.key());
206 if (!tagName)
207 continue;
208 const QVariant &tagValue = it.value();
209
210 switch (tagValue.typeId()) {
211 case QMetaType::QString:
212 gst_tag_setter_add_tags(GST_TAG_SETTER(element),
213 GST_TAG_MERGE_REPLACE,
214 tagName,
215 tagValue.toString().toUtf8().constData(),
216 nullptr);
217 break;
218 case QMetaType::Int:
219 case QMetaType::LongLong:
220 gst_tag_setter_add_tags(GST_TAG_SETTER(element),
221 GST_TAG_MERGE_REPLACE,
222 tagName,
223 tagValue.toInt(),
224 nullptr);
225 break;
226 case QMetaType::Double:
227 gst_tag_setter_add_tags(GST_TAG_SETTER(element),
228 GST_TAG_MERGE_REPLACE,
229 tagName,
230 tagValue.toDouble(),
231 nullptr);
232 break;
233 case QMetaType::QDate:
234 case QMetaType::QDateTime: {
235 QDateTime date = tagValue.toDateTime();
236 gst_tag_setter_add_tags(GST_TAG_SETTER(element),
237 GST_TAG_MERGE_REPLACE,
238 tagName,
239 gst_date_time_new(date.offsetFromUtc() / 60. / 60.,
240 date.date().year(), date.date().month(), date.date().day(),
241 date.time().hour(), date.time().minute(), date.time().second()),
242 nullptr);
243 break;
244 }
245 default: {
246 if (tagValue.typeId() == qMetaTypeId<QLocale::Language>()) {
248 gst_tag_setter_add_tags(GST_TAG_SETTER(element),
249 GST_TAG_MERGE_REPLACE,
250 tagName,
251 language.constData(),
252 nullptr);
253 }
254
255 break;
256 }
257 }
258 }
259}
260
261void QGstreamerMetaData::setMetaData(GstBin *bin) const
262{
263 GstIterator *elements = gst_bin_iterate_all_by_interface(bin, GST_TYPE_TAG_SETTER);
264 GValue item = G_VALUE_INIT;
265 while (gst_iterator_next(elements, &item) == GST_ITERATOR_OK) {
266 GstElement * const element = GST_ELEMENT(g_value_get_object(&item));
267 setMetaData(element);
268 }
269 gst_iterator_free(elements);
270}
271
272
\inmodule QtCore
Definition qbytearray.h:57
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:122
\inmodule QtCore\reentrant
Definition qdatetime.h:257
\inmodule QtCore \reentrant
Definition qdatetime.h:27
int month() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int day() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qint64 size() const
Returns the file size in bytes.
static QGstreamerMetaData fromGstTagList(const GstTagList *tags)
void setMetaData(GstBin *bin) const
\inmodule QtCore
Definition qhash.h:818
static QImage fromData(QByteArrayView data, const char *format=nullptr)
Definition qimage.cpp:3823
static QString languageToCode(Language language, LanguageCodeTypes codeTypes=AnyLanguageCode)
Returns the two- or three-letter language code for language, as defined in the ISO 639 standards.
Definition qlocale.cpp:1420
@ ISO639Part2
Definition qlocale.h:1066
static Language codeToLanguage(QStringView languageCode, LanguageCodeTypes codeTypes=AnyLanguageCode) noexcept
Returns the QLocale::Language enum corresponding to the two- or three-letter languageCode,...
Definition qlocale.cpp:1440
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
bool contains(const Key &key) const
Definition qmap.h:340
Key key(const T &value, const Key &defaultKey=Key()) const
Definition qmap.h:348
const_iterator cbegin() const noexcept
Definition qset.h:138
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
QByteArray toUtf8() const &
Definition qstring.h:563
\inmodule QtCore
Definition qtimezone.h:25
\inmodule QtCore \reentrant
Definition qdatetime.h:189
\inmodule QtCore
Definition qvariant.h:64
T value() const &
Definition qvariant.h:511
QDateTime toDateTime() const
Returns the variant as a QDateTime if the variant has userType() \l QMetaType::QDateTime,...
double toDouble(bool *ok=nullptr) const
Returns the variant as a double if the variant has userType() \l QMetaType::Double,...
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
QString toString() const
Returns the variant as a QString if the variant has a userType() including, but not limited to:
int typeId() const
Returns the storage type of the value stored in the variant.
Definition qvariant.h:337
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:531
QMap< QString, QString > map
[6]
QDate date
[1]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void * user_data
static const char * keyToTag(QMediaMetaData::Key key)
static QMediaMetaData::Key tagToKey(const char *tag)
static void addTagToMap(const GstTagList *list, const gchar *tag, gpointer user_data)
QMediaMetaData::Key key
const char * tag
static const char * keyToTag(QMediaMetaData::Key key)
QT_BEGIN_NAMESPACE struct @728 gstTagToMetaDataKey[]
const GLfloat * m
GLuint64 key
GLuint GLuint end
GLenum GLuint buffer
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint name
GLbyte GLbyte tz
GLuint GLfloat * val
static const QTextHtmlElement elements[Html_NumElements]
long long qint64
Definition qtypes.h:55
QList< int > list
[14]
QFileInfo info(fileName)
[8]
QDateTime dateTime
[12]
QGraphicsItem * item