Merge lp:~phablet-team/media-hub/video-support into lp:media-hub
- video-support
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~phablet-team/media-hub/video-support |
Merge into: | lp:media-hub |
Diff against target: |
1379 lines (+622/-50) 19 files modified
CMakeLists.txt (+1/-0) include/core/media/player.h (+13/-3) src/core/media/CMakeLists.txt (+6/-2) src/core/media/engine.h (+7/-0) src/core/media/gstreamer/engine.cpp (+69/-9) src/core/media/gstreamer/engine.h (+7/-0) src/core/media/gstreamer/playbin.h (+165/-18) src/core/media/mpris/player.h (+4/-0) src/core/media/player_implementation.cpp (+53/-7) src/core/media/player_implementation.h (+3/-0) src/core/media/player_skeleton.cpp (+94/-5) src/core/media/player_skeleton.h (+8/-0) src/core/media/player_stub.cpp (+143/-2) src/core/media/player_stub.h (+7/-0) src/core/media/server/server.cpp (+11/-0) src/core/media/track_list_implementation.cpp (+13/-0) src/core/media/track_list_implementation.h (+1/-0) src/core/media/track_list_skeleton.cpp (+15/-3) src/core/media/track_list_skeleton.h (+2/-1) |
To merge this branch: | bzr merge lp:~phablet-team/media-hub/video-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | code | Pending | |
Review via email: mp+212903@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-03-26.
Commit message
* Merged with EOS branch from tvoss
* Added on_frame_available listener and callback
* Create a decoding session and pass it to the hybris layer
* Allow playback to work again after a client quits or dies
* Added two new properties to see if the opened media is video or audio
* Background playlist support
Description of the change
* Merged with EOS branch from tvoss
* Added on_frame_available listener and callback
* Create a decoding session and pass it to the hybris layer
* Allow playback to work again after a client quits or dies
* Added two new properties to see if the opened media is video or audio
* Background playlist support
- 37. By Jim Hodapp
-
Merged with Sergio's packaging changes. Added a copyright header to server.cpp. Removed any includes for decoding_service.h since it's not being used right now.
- 38. By Jim Hodapp
-
Didn't mean to #include <visibility.h> in previous commit, undo that.
- 39. By Jim Hodapp
-
Enable libhyris-dev as a build-dep
- 40. By Jim Hodapp
-
Get rid of the visibility attribute.
- 41. By Jim Hodapp
-
Add libproperties-
cpp-dev as a Depends: for libmedia-hub-dev - 42. By Jim Hodapp
-
Merged with upstream changes to disable all unit-tests
- 43. By Jim Hodapp
-
Made ricmm's change recommendations and enabled the tests that still work properly.
- 44. By Jim Hodapp
-
Snap to the preceeding key unit after doing a seek.
- 45. By Jim Hodapp
-
Mock decoding_
service_ set_client_ death_cb so that the unittests don't crash when running on a non-target device. - 46. By Jim Hodapp
-
Enable the seeked_to signal
- 47. By Jim Hodapp
-
Merged with ricmm's EOS fix branch
- 48. By Jim Hodapp
-
Initial version of apparmor security context arbitration for open_uri. This does not yet check the trust store
- 49. By Jim Hodapp
-
Refine the apparmor arbitration a bit. Whitelist music-app explicitly until the trust store lands.
- 50. By Jim Hodapp
-
Only start when dbus is started instead of preventing media-hub from being able to be stopped
- 51. By Jim Hodapp
-
Enable streaming sources to work with media-hub
- 52. By Jim Hodapp
-
Allow apps to access their own media files in /opt
- 53. By Jim Hodapp
-
Merged with jdstrand's changes to confine media-hub with apparmor
- 54. By Jim Hodapp
-
Slightly improve the get_position_
duration_ works unit test - 55. By Jim Hodapp
-
Make sure the camer-app can play the click sound when a user captures a picture
Unmerged revisions
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-02-14 07:19:31 +0000 |
3 | +++ CMakeLists.txt 2014-03-26 17:18:55 +0000 |
4 | @@ -25,6 +25,7 @@ |
5 | pkg_check_modules(DBUS dbus-1 REQUIRED) |
6 | pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED) |
7 | pkg_check_modules(PROPERTIES_CPP properties-cpp REQUIRED) |
8 | +pkg_check_modules(GIO gio-2.0 REQUIRED) |
9 | |
10 | ##################################################################### |
11 | # Enable code coverage calculation with gcov/gcovr/lcov |
12 | |
13 | === modified file 'include/core/media/player.h' |
14 | --- include/core/media/player.h 2014-02-18 19:27:01 +0000 |
15 | +++ include/core/media/player.h 2014-03-26 17:18:55 +0000 |
16 | @@ -39,6 +39,11 @@ |
17 | public: |
18 | typedef double PlaybackRate; |
19 | typedef double Volume; |
20 | + typedef void* GLConsumerWrapperHybris; |
21 | + |
22 | + /** Used to set a callback function to be called when a frame is ready to be rendered **/ |
23 | + typedef void (*FrameAvailableCbHybris)(GLConsumerWrapperHybris wrapper, void *context); |
24 | + typedef void (*FrameAvailableCb)(void *context); |
25 | |
26 | struct Configuration; |
27 | |
28 | @@ -74,6 +79,8 @@ |
29 | virtual std::shared_ptr<TrackList> track_list() = 0; |
30 | |
31 | virtual bool open_uri(const Track::UriType& uri) = 0; |
32 | + virtual void create_video_sink(uint32_t texture_id) = 0; |
33 | + virtual GLConsumerWrapperHybris gl_consumer() const = 0; |
34 | virtual void next() = 0; |
35 | virtual void previous() = 0; |
36 | virtual void play() = 0; |
37 | @@ -81,11 +88,16 @@ |
38 | virtual void stop() = 0; |
39 | virtual void seek_to(const std::chrono::microseconds& offset) = 0; |
40 | |
41 | + // TODO: Convert this to be a signal |
42 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context) = 0; |
43 | + |
44 | virtual const core::Property<bool>& can_play() const = 0; |
45 | virtual const core::Property<bool>& can_pause() const = 0; |
46 | virtual const core::Property<bool>& can_seek() const = 0; |
47 | virtual const core::Property<bool>& can_go_previous() const = 0; |
48 | virtual const core::Property<bool>& can_go_next() const = 0; |
49 | + virtual const core::Property<bool>& is_video_source() const = 0; |
50 | + virtual const core::Property<bool>& is_audio_source() const = 0; |
51 | virtual const core::Property<PlaybackStatus>& playback_status() const = 0; |
52 | virtual const core::Property<LoopStatus>& loop_status() const = 0; |
53 | virtual const core::Property<PlaybackRate>& playback_rate() const = 0; |
54 | @@ -97,15 +109,13 @@ |
55 | virtual const core::Property<uint64_t>& position() const = 0; |
56 | virtual const core::Property<uint64_t>& duration() const = 0; |
57 | |
58 | - |
59 | virtual core::Property<LoopStatus>& loop_status() = 0; |
60 | virtual core::Property<PlaybackRate>& playback_rate() = 0; |
61 | virtual core::Property<bool>& is_shuffle() = 0; |
62 | virtual core::Property<Volume>& volume() = 0; |
63 | |
64 | - |
65 | virtual const core::Signal<uint64_t>& seeked_to() const = 0; |
66 | - |
67 | + virtual const core::Signal<void>& end_of_stream() const = 0; |
68 | protected: |
69 | Player(); |
70 | |
71 | |
72 | === modified file 'src/core/media/CMakeLists.txt' |
73 | --- src/core/media/CMakeLists.txt 2014-02-26 14:58:36 +0000 |
74 | +++ src/core/media/CMakeLists.txt 2014-03-26 17:18:55 +0000 |
75 | @@ -1,6 +1,6 @@ |
76 | pkg_check_modules(PC_GSTREAMER_1_0 REQUIRED gstreamer-1.0) |
77 | |
78 | -include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS}) |
79 | +include_directories(${PC_GSTREAMER_1_0_INCLUDE_DIRS} /usr/include/hybris) |
80 | |
81 | add_library( |
82 | media-hub-common SHARED |
83 | @@ -52,6 +52,7 @@ |
84 | ${DBUS_LIBRARIES} |
85 | ${DBUS_CPP_LDFLAGS} |
86 | ${GLog_LIBRARY} |
87 | + -lmedia |
88 | ) |
89 | |
90 | install( |
91 | @@ -82,9 +83,11 @@ |
92 | ${DBUS_CPP_LDFLAGS} |
93 | ${GLog_LIBRARY} |
94 | ${PC_GSTREAMER_1_0_LIBRARIES} |
95 | + ${GIO_LIBRARIES} |
96 | + -lmedia |
97 | ) |
98 | |
99 | -include_directories(${PROJECT_SOURCE_DIR}/src/) |
100 | +include_directories(${PROJECT_SOURCE_DIR}/src/ /usr/include/hybris) |
101 | |
102 | add_executable( |
103 | media-hub-server |
104 | @@ -102,6 +105,7 @@ |
105 | ${DBUS_CPP_LDFLAGS} |
106 | ${GLog_LIBRARY} |
107 | ${PC_GSTREAMER_1_0_LIBRARIES} |
108 | + -lmedia |
109 | ) |
110 | |
111 | install( |
112 | |
113 | === modified file 'src/core/media/engine.h' |
114 | --- src/core/media/engine.h 2014-02-18 19:27:01 +0000 |
115 | +++ src/core/media/engine.h 2014-03-26 17:18:55 +0000 |
116 | @@ -97,12 +97,16 @@ |
117 | virtual const core::Property<State>& state() const = 0; |
118 | |
119 | virtual bool open_resource_for_uri(const Track::UriType& uri) = 0; |
120 | + virtual void create_video_sink(uint32_t texture_id) = 0; |
121 | |
122 | virtual bool play() = 0; |
123 | virtual bool stop() = 0; |
124 | virtual bool pause() = 0; |
125 | virtual bool seek_to(const std::chrono::microseconds& ts) = 0; |
126 | |
127 | + virtual const core::Property<bool>& is_video_source() const = 0; |
128 | + virtual const core::Property<bool>& is_audio_source() const = 0; |
129 | + |
130 | virtual const core::Property<uint64_t>& position() const = 0; |
131 | virtual const core::Property<uint64_t>& duration() const = 0; |
132 | |
133 | @@ -110,6 +114,9 @@ |
134 | virtual core::Property<Volume>& volume() = 0; |
135 | |
136 | virtual const core::Property<std::tuple<Track::UriType, Track::MetaData>>& track_meta_data() const = 0; |
137 | + |
138 | + virtual const core::Signal<void>& about_to_finish_signal() const = 0; |
139 | + virtual const core::Signal<void>& end_of_stream_signal() const = 0; |
140 | }; |
141 | } |
142 | } |
143 | |
144 | === modified file 'src/core/media/gstreamer/engine.cpp' |
145 | --- src/core/media/gstreamer/engine.cpp 2014-02-20 19:05:17 +0000 |
146 | +++ src/core/media/gstreamer/engine.cpp 2014-03-26 17:18:55 +0000 |
147 | @@ -16,6 +16,9 @@ |
148 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
149 | */ |
150 | |
151 | +#include <stdio.h> |
152 | +#include <stdlib.h> |
153 | + |
154 | #include "bus.h" |
155 | #include "engine.h" |
156 | #include "meta_data_extractor.h" |
157 | @@ -43,14 +46,10 @@ |
158 | |
159 | struct gstreamer::Engine::Private |
160 | { |
161 | - void about_to_finish() |
162 | - { |
163 | - state = Engine::State::ready; |
164 | - } |
165 | - |
166 | void on_playbin_state_changed( |
167 | - const gstreamer::Bus::Message::Detail::StateChanged&) |
168 | + const gstreamer::Bus::Message::Detail::StateChanged& state_change) |
169 | { |
170 | + (void) state_change; |
171 | } |
172 | |
173 | void on_tag_available(const gstreamer::Bus::Message::Detail::Tag& tag) |
174 | @@ -163,13 +162,26 @@ |
175 | playbin.set_volume(new_volume.value); |
176 | } |
177 | |
178 | + void on_about_to_finish() |
179 | + { |
180 | + state = Engine::State::ready; |
181 | + about_to_finish(); |
182 | + } |
183 | + |
184 | + void on_end_of_stream() |
185 | + { |
186 | + end_of_stream(); |
187 | + } |
188 | + |
189 | Private() |
190 | : meta_data_extractor(new gstreamer::MetaDataExtractor()), |
191 | volume(media::Engine::Volume(1.)), |
192 | + is_video_source(false), |
193 | + is_audio_source(false), |
194 | about_to_finish_connection( |
195 | playbin.signals.about_to_finish.connect( |
196 | std::bind( |
197 | - &Private::about_to_finish, |
198 | + &Private::on_about_to_finish, |
199 | this))), |
200 | on_state_changed_connection( |
201 | playbin.signals.on_state_changed.connect( |
202 | @@ -188,7 +200,12 @@ |
203 | std::bind( |
204 | &Private::on_volume_changed, |
205 | this, |
206 | - std::placeholders::_1))) |
207 | + std::placeholders::_1))), |
208 | + on_end_of_stream_connection( |
209 | + playbin.signals.on_end_of_stream.connect( |
210 | + std::bind( |
211 | + &Private::on_end_of_stream, |
212 | + this))) |
213 | { |
214 | } |
215 | |
216 | @@ -198,11 +215,17 @@ |
217 | core::Property<uint64_t> position; |
218 | core::Property<uint64_t> duration; |
219 | core::Property<media::Engine::Volume> volume; |
220 | + core::Property<bool> is_video_source; |
221 | + core::Property<bool> is_audio_source; |
222 | gstreamer::Playbin playbin; |
223 | core::ScopedConnection about_to_finish_connection; |
224 | core::ScopedConnection on_state_changed_connection; |
225 | core::ScopedConnection on_tag_available_connection; |
226 | core::ScopedConnection on_volume_changed_connection; |
227 | + core::ScopedConnection on_end_of_stream_connection; |
228 | + |
229 | + core::Signal<void> about_to_finish; |
230 | + core::Signal<void> end_of_stream; |
231 | }; |
232 | |
233 | gstreamer::Engine::Engine() : d(new Private{}) |
234 | @@ -231,6 +254,11 @@ |
235 | return true; |
236 | } |
237 | |
238 | +void gstreamer::Engine::create_video_sink(uint32_t texture_id) |
239 | +{ |
240 | + d->playbin.create_video_sink(texture_id); |
241 | +} |
242 | + |
243 | bool gstreamer::Engine::play() |
244 | { |
245 | auto result = d->playbin.set_state_and_wait(GST_STATE_PLAYING); |
246 | @@ -256,7 +284,7 @@ |
247 | bool gstreamer::Engine::pause() |
248 | { |
249 | auto result = d->playbin.set_state_and_wait(GST_STATE_PAUSED); |
250 | - |
251 | + |
252 | if (result) |
253 | d->state = media::Engine::State::paused; |
254 | |
255 | @@ -268,6 +296,28 @@ |
256 | return d->playbin.seek(ts); |
257 | } |
258 | |
259 | +const core::Property<bool>& gstreamer::Engine::is_video_source() const |
260 | +{ |
261 | + gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type(); |
262 | + if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_VIDEO) |
263 | + d->is_video_source.set(true); |
264 | + else |
265 | + d->is_video_source.set(false); |
266 | + |
267 | + return d->is_video_source; |
268 | +} |
269 | + |
270 | +const core::Property<bool>& gstreamer::Engine::is_audio_source() const |
271 | +{ |
272 | + gstreamer::Playbin::MediaFileType type = d->playbin.media_file_type(); |
273 | + if (type == gstreamer::Playbin::MediaFileType::MEDIA_FILE_TYPE_AUDIO) |
274 | + d->is_audio_source.set(true); |
275 | + else |
276 | + d->is_audio_source.set(false); |
277 | + |
278 | + return d->is_audio_source; |
279 | +} |
280 | + |
281 | const core::Property<uint64_t>& gstreamer::Engine::position() const |
282 | { |
283 | d->position.set(d->playbin.position()); |
284 | @@ -295,3 +345,13 @@ |
285 | { |
286 | return d->track_meta_data; |
287 | } |
288 | + |
289 | +const core::Signal<void>& gstreamer::Engine::about_to_finish_signal() const |
290 | +{ |
291 | + return d->about_to_finish; |
292 | +} |
293 | + |
294 | +const core::Signal<void>& gstreamer::Engine::end_of_stream_signal() const |
295 | +{ |
296 | + return d->end_of_stream; |
297 | +} |
298 | |
299 | === modified file 'src/core/media/gstreamer/engine.h' |
300 | --- src/core/media/gstreamer/engine.h 2014-02-18 19:27:01 +0000 |
301 | +++ src/core/media/gstreamer/engine.h 2014-03-26 17:18:55 +0000 |
302 | @@ -33,12 +33,16 @@ |
303 | const core::Property<State>& state() const; |
304 | |
305 | bool open_resource_for_uri(const core::ubuntu::media::Track::UriType& uri); |
306 | + void create_video_sink(uint32_t texture_id); |
307 | |
308 | bool play(); |
309 | bool stop(); |
310 | bool pause(); |
311 | bool seek_to(const std::chrono::microseconds& ts); |
312 | |
313 | + const core::Property<bool>& is_video_source() const; |
314 | + const core::Property<bool>& is_audio_source() const; |
315 | + |
316 | const core::Property<uint64_t>& position() const; |
317 | const core::Property<uint64_t>& duration() const; |
318 | |
319 | @@ -47,6 +51,9 @@ |
320 | |
321 | const core::Property<std::tuple<core::ubuntu::media::Track::UriType, core::ubuntu::media::Track::MetaData>>& track_meta_data() const; |
322 | |
323 | + const core::Signal<void>& about_to_finish_signal() const; |
324 | + const core::Signal<void>& end_of_stream_signal() const; |
325 | + |
326 | private: |
327 | struct Private; |
328 | std::unique_ptr<Private> d; |
329 | |
330 | === modified file 'src/core/media/gstreamer/playbin.h' |
331 | --- src/core/media/gstreamer/playbin.h 2014-02-20 19:05:17 +0000 |
332 | +++ src/core/media/gstreamer/playbin.h 2014-03-26 17:18:55 +0000 |
333 | @@ -21,6 +21,11 @@ |
334 | |
335 | #include "bus.h" |
336 | |
337 | +#include <media/decoding_service.h> |
338 | +#include <media/media_codec_layer.h> |
339 | +#include <media/surface_texture_client_hybris.h> |
340 | + |
341 | +#include <gio/gio.h> |
342 | #include <gst/gst.h> |
343 | |
344 | #include <chrono> |
345 | @@ -37,6 +42,13 @@ |
346 | GST_PLAY_FLAG_TEXT = (1 << 2) |
347 | }; |
348 | |
349 | + enum MediaFileType |
350 | + { |
351 | + MEDIA_FILE_TYPE_NONE, |
352 | + MEDIA_FILE_TYPE_AUDIO, |
353 | + MEDIA_FILE_TYPE_VIDEO |
354 | + }; |
355 | + |
356 | static const std::string& pipeline_name() |
357 | { |
358 | static const std::string s{"playbin"}; |
359 | @@ -45,14 +57,15 @@ |
360 | |
361 | static void about_to_finish(GstElement*, |
362 | gpointer user_data) |
363 | - { auto thiz = static_cast<Playbin*>(user_data); |
364 | - |
365 | + { |
366 | + auto thiz = static_cast<Playbin*>(user_data); |
367 | thiz->signals.about_to_finish(); |
368 | } |
369 | |
370 | Playbin() |
371 | : pipeline(gst_element_factory_make("playbin", pipeline_name().c_str())), |
372 | bus{gst_element_get_bus(pipeline)}, |
373 | + file_type(MEDIA_FILE_TYPE_NONE), |
374 | on_new_message_connection( |
375 | bus.on_new_message.connect( |
376 | std::bind( |
377 | @@ -74,6 +87,8 @@ |
378 | this |
379 | ); |
380 | |
381 | + // When a client of media-hub dies, call on_client_died |
382 | + decoding_service_set_client_death_cb(&Playbin::on_client_died_cb, static_cast<void*>(this)); |
383 | } |
384 | |
385 | ~Playbin() |
386 | @@ -82,6 +97,43 @@ |
387 | gst_object_unref(pipeline); |
388 | } |
389 | |
390 | + static void on_client_died_cb(void *context) |
391 | + { |
392 | + if (context) |
393 | + { |
394 | + Playbin *pb = static_cast<Playbin*>(context); |
395 | + pb->on_client_died(); |
396 | + } |
397 | + } |
398 | + |
399 | + void on_client_died() |
400 | + { |
401 | + std::cout << "Client died, resetting pipeline" << std::endl; |
402 | + // When the client dies, tear down the current pipeline and get it |
403 | + // in a state that is ready for the next client that connects to the |
404 | + // service |
405 | + reset_pipeline(); |
406 | + } |
407 | + |
408 | + void reset_pipeline() |
409 | + { |
410 | + std::cout << __PRETTY_FUNCTION__ << std::endl; |
411 | + auto ret = gst_element_set_state(pipeline, GST_STATE_NULL); |
412 | + switch(ret) |
413 | + { |
414 | + case GST_STATE_CHANGE_FAILURE: |
415 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
416 | + break; |
417 | + case GST_STATE_CHANGE_NO_PREROLL: |
418 | + case GST_STATE_CHANGE_SUCCESS: |
419 | + case GST_STATE_CHANGE_ASYNC: |
420 | + break; |
421 | + default: |
422 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
423 | + } |
424 | + file_type = MEDIA_FILE_TYPE_NONE; |
425 | + } |
426 | + |
427 | void on_new_message(const Bus::Message& message) |
428 | { |
429 | switch(message.type) |
430 | @@ -101,6 +153,9 @@ |
431 | case GST_MESSAGE_STATE_CHANGED: |
432 | signals.on_state_changed(message.detail.state_changed); |
433 | break; |
434 | + case GST_MESSAGE_EOS: |
435 | + std::cout << "EOS detected" << std::endl; |
436 | + signals.on_end_of_stream(); |
437 | default: |
438 | break; |
439 | } |
440 | @@ -126,6 +181,8 @@ |
441 | ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"), |
442 | "audio-sink"); |
443 | |
444 | + std::cout << "audio_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") << std::endl; |
445 | + |
446 | g_object_set ( |
447 | pipeline, |
448 | "audio-sink", |
449 | @@ -136,26 +193,43 @@ |
450 | if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
451 | { |
452 | auto video_sink = gst_element_factory_make ( |
453 | - ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
454 | - "video-sink"); |
455 | + ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
456 | + "video-sink"); |
457 | |
458 | std::cout << "video_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") << std::endl; |
459 | |
460 | g_object_set ( |
461 | - pipeline, |
462 | - "video-sink", |
463 | - video_sink, |
464 | - NULL); |
465 | + pipeline, |
466 | + "video-sink", |
467 | + video_sink, |
468 | + NULL); |
469 | + } |
470 | + } |
471 | + |
472 | + void create_video_sink(uint32_t texture_id) |
473 | + { |
474 | + std::cout << "Creating video sink for texture_id: " << texture_id << std::endl; |
475 | + |
476 | + if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
477 | + { |
478 | + GstElement *video_sink = NULL; |
479 | + g_object_get (pipeline, "video_sink", &video_sink, NULL); |
480 | + |
481 | + // Get the service-side BufferQueue (IGraphicBufferProducer) and associate it with |
482 | + // the SurfaceTextureClientHybris instance |
483 | + IGBPWrapperHybris igbp = decoding_service_get_igraphicbufferproducer(); |
484 | + std::cout << "IGBPWrapperHybris: " << igbp << std::endl; |
485 | + SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp); |
486 | + std::cout << "SurfaceTextureClientHybris: " << stc << std::endl; |
487 | + // Because mirsink is being loaded, we are definitely doing * hardware rendering. |
488 | + surface_texture_client_set_hardware_rendering (stc, TRUE); |
489 | + g_object_set (G_OBJECT (video_sink), "surface", static_cast<gpointer>(stc), static_cast<char*>(NULL)); |
490 | } |
491 | } |
492 | |
493 | void set_volume(double new_volume) |
494 | { |
495 | - g_object_set( |
496 | - pipeline, |
497 | - "volume", |
498 | - new_volume, |
499 | - NULL); |
500 | + g_object_set(pipeline, "volume", new_volume, NULL); |
501 | } |
502 | |
503 | uint64_t position() const |
504 | @@ -178,11 +252,11 @@ |
505 | |
506 | void set_uri(const std::string& uri) |
507 | { |
508 | - g_object_set( |
509 | - pipeline, |
510 | - "uri", |
511 | - uri.c_str(), |
512 | - NULL); |
513 | + g_object_set(pipeline, "uri", uri.c_str(), NULL); |
514 | + if (is_video_file(uri)) |
515 | + file_type = MEDIA_FILE_TYPE_VIDEO; |
516 | + else if (is_audio_file(uri)) |
517 | + file_type = MEDIA_FILE_TYPE_AUDIO; |
518 | } |
519 | |
520 | std::string uri() const |
521 | @@ -236,8 +310,80 @@ |
522 | ms.count() * 1000); |
523 | } |
524 | |
525 | + std::string get_file_content_type(const std::string& uri) const |
526 | + { |
527 | + if (uri.empty()) |
528 | + return std::string(); |
529 | + |
530 | + std::string filename(uri); |
531 | + size_t pos = uri.find("file://") + 7; |
532 | + if (pos) |
533 | + filename = uri.substr(pos, std::string::npos); |
534 | + |
535 | + std::cout << "filename: " << filename << std::endl; |
536 | + |
537 | + GError *error = nullptr; |
538 | + std::unique_ptr<GFile, void(*)(void *)> file( |
539 | + g_file_new_for_path(filename.c_str()), g_object_unref); |
540 | + std::unique_ptr<GFileInfo, void(*)(void *)> info( |
541 | + g_file_query_info( |
542 | + file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE "," |
543 | + G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE, |
544 | + /* cancellable */ NULL, &error), |
545 | + g_object_unref); |
546 | + if (!info) |
547 | + { |
548 | + std::string error_str(error->message); |
549 | + g_error_free(error); |
550 | + |
551 | + std::cout << "Failed to query the URI for the presence of video content: " |
552 | + << error_str << std::endl; |
553 | + return std::string(); |
554 | + } |
555 | + |
556 | + std::string content_type(g_file_info_get_attribute_string( |
557 | + info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE)); |
558 | + |
559 | + return content_type; |
560 | + } |
561 | + |
562 | + bool is_audio_file(const std::string& uri) const |
563 | + { |
564 | + if (uri.empty()) |
565 | + return false; |
566 | + |
567 | + if (get_file_content_type(uri).find("audio/") == 0) |
568 | + { |
569 | + std::cout << "Found audio content" << std::endl; |
570 | + return true; |
571 | + } |
572 | + |
573 | + return false; |
574 | + } |
575 | + |
576 | + bool is_video_file(const std::string& uri) const |
577 | + { |
578 | + if (uri.empty()) |
579 | + return false; |
580 | + |
581 | + if (get_file_content_type(uri).find("video/") == 0) |
582 | + { |
583 | + std::cout << "Found video content" << std::endl; |
584 | + return true; |
585 | + } |
586 | + |
587 | + return false; |
588 | + } |
589 | + |
590 | + MediaFileType media_file_type() const |
591 | + { |
592 | + return file_type; |
593 | + } |
594 | + |
595 | GstElement* pipeline; |
596 | gstreamer::Bus bus; |
597 | + MediaFileType file_type; |
598 | + SurfaceTextureClientHybris stc_hybris; |
599 | core::Connection on_new_message_connection; |
600 | struct |
601 | { |
602 | @@ -247,6 +393,7 @@ |
603 | core::Signal<Bus::Message::Detail::ErrorWarningInfo> on_info; |
604 | core::Signal<Bus::Message::Detail::Tag> on_tag_available; |
605 | core::Signal<Bus::Message::Detail::StateChanged> on_state_changed; |
606 | + core::Signal<void> on_end_of_stream; |
607 | } signals; |
608 | }; |
609 | } |
610 | |
611 | === modified file 'src/core/media/mpris/player.h' |
612 | --- src/core/media/mpris/player.h 2014-02-18 19:27:01 +0000 |
613 | +++ src/core/media/mpris/player.h 2014-03-26 17:18:55 +0000 |
614 | @@ -54,11 +54,13 @@ |
615 | METHOD(Play, Player, std::chrono::seconds(1)) |
616 | METHOD(Seek, Player, std::chrono::seconds(1)) |
617 | METHOD(SetPosition, Player, std::chrono::seconds(1)) |
618 | + METHOD(CreateVideoSink, Player, std::chrono::seconds(1)) |
619 | METHOD(OpenUri, Player, std::chrono::seconds(1)) |
620 | |
621 | struct Signals |
622 | { |
623 | SIGNAL(Seeked, Player, uint64_t) |
624 | + SIGNAL(EndOfStream, Player, void) |
625 | }; |
626 | |
627 | struct Properties |
628 | @@ -74,6 +76,8 @@ |
629 | READABLE_PROPERTY(Duration, Player, uint64_t) |
630 | READABLE_PROPERTY(MinimumRate, Player, double) |
631 | READABLE_PROPERTY(MaximumRate, Player, double) |
632 | + READABLE_PROPERTY(IsVideoSource, Player, bool) |
633 | + READABLE_PROPERTY(IsAudioSource, Player, bool) |
634 | READABLE_PROPERTY(CanGoNext, Player, bool) |
635 | READABLE_PROPERTY(CanGoPrevious, Player, bool) |
636 | READABLE_PROPERTY(CanPlay, Player, bool) |
637 | |
638 | === modified file 'src/core/media/player_implementation.cpp' |
639 | --- src/core/media/player_implementation.cpp 2014-02-18 20:25:21 +0000 |
640 | +++ src/core/media/player_implementation.cpp 2014-03-26 17:18:55 +0000 |
641 | @@ -17,9 +17,13 @@ |
642 | |
643 | #include "player_implementation.h" |
644 | |
645 | +#include <unistd.h> |
646 | + |
647 | #include "engine.h" |
648 | #include "track_list_implementation.h" |
649 | |
650 | +#define UNUSED __attribute__((unused)) |
651 | + |
652 | namespace media = core::ubuntu::media; |
653 | |
654 | struct media::PlayerImplementation::Private |
655 | @@ -39,7 +43,7 @@ |
656 | { |
657 | engine->state().changed().connect( |
658 | [parent](const Engine::State& state) |
659 | - { |
660 | + { |
661 | switch(state) |
662 | { |
663 | case Engine::State::ready: parent->playback_status().set(media::Player::ready); break; |
664 | @@ -49,7 +53,8 @@ |
665 | default: |
666 | break; |
667 | }; |
668 | - }); |
669 | + }); |
670 | + |
671 | } |
672 | |
673 | PlayerImplementation* parent; |
674 | @@ -76,6 +81,8 @@ |
675 | can_seek().set(true); |
676 | can_go_previous().set(true); |
677 | can_go_next().set(true); |
678 | + is_video_source().set(false); |
679 | + is_audio_source().set(false); |
680 | is_shuffle().set(true); |
681 | playback_rate().set(1.f); |
682 | playback_status().set(Player::PlaybackStatus::null); |
683 | @@ -98,6 +105,33 @@ |
684 | return d->engine->duration().get(); |
685 | }; |
686 | duration().install(duration_getter); |
687 | + |
688 | + std::function<bool()> video_type_getter = [this]() |
689 | + { |
690 | + return d->engine->is_video_source().get(); |
691 | + }; |
692 | + is_video_source().install(video_type_getter); |
693 | + |
694 | + std::function<bool()> audio_type_getter = [this]() |
695 | + { |
696 | + return d->engine->is_audio_source().get(); |
697 | + }; |
698 | + is_audio_source().install(audio_type_getter); |
699 | + |
700 | + engine->about_to_finish_signal().connect([this]() |
701 | + { |
702 | + if (d->track_list->has_next()) |
703 | + { |
704 | + Track::UriType uri = d->track_list->query_uri_for_track(d->track_list->next()); |
705 | + if (!uri.empty()) |
706 | + d->parent->open_uri(uri); |
707 | + } |
708 | + }); |
709 | + |
710 | + engine->end_of_stream_signal().connect([this]() |
711 | + { |
712 | + end_of_stream()(); |
713 | + }); |
714 | } |
715 | |
716 | media::PlayerImplementation::~PlayerImplementation() |
717 | @@ -114,6 +148,17 @@ |
718 | return d->engine->open_resource_for_uri(uri); |
719 | } |
720 | |
721 | +void media::PlayerImplementation::create_video_sink(uint32_t texture_id) |
722 | +{ |
723 | + d->engine->create_video_sink(texture_id); |
724 | +} |
725 | + |
726 | +media::Player::GLConsumerWrapperHybris media::PlayerImplementation::gl_consumer() const |
727 | +{ |
728 | + // This method is client-side only and is simply a no-op for the service side |
729 | + return NULL; |
730 | +} |
731 | + |
732 | void media::PlayerImplementation::next() |
733 | { |
734 | } |
735 | @@ -124,11 +169,6 @@ |
736 | |
737 | void media::PlayerImplementation::play() |
738 | { |
739 | - /*if (playback_status() == media::Player::null) |
740 | - { |
741 | - if (d->track_list->has_next()) |
742 | - if (open_uri(d->track_list->next()->)) |
743 | - }*/ |
744 | d->engine->play(); |
745 | } |
746 | |
747 | @@ -142,6 +182,12 @@ |
748 | d->engine->stop(); |
749 | } |
750 | |
751 | +void media::PlayerImplementation::set_frame_available_callback( |
752 | + UNUSED FrameAvailableCb cb, UNUSED void *context) |
753 | +{ |
754 | + // This method is client-side only and is simply a no-op for the service side |
755 | +} |
756 | + |
757 | void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms) |
758 | { |
759 | d->engine->seek_to(ms); |
760 | |
761 | === modified file 'src/core/media/player_implementation.h' |
762 | --- src/core/media/player_implementation.h 2014-02-18 20:25:21 +0000 |
763 | +++ src/core/media/player_implementation.h 2014-03-26 17:18:55 +0000 |
764 | @@ -43,11 +43,14 @@ |
765 | virtual std::shared_ptr<TrackList> track_list(); |
766 | |
767 | virtual bool open_uri(const Track::UriType& uri); |
768 | + virtual void create_video_sink(uint32_t texture_id); |
769 | + virtual GLConsumerWrapperHybris gl_consumer() const; |
770 | virtual void next(); |
771 | virtual void previous(); |
772 | virtual void play(); |
773 | virtual void pause(); |
774 | virtual void stop(); |
775 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
776 | virtual void seek_to(const std::chrono::microseconds& offset); |
777 | |
778 | private: |
779 | |
780 | === modified file 'src/core/media/player_skeleton.cpp' |
781 | --- src/core/media/player_skeleton.cpp 2014-02-20 19:05:17 +0000 |
782 | +++ src/core/media/player_skeleton.cpp 2014-03-26 17:18:55 +0000 |
783 | @@ -44,6 +44,8 @@ |
784 | object->get_property<mpris::Player::Properties::CanControl>(), |
785 | object->get_property<mpris::Player::Properties::CanGoNext>(), |
786 | object->get_property<mpris::Player::Properties::CanGoPrevious>(), |
787 | + object->get_property<mpris::Player::Properties::IsVideoSource>(), |
788 | + object->get_property<mpris::Player::Properties::IsAudioSource>(), |
789 | object->get_property<mpris::Player::Properties::PlaybackStatus>(), |
790 | object->get_property<mpris::Player::Properties::LoopStatus>(), |
791 | object->get_property<mpris::Player::Properties::PlaybackRate>(), |
792 | @@ -54,6 +56,11 @@ |
793 | object->get_property<mpris::Player::Properties::Duration>(), |
794 | object->get_property<mpris::Player::Properties::MinimumRate>(), |
795 | object->get_property<mpris::Player::Properties::MaximumRate>() |
796 | + }, |
797 | + signals |
798 | + { |
799 | + object->get_signal<mpris::Player::Signals::Seeked>(), |
800 | + object->get_signal<mpris::Player::Signals::EndOfStream>() |
801 | } |
802 | { |
803 | } |
804 | @@ -111,6 +118,16 @@ |
805 | { |
806 | } |
807 | |
808 | + void handle_create_video_sink(const core::dbus::Message::Ptr& in) |
809 | + { |
810 | + uint32_t texture_id; |
811 | + in->reader() >> texture_id; |
812 | + impl->create_video_sink(texture_id); |
813 | + |
814 | + auto reply = dbus::Message::make_method_return(in); |
815 | + impl->access_bus()->send(reply); |
816 | + } |
817 | + |
818 | void handle_open_uri(const core::dbus::Message::Ptr& in) |
819 | { |
820 | Track::UriType uri; |
821 | @@ -131,6 +148,8 @@ |
822 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control; |
823 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next; |
824 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous; |
825 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source; |
826 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source; |
827 | |
828 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status; |
829 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status; |
830 | @@ -144,10 +163,41 @@ |
831 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate; |
832 | } properties; |
833 | |
834 | - /*struct |
835 | + struct Signals |
836 | { |
837 | - std::shared_ptr<dbus::Signal<mpris::Player::Signals::Seeked, uint64_t>> seeked; |
838 | - } signals;*/ |
839 | + typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
840 | + typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
841 | + |
842 | + Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, |
843 | + const std::shared_ptr<DBusEndOfStreamSignal>& eos) |
844 | + : dbus |
845 | + { |
846 | + seeked, |
847 | + eos |
848 | + }, |
849 | + seeked_to(), |
850 | + end_of_stream() |
851 | + { |
852 | + seeked_to.connect([this](std::uint64_t value) |
853 | + { |
854 | + std::cout << "value: " << value << std::endl; |
855 | + //dbus.seeked_to->emit(value); |
856 | + }); |
857 | + |
858 | + end_of_stream.connect([this]() |
859 | + { |
860 | + dbus.end_of_stream->emit(); |
861 | + }); |
862 | + } |
863 | + |
864 | + struct DBus |
865 | + { |
866 | + std::shared_ptr<DBusSeekedToSignal> seeked_to; |
867 | + std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; |
868 | + } dbus; |
869 | + core::Signal<uint64_t> seeked_to; |
870 | + core::Signal<void> end_of_stream; |
871 | + } signals; |
872 | |
873 | }; |
874 | |
875 | @@ -184,6 +234,10 @@ |
876 | std::bind(&Private::handle_set_position, |
877 | std::ref(d), |
878 | std::placeholders::_1)); |
879 | + d->object->install_method_handler<mpris::Player::CreateVideoSink>( |
880 | + std::bind(&Private::handle_create_video_sink, |
881 | + std::ref(d), |
882 | + std::placeholders::_1)); |
883 | d->object->install_method_handler<mpris::Player::OpenUri>( |
884 | std::bind(&Private::handle_open_uri, |
885 | std::ref(d), |
886 | @@ -219,6 +273,16 @@ |
887 | return *d->properties.can_go_next; |
888 | } |
889 | |
890 | +const core::Property<bool>& media::PlayerSkeleton::is_video_source() const |
891 | +{ |
892 | + return *d->properties.is_video_source; |
893 | +} |
894 | + |
895 | +const core::Property<bool>& media::PlayerSkeleton::is_audio_source() const |
896 | +{ |
897 | + return *d->properties.is_audio_source; |
898 | +} |
899 | + |
900 | const core::Property<media::Player::PlaybackStatus>& media::PlayerSkeleton::playback_status() const |
901 | { |
902 | return *d->properties.playback_status; |
903 | @@ -329,6 +393,17 @@ |
904 | return *d->properties.can_go_next; |
905 | } |
906 | |
907 | +core::Property<bool>& media::PlayerSkeleton::is_video_source() |
908 | +{ |
909 | + return *d->properties.is_video_source; |
910 | +} |
911 | + |
912 | +core::Property<bool>& media::PlayerSkeleton::is_audio_source() |
913 | +{ |
914 | + return *d->properties.is_audio_source; |
915 | +} |
916 | + |
917 | + |
918 | core::Property<media::Track::MetaData>& media::PlayerSkeleton::meta_data_for_current_track() |
919 | { |
920 | return *d->properties.meta_data_for_current_track; |
921 | @@ -346,6 +421,20 @@ |
922 | |
923 | const core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() const |
924 | { |
925 | - static const core::Signal<uint64_t> signal; |
926 | - return signal; |
927 | + return d->signals.seeked_to; |
928 | +} |
929 | + |
930 | +core::Signal<uint64_t>& media::PlayerSkeleton::seeked_to() |
931 | +{ |
932 | + return d->signals.seeked_to; |
933 | +} |
934 | + |
935 | +const core::Signal<void>& media::PlayerSkeleton::end_of_stream() const |
936 | +{ |
937 | + return d->signals.end_of_stream; |
938 | +} |
939 | + |
940 | +core::Signal<void>& media::PlayerSkeleton::end_of_stream() |
941 | +{ |
942 | + return d->signals.end_of_stream; |
943 | } |
944 | |
945 | === modified file 'src/core/media/player_skeleton.h' |
946 | --- src/core/media/player_skeleton.h 2014-02-18 19:27:01 +0000 |
947 | +++ src/core/media/player_skeleton.h 2014-03-26 17:18:55 +0000 |
948 | @@ -46,6 +46,8 @@ |
949 | virtual const core::Property<bool>& can_seek() const; |
950 | virtual const core::Property<bool>& can_go_previous() const; |
951 | virtual const core::Property<bool>& can_go_next() const; |
952 | + virtual const core::Property<bool>& is_video_source() const; |
953 | + virtual const core::Property<bool>& is_audio_source() const; |
954 | virtual const core::Property<PlaybackStatus>& playback_status() const; |
955 | virtual const core::Property<LoopStatus>& loop_status() const; |
956 | virtual const core::Property<PlaybackRate>& playback_rate() const; |
957 | @@ -63,6 +65,7 @@ |
958 | virtual core::Property<Volume>& volume(); |
959 | |
960 | virtual const core::Signal<uint64_t>& seeked_to() const; |
961 | + virtual const core::Signal<void>& end_of_stream() const; |
962 | |
963 | protected: |
964 | PlayerSkeleton(const core::dbus::types::ObjectPath& session_path); |
965 | @@ -73,12 +76,17 @@ |
966 | virtual core::Property<bool>& can_seek(); |
967 | virtual core::Property<bool>& can_go_previous(); |
968 | virtual core::Property<bool>& can_go_next(); |
969 | + virtual core::Property<bool>& is_video_source(); |
970 | + virtual core::Property<bool>& is_audio_source(); |
971 | virtual core::Property<Track::MetaData>& meta_data_for_current_track(); |
972 | virtual core::Property<PlaybackRate>& minimum_playback_rate(); |
973 | virtual core::Property<PlaybackRate>& maximum_playback_rate(); |
974 | virtual core::Property<uint64_t>& position(); |
975 | virtual core::Property<uint64_t>& duration(); |
976 | |
977 | + virtual core::Signal<uint64_t>& seeked_to(); |
978 | + virtual core::Signal<void>& end_of_stream(); |
979 | + |
980 | private: |
981 | struct Private; |
982 | std::unique_ptr<Private> d; |
983 | |
984 | === modified file 'src/core/media/player_stub.cpp' |
985 | --- src/core/media/player_stub.cpp 2014-02-20 19:05:17 +0000 |
986 | +++ src/core/media/player_stub.cpp 2014-03-26 17:18:55 +0000 |
987 | @@ -31,8 +31,15 @@ |
988 | #include <core/dbus/property.h> |
989 | #include <core/dbus/types/object_path.h> |
990 | |
991 | +// Hybris |
992 | +#include <media/decoding_service.h> |
993 | +#include <media/media_codec_layer.h> |
994 | +#include <media/surface_texture_client_hybris.h> |
995 | + |
996 | #include <limits> |
997 | |
998 | +#define UNUSED __attribute__((unused)) |
999 | + |
1000 | namespace dbus = core::dbus; |
1001 | namespace media = core::ubuntu::media; |
1002 | |
1003 | @@ -42,6 +49,12 @@ |
1004 | const std::shared_ptr<dbus::Service>& remote, |
1005 | const dbus::types::ObjectPath& path |
1006 | ) : parent(parent), |
1007 | + texture_id(0), |
1008 | + igbc_wrapper(nullptr), |
1009 | + glc_wrapper(nullptr), |
1010 | + decoding_session(decoding_service_create_session()), |
1011 | + frame_available_cb(nullptr), |
1012 | + frame_available_context(nullptr), |
1013 | path(path), |
1014 | object(remote->object_for_path(path)), |
1015 | properties |
1016 | @@ -52,6 +65,8 @@ |
1017 | object->get_property<mpris::Player::Properties::CanControl>(), |
1018 | object->get_property<mpris::Player::Properties::CanGoNext>(), |
1019 | object->get_property<mpris::Player::Properties::CanGoPrevious>(), |
1020 | + object->get_property<mpris::Player::Properties::IsVideoSource>(), |
1021 | + object->get_property<mpris::Player::Properties::IsAudioSource>(), |
1022 | object->get_property<mpris::Player::Properties::PlaybackStatus>(), |
1023 | object->get_property<mpris::Player::Properties::LoopStatus>(), |
1024 | object->get_property<mpris::Player::Properties::PlaybackRate>(), |
1025 | @@ -62,13 +77,67 @@ |
1026 | object->get_property<mpris::Player::Properties::Duration>(), |
1027 | object->get_property<mpris::Player::Properties::MinimumRate>(), |
1028 | object->get_property<mpris::Player::Properties::MaximumRate>() |
1029 | + }, |
1030 | + signals |
1031 | + { |
1032 | + object->get_signal<mpris::Player::Signals::Seeked>(), |
1033 | + object->get_signal<mpris::Player::Signals::EndOfStream>() |
1034 | } |
1035 | { |
1036 | } |
1037 | |
1038 | + ~Private() |
1039 | + { |
1040 | + } |
1041 | + |
1042 | + static void on_frame_available_cb(UNUSED GLConsumerWrapperHybris wrapper, void *context) |
1043 | + { |
1044 | + if (context != nullptr) { |
1045 | + Private *p = static_cast<Private*>(context); |
1046 | + p->on_frame_available(); |
1047 | + } |
1048 | + else |
1049 | + std::cout << "context is nullptr, can't call on_frame_available()" << std::endl; |
1050 | + } |
1051 | + |
1052 | + void on_frame_available() |
1053 | + { |
1054 | + if (frame_available_cb != nullptr) { |
1055 | + frame_available_cb(frame_available_context); |
1056 | + } |
1057 | + else |
1058 | + std::cout << "frame_available_cb is nullptr, can't call frame_available_cb()" << std::endl; |
1059 | + } |
1060 | + |
1061 | + void set_frame_available_cb(FrameAvailableCb cb, void *context) |
1062 | + { |
1063 | + frame_available_cb = cb; |
1064 | + frame_available_context = context; |
1065 | + |
1066 | + gl_consumer_set_frame_available_cb(glc_wrapper, &Private::on_frame_available_cb, static_cast<void*>(this)); |
1067 | + } |
1068 | + |
1069 | + /** We need a GLConsumerHybris instance for doing texture streaming over the |
1070 | + * process boundary **/ |
1071 | + void get_gl_consumer() |
1072 | + { |
1073 | + igbc_wrapper = decoding_service_get_igraphicbufferconsumer(); |
1074 | + glc_wrapper = gl_consumer_create_by_id_with_igbc(texture_id, igbc_wrapper); |
1075 | + |
1076 | + } |
1077 | + |
1078 | std::shared_ptr<Service> parent; |
1079 | std::shared_ptr<TrackList> track_list; |
1080 | |
1081 | + uint32_t texture_id; |
1082 | + IGBCWrapperHybris igbc_wrapper; |
1083 | + GLConsumerWrapperHybris glc_wrapper; |
1084 | + |
1085 | + DSSessionWrapperHybris decoding_session; |
1086 | + |
1087 | + FrameAvailableCb frame_available_cb; |
1088 | + void *frame_available_context; |
1089 | + |
1090 | dbus::Bus::Ptr bus; |
1091 | dbus::types::ObjectPath path; |
1092 | dbus::Object::Ptr object; |
1093 | @@ -81,6 +150,8 @@ |
1094 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanControl>> can_control; |
1095 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoNext>> can_go_next; |
1096 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanGoPrevious>> can_go_previous; |
1097 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsVideoSource>> is_video_source; |
1098 | + std::shared_ptr<core::dbus::Property<mpris::Player::Properties::IsAudioSource>> is_audio_source; |
1099 | |
1100 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::PlaybackStatus>> playback_status; |
1101 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::LoopStatus>> loop_status; |
1102 | @@ -93,6 +164,42 @@ |
1103 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MinimumRate>> minimum_playback_rate; |
1104 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::MaximumRate>> maximum_playback_rate; |
1105 | } properties; |
1106 | + |
1107 | + struct Signals |
1108 | + { |
1109 | + typedef core::dbus::Signal<mpris::Player::Signals::Seeked, mpris::Player::Signals::Seeked::ArgumentType> DBusSeekedToSignal; |
1110 | + typedef core::dbus::Signal<mpris::Player::Signals::EndOfStream, mpris::Player::Signals::EndOfStream::ArgumentType> DBusEndOfStreamSignal; |
1111 | + |
1112 | + Signals(const std::shared_ptr<DBusSeekedToSignal>& seeked, |
1113 | + const std::shared_ptr<DBusEndOfStreamSignal>& eos) |
1114 | + : dbus |
1115 | + { |
1116 | + seeked, |
1117 | + eos |
1118 | + }, |
1119 | + seeked_to(), |
1120 | + end_of_stream() |
1121 | + { |
1122 | + dbus.seeked_to->connect([this](std::uint64_t value) |
1123 | + { |
1124 | + seeked_to(value); |
1125 | + }); |
1126 | + |
1127 | + dbus.end_of_stream->connect([this]() |
1128 | + { |
1129 | + std::cout << "EndOfStream signal arrived via the bus." << std::endl; |
1130 | + end_of_stream(); |
1131 | + }); |
1132 | + } |
1133 | + |
1134 | + struct DBus |
1135 | + { |
1136 | + std::shared_ptr<DBusSeekedToSignal> seeked_to; |
1137 | + std::shared_ptr<DBusEndOfStreamSignal> end_of_stream; |
1138 | + } dbus; |
1139 | + core::Signal<uint64_t> seeked_to; |
1140 | + core::Signal<void> end_of_stream; |
1141 | + } signals; |
1142 | }; |
1143 | |
1144 | media::PlayerStub::PlayerStub( |
1145 | @@ -125,6 +232,21 @@ |
1146 | return op.value(); |
1147 | } |
1148 | |
1149 | +void media::PlayerStub::create_video_sink(uint32_t texture_id) |
1150 | +{ |
1151 | + auto op = d->object->invoke_method_synchronously<mpris::Player::CreateVideoSink, void>(texture_id); |
1152 | + d->texture_id = texture_id; |
1153 | + d->get_gl_consumer(); |
1154 | + |
1155 | + if (op.is_error()) |
1156 | + throw std::runtime_error("Problem switching to next track on remote object"); |
1157 | +} |
1158 | + |
1159 | +GLConsumerWrapperHybris media::PlayerStub::gl_consumer() const |
1160 | +{ |
1161 | + return d->glc_wrapper; |
1162 | +} |
1163 | + |
1164 | void media::PlayerStub::next() |
1165 | { |
1166 | auto op = d->object->invoke_method_synchronously<mpris::Player::Next, void>(); |
1167 | @@ -173,6 +295,11 @@ |
1168 | throw std::runtime_error("Problem stopping playback on remote object"); |
1169 | } |
1170 | |
1171 | +void media::PlayerStub::set_frame_available_callback(FrameAvailableCb cb, void *context) |
1172 | +{ |
1173 | + d->set_frame_available_cb(cb, context); |
1174 | +} |
1175 | + |
1176 | const core::Property<bool>& media::PlayerStub::can_play() const |
1177 | { |
1178 | return *d->properties.can_play; |
1179 | @@ -198,6 +325,16 @@ |
1180 | return *d->properties.can_go_next; |
1181 | } |
1182 | |
1183 | +const core::Property<bool>& media::PlayerStub::is_video_source() const |
1184 | +{ |
1185 | + return *d->properties.is_video_source; |
1186 | +} |
1187 | + |
1188 | +const core::Property<bool>& media::PlayerStub::is_audio_source() const |
1189 | +{ |
1190 | + return *d->properties.is_audio_source; |
1191 | +} |
1192 | + |
1193 | const core::Property<media::Player::PlaybackStatus>& media::PlayerStub::playback_status() const |
1194 | { |
1195 | return *d->properties.playback_status; |
1196 | @@ -270,6 +407,10 @@ |
1197 | |
1198 | const core::Signal<uint64_t>& media::PlayerStub::seeked_to() const |
1199 | { |
1200 | - static core::Signal<uint64_t> signal; |
1201 | - return signal; |
1202 | + return d->signals.seeked_to; |
1203 | +} |
1204 | + |
1205 | +const core::Signal<void>& media::PlayerStub::end_of_stream() const |
1206 | +{ |
1207 | + return d->signals.end_of_stream; |
1208 | } |
1209 | |
1210 | === modified file 'src/core/media/player_stub.h' |
1211 | --- src/core/media/player_stub.h 2014-02-18 19:27:01 +0000 |
1212 | +++ src/core/media/player_stub.h 2014-03-26 17:18:55 +0000 |
1213 | @@ -45,6 +45,8 @@ |
1214 | virtual std::shared_ptr<TrackList> track_list(); |
1215 | |
1216 | virtual bool open_uri(const Track::UriType& uri); |
1217 | + virtual void create_video_sink(uint32_t texture_id); |
1218 | + virtual GLConsumerWrapperHybris gl_consumer() const; |
1219 | virtual void next(); |
1220 | virtual void previous(); |
1221 | virtual void play(); |
1222 | @@ -52,11 +54,15 @@ |
1223 | virtual void seek_to(const std::chrono::microseconds& offset); |
1224 | virtual void stop(); |
1225 | |
1226 | + virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
1227 | + |
1228 | virtual const core::Property<bool>& can_play() const; |
1229 | virtual const core::Property<bool>& can_pause() const; |
1230 | virtual const core::Property<bool>& can_seek() const; |
1231 | virtual const core::Property<bool>& can_go_previous() const; |
1232 | virtual const core::Property<bool>& can_go_next() const; |
1233 | + virtual const core::Property<bool>& is_video_source() const; |
1234 | + virtual const core::Property<bool>& is_audio_source() const; |
1235 | virtual const core::Property<PlaybackStatus>& playback_status() const; |
1236 | virtual const core::Property<LoopStatus>& loop_status() const; |
1237 | virtual const core::Property<PlaybackRate>& playback_rate() const; |
1238 | @@ -74,6 +80,7 @@ |
1239 | virtual core::Property<Volume>& volume(); |
1240 | |
1241 | virtual const core::Signal<uint64_t>& seeked_to() const; |
1242 | + virtual const core::Signal<void>& end_of_stream() const; |
1243 | |
1244 | private: |
1245 | struct Private; |
1246 | |
1247 | === modified file 'src/core/media/server/server.cpp' |
1248 | --- src/core/media/server/server.cpp 2014-02-12 15:53:57 +0000 |
1249 | +++ src/core/media/server/server.cpp 2014-03-26 17:18:55 +0000 |
1250 | @@ -2,12 +2,23 @@ |
1251 | #include <core/media/player.h> |
1252 | #include <core/media/track_list.h> |
1253 | |
1254 | +#include <media/decoding_service.h> |
1255 | +#include <media/media_codec_layer.h> |
1256 | + |
1257 | #include "core/media/service_implementation.h" |
1258 | |
1259 | +#include <iostream> |
1260 | + |
1261 | namespace media = core::ubuntu::media; |
1262 | |
1263 | +using namespace std; |
1264 | + |
1265 | int main() |
1266 | { |
1267 | + // Init hybris-level DecodingService |
1268 | + decoding_service_init(); |
1269 | + cout << "Starting DecodingService..." << endl; |
1270 | + |
1271 | auto service = std::make_shared<media::ServiceImplementation>(); |
1272 | service->run(); |
1273 | |
1274 | |
1275 | === modified file 'src/core/media/track_list_implementation.cpp' |
1276 | --- src/core/media/track_list_implementation.cpp 2014-02-12 15:53:57 +0000 |
1277 | +++ src/core/media/track_list_implementation.cpp 2014-03-26 17:18:55 +0000 |
1278 | @@ -16,6 +16,9 @@ |
1279 | * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1280 | */ |
1281 | |
1282 | +#include <stdio.h> |
1283 | +#include <stdlib.h> |
1284 | + |
1285 | #include "track_list_implementation.h" |
1286 | |
1287 | #include "engine.h" |
1288 | @@ -45,6 +48,16 @@ |
1289 | { |
1290 | } |
1291 | |
1292 | +media::Track::UriType media::TrackListImplementation::query_uri_for_track(const media::Track::Id& id) |
1293 | +{ |
1294 | + auto it = d->meta_data_cache.find(id); |
1295 | + |
1296 | + if (it == d->meta_data_cache.end()) |
1297 | + return Track::UriType{}; |
1298 | + |
1299 | + return std::get<0>(it->second); |
1300 | +} |
1301 | + |
1302 | media::Track::MetaData media::TrackListImplementation::query_meta_data_for_track(const media::Track::Id& id) |
1303 | { |
1304 | auto it = d->meta_data_cache.find(id); |
1305 | |
1306 | === modified file 'src/core/media/track_list_implementation.h' |
1307 | --- src/core/media/track_list_implementation.h 2014-02-12 15:53:57 +0000 |
1308 | +++ src/core/media/track_list_implementation.h 2014-03-26 17:18:55 +0000 |
1309 | @@ -36,6 +36,7 @@ |
1310 | const std::shared_ptr<Engine::MetaDataExtractor>& extractor); |
1311 | ~TrackListImplementation(); |
1312 | |
1313 | + Track::UriType query_uri_for_track(const Track::Id& id); |
1314 | Track::MetaData query_meta_data_for_track(const Track::Id& id); |
1315 | |
1316 | void add_track_with_uri_at(const Track::UriType& uri, const Track::Id& position, bool make_current); |
1317 | |
1318 | === modified file 'src/core/media/track_list_skeleton.cpp' |
1319 | --- src/core/media/track_list_skeleton.cpp 2014-02-12 15:53:57 +0000 |
1320 | +++ src/core/media/track_list_skeleton.cpp 2014-03-26 17:18:55 +0000 |
1321 | @@ -48,7 +48,8 @@ |
1322 | object(object), |
1323 | can_edit_tracks(object->get_property<mpris::TrackList::Properties::CanEditTracks>()), |
1324 | tracks(object->get_property<mpris::TrackList::Properties::Tracks>()), |
1325 | - current_track(tracks->get().begin()) |
1326 | + current_track(tracks->get().begin()), |
1327 | + empty_iterator(tracks->get().begin()) |
1328 | { |
1329 | } |
1330 | |
1331 | @@ -103,6 +104,7 @@ |
1332 | std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::CanEditTracks>> can_edit_tracks; |
1333 | std::shared_ptr<core::dbus::Property<mpris::TrackList::Properties::Tracks>> tracks; |
1334 | TrackList::ConstIterator current_track; |
1335 | + TrackList::ConstIterator empty_iterator; |
1336 | |
1337 | core::Signal<void> on_track_list_replaced; |
1338 | core::Signal<Track::Id> on_track_added; |
1339 | @@ -142,12 +144,22 @@ |
1340 | |
1341 | bool media::TrackListSkeleton::has_next() const |
1342 | { |
1343 | - return std::next(d->current_track) != d->tracks->get().end(); |
1344 | + return d->current_track != d->tracks->get().end(); |
1345 | } |
1346 | |
1347 | const media::Track::Id& media::TrackListSkeleton::next() |
1348 | { |
1349 | - return *(d->current_track = std::next(d->current_track)); |
1350 | + if (d->tracks->get().empty()) |
1351 | + return *(d->current_track); |
1352 | + |
1353 | + if (d->tracks->get().size() && (d->current_track == d->empty_iterator)) |
1354 | + { |
1355 | + d->current_track = d->tracks->get().begin(); |
1356 | + return *(d->current_track = std::next(d->current_track)); |
1357 | + } |
1358 | + |
1359 | + d->current_track = std::next(d->current_track); |
1360 | + return *(d->current_track); |
1361 | } |
1362 | |
1363 | const core::Property<bool>& media::TrackListSkeleton::can_edit_tracks() const |
1364 | |
1365 | === modified file 'src/core/media/track_list_skeleton.h' |
1366 | --- src/core/media/track_list_skeleton.h 2014-02-12 15:53:57 +0000 |
1367 | +++ src/core/media/track_list_skeleton.h 2014-03-26 17:18:55 +0000 |
1368 | @@ -48,9 +48,10 @@ |
1369 | const core::Signal<Track::Id>& on_track_removed() const; |
1370 | const core::Signal<Track::Id>& on_track_changed() const; |
1371 | |
1372 | + core::Property<Container>& tracks(); |
1373 | + |
1374 | protected: |
1375 | core::Property<bool>& can_edit_tracks(); |
1376 | - core::Property<Container>& tracks(); |
1377 | |
1378 | core::Signal<void>& on_track_list_replaced(); |
1379 | core::Signal<Track::Id>& on_track_added(); |