Merge lp:~jamesh/thumbnailer/dbus-service into lp:thumbnailer
- dbus-service
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Jussi Pakkanen |
Approved revision: | 107 |
Merged at revision: | 79 |
Proposed branch: | lp:~jamesh/thumbnailer/dbus-service |
Merge into: | lp:thumbnailer |
Prerequisite: | lp:~jpakkane/thumbnailer/lastfmtest |
Diff against target: |
992 lines (+772/-31) 22 files modified
CMakeLists.txt (+3/-1) debian/changelog (+6/-9) debian/control (+31/-4) debian/qtdeclarative5-ubuntu-thumbnailer0.1.install (+1/-0) debian/thumbnailer-service.install (+2/-0) plugins/Ubuntu/Thumbnailer/CMakeLists.txt (+22/-0) plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp (+90/-0) plugins/Ubuntu/Thumbnailer/albumartgenerator.h (+36/-0) plugins/Ubuntu/Thumbnailer/plugin.cpp (+47/-0) plugins/Ubuntu/Thumbnailer/plugin.h (+34/-0) plugins/Ubuntu/Thumbnailer/qmldir (+2/-0) plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp (+87/-0) plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h (+36/-0) src/CMakeLists.txt (+2/-0) src/service/CMakeLists.txt (+34/-0) src/service/com.canonical.Thumbnailer.service.in (+4/-0) src/service/dbus-interface.xml (+17/-0) src/service/dbusinterface.cpp (+168/-0) src/service/dbusinterface.h (+40/-0) src/service/main.cpp (+44/-0) src/thumbnailer.cpp (+4/-17) tests/qml/tst_image_provider.qml (+62/-0) |
To merge this branch: | bzr merge lp:~jamesh/thumbnailer/dbus-service |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jussi Pakkanen (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+212347@code.launchpad.net |
Commit message
Add a D-Bus service that uses libthumbnailer to download cover art and then provides that art to the client via a read only file descriptor. This allows confined applications to safely access a shared media art cache.
Description of the change
Add a D-Bus service that uses libthumbnailer to download cover art and then provides that art to the client via a read only file descriptor. This allows confined applications to safely access a shared media art cache.
I've put the service in its own binary package marked "Multi-Arch: foreign", since we only need one copy installed on multi-arch systems, and the D-Bus interface should be usable by all architectures on the system.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 98. By James Henstridge
-
Fix up installation of service file.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:98
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Jussi Pakkanen (jpakkane) wrote : | # |
> catch (std::exception &e)
The recommended practice is to catch exceptions by const ref rather than plain ref.
> std::thread t(&getCoverArt,
This may throw, please wrap in try/catch.
> // This should be replaced with actual lookup code.
I think it has been. :)
> /**
> + * A class that sends a broadcast signal that the state of media
> + * files has changed.
> + */
This is still from InvalidationSender and thus not accurate.
Jussi Pakkanen (jpakkane) wrote : | # |
The code talks about album art but the method is called GetCoverArt. We should use one term consistently here, I vote for AlbumArt.
James Henstridge (jamesh) wrote : | # |
Good catch. It looks like I introduced that discrepancy when cleaning up the ubuntu-ui-toolkit branch (looking at the strings in the .so I was testing shows GetCoverArt). I've updated this branch in favour of GetAlbumArt, to match the C++ API name.
- 99. By James Henstridge
-
Update per Jussi's review comments.
James Henstridge (jamesh) wrote : | # |
I've done fresh builds of thumbnailer and ubuntu-ui-toolkit packages, and verified that they talk to each other correctly with these changes.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:99
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Jussi Pakkanen (jpakkane) wrote : | # |
Here's something that bothers me:
static void getAlbumArt(
unique_
This function takes a unique_gobj by value but unique_gobj does not have a copy constructor or operator=. Maybe it invokes the move constructor because it is called with a temporary object?
Anyhow, it works so if no-one can give a feasible case why this would break I'm fine with merging this.
James Henstridge (jamesh) wrote : | # |
The move constructor is the only way this could work, yes.
That said, there isn't much reason the type couldn't have a copy constructor: it's holding a reference counted object after all.
- 100. By James Henstridge
-
Copy over the libthumbnailer QML image providers over from
ubuntu-ui-toolkit. - 101. By James Henstridge
-
Add packaging for thumbnailer QML plugin.
- 102. By James Henstridge
-
Register a bogus type so the QML module can be imported.
James Henstridge (jamesh) wrote : | # |
MP updated with QML plugin code. Note that the bogus qmlRegisterType call is necessary for the plugin to be recognised: plugins that don't register any types are considered broken.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:102
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 103. By James Henstridge
-
Merge from trunk, fixing conflicts.
- 104. By James Henstridge
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:103
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:104
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Jussi Pakkanen (jpakkane) wrote : | # |
The main issue seems to be that the service is called thumbnailer-
That being said, here are a few minor things:
"__ThumbnailerI
#ifndef PLUGIN_H is a bit too generic and may clash, should be THUMBNAILERPLUGIN_H or somesuch.
- 105. By James Henstridge
-
Add a test for the image provider. Not currently hooked up as an
automated test, since it can't run headless.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:105
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 106. By James Henstridge
-
Add a note to the D-Bus interface definition file warning about security
considerations when adding new methods to the service.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:106
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 107. By James Henstridge
-
Other fixes from Jussi's review comments.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:107
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-03-28 10:11:10 +0000 |
3 | +++ CMakeLists.txt 2014-03-28 10:11:10 +0000 |
4 | @@ -29,9 +29,10 @@ |
5 | set(SHARE_PRIV_ABS ${CMAKE_INSTALL_PREFIX}/${SHARE_PRIV_DIR}) |
6 | |
7 | find_package(Threads REQUIRED) |
8 | +find_package(Qt5Core REQUIRED) |
9 | include(FindPkgConfig) |
10 | pkg_check_modules(GST_DEPS REQUIRED gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-pbutils-1.0 gstreamer-app-1.0) |
11 | -pkg_check_modules(GIO_DEPS REQUIRED gio-2.0) |
12 | +pkg_check_modules(GIO_DEPS REQUIRED gio-2.0 gio-unix-2.0) |
13 | pkg_check_modules(IMG_DEPS REQUIRED gdk-pixbuf-2.0 libexif) |
14 | pkg_check_modules(SOUP_DEPS REQUIRED libsoup-2.4) |
15 | pkg_check_modules(XML_DEPS REQUIRED libxml-2.0) |
16 | @@ -46,6 +47,7 @@ |
17 | |
18 | enable_testing() |
19 | add_subdirectory(src) |
20 | +add_subdirectory(plugins/Ubuntu/Thumbnailer) |
21 | add_subdirectory(tests) |
22 | add_subdirectory(tools) |
23 | add_subdirectory(include) |
24 | |
25 | === modified file 'debian/changelog' |
26 | --- debian/changelog 2014-03-28 10:11:10 +0000 |
27 | +++ debian/changelog 2014-03-28 10:11:10 +0000 |
28 | @@ -1,4 +1,9 @@ |
29 | -<<<<<<< TREE |
30 | +thumbnailer (1.1-0ubuntu1) UNRELEASED; urgency=medium |
31 | + |
32 | + * New minor release. |
33 | + |
34 | + -- Jussi Pakkanen <jussi.pakkanen@ubuntu.com> Mon, 10 Mar 2014 15:15:28 +0200 |
35 | + |
36 | thumbnailer (1.0+14.04.20140327-0ubuntu1) trusty; urgency=low |
37 | |
38 | [ Jussi Pakkanen ] |
39 | @@ -13,14 +18,6 @@ |
40 | |
41 | -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 19 Mar 2014 20:16:40 +0000 |
42 | |
43 | -======= |
44 | -thumbnailer (1.1-0ubuntu1) UNRELEASED; urgency=medium |
45 | - |
46 | - * New minor release. |
47 | - |
48 | - -- Jussi Pakkanen <jussi.pakkanen@ubuntu.com> Mon, 10 Mar 2014 15:15:28 +0200 |
49 | - |
50 | ->>>>>>> MERGE-SOURCE |
51 | thumbnailer (1.0+14.04.20140307-0ubuntu1) trusty; urgency=low |
52 | |
53 | [ Jussi Pakkanen ] |
54 | |
55 | === modified file 'debian/control' |
56 | --- debian/control 2014-03-28 10:11:10 +0000 |
57 | +++ debian/control 2014-03-28 10:11:10 +0000 |
58 | @@ -6,14 +6,18 @@ |
59 | Build-Depends: cmake, |
60 | debhelper (>= 9), |
61 | gstreamer1.0-plugins-good, |
62 | + libexif-dev, |
63 | libgdk-pixbuf2.0-dev, |
64 | + libgstreamer1.0-dev, |
65 | libgstreamer-plugins-base1.0-dev, |
66 | - libgstreamer1.0-dev, |
67 | - shared-mime-info, |
68 | libgtest-dev, |
69 | + libsoup2.4-dev, |
70 | libxml2-dev, |
71 | - libsoup2.4-dev, |
72 | - libexif-dev, |
73 | + qt5-default, |
74 | + qtbase5-dev, |
75 | + qtbase5-dev-tools, |
76 | + qtdeclarative5-dev, |
77 | + shared-mime-info, |
78 | Homepage: https://launchpad.net/thumbnailer |
79 | # if you don't have have commit access to this branch but would like to upload |
80 | # directly to Ubuntu, don't worry: your changes will be merged back into the |
81 | @@ -43,3 +47,26 @@ |
82 | Description: development files for thumbnailer |
83 | This package contains development files |
84 | for the thumbnailer package. |
85 | + |
86 | +Package: thumbnailer-service |
87 | +Architecture: any |
88 | +Multi-Arch: foreign |
89 | +Pre-Depends: ${misc:Pre-Depends}, |
90 | +Depends: ${misc:Depends}, |
91 | + ${shlibs:Depends}, |
92 | + libthumbnailer0 (= ${binary:Version}), |
93 | +Description: D-Bus service for out of process thumbnailing |
94 | + This package provides a D-Bus service that can provide thumbnails on |
95 | + behalf of another process. |
96 | + |
97 | +Package: qtdeclarative5-ubuntu-thumbnailer0.1 |
98 | +Architecture: any |
99 | +Multi-Arch: same |
100 | +Pre-Depends: ${misc:Pre-Depends}, |
101 | +Depends: ${misc:Depends}, |
102 | + ${shlibs:Depends}, |
103 | + libthumbnailer0 (= ${binary:Version}), |
104 | +Recommends: thumbnailer-service (= ${binary:Version}), |
105 | +Description: QML interface for the thumbnailer. |
106 | + This package provides image providers that allow access to the |
107 | + thumbnailer from Qt Quick 2 / QML applications. |
108 | |
109 | === added file 'debian/qtdeclarative5-ubuntu-thumbnailer0.1.install' |
110 | --- debian/qtdeclarative5-ubuntu-thumbnailer0.1.install 1970-01-01 00:00:00 +0000 |
111 | +++ debian/qtdeclarative5-ubuntu-thumbnailer0.1.install 2014-03-28 10:11:10 +0000 |
112 | @@ -0,0 +1,1 @@ |
113 | +usr/lib/*/qt5/qml/Ubuntu/Thumbnailer.0.1/* |
114 | |
115 | === added file 'debian/thumbnailer-service.install' |
116 | --- debian/thumbnailer-service.install 1970-01-01 00:00:00 +0000 |
117 | +++ debian/thumbnailer-service.install 2014-03-28 10:11:10 +0000 |
118 | @@ -0,0 +1,2 @@ |
119 | +usr/lib/*/thumbnailer/thumbnailer-service |
120 | +usr/share/dbus-1/services/com.canonical.Thumbnailer.service |
121 | |
122 | === added directory 'plugins' |
123 | === added directory 'plugins/Ubuntu' |
124 | === added directory 'plugins/Ubuntu/Thumbnailer' |
125 | === added file 'plugins/Ubuntu/Thumbnailer/CMakeLists.txt' |
126 | --- plugins/Ubuntu/Thumbnailer/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
127 | +++ plugins/Ubuntu/Thumbnailer/CMakeLists.txt 2014-03-28 10:11:10 +0000 |
128 | @@ -0,0 +1,22 @@ |
129 | + |
130 | +set(QML_PLUGIN_DIR "${CMAKE_INSTALL_LIBDIR}/qt5/qml/Ubuntu/Thumbnailer.0.1") |
131 | + |
132 | +add_library(thumbnailer-qml MODULE |
133 | + plugin.cpp |
134 | + albumartgenerator.cpp |
135 | + thumbnailgenerator.cpp |
136 | +) |
137 | + |
138 | +set_target_properties(thumbnailer-qml PROPERTIES AUTOMOC TRUE) |
139 | +qt5_use_modules(thumbnailer-qml Qml Quick DBus) |
140 | +target_link_libraries(thumbnailer-qml thumbnailer) |
141 | + |
142 | +install( |
143 | + TARGETS thumbnailer-qml |
144 | + LIBRARY DESTINATION ${QML_PLUGIN_DIR} |
145 | +) |
146 | + |
147 | +install( |
148 | + FILES qmldir |
149 | + DESTINATION ${QML_PLUGIN_DIR} |
150 | +) |
151 | |
152 | === added file 'plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp' |
153 | --- plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp 1970-01-01 00:00:00 +0000 |
154 | +++ plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp 2014-03-28 10:11:10 +0000 |
155 | @@ -0,0 +1,90 @@ |
156 | +/* |
157 | + * Copyright 2014 Canonical Ltd. |
158 | + * |
159 | + * This program is free software; you can redistribute it and/or modify |
160 | + * it under the terms of the GNU Lesser General Public License as published by |
161 | + * the Free Software Foundation; version 3. |
162 | + * |
163 | + * This program is distributed in the hope that it will be useful, |
164 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
165 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
166 | + * GNU Lesser General Public License for more details. |
167 | + * |
168 | + * You should have received a copy of the GNU Lesser General Public License |
169 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
170 | + * |
171 | + * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> |
172 | + * James Henstridge <james.henstridge@canonical.com> |
173 | +*/ |
174 | + |
175 | +#include "albumartgenerator.h" |
176 | +#include <stdexcept> |
177 | +#include <QDebug> |
178 | +#include <QFile> |
179 | +#include <QUrlQuery> |
180 | +#include <QDBusUnixFileDescriptor> |
181 | +#include <QDBusReply> |
182 | + |
183 | +static const char DEFAULT_ALBUM_ART[] = "/usr/share/unity/icons/album_missing.png"; |
184 | + |
185 | +static const char BUS_NAME[] = "com.canonical.Thumbnailer"; |
186 | +static const char BUS_PATH[] = "/com/canonical/Thumbnailer"; |
187 | +static const char THUMBNAILER_IFACE[] = "com.canonical.Thumbnailer"; |
188 | +static const char GET_ALBUM_ART[] = "GetAlbumArt"; |
189 | + |
190 | +AlbumArtGenerator::AlbumArtGenerator() |
191 | + : QQuickImageProvider(QQuickImageProvider::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading), |
192 | + iface(BUS_NAME, BUS_PATH, THUMBNAILER_IFACE) { |
193 | +} |
194 | + |
195 | +static QImage fallbackImage(QSize *realSize) { |
196 | + QImage fallback; |
197 | + fallback.load(DEFAULT_ALBUM_ART); |
198 | + *realSize = fallback.size(); |
199 | + return fallback; |
200 | +} |
201 | + |
202 | +QImage AlbumArtGenerator::requestImage(const QString &id, QSize *realSize, |
203 | + const QSize &requestedSize) { |
204 | + QUrlQuery query(id); |
205 | + if (!query.hasQueryItem("artist") || !query.hasQueryItem("album")) { |
206 | + qWarning() << "Invalid albumart uri:" << id; |
207 | + return fallbackImage(realSize); |
208 | + } |
209 | + |
210 | + const QString artist = query.queryItemValue("artist", QUrl::FullyDecoded); |
211 | + const QString album = query.queryItemValue("album", QUrl::FullyDecoded); |
212 | + |
213 | + QString desiredSize = "original"; |
214 | + int size = requestedSize.width() > requestedSize.height() ? requestedSize.width() : requestedSize.height(); |
215 | + if (size < 128) { |
216 | + desiredSize = "small"; |
217 | + } else if (size < 256) { |
218 | + desiredSize = "large"; |
219 | + } else if (size < 512) { |
220 | + desiredSize = "xlarge"; |
221 | + } |
222 | + |
223 | + // perform dbus call |
224 | + QDBusReply<QDBusUnixFileDescriptor> reply = iface.call( |
225 | + GET_ALBUM_ART, artist, album, desiredSize); |
226 | + if (!reply.isValid()) { |
227 | + qWarning() << "D-Bus error: " << reply.error().message(); |
228 | + return fallbackImage(realSize); |
229 | + } |
230 | + |
231 | + try { |
232 | + QFile file; |
233 | + file.open(reply.value().fileDescriptor(), QIODevice::ReadOnly); |
234 | + QImage image; |
235 | + image.load(&file, NULL); |
236 | + *realSize = image.size(); |
237 | + return image; |
238 | + } catch (const std::exception &e) { |
239 | + qDebug() << "Album art loader failed: " << e.what(); |
240 | + } catch (...) { |
241 | + qDebug() << "Unknown error when generating image."; |
242 | + } |
243 | + |
244 | + return fallbackImage(realSize); |
245 | +} |
246 | |
247 | === added file 'plugins/Ubuntu/Thumbnailer/albumartgenerator.h' |
248 | --- plugins/Ubuntu/Thumbnailer/albumartgenerator.h 1970-01-01 00:00:00 +0000 |
249 | +++ plugins/Ubuntu/Thumbnailer/albumartgenerator.h 2014-03-28 10:11:10 +0000 |
250 | @@ -0,0 +1,36 @@ |
251 | +/* |
252 | + * Copyright 2014 Canonical Ltd. |
253 | + * |
254 | + * This program is free software; you can redistribute it and/or modify |
255 | + * it under the terms of the GNU Lesser General Public License as published by |
256 | + * the Free Software Foundation; version 3. |
257 | + * |
258 | + * This program is distributed in the hope that it will be useful, |
259 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
260 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
261 | + * GNU Lesser General Public License for more details. |
262 | + * |
263 | + * You should have received a copy of the GNU Lesser General Public License |
264 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
265 | + * |
266 | + * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> |
267 | + * James Henstridge <james.henstridge@canonical.com> |
268 | +*/ |
269 | + |
270 | +#ifndef ALBUMART_GENERATOR_H |
271 | +#define ALBUMART_GENERATOR_H |
272 | + |
273 | +#include <QDBusInterface> |
274 | +#include <QQuickImageProvider> |
275 | + |
276 | +class AlbumArtGenerator: public QQuickImageProvider |
277 | +{ |
278 | +private: |
279 | + QDBusInterface iface; |
280 | + |
281 | +public: |
282 | + AlbumArtGenerator(); |
283 | + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); |
284 | +}; |
285 | + |
286 | +#endif |
287 | |
288 | === added file 'plugins/Ubuntu/Thumbnailer/plugin.cpp' |
289 | --- plugins/Ubuntu/Thumbnailer/plugin.cpp 1970-01-01 00:00:00 +0000 |
290 | +++ plugins/Ubuntu/Thumbnailer/plugin.cpp 2014-03-28 10:11:10 +0000 |
291 | @@ -0,0 +1,47 @@ |
292 | +/* |
293 | + * Copyright 2014 Canonical Ltd. |
294 | + * |
295 | + * This program is free software; you can redistribute it and/or modify |
296 | + * it under the terms of the GNU Lesser General Public License as published by |
297 | + * the Free Software Foundation; version 3. |
298 | + * |
299 | + * This program is distributed in the hope that it will be useful, |
300 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
301 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
302 | + * GNU Lesser General Public License for more details. |
303 | + * |
304 | + * You should have received a copy of the GNU Lesser General Public License |
305 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
306 | + * |
307 | + * Authors: James Henstridge <james.henstridge@canonical.com> |
308 | +*/ |
309 | + |
310 | +#include "plugin.h" |
311 | +#include "albumartgenerator.h" |
312 | +#include "thumbnailgenerator.h" |
313 | + |
314 | +void ThumbnailerPlugin::registerTypes(const char *uri) { |
315 | + qmlRegisterTypeNotAvailable( |
316 | + uri, 0, 1, "__ThumbnailerIgnoreMe", |
317 | + "Ignore this: QML plugins must contain at least one type"); |
318 | +} |
319 | + |
320 | +void ThumbnailerPlugin::initializeEngine(QQmlEngine *engine, const char *uri) { |
321 | + QQmlExtensionPlugin::initializeEngine(engine, uri); |
322 | + |
323 | + try { |
324 | + engine->addImageProvider("albumart", new AlbumArtGenerator()); |
325 | + } catch (const std::exception &e) { |
326 | + qWarning() << "Failed to register albumart image provider:" << e.what(); |
327 | + } catch (...) { |
328 | + qWarning() << "Failed to register albumart image provider."; |
329 | + } |
330 | + |
331 | + try { |
332 | + engine->addImageProvider("thumbnailer", new ThumbnailGenerator()); |
333 | + } catch (const std::exception &e) { |
334 | + qWarning() << "Failed to register thumbnailer image provider:" << e.what(); |
335 | + } catch (...) { |
336 | + qWarning() << "Failed to register thumbnailer image provider."; |
337 | + } |
338 | +} |
339 | |
340 | === added file 'plugins/Ubuntu/Thumbnailer/plugin.h' |
341 | --- plugins/Ubuntu/Thumbnailer/plugin.h 1970-01-01 00:00:00 +0000 |
342 | +++ plugins/Ubuntu/Thumbnailer/plugin.h 2014-03-28 10:11:10 +0000 |
343 | @@ -0,0 +1,34 @@ |
344 | +/* |
345 | + * Copyright 2014 Canonical Ltd. |
346 | + * |
347 | + * This program is free software; you can redistribute it and/or modify |
348 | + * it under the terms of the GNU Lesser General Public License as published by |
349 | + * the Free Software Foundation; version 3. |
350 | + * |
351 | + * This program is distributed in the hope that it will be useful, |
352 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
353 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
354 | + * GNU Lesser General Public License for more details. |
355 | + * |
356 | + * You should have received a copy of the GNU Lesser General Public License |
357 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
358 | + * |
359 | + * Authors: James Henstridge <james.henstridge@canonical.com> |
360 | +*/ |
361 | + |
362 | +#ifndef THUMBNAILER_PLUGIN_H |
363 | +#define THUMBNAILER_PLUGIN_H |
364 | + |
365 | +#include <QtQml> |
366 | + |
367 | +class ThumbnailerPlugin : public QQmlExtensionPlugin |
368 | +{ |
369 | + Q_OBJECT |
370 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
371 | + |
372 | +public: |
373 | + virtual void registerTypes(const char *uri) override; |
374 | + virtual void initializeEngine(QQmlEngine *engine, const char *uri) override; |
375 | +}; |
376 | + |
377 | +#endif |
378 | |
379 | === added file 'plugins/Ubuntu/Thumbnailer/qmldir' |
380 | --- plugins/Ubuntu/Thumbnailer/qmldir 1970-01-01 00:00:00 +0000 |
381 | +++ plugins/Ubuntu/Thumbnailer/qmldir 2014-03-28 10:11:10 +0000 |
382 | @@ -0,0 +1,2 @@ |
383 | +module Ubuntu.Thumbnailer |
384 | +plugin thumbnailer-qml |
385 | |
386 | === added file 'plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp' |
387 | --- plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp 1970-01-01 00:00:00 +0000 |
388 | +++ plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp 2014-03-28 10:11:10 +0000 |
389 | @@ -0,0 +1,87 @@ |
390 | +/* |
391 | + * Copyright 2013 Canonical Ltd. |
392 | + * |
393 | + * This program is free software; you can redistribute it and/or modify |
394 | + * it under the terms of the GNU Lesser General Public License as published by |
395 | + * the Free Software Foundation; version 3. |
396 | + * |
397 | + * This program is distributed in the hope that it will be useful, |
398 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
399 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
400 | + * GNU Lesser General Public License for more details. |
401 | + * |
402 | + * You should have received a copy of the GNU Lesser General Public License |
403 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
404 | + * |
405 | + * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> |
406 | +*/ |
407 | + |
408 | +#include "thumbnailgenerator.h" |
409 | +#include <stdexcept> |
410 | +#include <QDebug> |
411 | +#include <QMimeDatabase> |
412 | +#include <QUrl> |
413 | + |
414 | +static const char *DEFAULT_VIDEO_ART = "/usr/share/unity/icons/video_missing.png"; |
415 | +static const char *DEFAULT_ALBUM_ART = "/usr/share/unity/icons/album_missing.png"; |
416 | + |
417 | +ThumbnailGenerator::ThumbnailGenerator() : QQuickImageProvider(QQuickImageProvider::Image, |
418 | + QQmlImageProviderBase::ForceAsynchronousImageLoading) { |
419 | + |
420 | +} |
421 | + |
422 | +QImage ThumbnailGenerator::requestImage(const QString &id, QSize *realSize, |
423 | + const QSize &requestedSize) { |
424 | + /* Allow appending a query string (e.g. ?something=timestamp) |
425 | + * to the id and then ignore it. |
426 | + * This is workaround to force reloading a thumbnail when it has |
427 | + * the same file name on disk but we know the content has changed. |
428 | + * It is necessary because in such a situation the QML image cache |
429 | + * will kick in and this ImageProvider will never get called. |
430 | + * The only "solution" is setting Image.cache = false, but in some |
431 | + * cases we don't want to do that for performance reasons, so this |
432 | + * is the only way around the issue for now. */ |
433 | + std::string src_path(QUrl(id).path().toUtf8().data()); |
434 | + std::string tgt_path; |
435 | + try { |
436 | + ThumbnailSize desiredSize; |
437 | + const int xlarge_cutoff = 512; |
438 | + const int large_cutoff = 256; |
439 | + const int small_cutoff = 128; |
440 | + if(requestedSize.width() > xlarge_cutoff || requestedSize.height() > xlarge_cutoff) { |
441 | + desiredSize = TN_SIZE_ORIGINAL; |
442 | + } if(requestedSize.width() > large_cutoff || requestedSize.height() > large_cutoff) { |
443 | + desiredSize = TN_SIZE_XLARGE; |
444 | + } else if(requestedSize.width() > small_cutoff || requestedSize.height() > small_cutoff) { |
445 | + desiredSize = TN_SIZE_LARGE; |
446 | + } else { |
447 | + desiredSize = TN_SIZE_SMALL; |
448 | + } |
449 | + tgt_path = tn.get_thumbnail(src_path, desiredSize); |
450 | + if(!tgt_path.empty()) { |
451 | + QString tgt(tgt_path.c_str()); |
452 | + QImage image; |
453 | + image.load(tgt); |
454 | + *realSize = image.size(); |
455 | + return image; |
456 | + } |
457 | + } catch(std::runtime_error &e) { |
458 | + qDebug() << "Thumbnail generator failed: " << e.what(); |
459 | + } |
460 | + return getFallbackImage(id, realSize, requestedSize); |
461 | +} |
462 | + |
463 | +QImage ThumbnailGenerator::getFallbackImage(const QString &id, QSize *size, |
464 | + const QSize &requestedSize) { |
465 | + Q_UNUSED(requestedSize); |
466 | + QMimeDatabase db; |
467 | + QMimeType mime = db.mimeTypeForFile(id); |
468 | + QImage result; |
469 | + if(mime.name().contains("audio")) { |
470 | + result.load(DEFAULT_ALBUM_ART); |
471 | + } else if(mime.name().contains("video")) { |
472 | + result.load(DEFAULT_VIDEO_ART); |
473 | + } |
474 | + *size = result.size(); |
475 | + return result; |
476 | +} |
477 | |
478 | === added file 'plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h' |
479 | --- plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h 1970-01-01 00:00:00 +0000 |
480 | +++ plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h 2014-03-28 10:11:10 +0000 |
481 | @@ -0,0 +1,36 @@ |
482 | +/* |
483 | + * Copyright 2013 Canonical Ltd. |
484 | + * |
485 | + * This program is free software; you can redistribute it and/or modify |
486 | + * it under the terms of the GNU Lesser General Public License as published by |
487 | + * the Free Software Foundation; version 3. |
488 | + * |
489 | + * This program is distributed in the hope that it will be useful, |
490 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
491 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
492 | + * GNU Lesser General Public License for more details. |
493 | + * |
494 | + * You should have received a copy of the GNU Lesser General Public License |
495 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
496 | + * |
497 | + * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com> |
498 | +*/ |
499 | + |
500 | +#ifndef THUMBNAIL_GENERATOR_H |
501 | +#define THUMBNAIL_GENERATOR_H |
502 | + |
503 | +#include <QQuickImageProvider> |
504 | +#include <thumbnailer.h> |
505 | + |
506 | +class ThumbnailGenerator: public QQuickImageProvider |
507 | +{ |
508 | +private: |
509 | + Thumbnailer tn; |
510 | + |
511 | +public: |
512 | + ThumbnailGenerator(); |
513 | + QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize); |
514 | + QImage getFallbackImage(const QString &id, QSize *size, const QSize &requestedSize); |
515 | +}; |
516 | + |
517 | +#endif |
518 | |
519 | === modified file 'src/CMakeLists.txt' |
520 | --- src/CMakeLists.txt 2014-03-28 10:11:10 +0000 |
521 | +++ src/CMakeLists.txt 2014-03-28 10:11:10 +0000 |
522 | @@ -37,3 +37,5 @@ |
523 | RUNTIME DESTINATION ${SHARE_PRIV_DIR} |
524 | LIBRARY DESTINATION ${SHARE_PRIV_DIR} |
525 | ) |
526 | + |
527 | +add_subdirectory(service) |
528 | |
529 | === added directory 'src/service' |
530 | === added file 'src/service/CMakeLists.txt' |
531 | --- src/service/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
532 | +++ src/service/CMakeLists.txt 2014-03-28 10:11:10 +0000 |
533 | @@ -0,0 +1,34 @@ |
534 | +add_definitions(${THUMBNAILER_CFLAGS}) |
535 | +include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
536 | + |
537 | +add_executable(thumbnailer-service |
538 | + main.cpp |
539 | + dbusinterface.cpp |
540 | + dbus-generated.c |
541 | +) |
542 | + |
543 | +target_link_libraries(thumbnailer-service thumbnailer) |
544 | + |
545 | +install( |
546 | + TARGETS thumbnailer-service |
547 | + RUNTIME DESTINATION ${SHARE_PRIV_DIR} |
548 | +) |
549 | + |
550 | +find_program(gdbus_codegen gdbus-codegen) |
551 | +if(NOT gdbus_codegen) |
552 | + msg(FATAL_ERROR "Could not locate gdbus-codegen") |
553 | +endif() |
554 | + |
555 | +add_custom_command( |
556 | + OUTPUT dbus-generated.c dbus-generated.h |
557 | + COMMAND ${gdbus_codegen} --interface-prefix=com.canonical. --generate-c-code dbus-generated --c-namespace TN ${CMAKE_CURRENT_SOURCE_DIR}/dbus-interface.xml |
558 | + MAIN_DEPENDENCY dbus-interface.xml |
559 | +) |
560 | + |
561 | +# Install the service file. |
562 | +configure_file(com.canonical.Thumbnailer.service.in com.canonical.Thumbnailer.service) |
563 | + |
564 | +install( |
565 | + FILES ${CMAKE_CURRENT_BINARY_DIR}/com.canonical.Thumbnailer.service |
566 | + DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services |
567 | +) |
568 | |
569 | === added file 'src/service/com.canonical.Thumbnailer.service.in' |
570 | --- src/service/com.canonical.Thumbnailer.service.in 1970-01-01 00:00:00 +0000 |
571 | +++ src/service/com.canonical.Thumbnailer.service.in 2014-03-28 10:11:10 +0000 |
572 | @@ -0,0 +1,4 @@ |
573 | +[D-BUS Service] |
574 | +Name=com.canonical.Thumbnailer |
575 | +Exec=@SHARE_PRIV_ABS@/thumbnailer-service |
576 | + |
577 | |
578 | === added file 'src/service/dbus-interface.xml' |
579 | --- src/service/dbus-interface.xml 1970-01-01 00:00:00 +0000 |
580 | +++ src/service/dbus-interface.xml 2014-03-28 10:11:10 +0000 |
581 | @@ -0,0 +1,17 @@ |
582 | +<node> |
583 | + <interface name="com.canonical.Thumbnailer"> |
584 | + <method name="GetAlbumArt"> |
585 | + <arg direction="in" type="s" name="artist" /> |
586 | + <arg direction="in" type="s" name="album" /> |
587 | + <!-- possible values are "small", "large", "xlarge" and "original" --> |
588 | + <arg direction="in" type="s" name="desiredSize" /> |
589 | + <arg direction="out" type="h" name="fd" /> |
590 | + <annotation name="org.gtk.GDBus.C.UnixFD" value="true" /> |
591 | + </method> |
592 | + |
593 | + <!-- Note: if adding additional thumbnailing methods that take a |
594 | + file name as input, ensure that the calling process has |
595 | + permission to read said file. Otherwise we will leak |
596 | + information to confined applications. --> |
597 | + </interface> |
598 | +</node> |
599 | |
600 | === added file 'src/service/dbusinterface.cpp' |
601 | --- src/service/dbusinterface.cpp 1970-01-01 00:00:00 +0000 |
602 | +++ src/service/dbusinterface.cpp 2014-03-28 10:11:10 +0000 |
603 | @@ -0,0 +1,168 @@ |
604 | +/* |
605 | + * Copyright (C) 2014 Canonical, Ltd. |
606 | + * |
607 | + * Authors: |
608 | + * James Henstridge <james.henstridge@canonical.com> |
609 | + * |
610 | + * This library is free software; you can redistribute it and/or modify it under |
611 | + * the terms of version 3 of the GNU General Public License as published |
612 | + * by the Free Software Foundation. |
613 | + * |
614 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
615 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
616 | + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
617 | + * details. |
618 | + * |
619 | + * You should have received a copy of the GNU General Public License |
620 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
621 | + */ |
622 | + |
623 | +#include "dbusinterface.h" |
624 | + |
625 | +#include <cstdio> |
626 | +#include <cstring> |
627 | +#include <memory> |
628 | +#include <stdexcept> |
629 | +#include <string> |
630 | +#include <thread> |
631 | +#include <fcntl.h> |
632 | +#include <unistd.h> |
633 | + |
634 | +#include <glib.h> |
635 | +#include <glib-object.h> |
636 | +#include <gio/gio.h> |
637 | +#include <gio/gunixfdlist.h> |
638 | +#include <thumbnailer.h> |
639 | + |
640 | +#include <internal/gobj_memory.h> |
641 | +#include "dbus-generated.h" |
642 | + |
643 | +using namespace std; |
644 | + |
645 | +static const char BUS_NAME[] = "com.canonical.MediaScanner2"; |
646 | +static const char ART_ERROR[] = "com.canonical.MediaScanner2.Error.Failed"; |
647 | + |
648 | +static const char MISSING_ALBUM_ART[] = "/usr/share/unity/icons/album_missing.png"; |
649 | + |
650 | +struct DBusInterfacePrivate { |
651 | + const std::string bus_path; |
652 | + unique_gobj<GDBusConnection> bus; |
653 | + unique_gobj<TNThumbnailer> iface; |
654 | + unsigned int handler_id; |
655 | + std::shared_ptr<Thumbnailer> thumbnailer; |
656 | + |
657 | + DBusInterfacePrivate(GDBusConnection *g_bus, const std::string& bus_path) |
658 | + : bus_path(bus_path), |
659 | + bus(static_cast<GDBusConnection*>(g_object_ref(g_bus))), |
660 | + iface(tn_thumbnailer_skeleton_new()), |
661 | + handler_id(0), |
662 | + thumbnailer(std::make_shared<Thumbnailer>()) { |
663 | + handler_id = g_signal_connect( |
664 | + iface.get(), "handle-get-album-art", |
665 | + G_CALLBACK(&DBusInterfacePrivate::handleGetAlbumArt), this); |
666 | + |
667 | + GError *error = nullptr; |
668 | + if (!g_dbus_interface_skeleton_export( |
669 | + G_DBUS_INTERFACE_SKELETON(iface.get()), bus.get(), |
670 | + bus_path.c_str(), &error)) { |
671 | + string errortxt(error->message); |
672 | + g_error_free(error); |
673 | + |
674 | + string msg = "Failed to export interface: "; |
675 | + msg += errortxt; |
676 | + throw runtime_error(msg); |
677 | + } |
678 | + } |
679 | + |
680 | + ~DBusInterfacePrivate() { |
681 | + g_dbus_interface_skeleton_unexport( |
682 | + G_DBUS_INTERFACE_SKELETON(iface.get())); |
683 | + g_signal_handler_disconnect(iface.get(), handler_id); |
684 | + } |
685 | + |
686 | + static gboolean handleGetAlbumArt(TNThumbnailer *iface, GDBusMethodInvocation *invocation, GUnixFDList *, const char *artist, const char *album, const char *size, void *user_data) { |
687 | + auto p = static_cast<DBusInterfacePrivate*>(user_data); |
688 | + fprintf(stderr, "Look up cover art for %s/%s at size %s\n", artist, album, size); |
689 | + |
690 | + ThumbnailSize desiredSize; |
691 | + if (!strcmp(size, "small")) { |
692 | + desiredSize = TN_SIZE_SMALL; |
693 | + } else if (!strcmp(size, "large")) { |
694 | + desiredSize = TN_SIZE_LARGE; |
695 | + } else if (!strcmp(size, "xlarge")) { |
696 | + desiredSize = TN_SIZE_XLARGE; |
697 | + } else if (!strcmp(size, "original")) { |
698 | + desiredSize = TN_SIZE_ORIGINAL; |
699 | + } else { |
700 | + std::string error("Unknown size: "); |
701 | + error += size; |
702 | + g_dbus_method_invocation_return_dbus_error( |
703 | + invocation, ART_ERROR, error.c_str()); |
704 | + return TRUE; |
705 | + } |
706 | + |
707 | + try { |
708 | + std::thread t(&getAlbumArt, |
709 | + unique_gobj<TNThumbnailer>(static_cast<TNThumbnailer*>(g_object_ref(iface))), |
710 | + unique_gobj<GDBusMethodInvocation>(static_cast<GDBusMethodInvocation*>(g_object_ref(invocation))), |
711 | + p->thumbnailer, |
712 | + std::string(artist), std::string(album), desiredSize); |
713 | + t.detach(); |
714 | + } catch (const std::exception &e) { |
715 | + g_dbus_method_invocation_return_dbus_error( |
716 | + invocation, ART_ERROR, e.what()); |
717 | + } |
718 | + return TRUE; |
719 | + } |
720 | + |
721 | + static void getAlbumArt(unique_gobj<TNThumbnailer> iface, |
722 | + unique_gobj<GDBusMethodInvocation> invocation, |
723 | + std::shared_ptr<Thumbnailer> thumbnailer, |
724 | + const std::string artist, const std::string album, |
725 | + ThumbnailSize desiredSize) { |
726 | + std::string art; |
727 | + try { |
728 | + art = thumbnailer->get_album_art( |
729 | + artist, album, desiredSize, TN_REMOTE); |
730 | + } catch (const std::exception &e) { |
731 | + g_dbus_method_invocation_return_dbus_error( |
732 | + invocation.get(), ART_ERROR, e.what()); |
733 | + return; |
734 | + } |
735 | + |
736 | + if (art.empty()) { |
737 | + g_dbus_method_invocation_return_dbus_error( |
738 | + invocation.get(), ART_ERROR, "Could not get thumbnail"); |
739 | + return; |
740 | + } |
741 | + int fd = open(art.c_str(), O_RDONLY); |
742 | + if (fd < 0) { |
743 | + g_dbus_method_invocation_return_dbus_error( |
744 | + invocation.get(), ART_ERROR, strerror(errno)); |
745 | + return; |
746 | + } |
747 | + |
748 | + unique_gobj<GUnixFDList> fd_list(g_unix_fd_list_new()); |
749 | + GError *error = nullptr; |
750 | + g_unix_fd_list_append(fd_list.get(), fd, &error); |
751 | + close(fd); |
752 | + if (error != nullptr) { |
753 | + g_dbus_method_invocation_return_dbus_error( |
754 | + invocation.get(), ART_ERROR, error->message); |
755 | + g_error_free(error); |
756 | + return; |
757 | + } |
758 | + |
759 | + tn_thumbnailer_complete_get_album_art( |
760 | + iface.get(), invocation.get(), fd_list.get(), g_variant_new_handle(0)); |
761 | + } |
762 | + |
763 | +}; |
764 | + |
765 | +DBusInterface::DBusInterface(GDBusConnection *bus, const std::string& bus_path) |
766 | + : p(new DBusInterfacePrivate(bus, bus_path)) { |
767 | +} |
768 | + |
769 | +DBusInterface::~DBusInterface() { |
770 | + delete p; |
771 | +} |
772 | |
773 | === added file 'src/service/dbusinterface.h' |
774 | --- src/service/dbusinterface.h 1970-01-01 00:00:00 +0000 |
775 | +++ src/service/dbusinterface.h 2014-03-28 10:11:10 +0000 |
776 | @@ -0,0 +1,40 @@ |
777 | +/* |
778 | + * Copyright (C) 2014 Canonical, Ltd. |
779 | + * |
780 | + * Authors: |
781 | + * James Henstridge <james.henstridge@canonical.com> |
782 | + * |
783 | + * This library is free software; you can redistribute it and/or modify it under |
784 | + * the terms of version 3 of the GNU General Public License as published |
785 | + * by the Free Software Foundation. |
786 | + * |
787 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
788 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
789 | + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
790 | + * details. |
791 | + * |
792 | + * You should have received a copy of the GNU General Public License |
793 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
794 | + */ |
795 | + |
796 | +#ifndef DBUSINTERFACE_H |
797 | +#define DBUSINTERFACE_H |
798 | + |
799 | +#include <string> |
800 | + |
801 | +struct DBusInterfacePrivate; |
802 | +typedef struct _GDBusConnection GDBusConnection; |
803 | + |
804 | +class DBusInterface final { |
805 | +public: |
806 | + DBusInterface(GDBusConnection *bus, const std::string& bus_path); |
807 | + ~DBusInterface(); |
808 | + |
809 | + DBusInterface(const DBusInterface&) = delete; |
810 | + DBusInterface& operator=(DBusInterface&) = delete; |
811 | + |
812 | +private: |
813 | + DBusInterfacePrivate *p; |
814 | +}; |
815 | + |
816 | +#endif |
817 | |
818 | === added file 'src/service/main.cpp' |
819 | --- src/service/main.cpp 1970-01-01 00:00:00 +0000 |
820 | +++ src/service/main.cpp 2014-03-28 10:11:10 +0000 |
821 | @@ -0,0 +1,44 @@ |
822 | +#include <cstdio> |
823 | +#include <memory> |
824 | +#include <stdexcept> |
825 | +#include <glib.h> |
826 | +#include <gio/gio.h> |
827 | + |
828 | +#include "dbusinterface.h" |
829 | + |
830 | +static const char BUS_NAME[] = "com.canonical.Thumbnailer"; |
831 | +static const char BUS_PATH[] = "/com/canonical/Thumbnailer"; |
832 | + |
833 | +static std::unique_ptr<GMainLoop,void(*)(GMainLoop*)> main_loop( |
834 | + g_main_loop_new(nullptr, FALSE), g_main_loop_unref); |
835 | + |
836 | +static void nameLost(GDBusConnection *, const char *, void *) { |
837 | + fprintf(stderr, "Could no acquire D-Bus name %s. Quitting.\n", BUS_NAME); |
838 | + g_main_loop_quit(main_loop.get()); |
839 | +} |
840 | + |
841 | +int main(int argc, char **argv) { |
842 | + GError *error = nullptr; |
843 | + std::unique_ptr<GDBusConnection, void(*)(void*)> bus( |
844 | + g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error), |
845 | + g_object_unref); |
846 | + if (error != nullptr) { |
847 | + fprintf(stderr, "Failed to connect to session bus: %s\n", error->message); |
848 | + g_error_free(error); |
849 | + return 1; |
850 | + } |
851 | + |
852 | + DBusInterface dbus(bus.get(), BUS_PATH); |
853 | + |
854 | + unsigned int name_id = g_bus_own_name_on_connection( |
855 | + bus.get(), BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, |
856 | + nullptr, &nameLost, nullptr, nullptr); |
857 | + |
858 | + g_main_loop_run(main_loop.get()); |
859 | + |
860 | + if (name_id != 0) { |
861 | + g_bus_unown_name(name_id); |
862 | + } |
863 | + |
864 | + return 0; |
865 | +} |
866 | |
867 | === modified file 'src/thumbnailer.cpp' |
868 | --- src/thumbnailer.cpp 2014-03-28 10:11:10 +0000 |
869 | +++ src/thumbnailer.cpp 2014-03-28 10:11:10 +0000 |
870 | @@ -53,16 +53,12 @@ |
871 | |
872 | ThumbnailerPrivate() {}; |
873 | |
874 | -<<<<<<< TREE |
875 | - string create_thumbnail(const string &abspath, ThumbnailSize desired_size); |
876 | + string create_thumbnail(const string &abspath, ThumbnailSize desired_size, |
877 | + ThumbnailPolicy policy); |
878 | string create_random_filename(); |
879 | -======= |
880 | - string create_thumbnail(const string &abspath, ThumbnailSize desired_size, |
881 | - ThumbnailPolicy policy); |
882 | ->>>>>>> MERGE-SOURCE |
883 | }; |
884 | |
885 | -<<<<<<< TREE |
886 | + |
887 | string ThumbnailerPrivate::create_random_filename() { |
888 | string fname; |
889 | char *dirbase = getenv("TMPDIR"); // Set when in a confined application. |
890 | @@ -77,8 +73,6 @@ |
891 | return fname; |
892 | } |
893 | |
894 | -string ThumbnailerPrivate::create_thumbnail(const string &abspath, ThumbnailSize desired_size) { |
895 | -======= |
896 | string ThumbnailerPrivate::create_audio_thumbnail(const string &/*abspath*/, |
897 | ThumbnailSize /*desired_size*/, ThumbnailPolicy /*policy*/) { |
898 | // There was a symbol clash between 1.0 and 0.10 versions of |
899 | @@ -101,14 +95,8 @@ |
900 | return ""; |
901 | } |
902 | string ThumbnailerPrivate::create_generic_thumbnail(const string &abspath, ThumbnailSize desired_size) { |
903 | ->>>>>>> MERGE-SOURCE |
904 | int tmpw, tmph; |
905 | string tnfile = cache.get_cache_file_name(abspath, desired_size); |
906 | -<<<<<<< TREE |
907 | - string tmpname = create_random_filename(); |
908 | - |
909 | -======= |
910 | ->>>>>>> MERGE-SOURCE |
911 | // Special case: full size image files are their own preview. |
912 | if(desired_size == TN_SIZE_ORIGINAL && |
913 | gdk_pixbuf_get_file_info(abspath.c_str(), &tmpw, &tmph)) { |
914 | @@ -123,9 +111,8 @@ |
915 | } |
916 | |
917 | string ThumbnailerPrivate::create_video_thumbnail(const string &abspath, ThumbnailSize desired_size) { |
918 | - char filebuf[] = "/tmp/some/long/text/here/so/path/will/fit"; |
919 | string tnfile = cache.get_cache_file_name(abspath, desired_size); |
920 | - string tmpname = tmpnam(filebuf); |
921 | + string tmpname = create_random_filename(); |
922 | if(video.extract(abspath, tmpname)) { |
923 | scaler.scale(tmpname, tnfile, desired_size, abspath); |
924 | unlink(tmpname.c_str()); |
925 | |
926 | === added directory 'tests/qml' |
927 | === added file 'tests/qml/tst_image_provider.qml' |
928 | --- tests/qml/tst_image_provider.qml 1970-01-01 00:00:00 +0000 |
929 | +++ tests/qml/tst_image_provider.qml 2014-03-28 10:11:10 +0000 |
930 | @@ -0,0 +1,62 @@ |
931 | +import QtQuick 2.0 |
932 | +import QtTest 1.0 |
933 | +import Ubuntu.Thumbnailer 0.1 |
934 | + |
935 | +Item { |
936 | + Image { |
937 | + id: image |
938 | + width: 200 |
939 | + height: 200 |
940 | + |
941 | + SignalSpy { |
942 | + id: spy |
943 | + target: image |
944 | + signalName: "statusChanged" |
945 | + } |
946 | + } |
947 | + |
948 | + Canvas { |
949 | + id: canvas |
950 | + width: 200 |
951 | + height: 200 |
952 | + renderStrategy: Canvas.Immediate |
953 | + renderTarget: Canvas.Image |
954 | + } |
955 | + |
956 | + TestCase { |
957 | + name: "ThumbnailerProviderTests" |
958 | + when: windowShown |
959 | + |
960 | + function test_albumart() { |
961 | + var ctx = loadImage( |
962 | + "image://albumart/artist=Gotye&album=Making%20Mirrors"); |
963 | + comparePixel(ctx, 0, 0, 242, 228, 209, 255); |
964 | + } |
965 | + |
966 | + function loadImage(uri) { |
967 | + image.source = uri |
968 | + while (image.status == Image.Loading) { |
969 | + spy.wait(); |
970 | + } |
971 | + compare(image.status, Image.Ready); |
972 | + |
973 | + var ctx = canvas.getContext("2d"); |
974 | + ctx.drawImage(image, 0, 0); |
975 | + return ctx; |
976 | + } |
977 | + |
978 | + function comparePixel(ctx,x,y,r,g,b,a, d) { |
979 | + var c = ctx.getImageData(x,y,1,1).data; |
980 | + if (d === undefined) |
981 | + d = 0; |
982 | + r = Math.round(r); |
983 | + g = Math.round(g); |
984 | + b = Math.round(b); |
985 | + a = Math.round(a); |
986 | + var notSame = Math.abs(c[0]-r)>d || Math.abs(c[1]-g)>d || Math.abs(c[2]-b)>d || Math.abs(c[3]-a)>d; |
987 | + if (notSame) |
988 | + qtest_fail('Pixel compare fail:\nactual :[' + c[0]+','+c[1]+','+c[2]+','+c[3] + ']\nexpected:['+r+','+g+','+b+','+a+'] +/- '+d, 1); |
989 | + |
990 | + } |
991 | + } |
992 | +} |
FAILED: Continuous integration, rev:97 jenkins. qa.ubuntu. com/job/ thumbnailer- ci/47/ jenkins. qa.ubuntu. com/job/ thumbnailer- trusty- amd64-ci/ 35/console jenkins. qa.ubuntu. com/job/ thumbnailer- trusty- armhf-ci/ 35/console jenkins. qa.ubuntu. com/job/ thumbnailer- trusty- i386-ci/ 35/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/thumbnailer -ci/47/ rebuild
http://