|
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 "qt7backend.h" |
|
43 #include "qt7playermetadata.h" |
|
44 #include "qt7playersession.h" |
|
45 #include <QtCore/qvarlengtharray.h> |
|
46 |
|
47 #import <QTKit/QTMovie.h> |
|
48 |
|
49 #ifdef QUICKTIME_C_API_AVAILABLE |
|
50 #include <QuickTime/QuickTime.h> |
|
51 #undef check // avoid name clash; |
|
52 #endif |
|
53 |
|
54 QT_USE_NAMESPACE |
|
55 |
|
56 QT7PlayerMetaDataControl::QT7PlayerMetaDataControl(QT7PlayerSession *session, QObject *parent) |
|
57 :QMetaDataReaderControl(parent), m_session(session) |
|
58 { |
|
59 } |
|
60 |
|
61 QT7PlayerMetaDataControl::~QT7PlayerMetaDataControl() |
|
62 { |
|
63 } |
|
64 |
|
65 bool QT7PlayerMetaDataControl::isMetaDataAvailable() const |
|
66 { |
|
67 return !m_tags.isEmpty(); |
|
68 } |
|
69 |
|
70 bool QT7PlayerMetaDataControl::isWritable() const |
|
71 { |
|
72 return false; |
|
73 } |
|
74 |
|
75 QVariant QT7PlayerMetaDataControl::metaData(QtMultimediaKit::MetaData key) const |
|
76 { |
|
77 return m_tags.value(key); |
|
78 } |
|
79 |
|
80 QList<QtMultimediaKit::MetaData> QT7PlayerMetaDataControl::availableMetaData() const |
|
81 { |
|
82 return m_tags.keys(); |
|
83 } |
|
84 |
|
85 QVariant QT7PlayerMetaDataControl::extendedMetaData(const QString &key) const |
|
86 { |
|
87 Q_UNUSED(key); |
|
88 return QVariant(); |
|
89 } |
|
90 |
|
91 QStringList QT7PlayerMetaDataControl::availableExtendedMetaData() const |
|
92 { |
|
93 return QStringList(); |
|
94 } |
|
95 |
|
96 #ifdef QUICKTIME_C_API_AVAILABLE |
|
97 |
|
98 static QString stripCopyRightSymbol(const QString &key) |
|
99 { |
|
100 return key.right(key.length()-1); |
|
101 } |
|
102 |
|
103 static QString convertQuickTimeKeyToUserKey(const QString &key) |
|
104 { |
|
105 if (key == QLatin1String("com.apple.quicktime.displayname")) |
|
106 return QLatin1String("nam"); |
|
107 else if (key == QLatin1String("com.apple.quicktime.album")) |
|
108 return QLatin1String("alb"); |
|
109 else if (key == QLatin1String("com.apple.quicktime.artist")) |
|
110 return QLatin1String("ART"); |
|
111 else |
|
112 return QLatin1String("???"); |
|
113 } |
|
114 |
|
115 static OSStatus readMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, QTPropertyClass propClass, |
|
116 QTPropertyID id, QTPropertyValuePtr *value, ByteCount *size) |
|
117 { |
|
118 QTPropertyValueType type; |
|
119 ByteCount propSize; |
|
120 UInt32 propFlags; |
|
121 OSStatus err = QTMetaDataGetItemPropertyInfo(metaDataRef, item, propClass, id, &type, &propSize, &propFlags); |
|
122 |
|
123 if (err == noErr) { |
|
124 *value = malloc(propSize); |
|
125 if (*value != 0) { |
|
126 err = QTMetaDataGetItemProperty(metaDataRef, item, propClass, id, propSize, *value, size); |
|
127 |
|
128 if (err == noErr && (type == 'code' || type == 'itsk' || type == 'itlk')) { |
|
129 // convert from native endian to big endian |
|
130 OSTypePtr pType = (OSTypePtr)*value; |
|
131 *pType = EndianU32_NtoB(*pType); |
|
132 } |
|
133 } |
|
134 else |
|
135 return -1; |
|
136 } |
|
137 |
|
138 return err; |
|
139 } |
|
140 |
|
141 static UInt32 getMetaType(QTMetaDataRef metaDataRef, QTMetaDataItem item) |
|
142 { |
|
143 QTPropertyValuePtr value = 0; |
|
144 ByteCount ignore = 0; |
|
145 OSStatus err = readMetaValue( |
|
146 metaDataRef, item, kPropertyClass_MetaDataItem, kQTMetaDataItemPropertyID_DataType, &value, &ignore); |
|
147 |
|
148 if (err == noErr) { |
|
149 UInt32 type = *((UInt32 *) value); |
|
150 if (value) |
|
151 free(value); |
|
152 return type; |
|
153 } |
|
154 |
|
155 return 0; |
|
156 } |
|
157 |
|
158 static QString cFStringToQString(CFStringRef str) |
|
159 { |
|
160 if(!str) |
|
161 return QString(); |
|
162 CFIndex length = CFStringGetLength(str); |
|
163 const UniChar *chars = CFStringGetCharactersPtr(str); |
|
164 if (chars) |
|
165 return QString(reinterpret_cast<const QChar *>(chars), length); |
|
166 |
|
167 QVarLengthArray<UniChar> buffer(length); |
|
168 CFStringGetCharacters(str, CFRangeMake(0, length), buffer.data()); |
|
169 return QString(reinterpret_cast<const QChar *>(buffer.constData()), length); |
|
170 } |
|
171 |
|
172 |
|
173 static QString getMetaValue(QTMetaDataRef metaDataRef, QTMetaDataItem item, SInt32 id) |
|
174 { |
|
175 QTPropertyValuePtr value = 0; |
|
176 ByteCount size = 0; |
|
177 OSStatus err = readMetaValue(metaDataRef, item, kPropertyClass_MetaDataItem, id, &value, &size); |
|
178 QString string; |
|
179 |
|
180 if (err == noErr) { |
|
181 UInt32 dataType = getMetaType(metaDataRef, item); |
|
182 switch (dataType){ |
|
183 case kQTMetaDataTypeUTF8: |
|
184 case kQTMetaDataTypeMacEncodedText: |
|
185 string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF8, false)); |
|
186 break; |
|
187 case kQTMetaDataTypeUTF16BE: |
|
188 string = cFStringToQString(CFStringCreateWithBytes(0, (UInt8*)value, size, kCFStringEncodingUTF16BE, false)); |
|
189 break; |
|
190 default: |
|
191 break; |
|
192 } |
|
193 |
|
194 if (value) |
|
195 free(value); |
|
196 } |
|
197 |
|
198 return string; |
|
199 } |
|
200 |
|
201 |
|
202 static void readFormattedData(QTMetaDataRef metaDataRef, OSType format, QMultiMap<QString, QString> &result) |
|
203 { |
|
204 QTMetaDataItem item = kQTMetaDataItemUninitialized; |
|
205 OSStatus err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); |
|
206 while (err == noErr){ |
|
207 QString key = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Key); |
|
208 if (format == kQTMetaDataStorageFormatQuickTime) |
|
209 key = convertQuickTimeKeyToUserKey(key); |
|
210 else |
|
211 key = stripCopyRightSymbol(key); |
|
212 |
|
213 if (!result.contains(key)){ |
|
214 QString val = getMetaValue(metaDataRef, item, kQTMetaDataItemPropertyID_Value); |
|
215 result.insert(key, val); |
|
216 } |
|
217 err = QTMetaDataGetNextItem(metaDataRef, format, item, kQTMetaDataKeyFormatWildcard, 0, 0, &item); |
|
218 } |
|
219 } |
|
220 #endif |
|
221 |
|
222 |
|
223 void QT7PlayerMetaDataControl::updateTags() |
|
224 { |
|
225 bool wasEmpty = m_tags.isEmpty(); |
|
226 m_tags.clear(); |
|
227 |
|
228 QTMovie *movie = (QTMovie*)m_session->movie(); |
|
229 |
|
230 if (movie) { |
|
231 QMultiMap<QString, QString> metaMap; |
|
232 |
|
233 #ifdef QUICKTIME_C_API_AVAILABLE |
|
234 QTMetaDataRef metaDataRef; |
|
235 OSStatus err = QTCopyMovieMetaData([movie quickTimeMovie], &metaDataRef); |
|
236 if (err == noErr) { |
|
237 readFormattedData(metaDataRef, kQTMetaDataStorageFormatUserData, metaMap); |
|
238 readFormattedData(metaDataRef, kQTMetaDataStorageFormatQuickTime, metaMap); |
|
239 readFormattedData(metaDataRef, kQTMetaDataStorageFormatiTunes, metaMap); |
|
240 } |
|
241 #else |
|
242 AutoReleasePool pool; |
|
243 NSString *name = [movie attributeForKey:@"QTMovieDisplayNameAttribute"]; |
|
244 metaMap.insert(QLatin1String("nam"), QString::fromUtf8([name UTF8String])); |
|
245 #endif // QUICKTIME_C_API_AVAILABLE |
|
246 |
|
247 m_tags.insert(QtMultimediaKit::AlbumArtist, metaMap.value(QLatin1String("ART"))); |
|
248 m_tags.insert(QtMultimediaKit::AlbumTitle, metaMap.value(QLatin1String("alb"))); |
|
249 m_tags.insert(QtMultimediaKit::Title, metaMap.value(QLatin1String("nam"))); |
|
250 m_tags.insert(QtMultimediaKit::Date, metaMap.value(QLatin1String("day"))); |
|
251 m_tags.insert(QtMultimediaKit::Genre, metaMap.value(QLatin1String("gnre"))); |
|
252 m_tags.insert(QtMultimediaKit::TrackNumber, metaMap.value(QLatin1String("trk"))); |
|
253 m_tags.insert(QtMultimediaKit::Description, metaMap.value(QLatin1String("des"))); |
|
254 } |
|
255 |
|
256 if (!wasEmpty || !m_tags.isEmpty()) |
|
257 emit metaDataChanged(); |
|
258 } |
|
259 |
|
260 #include "moc_qt7playermetadata.cpp" |