/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the Qt Mobility Components. ** ** $QT_BEGIN_LICENSE:LGPL$ ** GNU Lesser General Public License Usage ** This file may be used under the terms of the GNU Lesser General Public ** License version 2.1 as published by the Free Software Foundation and ** appearing in the file LICENSE.LGPL included in the packaging of this ** file. Please review the following information to ensure the GNU Lesser ** General Public License version 2.1 requirements will be met: ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU General ** Public License version 3.0 as published by the Free Software Foundation ** and appearing in the file LICENSE.GPL included in the packaging of this ** file. Please review the following information to ensure the GNU General ** Public License version 3.0 requirements will be met: ** http://www.gnu.org/copyleft/gpl.html. ** ** Other Usage ** Alternatively, this file may be used in accordance with the terms and ** conditions contained in a signed written agreement between you and Nokia. ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qwmpmetadata.h" #include "qwmpevents.h" #include "qwmpglobal.h" #include #include #include #include #include #include #include #include struct QWmpMetaDataKeyLookup { QtMultimediaKit::MetaData key; const wchar_t *token; }; static const QWmpMetaDataKeyLookup qt_wmpMetaDataKeys[] = { { QtMultimediaKit::Title, L"Title" }, { QtMultimediaKit::SubTitle, L"WM/SubTitle" }, { QtMultimediaKit::Author, L"Author" }, { QtMultimediaKit::Comment, L"Comment" }, { QtMultimediaKit::Description, L"Description" }, { QtMultimediaKit::Category, L"WM/Category" }, { QtMultimediaKit::Genre, L"WM/Genre" }, //{ QtMultimediaKit::Date, 0 }, { QtMultimediaKit::Year, L"WM/Year" }, { QtMultimediaKit::UserRating, L"UserRating" }, //{ QtMultimediaKit::MetaDatawords, 0 }, { QtMultimediaKit::Language, L"Language" }, { QtMultimediaKit::Publisher, L"WM/Publisher" }, { QtMultimediaKit::Copyright, L"Copyright" }, { QtMultimediaKit::ParentalRating, L"ParentalRating" }, { QtMultimediaKit::RatingOrganisation, L"RatingOrganisation" }, // Media { QtMultimediaKit::Size, L"FileSize" }, { QtMultimediaKit::MediaType, L"MediaType" }, { QtMultimediaKit::Duration, L"Duration" }, // Audio { QtMultimediaKit::AudioBitRate, L"AudioBitrate" }, { QtMultimediaKit::AudioCodec, L"AudioCodec" }, { QtMultimediaKit::ChannelCount, L"Channels" }, { QtMultimediaKit::SampleRate, L"Frequency" }, // Music { QtMultimediaKit::AlbumTitle, L"WM/AlbumTitle" }, { QtMultimediaKit::AlbumArtist, L"WM/AlbumArtist" }, { QtMultimediaKit::ContributingArtist, L"Author" }, { QtMultimediaKit::Composer, L"WM/Composer" }, { QtMultimediaKit::Conductor, L"WM/Conductor" }, { QtMultimediaKit::Lyrics, L"WM/Lyrics" }, { QtMultimediaKit::Mood, L"WM/Mood" }, { QtMultimediaKit::TrackNumber, L"WM/TrackNumber" }, //{ QtMultimediaKit::TrackCount, 0 }, //{ QtMultimediaKit::CoverArtUrlSmall, 0 }, //{ QtMultimediaKit::CoverArtUrlLarge, 0 }, // Image/Video //{ QtMultimediaKit::Resolution, 0 }, //{ QtMultimediaKit::PixelAspectRatio, 0 }, // Video //{ QtMultimediaKit::FrameRate, 0 }, { QtMultimediaKit::VideoBitRate, L"VideoBitRate" }, { QtMultimediaKit::VideoCodec, L"VideoCodec" }, //{ QtMultimediaKit::PosterUrl, 0 }, // Movie { QtMultimediaKit::ChapterNumber, L"ChapterNumber" }, { QtMultimediaKit::Director, L"WM/Director" }, { QtMultimediaKit::LeadPerformer, L"LeadPerformer" }, { QtMultimediaKit::Writer, L"WM/Writer" }, // Photos { QtMultimediaKit::CameraManufacturer, L"CameraManufacturer" }, { QtMultimediaKit::CameraModel, L"CameraModel" }, { QtMultimediaKit::Event, L"Event" }, { QtMultimediaKit::Subject, L"Subject" } }; QWmpMetaData::QWmpMetaData(IWMPCore3 *player, QWmpEvents *events, QObject *parent) : QMetaDataReaderControl(parent) , m_media(0) { player->get_currentMedia(&m_media); connect(events, SIGNAL(CurrentItemChange(IDispatch*)), this, SLOT(currentItemChangeEvent(IDispatch*))); connect(events, SIGNAL(MediaChange(IDispatch*)), this, SLOT(mediaChangeEvent(IDispatch*))); } QWmpMetaData::~QWmpMetaData() { if (m_media) m_media->Release(); } bool QWmpMetaData::isMetaDataAvailable() const { return m_media != 0; } bool QWmpMetaData::isWritable() const { return m_media != 0; } QVariant QWmpMetaData::metaData(QtMultimediaKit::MetaData key) const { static const int count = sizeof(qt_wmpMetaDataKeys) / sizeof(QWmpMetaDataKeyLookup); switch (key) { case QtMultimediaKit::Date: { QVariant day = value(m_media, QAutoBStr(L"ReleaseDateDay")); QVariant month = value(m_media, QAutoBStr(L"ReleaseDateMonth")); QVariant year = value(m_media, QAutoBStr(L"ReleaseDateYear")); if (!day.isNull() && !month.isNull() && !year.isNull()) return QDate(year.toInt(), month.toInt(), day.toInt()); } break; case QtMultimediaKit::CoverArtUrlSmall: return albumArtUrl(m_media, "_Small.jpg"); case QtMultimediaKit::CoverArtUrlLarge: return albumArtUrl(m_media, "_Large.jpg"); case QtMultimediaKit::Resolution: { QVariant width = value(m_media, QAutoBStr(L"WM/VideoWidth")); QVariant height = value(m_media, QAutoBStr(L"WM/VideoHeight")); if (!width.isNull() && !height.isNull()) return QSize(width.toInt(), height.toInt()); } break; case QtMultimediaKit::PixelAspectRatio: { QVariant x = value(m_media, QAutoBStr(L"PixelAspectRatioX")); QVariant y = value(m_media, QAutoBStr(L"PixelAspectRatioY")); if (!x.isNull() && !y.isNull()) return QSize(x.toInt(), y.toInt()); } break; case QtMultimediaKit::VideoFrameRate: break; default: for (int i = 0; i < count; ++i) { if (qt_wmpMetaDataKeys[i].key == key) return value(m_media, QAutoBStr(qt_wmpMetaDataKeys[i].token)); } break; } return QVariant(); } QList QWmpMetaData::availableMetaData() const { QList keys; if (m_media) { // WMP will return a list of all possible keys so there's no point in filtering the keys // in the lookup table. static const int count = sizeof(qt_wmpMetaDataKeys) / sizeof(QWmpMetaDataKeyLookup); for (int i = 0; i < count; ++i) keys.append(qt_wmpMetaDataKeys[i].key); BSTR string = 0; if (m_media->get_sourceURL(&string) == S_OK) { QString url = QString::fromWCharArray(static_cast(string)); ::SysFreeString(string); if (m_media->getItemInfo(QAutoBStr(L"WM/WMCollectionGroupID"), &string) == S_OK) { QString uuid = QString::fromWCharArray(static_cast(string)); ::SysFreeString(string); QString albumArtLarge = QLatin1String("AlbumArt_") + uuid + QLatin1String("_Large.jpg"); QString albumArtSmall = QLatin1String("AlbumArt_") + uuid + QLatin1String("_Small.jpg"); QDir dir = QFileInfo(url).absoluteDir(); if (dir.exists(albumArtLarge)) keys.append(QtMultimediaKit::CoverArtUrlLarge); if (dir.exists(albumArtSmall)) keys.append(QtMultimediaKit::CoverArtUrlSmall); } } } return keys; } QVariant QWmpMetaData::extendedMetaData(const QString &key) const { return value(m_media, QAutoBStr(key)); } QStringList QWmpMetaData::availableExtendedMetaData() const { return keys(m_media); } void QWmpMetaData::currentItemChangeEvent(IDispatch *dispatch) { IWMPMedia *media = m_media; m_media = 0; if (dispatch) dispatch->QueryInterface(__uuidof(IWMPMedia), reinterpret_cast(&m_media)); if (media) { if (m_media) emit metaDataChanged(); else emit metaDataAvailableChanged(false); media->Release(); } else { if (m_media) emit metaDataAvailableChanged(false); } } void QWmpMetaData::mediaChangeEvent(IDispatch *dispatch) { IWMPMedia *media = 0; if (dispatch && dispatch->QueryInterface( __uuidof(IWMPMedia), reinterpret_cast(&media)) == S_OK) { VARIANT_BOOL isEqual = VARIANT_FALSE; if (media->get_isIdentical(m_media, &isEqual) == S_OK && isEqual) emit metaDataChanged(); media->Release(); } } QStringList QWmpMetaData::keys(IWMPMedia *media) { QStringList keys; long count = 0; if (media && media->get_attributeCount(&count) == S_OK) { for (long i = 0; i < count; ++i) { BSTR string; if (media->getAttributeName(i, &string) == S_OK) { keys.append(QString::fromWCharArray(string, ::SysStringLen(string))); ::SysFreeString(string); } } } return keys; } QVariant QWmpMetaData::value(IWMPMedia *media, BSTR key) { QVariantList values; IWMPMedia3 *media3 = 0; if (media && media->QueryInterface( __uuidof(IWMPMedia3), reinterpret_cast(&media3)) == S_OK) { long count = 0; media3->getAttributeCountByType(key, 0, &count); // The count appears to only be valid for static properties, dynamic properties like // PlaylistIndex will have a count of zero but return a value for index 0. if (count == 0) count = 1; for (long i = 0; i < count; ++i) { VARIANT var; VariantInit(&var); if (media3->getItemInfoByType(key, 0, i, &var) == S_OK) { QVariant value = convertVariant(var); if (!value.isNull()) values.append(value); VariantClear(&var); } } media3->Release(); } switch (values.count()) { case 0: return QVariant(); case 1: return values.first(); default: return values; } } QMediaContent QWmpMetaData::resources(IWMPMedia *media) { QMediaContent content; BSTR string = 0; if (media->get_sourceURL(&string) == S_OK) { QString url = QString::fromWCharArray(static_cast(string)); ::SysFreeString(string); content = QMediaContent(QUrl(url)); } return content; } QVariant QWmpMetaData::convertVariant(const VARIANT &variant) { switch (variant.vt) { case VT_I2: return variant.iVal; case VT_I4: return variant.lVal; case VT_I8: return variant.llVal; case VT_UI2: return variant.uiVal; case VT_UI4: return quint32(variant.ulVal); case VT_UI8: return variant.ullVal; case VT_INT: return variant.intVal; case VT_UINT: return variant.uintVal; case VT_BSTR: return QString::fromWCharArray(variant.bstrVal, ::SysStringLen(variant.bstrVal)); case VT_DISPATCH: { IWMPMetadataPicture *picture = 0; IWMPMetadataText *text = 0; if (variant.pdispVal->QueryInterface( __uuidof(IWMPMetadataPicture), reinterpret_cast(&picture)) == S_OK) { QUrl url; BSTR string; if (picture->get_URL(&string) == S_OK) { url = QUrl(QString::fromWCharArray(string, ::SysStringLen(string))); ::SysFreeString(string); } picture->Release(); return qVariantFromValue(url); } else if (variant.pdispVal->QueryInterface( __uuidof(IWMPMetadataText), reinterpret_cast(&text)) == S_OK) { QString description; BSTR string; if (text->get_description(&string) == S_OK) { description = QString::fromWCharArray(string, SysStringLen(string)); ::SysFreeString(string); } text->Release(); return description; } else { qWarning("Unknown dispatch type"); } } break; default: qWarning("Unsupported Type %d %x", variant.vt, variant.vt); break; } return QVariant(); } QVariant QWmpMetaData::albumArtUrl(IWMPMedia *media, const char *suffix) { BSTR string = 0; if (media && media->get_sourceURL(&string) == S_OK) { QString url = QString::fromWCharArray(static_cast(string)); ::SysFreeString(string); if (media->getItemInfo(QAutoBStr(L"WM/WMCollectionGroupID"), &string) == S_OK) { QString uuid = QString::fromWCharArray(static_cast(string)); ::SysFreeString(string); QString fileName = QLatin1String("AlbumArt_") + uuid + QLatin1String(suffix); QDir dir = QFileInfo(url).absoluteDir(); if (dir.exists(fileName)) { return qVariantFromValue( QUrl(QLatin1String("file:///") + dir.absoluteFilePath(fileName))); } } } return QVariant(); }