|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the Qt Mobility Components. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 #include "qwmpmetadata.h" |
|
43 |
|
44 #include "qwmpevents.h" |
|
45 #include "qwmpglobal.h" |
|
46 |
|
47 #include <qmediacontent.h> |
|
48 |
|
49 #include <QtCore/qdatetime.h> |
|
50 #include <QtCore/qdir.h> |
|
51 #include <QtCore/qfileinfo.h> |
|
52 #include <QtCore/qsize.h> |
|
53 #include <QtCore/qstringlist.h> |
|
54 #include <QtCore/qurl.h> |
|
55 #include <QtCore/qvariant.h> |
|
56 |
|
57 |
|
58 struct QWmpMetaDataKeyLookup |
|
59 { |
|
60 QtMultimediaKit::MetaData key; |
|
61 const wchar_t *token; |
|
62 }; |
|
63 |
|
64 static const QWmpMetaDataKeyLookup qt_wmpMetaDataKeys[] = |
|
65 { |
|
66 { QtMultimediaKit::Title, L"Title" }, |
|
67 { QtMultimediaKit::SubTitle, L"WM/SubTitle" }, |
|
68 { QtMultimediaKit::Author, L"Author" }, |
|
69 { QtMultimediaKit::Comment, L"Comment" }, |
|
70 { QtMultimediaKit::Description, L"Description" }, |
|
71 { QtMultimediaKit::Category, L"WM/Category" }, |
|
72 { QtMultimediaKit::Genre, L"WM/Genre" }, |
|
73 //{ QtMultimediaKit::Date, 0 }, |
|
74 { QtMultimediaKit::Year, L"WM/Year" }, |
|
75 { QtMultimediaKit::UserRating, L"UserRating" }, |
|
76 //{ QtMultimediaKit::MetaDatawords, 0 }, |
|
77 { QtMultimediaKit::Language, L"Language" }, |
|
78 { QtMultimediaKit::Publisher, L"WM/Publisher" }, |
|
79 { QtMultimediaKit::Copyright, L"Copyright" }, |
|
80 { QtMultimediaKit::ParentalRating, L"ParentalRating" }, |
|
81 { QtMultimediaKit::RatingOrganisation, L"RatingOrganisation" }, |
|
82 |
|
83 // Media |
|
84 { QtMultimediaKit::Size, L"FileSize" }, |
|
85 { QtMultimediaKit::MediaType, L"MediaType" }, |
|
86 { QtMultimediaKit::Duration, L"Duration" }, |
|
87 |
|
88 // Audio |
|
89 { QtMultimediaKit::AudioBitRate, L"AudioBitrate" }, |
|
90 { QtMultimediaKit::AudioCodec, L"AudioCodec" }, |
|
91 { QtMultimediaKit::ChannelCount, L"Channels" }, |
|
92 { QtMultimediaKit::SampleRate, L"Frequency" }, |
|
93 |
|
94 // Music |
|
95 { QtMultimediaKit::AlbumTitle, L"WM/AlbumTitle" }, |
|
96 { QtMultimediaKit::AlbumArtist, L"WM/AlbumArtist" }, |
|
97 { QtMultimediaKit::ContributingArtist, L"Author" }, |
|
98 { QtMultimediaKit::Composer, L"WM/Composer" }, |
|
99 { QtMultimediaKit::Conductor, L"WM/Conductor" }, |
|
100 { QtMultimediaKit::Lyrics, L"WM/Lyrics" }, |
|
101 { QtMultimediaKit::Mood, L"WM/Mood" }, |
|
102 { QtMultimediaKit::TrackNumber, L"WM/TrackNumber" }, |
|
103 //{ QtMultimediaKit::TrackCount, 0 }, |
|
104 //{ QtMultimediaKit::CoverArtUrlSmall, 0 }, |
|
105 //{ QtMultimediaKit::CoverArtUrlLarge, 0 }, |
|
106 |
|
107 // Image/Video |
|
108 //{ QtMultimediaKit::Resolution, 0 }, |
|
109 //{ QtMultimediaKit::PixelAspectRatio, 0 }, |
|
110 |
|
111 // Video |
|
112 //{ QtMultimediaKit::FrameRate, 0 }, |
|
113 { QtMultimediaKit::VideoBitRate, L"VideoBitRate" }, |
|
114 { QtMultimediaKit::VideoCodec, L"VideoCodec" }, |
|
115 |
|
116 //{ QtMultimediaKit::PosterUrl, 0 }, |
|
117 |
|
118 // Movie |
|
119 { QtMultimediaKit::ChapterNumber, L"ChapterNumber" }, |
|
120 { QtMultimediaKit::Director, L"WM/Director" }, |
|
121 { QtMultimediaKit::LeadPerformer, L"LeadPerformer" }, |
|
122 { QtMultimediaKit::Writer, L"WM/Writer" }, |
|
123 |
|
124 // Photos |
|
125 { QtMultimediaKit::CameraManufacturer, L"CameraManufacturer" }, |
|
126 { QtMultimediaKit::CameraModel, L"CameraModel" }, |
|
127 { QtMultimediaKit::Event, L"Event" }, |
|
128 { QtMultimediaKit::Subject, L"Subject" } |
|
129 }; |
|
130 |
|
131 QWmpMetaData::QWmpMetaData(IWMPCore3 *player, QWmpEvents *events, QObject *parent) |
|
132 : QMetaDataReaderControl(parent) |
|
133 , m_media(0) |
|
134 { |
|
135 player->get_currentMedia(&m_media); |
|
136 |
|
137 connect(events, SIGNAL(CurrentItemChange(IDispatch*)), |
|
138 this, SLOT(currentItemChangeEvent(IDispatch*))); |
|
139 connect(events, SIGNAL(MediaChange(IDispatch*)), this, SLOT(mediaChangeEvent(IDispatch*))); |
|
140 } |
|
141 |
|
142 QWmpMetaData::~QWmpMetaData() |
|
143 { |
|
144 if (m_media) |
|
145 m_media->Release(); |
|
146 } |
|
147 |
|
148 bool QWmpMetaData::isMetaDataAvailable() const |
|
149 { |
|
150 return m_media != 0; |
|
151 } |
|
152 |
|
153 bool QWmpMetaData::isWritable() const |
|
154 { |
|
155 return m_media != 0; |
|
156 } |
|
157 |
|
158 QVariant QWmpMetaData::metaData(QtMultimediaKit::MetaData key) const |
|
159 { |
|
160 static const int count = sizeof(qt_wmpMetaDataKeys) / sizeof(QWmpMetaDataKeyLookup); |
|
161 |
|
162 switch (key) { |
|
163 case QtMultimediaKit::Date: |
|
164 { |
|
165 QVariant day = value(m_media, QAutoBStr(L"ReleaseDateDay")); |
|
166 QVariant month = value(m_media, QAutoBStr(L"ReleaseDateMonth")); |
|
167 QVariant year = value(m_media, QAutoBStr(L"ReleaseDateYear")); |
|
168 |
|
169 if (!day.isNull() && !month.isNull() && !year.isNull()) |
|
170 return QDate(year.toInt(), month.toInt(), day.toInt()); |
|
171 } |
|
172 break; |
|
173 case QtMultimediaKit::CoverArtUrlSmall: |
|
174 return albumArtUrl(m_media, "_Small.jpg"); |
|
175 case QtMultimediaKit::CoverArtUrlLarge: |
|
176 return albumArtUrl(m_media, "_Large.jpg"); |
|
177 case QtMultimediaKit::Resolution: |
|
178 { |
|
179 QVariant width = value(m_media, QAutoBStr(L"WM/VideoWidth")); |
|
180 QVariant height = value(m_media, QAutoBStr(L"WM/VideoHeight")); |
|
181 |
|
182 if (!width.isNull() && !height.isNull()) |
|
183 return QSize(width.toInt(), height.toInt()); |
|
184 } |
|
185 break; |
|
186 case QtMultimediaKit::PixelAspectRatio: |
|
187 { |
|
188 QVariant x = value(m_media, QAutoBStr(L"PixelAspectRatioX")); |
|
189 QVariant y = value(m_media, QAutoBStr(L"PixelAspectRatioY")); |
|
190 |
|
191 if (!x.isNull() && !y.isNull()) |
|
192 return QSize(x.toInt(), y.toInt()); |
|
193 } |
|
194 break; |
|
195 case QtMultimediaKit::VideoFrameRate: |
|
196 break; |
|
197 default: |
|
198 for (int i = 0; i < count; ++i) { |
|
199 if (qt_wmpMetaDataKeys[i].key == key) |
|
200 return value(m_media, QAutoBStr(qt_wmpMetaDataKeys[i].token)); |
|
201 } |
|
202 break; |
|
203 } |
|
204 return QVariant(); |
|
205 } |
|
206 |
|
207 QList<QtMultimediaKit::MetaData> QWmpMetaData::availableMetaData() const |
|
208 { |
|
209 QList<QtMultimediaKit::MetaData> keys; |
|
210 |
|
211 if (m_media) { |
|
212 // WMP will return a list of all possible keys so there's no point in filtering the keys |
|
213 // in the lookup table. |
|
214 static const int count = sizeof(qt_wmpMetaDataKeys) / sizeof(QWmpMetaDataKeyLookup); |
|
215 for (int i = 0; i < count; ++i) |
|
216 keys.append(qt_wmpMetaDataKeys[i].key); |
|
217 |
|
218 BSTR string = 0; |
|
219 if (m_media->get_sourceURL(&string) == S_OK) { |
|
220 QString url = QString::fromWCharArray(static_cast<const wchar_t *>(string)); |
|
221 ::SysFreeString(string); |
|
222 |
|
223 if (m_media->getItemInfo(QAutoBStr(L"WM/WMCollectionGroupID"), &string) == S_OK) { |
|
224 QString uuid = QString::fromWCharArray(static_cast<const wchar_t *>(string)); |
|
225 ::SysFreeString(string); |
|
226 |
|
227 QString albumArtLarge = QLatin1String("AlbumArt_") + uuid + QLatin1String("_Large.jpg"); |
|
228 QString albumArtSmall = QLatin1String("AlbumArt_") + uuid + QLatin1String("_Small.jpg"); |
|
229 |
|
230 QDir dir = QFileInfo(url).absoluteDir(); |
|
231 |
|
232 if (dir.exists(albumArtLarge)) |
|
233 keys.append(QtMultimediaKit::CoverArtUrlLarge); |
|
234 if (dir.exists(albumArtSmall)) |
|
235 keys.append(QtMultimediaKit::CoverArtUrlSmall); |
|
236 } |
|
237 } |
|
238 } |
|
239 return keys; |
|
240 } |
|
241 |
|
242 QVariant QWmpMetaData::extendedMetaData(const QString &key) const |
|
243 { |
|
244 return value(m_media, QAutoBStr(key)); |
|
245 } |
|
246 |
|
247 QStringList QWmpMetaData::availableExtendedMetaData() const |
|
248 { |
|
249 return keys(m_media); |
|
250 } |
|
251 |
|
252 void QWmpMetaData::currentItemChangeEvent(IDispatch *dispatch) |
|
253 { |
|
254 IWMPMedia *media = m_media; |
|
255 |
|
256 m_media = 0; |
|
257 if (dispatch) |
|
258 dispatch->QueryInterface(__uuidof(IWMPMedia), reinterpret_cast<void **>(&m_media)); |
|
259 |
|
260 if (media) { |
|
261 if (m_media) |
|
262 emit metaDataChanged(); |
|
263 else |
|
264 emit metaDataAvailableChanged(false); |
|
265 |
|
266 media->Release(); |
|
267 } else { |
|
268 if (m_media) |
|
269 emit metaDataAvailableChanged(false); |
|
270 } |
|
271 } |
|
272 |
|
273 void QWmpMetaData::mediaChangeEvent(IDispatch *dispatch) |
|
274 { |
|
275 IWMPMedia *media = 0; |
|
276 if (dispatch && dispatch->QueryInterface( |
|
277 __uuidof(IWMPMedia), reinterpret_cast<void **>(&media)) == S_OK) { |
|
278 VARIANT_BOOL isEqual = VARIANT_FALSE; |
|
279 if (media->get_isIdentical(m_media, &isEqual) == S_OK && isEqual) |
|
280 emit metaDataChanged(); |
|
281 media->Release(); |
|
282 } |
|
283 } |
|
284 |
|
285 |
|
286 QStringList QWmpMetaData::keys(IWMPMedia *media) |
|
287 { |
|
288 QStringList keys; |
|
289 |
|
290 long count = 0; |
|
291 if (media && media->get_attributeCount(&count) == S_OK) { |
|
292 for (long i = 0; i < count; ++i) { |
|
293 BSTR string; |
|
294 if (media->getAttributeName(i, &string) == S_OK) { |
|
295 keys.append(QString::fromWCharArray(string, ::SysStringLen(string))); |
|
296 |
|
297 ::SysFreeString(string); |
|
298 } |
|
299 } |
|
300 } |
|
301 return keys; |
|
302 } |
|
303 |
|
304 QVariant QWmpMetaData::value(IWMPMedia *media, BSTR key) |
|
305 { |
|
306 QVariantList values; |
|
307 IWMPMedia3 *media3 = 0; |
|
308 if (media && media->QueryInterface( |
|
309 __uuidof(IWMPMedia3), reinterpret_cast<void **>(&media3)) == S_OK) { |
|
310 long count = 0; |
|
311 media3->getAttributeCountByType(key, 0, &count); |
|
312 |
|
313 // The count appears to only be valid for static properties, dynamic properties like |
|
314 // PlaylistIndex will have a count of zero but return a value for index 0. |
|
315 if (count == 0) |
|
316 count = 1; |
|
317 |
|
318 for (long i = 0; i < count; ++i) { |
|
319 VARIANT var; |
|
320 VariantInit(&var); |
|
321 |
|
322 if (media3->getItemInfoByType(key, 0, i, &var) == S_OK) { |
|
323 QVariant value = convertVariant(var); |
|
324 |
|
325 if (!value.isNull()) |
|
326 values.append(value); |
|
327 |
|
328 VariantClear(&var); |
|
329 } |
|
330 } |
|
331 media3->Release(); |
|
332 } |
|
333 |
|
334 switch (values.count()) { |
|
335 case 0: |
|
336 return QVariant(); |
|
337 case 1: |
|
338 return values.first(); |
|
339 default: |
|
340 return values; |
|
341 } |
|
342 } |
|
343 |
|
344 QMediaContent QWmpMetaData::resources(IWMPMedia *media) |
|
345 { |
|
346 QMediaContent content; |
|
347 |
|
348 BSTR string = 0; |
|
349 if (media->get_sourceURL(&string) == S_OK) { |
|
350 QString url = QString::fromWCharArray(static_cast<const wchar_t *>(string)); |
|
351 ::SysFreeString(string); |
|
352 |
|
353 content = QMediaContent(QUrl(url)); |
|
354 } |
|
355 |
|
356 return content; |
|
357 } |
|
358 |
|
359 QVariant QWmpMetaData::convertVariant(const VARIANT &variant) |
|
360 { |
|
361 switch (variant.vt) { |
|
362 case VT_I2: |
|
363 return variant.iVal; |
|
364 case VT_I4: |
|
365 return variant.lVal; |
|
366 case VT_I8: |
|
367 return variant.llVal; |
|
368 case VT_UI2: |
|
369 return variant.uiVal; |
|
370 case VT_UI4: |
|
371 return quint32(variant.ulVal); |
|
372 case VT_UI8: |
|
373 return variant.ullVal; |
|
374 case VT_INT: |
|
375 return variant.intVal; |
|
376 case VT_UINT: |
|
377 return variant.uintVal; |
|
378 case VT_BSTR: |
|
379 return QString::fromWCharArray(variant.bstrVal, ::SysStringLen(variant.bstrVal)); |
|
380 case VT_DISPATCH: |
|
381 { |
|
382 IWMPMetadataPicture *picture = 0; |
|
383 IWMPMetadataText *text = 0; |
|
384 |
|
385 if (variant.pdispVal->QueryInterface( |
|
386 __uuidof(IWMPMetadataPicture), reinterpret_cast<void **>(&picture)) == S_OK) { |
|
387 QUrl url; |
|
388 BSTR string; |
|
389 if (picture->get_URL(&string) == S_OK) { |
|
390 url = QUrl(QString::fromWCharArray(string, ::SysStringLen(string))); |
|
391 |
|
392 ::SysFreeString(string); |
|
393 } |
|
394 picture->Release(); |
|
395 return qVariantFromValue(url); |
|
396 } else if (variant.pdispVal->QueryInterface( |
|
397 __uuidof(IWMPMetadataText), reinterpret_cast<void **>(&text)) == S_OK) { |
|
398 QString description; |
|
399 BSTR string; |
|
400 if (text->get_description(&string) == S_OK) { |
|
401 description = QString::fromWCharArray(string, SysStringLen(string)); |
|
402 |
|
403 ::SysFreeString(string); |
|
404 } |
|
405 text->Release(); |
|
406 return description; |
|
407 } else { |
|
408 qWarning("Unknown dispatch type"); |
|
409 } |
|
410 } |
|
411 break; |
|
412 default: |
|
413 qWarning("Unsupported Type %d %x", variant.vt, variant.vt); |
|
414 break; |
|
415 } |
|
416 |
|
417 return QVariant(); |
|
418 } |
|
419 |
|
420 QVariant QWmpMetaData::albumArtUrl(IWMPMedia *media, const char *suffix) |
|
421 { |
|
422 BSTR string = 0; |
|
423 if (media && media->get_sourceURL(&string) == S_OK) { |
|
424 QString url = QString::fromWCharArray(static_cast<const wchar_t *>(string)); |
|
425 ::SysFreeString(string); |
|
426 |
|
427 if (media->getItemInfo(QAutoBStr(L"WM/WMCollectionGroupID"), &string) == S_OK) { |
|
428 QString uuid = QString::fromWCharArray(static_cast<const wchar_t *>(string)); |
|
429 ::SysFreeString(string); |
|
430 |
|
431 QString fileName = QLatin1String("AlbumArt_") + uuid + QLatin1String(suffix); |
|
432 |
|
433 QDir dir = QFileInfo(url).absoluteDir(); |
|
434 |
|
435 if (dir.exists(fileName)) { |
|
436 return qVariantFromValue( |
|
437 QUrl(QLatin1String("file:///") + dir.absoluteFilePath(fileName))); |
|
438 } |
|
439 } |
|
440 } |
|
441 return QVariant(); |
|
442 } |