Merge lp:~phablet-team/media-hub/video-support into lp:media-hub

Proposed by Jim Hodapp
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
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

To post a comment you must log in.
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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();

Subscribers

People subscribed via source and target branches