diff -r 000000000000 -r 876b1a06bc25 plugins/multimedia/wmp/qwmpmetadata.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/multimedia/wmp/qwmpmetadata.cpp Wed Aug 25 15:49:42 2010 +0300 @@ -0,0 +1,442 @@ +/**************************************************************************** +** +** 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$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $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(); +}