1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "camerabinmetadata.h" |
41 | |
42 | #include <QtMultimedia/qmediametadata.h> |
43 | |
44 | #include <gst/gst.h> |
45 | #include <gst/gstversion.h> |
46 | #include <private/qgstutils_p.h> |
47 | |
48 | #include <QDebug> |
49 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | namespace { |
53 | struct QGStreamerMetaDataKey |
54 | { |
55 | QString qtName; |
56 | const char *gstName; |
57 | QVariant::Type type; |
58 | |
59 | QGStreamerMetaDataKey(const QString &qtn, const char *gstn, QVariant::Type t) |
60 | : qtName(qtn) |
61 | , gstName(gstn) |
62 | , type(t) |
63 | { } |
64 | }; |
65 | } |
66 | |
67 | typedef QList<QGStreamerMetaDataKey> QGStreamerMetaDataKeys; |
68 | Q_GLOBAL_STATIC(QGStreamerMetaDataKeys, metadataKeys) |
69 | |
70 | static const QGStreamerMetaDataKeys *qt_gstreamerMetaDataKeys() |
71 | { |
72 | if (metadataKeys->isEmpty()) { |
73 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Title, GST_TAG_TITLE, QVariant::String)); |
74 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::SubTitle, 0, QVariant::String)); |
75 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Author, 0, QVariant::String)); |
76 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Comment, GST_TAG_COMMENT, QVariant::String)); |
77 | #if GST_CHECK_VERSION(0,10,31) |
78 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Date, GST_TAG_DATE_TIME, QVariant::DateTime)); |
79 | #endif |
80 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Description, GST_TAG_DESCRIPTION, QVariant::String)); |
81 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Category, 0, QVariant::String)); |
82 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Genre, GST_TAG_GENRE, QVariant::String)); |
83 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Year, 0, QVariant::Int)); |
84 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::UserRating, , QVariant::Int)); |
85 | |
86 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Language, GST_TAG_LANGUAGE_CODE, QVariant::String)); |
87 | |
88 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Publisher, GST_TAG_ORGANIZATION, QVariant::String)); |
89 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Copyright, GST_TAG_COPYRIGHT, QVariant::String)); |
90 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::ParentalRating, 0, QVariant::String)); |
91 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::RatingOrganisation, 0, QVariant::String)); |
92 | |
93 | // Media |
94 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Size, 0, QVariant::Int)); |
95 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::MediaType, 0, QVariant::String)); |
96 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Duration, GST_TAG_DURATION, QVariant::Int)); |
97 | |
98 | // Audio |
99 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::AudioBitRate, GST_TAG_BITRATE, QVariant::Int)); |
100 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::AudioCodec, GST_TAG_AUDIO_CODEC, QVariant::String)); |
101 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::ChannelCount, 0, QVariant::Int)); |
102 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::SampleRate, 0, QVariant::Int)); |
103 | |
104 | // Music |
105 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::AlbumTitle, GST_TAG_ALBUM, QVariant::String)); |
106 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::AlbumArtist, GST_TAG_ARTIST, QVariant::String)); |
107 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::ContributingArtist, GST_TAG_PERFORMER, QVariant::String)); |
108 | #if GST_CHECK_VERSION(0,10,19) |
109 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Composer, GST_TAG_COMPOSER, QVariant::String)); |
110 | #endif |
111 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Conductor, 0, QVariant::String)); |
112 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Lyrics, 0, QVariant::String)); |
113 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Mood, 0, QVariant::String)); |
114 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::TrackNumber, GST_TAG_TRACK_NUMBER, QVariant::Int)); |
115 | |
116 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::CoverArtUrlSmall, 0, QVariant::String)); |
117 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::CoverArtUrlLarge, 0, QVariant::String)); |
118 | |
119 | // Image/Video |
120 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Resolution, 0, QVariant::Size)); |
121 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::PixelAspectRatio, 0, QVariant::Size)); |
122 | |
123 | // Video |
124 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::VideoFrameRate, 0, QVariant::String)); |
125 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::VideoBitRate, 0, QVariant::Double)); |
126 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::VideoCodec, GST_TAG_VIDEO_CODEC, QVariant::String)); |
127 | |
128 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::PosterUrl, 0, QVariant::String)); |
129 | |
130 | // Movie |
131 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::ChapterNumber, 0, QVariant::Int)); |
132 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Director, 0, QVariant::String)); |
133 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::LeadPerformer, GST_TAG_PERFORMER, QVariant::String)); |
134 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Writer, 0, QVariant::String)); |
135 | #if GST_CHECK_VERSION(0,10,30) |
136 | // Photos |
137 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::CameraManufacturer, GST_TAG_DEVICE_MANUFACTURER, QVariant::String)); |
138 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::CameraModel, GST_TAG_DEVICE_MODEL, QVariant::String)); |
139 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Event, 0, QVariant::String)); |
140 | //metadataKeys->append(QGStreamerMetaDataKey(QMediaMetaData::Subject, 0, QVariant::String)); |
141 | |
142 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::Orientation, GST_TAG_IMAGE_ORIENTATION, QVariant::String)); |
143 | |
144 | // GPS |
145 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::GPSLatitude, GST_TAG_GEO_LOCATION_LATITUDE, QVariant::Double)); |
146 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::GPSLongitude, GST_TAG_GEO_LOCATION_LONGITUDE, QVariant::Double)); |
147 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::GPSAltitude, GST_TAG_GEO_LOCATION_ELEVATION, QVariant::Double)); |
148 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::GPSTrack, GST_TAG_GEO_LOCATION_MOVEMENT_DIRECTION, QVariant::Double)); |
149 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::GPSSpeed, GST_TAG_GEO_LOCATION_MOVEMENT_SPEED, QVariant::Double)); |
150 | metadataKeys->append(t: QGStreamerMetaDataKey(QMediaMetaData::GPSImgDirection, GST_TAG_GEO_LOCATION_CAPTURE_DIRECTION, QVariant::Double)); |
151 | #endif |
152 | } |
153 | |
154 | return metadataKeys; |
155 | } |
156 | |
157 | CameraBinMetaData::CameraBinMetaData(QObject *parent) |
158 | :QMetaDataWriterControl(parent) |
159 | { |
160 | } |
161 | |
162 | QVariant CameraBinMetaData::metaData(const QString &key) const |
163 | { |
164 | #if GST_CHECK_VERSION(0,10,30) |
165 | if (key == QMediaMetaData::Orientation) { |
166 | return QGstUtils::fromGStreamerOrientation(value: m_values.value(akey: QByteArray(GST_TAG_IMAGE_ORIENTATION))); |
167 | } else if (key == QMediaMetaData::GPSSpeed) { |
168 | const double metersPerSec = m_values.value(akey: QByteArray(GST_TAG_GEO_LOCATION_MOVEMENT_SPEED)).toDouble(); |
169 | return (metersPerSec * 3600) / 1000; |
170 | } |
171 | #endif |
172 | |
173 | const auto keys = *qt_gstreamerMetaDataKeys(); |
174 | for (const QGStreamerMetaDataKey &metadataKey : keys) { |
175 | if (metadataKey.qtName == key) |
176 | return m_values.value(akey: QByteArray::fromRawData(metadataKey.gstName, size: qstrlen(str: metadataKey.gstName))); |
177 | } |
178 | return QVariant(); |
179 | } |
180 | |
181 | void CameraBinMetaData::setMetaData(const QString &key, const QVariant &value) |
182 | { |
183 | QVariant correctedValue = value; |
184 | #if GST_CHECK_VERSION(0,10,30) |
185 | if (value.isValid()) { |
186 | if (key == QMediaMetaData::Orientation) { |
187 | correctedValue = QGstUtils::toGStreamerOrientation(value); |
188 | } else if (key == QMediaMetaData::GPSSpeed) { |
189 | // kilometers per hour to meters per second. |
190 | correctedValue = (value.toDouble() * 1000) / 3600; |
191 | } |
192 | } |
193 | #endif |
194 | |
195 | const auto keys = *qt_gstreamerMetaDataKeys(); |
196 | for (const QGStreamerMetaDataKey &metadataKey : keys) { |
197 | if (metadataKey.qtName == key) { |
198 | const char *name = metadataKey.gstName; |
199 | |
200 | if (correctedValue.isValid()) { |
201 | correctedValue.convert(targetTypeId: metadataKey.type); |
202 | m_values.insert(akey: QByteArray::fromRawData(name, size: qstrlen(str: name)), avalue: correctedValue); |
203 | } else { |
204 | m_values.remove(akey: QByteArray::fromRawData(name, size: qstrlen(str: name))); |
205 | } |
206 | |
207 | emit QMetaDataWriterControl::metaDataChanged(); |
208 | emit metaDataChanged(m_values); |
209 | |
210 | return; |
211 | } |
212 | } |
213 | } |
214 | |
215 | QStringList CameraBinMetaData::availableMetaData() const |
216 | { |
217 | static QMap<QByteArray, QString> keysMap; |
218 | if (keysMap.isEmpty()) { |
219 | const auto keys = *qt_gstreamerMetaDataKeys(); |
220 | for (const QGStreamerMetaDataKey &metadataKey : keys) |
221 | keysMap[QByteArray(metadataKey.gstName)] = metadataKey.qtName; |
222 | } |
223 | |
224 | QStringList res; |
225 | for (auto it = m_values.keyBegin(), end = m_values.keyEnd(); it != end; ++it) { |
226 | QString tag = keysMap.value(akey: *it); |
227 | if (!tag.isEmpty()) |
228 | res.append(t: tag); |
229 | } |
230 | |
231 | return res; |
232 | } |
233 | |
234 | QT_END_NAMESPACE |
235 | |