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