Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
mfmetadata.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
4#include <qmediametadata.h>
5#include <qdatetime.h>
6#include <qtimezone.h>
7#include <qimage.h>
8#include <quuid.h>
9
10#include <mfapi.h>
11#include <mfidl.h>
12#include <propvarutil.h>
13#include <propkey.h>
14
15#include "private/qwindowsmultimediautils_p.h"
16#include "mfmetadata_p.h"
17
18//#define DEBUG_MEDIAFOUNDATION
19
20static const PROPERTYKEY PROP_KEY_NULL = {GUID_NULL, 0};
21
22static QVariant convertValue(const PROPVARIANT& var)
23{
25 switch (var.vt) {
26 case VT_LPWSTR:
27 value = QString::fromUtf16(reinterpret_cast<const char16_t *>(var.pwszVal));
28 break;
29 case VT_UI4:
30 value = uint(var.ulVal);
31 break;
32 case VT_UI8:
33 value = qulonglong(var.uhVal.QuadPart);
34 break;
35 case VT_BOOL:
36 value = bool(var.boolVal);
37 break;
38 case VT_FILETIME:
39 SYSTEMTIME t;
40 if (!FileTimeToSystemTime(&var.filetime, &t))
41 break;
42
43 value = QDateTime(QDate(t.wYear, t.wMonth, t.wDay),
44 QTime(t.wHour, t.wMinute, t.wSecond, t.wMilliseconds),
46 break;
47 case VT_STREAM:
48 {
49 STATSTG stat;
50 if (FAILED(var.pStream->Stat(&stat, STATFLAG_NONAME)))
51 break;
52 void *data = malloc(stat.cbSize.QuadPart);
53 ULONG read = 0;
54 if (FAILED(var.pStream->Read(data, stat.cbSize.QuadPart, &read))) {
55 free(data);
56 break;
57 }
59 free(data);
60 }
61 break;
62 case VT_VECTOR | VT_LPWSTR:
63 QStringList vList;
64 for (ULONG i = 0; i < var.calpwstr.cElems; ++i)
65 vList.append(QString::fromUtf16(reinterpret_cast<const char16_t *>(var.calpwstr.pElems[i])));
66 value = vList;
67 break;
68 }
69 return value;
70}
71
72static QVariant metaDataValue(IPropertyStore *content, const PROPERTYKEY &key)
73{
75
76 PROPVARIANT var;
77 PropVariantInit(&var);
78 HRESULT hr = S_FALSE;
79 if (content)
80 hr = content->GetValue(key, &var);
81
82 if (SUCCEEDED(hr)) {
84
85 // some metadata needs to be reformatted
86 if (value.isValid() && content) {
87 if (key == PKEY_Media_ClassPrimaryID /*QMediaMetaData::MediaType*/) {
88 QString v = value.toString();
89 if (v == QLatin1String("{D1607DBC-E323-4BE2-86A1-48A42A28441E}"))
90 value = QStringLiteral("Music");
91 else if (v == QLatin1String("{DB9830BD-3AB3-4FAB-8A37-1A995F7FF74B}"))
92 value = QStringLiteral("Video");
93 else if (v == QLatin1String("{01CD0F29-DA4E-4157-897B-6275D50C4F11}"))
94 value = QStringLiteral("Audio");
95 else if (v == QLatin1String("{FCF24A76-9A57-4036-990D-E35DD8B244E1}"))
96 value = QStringLiteral("Other");
97 } else if (key == PKEY_Media_Duration) {
98 // duration is provided in 100-nanosecond units, convert to milliseconds
99 value = (value.toLongLong() + 10000) / 10000;
100 } else if (key == PKEY_Video_Compression) {
102 } else if (key == PKEY_Audio_Format) {
104 } else if (key == PKEY_Video_FrameHeight /*Resolution*/) {
105 QSize res;
106 res.setHeight(value.toUInt());
107 if (content && SUCCEEDED(content->GetValue(PKEY_Video_FrameWidth, &var)))
108 res.setWidth(convertValue(var).toUInt());
109 value = res;
110 } else if (key == PKEY_Video_Orientation) {
111 uint orientation = 0;
112 if (content && SUCCEEDED(content->GetValue(PKEY_Video_Orientation, &var)))
113 orientation = convertValue(var).toUInt();
114 value = orientation;
115 } else if (key == PKEY_Video_FrameRate) {
116 value = value.toReal() / 1000.f;
117 }
118 }
119 }
120
121 PropVariantClear(&var);
122 return value;
123}
124
125QMediaMetaData MFMetaData::fromNative(IMFMediaSource* mediaSource)
126{
127 QMediaMetaData metaData;
128
129 IPropertyStore *content = nullptr;
130 if (!SUCCEEDED(MFGetService(mediaSource, MF_PROPERTY_HANDLER_SERVICE, IID_PPV_ARGS(&content))))
131 return metaData;
132
133 Q_ASSERT(content);
134 DWORD cProps;
135 if (SUCCEEDED(content->GetCount(&cProps))) {
136 for (DWORD i = 0; i < cProps; i++)
137 {
138 PROPERTYKEY key;
139 if (FAILED(content->GetAt(i, &key)))
140 continue;
141 QMediaMetaData::Key mediaKey;
142 if (key == PKEY_Author) {
143 mediaKey = QMediaMetaData::Author;
144 } else if (key == PKEY_Title) {
145 mediaKey = QMediaMetaData::Title;
146// } else if (key == PKEY_Media_SubTitle) {
147// mediaKey = QMediaMetaData::SubTitle;
148// } else if (key == PKEY_ParentalRating) {
149// mediaKey = QMediaMetaData::ParentalRating;
150 } else if (key == PKEY_Media_EncodingSettings) {
152 } else if (key == PKEY_Copyright) {
153 mediaKey = QMediaMetaData::Copyright;
154 } else if (key == PKEY_Comment) {
155 mediaKey = QMediaMetaData::Comment;
156 } else if (key == PKEY_Media_ProviderStyle) {
157 mediaKey = QMediaMetaData::Genre;
158 } else if (key == PKEY_Media_DateEncoded) {
159 mediaKey = QMediaMetaData::Date;
160// } else if (key == PKEY_Rating) {
161// mediaKey = QMediaMetaData::UserRating;
162// } else if (key == PKEY_Keywords) {
163// mediaKey = QMediaMetaData::Keywords;
164 } else if (key == PKEY_Language) {
165 mediaKey = QMediaMetaData::Language;
166 } else if (key == PKEY_Media_Publisher) {
167 mediaKey = QMediaMetaData::Publisher;
168 } else if (key == PKEY_Media_ClassPrimaryID) {
169 mediaKey = QMediaMetaData::MediaType;
170 } else if (key == PKEY_Media_Duration) {
171 mediaKey = QMediaMetaData::Duration;
172 } else if (key == PKEY_Audio_EncodingBitrate) {
174 } else if (key == PKEY_Audio_Format) {
176// } else if (key == PKEY_Media_AverageLevel) {
177// mediaKey = QMediaMetaData::AverageLevel;
178// } else if (key == PKEY_Audio_ChannelCount) {
179// mediaKey = QMediaMetaData::ChannelCount;
180// } else if (key == PKEY_Audio_PeakValue) {
181// mediaKey = QMediaMetaData::PeakValue;
182// } else if (key == PKEY_Audio_SampleRate) {
183// mediaKey = QMediaMetaData::SampleRate;
184 } else if (key == PKEY_Music_AlbumTitle) {
186 } else if (key == PKEY_Music_AlbumArtist) {
188 } else if (key == PKEY_Music_Artist) {
190 } else if (key == PKEY_Music_Composer) {
191 mediaKey = QMediaMetaData::Composer;
192// } else if (key == PKEY_Music_Conductor) {
193// mediaKey = QMediaMetaData::Conductor;
194// } else if (key == PKEY_Music_Lyrics) {
195// mediaKey = QMediaMetaData::Lyrics;
196// } else if (key == PKEY_Music_Mood) {
197// mediaKey = QMediaMetaData::Mood;
198 } else if (key == PKEY_Music_TrackNumber) {
200 } else if (key == PKEY_Music_Genre) {
201 mediaKey = QMediaMetaData::Genre;
202 } else if (key == PKEY_ThumbnailStream) {
204 } else if (key == PKEY_Video_FrameHeight) {
206 } else if (key == PKEY_Video_Orientation) {
208 } else if (key == PKEY_Video_FrameRate) {
210 } else if (key == PKEY_Video_EncodingBitrate) {
212 } else if (key == PKEY_Video_Compression) {
214// } else if (key == PKEY_Video_Director) {
215// mediaKey = QMediaMetaData::Director;
216// } else if (key == PKEY_Media_Writer) {
217// mediaKey = QMediaMetaData::Writer;
218 } else {
219 continue;
220 }
221 metaData.insert(mediaKey, metaDataValue(content, key));
222 }
223 }
224
225 content->Release();
226
227 return metaData;
228}
229
231{
232 switch (key) {
234 return PKEY_Title;
236 return PKEY_Author;
238 return PKEY_Comment;
240 return PKEY_Music_Genre;
242 return PKEY_Copyright;
244 return PKEY_Media_Publisher;
246 return PKEY_Media_AuthorUrl;
248 return PKEY_Music_AlbumTitle;
250 return PKEY_Music_AlbumArtist;
252 return PKEY_Music_TrackNumber;
254 return PKEY_Media_DateEncoded;
256 return PKEY_Music_Composer;
258 return PKEY_Media_Duration;
260 return PKEY_Language;
262 return PKEY_Media_EncodingSettings;
264 return PKEY_Audio_EncodingBitrate;
266 return PKEY_Music_Artist;
268 return PKEY_ThumbnailStream;
270 return PKEY_Video_Orientation;
272 return PKEY_Video_FrameRate;
274 return PKEY_Video_EncodingBitrate;
276 return PKEY_Media_ClassPrimaryID;
277 default:
278 return PROP_KEY_NULL;
279 }
280}
281
282static void setStringProperty(IPropertyStore *content, REFPROPERTYKEY key, const QString &value)
283{
284 PROPVARIANT propValue = {};
285 if (SUCCEEDED(InitPropVariantFromString(reinterpret_cast<LPCWSTR>(value.utf16()), &propValue))) {
286 if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
287 content->SetValue(key, propValue);
288 PropVariantClear(&propValue);
289 }
290}
291
292static void setUInt32Property(IPropertyStore *content, REFPROPERTYKEY key, quint32 value)
293{
294 PROPVARIANT propValue = {};
295 if (SUCCEEDED(InitPropVariantFromUInt32(ULONG(value), &propValue))) {
296 if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
297 content->SetValue(key, propValue);
298 PropVariantClear(&propValue);
299 }
300}
301
302static void setUInt64Property(IPropertyStore *content, REFPROPERTYKEY key, quint64 value)
303{
304 PROPVARIANT propValue = {};
305 if (SUCCEEDED(InitPropVariantFromUInt64(ULONGLONG(value), &propValue))) {
306 if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
307 content->SetValue(key, propValue);
308 PropVariantClear(&propValue);
309 }
310}
311
312static void setFileTimeProperty(IPropertyStore *content, REFPROPERTYKEY key, const FILETIME *ft)
313{
314 PROPVARIANT propValue = {};
315 if (SUCCEEDED(InitPropVariantFromFileTime(ft, &propValue))) {
316 if (SUCCEEDED(PSCoerceToCanonicalValue(key, &propValue)))
317 content->SetValue(key, propValue);
318 PropVariantClear(&propValue);
319 }
320}
321
322void MFMetaData::toNative(const QMediaMetaData &metaData, IPropertyStore *content)
323{
324 if (content) {
325
326 for (const auto &key : metaData.keys()) {
327
328 QVariant value = metaData.value(key);
329
331
332 QString strValue = metaData.stringValue(key);
333 QString v;
334
335 // Sets property to one of the MediaClassPrimaryID values defined by Microsoft:
336 // https://docs.microsoft.com/en-us/windows/win32/wmformat/wm-mediaprimaryid
337 if (strValue == QLatin1String("Music"))
338 v = QLatin1String("{D1607DBC-E323-4BE2-86A1-48A42A28441E}");
339 else if (strValue == QLatin1String("Video"))
340 v = QLatin1String("{DB9830BD-3AB3-4FAB-8A37-1A995F7FF74B}");
341 else if (strValue == QLatin1String("Audio"))
342 v = QLatin1String("{01CD0F29-DA4E-4157-897B-6275D50C4F11}");
343 else
344 v = QLatin1String("{FCF24A76-9A57-4036-990D-E35DD8B244E1}");
345
346 setStringProperty(content, PKEY_Media_ClassPrimaryID, v);
347
348 } else if (key == QMediaMetaData::Key::Duration) {
349
350 setUInt64Property(content, PKEY_Media_Duration, value.toULongLong() * 10000);
351
352 } else if (key == QMediaMetaData::Key::Resolution) {
353
354 QSize res = value.toSize();
355 setUInt32Property(content, PKEY_Video_FrameWidth, quint32(res.width()));
356 setUInt32Property(content, PKEY_Video_FrameHeight, quint32(res.height()));
357
359
360 setUInt32Property(content, PKEY_Video_Orientation, value.toUInt());
361
363
364 qreal fps = value.toReal();
365 setUInt32Property(content, PKEY_Video_FrameRate, quint32(fps * 1000));
366
368
369 setUInt32Property(content, PKEY_Music_TrackNumber, value.toUInt());
370
372
373 setUInt32Property(content, PKEY_Audio_EncodingBitrate, value.toUInt());
374
376
377 setUInt32Property(content, PKEY_Video_EncodingBitrate, value.toUInt());
378
379 } else if (key == QMediaMetaData::Key::Date) {
380
381 // Convert QDateTime to FILETIME by converting to 100-nsecs since
382 // 01/01/1970 UTC and adding the difference from 1601 to 1970.
383 ULARGE_INTEGER t = {};
384 t.QuadPart = ULONGLONG(value.toDateTime().toUTC().toMSecsSinceEpoch() * 10000
385 + 116444736000000000LL);
386
387 FILETIME ft = {};
388 ft.dwHighDateTime = t.HighPart;
389 ft.dwLowDateTime = t.LowPart;
390
391 setFileTimeProperty(content, PKEY_Media_DateEncoded, &ft);
392
393 } else {
394
395 // By default use as string and let PSCoerceToCanonicalValue()
396 // do validation and type conversion.
397 REFPROPERTYKEY propKey = propertyKeyForMetaDataKey(key);
398
399 if (propKey != PROP_KEY_NULL) {
400 QString strValue = metaData.stringValue(key);
401 if (!strValue.isEmpty())
402 setStringProperty(content, propKey, strValue);
403 }
404 }
405 }
406 }
407}
408
static QMediaMetaData fromNative(IMFMediaSource *mediaSource)
static void toNative(const QMediaMetaData &metaData, IPropertyStore *content)
\inmodule QtCore\reentrant
Definition qdatetime.h:283
\inmodule QtCore \reentrant
Definition qdatetime.h:29
static QImage fromData(QByteArrayView data, const char *format=nullptr)
Definition qimage.cpp:3841
\inmodule QtMultimedia
Q_INVOKABLE QString stringValue(Key k) const
\qmlmethod string QtMultimedia::mediaMetaData::stringValue(Key key) Returns the meta data for key key...
Q_INVOKABLE void insert(Key k, const QVariant &value)
\qmlmethod void QtMultimedia::mediaMetaData::insert(Key k, variant value) Inserts a value into a Key:...
Q_INVOKABLE QVariant value(Key k) const
\variable QMediaMetaData::NumMetaData
Q_INVOKABLE QList< Key > keys() const
\qmlmethod list<Key> QtMultimedia::mediaMetaData::keys() Returns a list of MediaMetaData....
Key
Provides meta-data for media files.
\inmodule QtCore
Definition qsize.h:25
constexpr void setHeight(int h) noexcept
Sets the height to the given height.
Definition qsize.h:139
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromUtf16(const char16_t *, qsizetype size=-1)
Definition qstring.cpp:6045
\inmodule QtCore
Definition qtimezone.h:26
\inmodule QtCore \reentrant
Definition qdatetime.h:215
\inmodule QtCore
Definition qvariant.h:65
static QVariant metaDataValue(IPropertyStore *content, const PROPERTYKEY &key)
static void setUInt32Property(IPropertyStore *content, REFPROPERTYKEY key, quint32 value)
static void setUInt64Property(IPropertyStore *content, REFPROPERTYKEY key, quint64 value)
static QVariant convertValue(const PROPVARIANT &var)
static void setFileTimeProperty(IPropertyStore *content, REFPROPERTYKEY key, const FILETIME *ft)
static const PROPERTYKEY PROP_KEY_NULL
static REFPROPERTYKEY propertyKeyForMetaDataKey(QMediaMetaData::Key key)
static void setStringProperty(IPropertyStore *content, REFPROPERTYKEY key, const QString &value)
Q_MULTIMEDIA_EXPORT QMediaFormat::AudioCodec codecForAudioFormat(GUID format)
Q_MULTIMEDIA_EXPORT QMediaFormat::VideoCodec codecForVideoFormat(GUID format)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLsizei const GLfloat * v
[13]
GLuint64 key
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint res
GLdouble GLdouble t
Definition qopenglext.h:243
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define QStringLiteral(str)
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
quint64 qulonglong
Definition qtypes.h:64
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
ReturnedValue read(const char *data)
long HRESULT