Merge lp:~thomas-voss/media-hub/refactor-video-sink-interface-to-not-rely-on-hybris-types into lp:media-hub
- refactor-video-sink-interface-to-not-rely-on-hybris-types
- Merge into trunk
Status: | Work in progress |
---|---|
Proposed branch: | lp:~thomas-voss/media-hub/refactor-video-sink-interface-to-not-rely-on-hybris-types |
Merge into: | lp:media-hub |
Diff against target: |
3244 lines (+1829/-681) 38 files modified
CMakeLists.txt (+10/-2) debian/changelog (+6/-0) debian/control (+5/-5) debian/libmedia-hub-common3.symbols (+1/-1) include/core/media/player.h (+15/-15) include/core/media/video/dimensions.h (+115/-0) include/core/media/video/sink.h (+145/-0) src/core/media/CMakeLists.txt (+15/-1) src/core/media/client_death_observer.cpp (+42/-0) src/core/media/client_death_observer.h (+62/-0) src/core/media/codec.h (+40/-0) src/core/media/engine.h (+3/-1) src/core/media/gstreamer/engine.cpp (+6/-7) src/core/media/gstreamer/engine.h (+1/-1) src/core/media/gstreamer/playbin.cpp (+501/-0) src/core/media/gstreamer/playbin.h (+47/-445) src/core/media/hybris_client_death_observer.cpp (+84/-0) src/core/media/hybris_client_death_observer.h (+63/-0) src/core/media/hybris_recorder_observer.cpp (+99/-0) src/core/media/hybris_recorder_observer.h (+52/-0) src/core/media/mpris/player.h (+16/-1) src/core/media/player.cpp (+5/-0) src/core/media/player_implementation.cpp (+19/-39) src/core/media/player_implementation.h (+2/-4) src/core/media/player_skeleton.cpp (+28/-7) src/core/media/player_skeleton.h (+2/-2) src/core/media/player_stub.cpp (+19/-95) src/core/media/player_stub.h (+4/-7) src/core/media/recorder_observer.cpp (+28/-0) src/core/media/recorder_observer.h (+64/-0) src/core/media/server/server.cpp (+24/-4) src/core/media/service_implementation.cpp (+10/-17) src/core/media/video/hybris_gl_sink.cpp (+116/-0) src/core/media/video/hybris_gl_sink.h (+67/-0) src/core/media/video/platform_default_sink.cpp (+67/-0) src/core/media/video/platform_default_sink.h (+41/-0) tests/unit-tests/CMakeLists.txt (+5/-1) tests/unit-tests/libmedia-mock.cpp (+0/-26) |
To merge this branch: | bzr merge lp:~thomas-voss/media-hub/refactor-video-sink-interface-to-not-rely-on-hybris-types |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jim Hodapp (community) | code | Needs Fixing | |
Review via email: mp+241435@code.launchpad.net |
Commit message
Refactor client-facing interfaces to pull out explicit dependency on hybris-based media layer.
Description of the change
Refactor client-facing interfaces to pull out explicit dependency on hybris-based media layer.
- 95. By Thomas Voß
-
Split out playbin impl to its own file.
Make sure that buffer streaming is only enabled on platforms supporting it. - 96. By Thomas Voß
-
[ Ubuntu daily release ]
* New rebuild forced
[ Justin McPherson ]
* #1239432 Music fails to pause on incoming/outgoing calls (LP:
#1239432)
[ thomas-voss ]
* Bump build dependency on dbus-cpp to pull in exception safe dtor.
(LP: #1390618) - 97. By Thomas Voß
-
Make video::Dimensions use tagged integer types to clearly distinguish width and height at compile time.
- 98. By Thomas Voß
-
Adjust naming of signal in gstreamer::Playbin and remove cached queries for video width and video height.
- 99. By Thomas Voß
-
Make video sink creation throw an exception and report the error to clients if the platform does not support zero-copy buffer streaming over process boundaries.
- 100. By Thomas Voß
-
Make the player stub throw an exception if video sink creation failed on the service side.
- 101. By Thomas Voß
-
Remove unneeded libmedia-mock.cpp file.
- 102. By Thomas Voß
-
Consider a full-blown 4x4 transformation matrix.
- 103. By Thomas Voß
-
Only compile the hybris gl sink if hybris is actually available.
- 104. By Thomas Voß
-
Factor out common RecorderObserver interface and provide a hybris-based implementation.
Thomas Voß (thomas-voss) : | # |
- 105. By Thomas Voß
-
Address reviewer comments.
- 106. By Thomas Voß
-
[ Jim Hodapp ]
* Pause playback when a headphone is unplugged or an A2DP device is
unpaired (LP: #1368300)
[ Ricardo Mendoza ]
* Pause playback when a headphone is unplugged or an A2DP device is
unpaired (LP: #1368300) - 107. By Thomas Voß
-
Move installation/symbol files in debian symbol to account for version bump.
- 108. By Thomas Voß
-
Address remaining reviewer comment.
Unmerged revisions
- 108. By Thomas Voß
-
Address remaining reviewer comment.
- 107. By Thomas Voß
-
Move installation/symbol files in debian symbol to account for version bump.
- 106. By Thomas Voß
-
[ Jim Hodapp ]
* Pause playback when a headphone is unplugged or an A2DP device is
unpaired (LP: #1368300)
[ Ricardo Mendoza ]
* Pause playback when a headphone is unplugged or an A2DP device is
unpaired (LP: #1368300) - 105. By Thomas Voß
-
Address reviewer comments.
- 104. By Thomas Voß
-
Factor out common RecorderObserver interface and provide a hybris-based implementation.
- 103. By Thomas Voß
-
Only compile the hybris gl sink if hybris is actually available.
- 102. By Thomas Voß
-
Consider a full-blown 4x4 transformation matrix.
- 101. By Thomas Voß
-
Remove unneeded libmedia-mock.cpp file.
- 100. By Thomas Voß
-
Make the player stub throw an exception if video sink creation failed on the service side.
- 99. By Thomas Voß
-
Make video sink creation throw an exception and report the error to clients if the platform does not support zero-copy buffer streaming over process boundaries.
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-11-03 00:56:55 +0000 |
3 | +++ CMakeLists.txt 2014-11-25 10:52:42 +0000 |
4 | @@ -2,7 +2,7 @@ |
5 | |
6 | project(ubuntu-media-hub) |
7 | |
8 | -set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 2) |
9 | +set(UBUNTU_MEDIA_HUB_VERSION_MAJOR 3) |
10 | set(UBUNTU_MEDIA_HUB_VERSION_MINOR 0) |
11 | set(UBUNTU_MEDIA_HUB_VERSION_PATCH 0) |
12 | |
13 | @@ -27,7 +27,15 @@ |
14 | pkg_check_modules(PROCESS_CPP process-cpp REQUIRED) |
15 | pkg_check_modules(PROPERTIES_CPP properties-cpp REQUIRED) |
16 | pkg_check_modules(GIO gio-2.0 REQUIRED) |
17 | -pkg_check_modules(HYBRIS_MEDIA libmedia REQUIRED) |
18 | +pkg_check_modules(HYBRIS_MEDIA libmedia) |
19 | + |
20 | +# We do not require the hybris media layer anymore and instead fallback |
21 | +# to a dummy implementation for now. Later on, we will have to tune |
22 | +# core::ubuntu::media::video::make_platform_default_sink(...) to account for |
23 | +# things like libva. |
24 | +if (HYBRIS_MEDIA_FOUND) |
25 | + add_definitions(-DMEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
26 | +endif (HYBRIS_MEDIA_FOUND) |
27 | |
28 | ##################################################################### |
29 | # Enable code coverage calculation with gcov/gcovr/lcov |
30 | |
31 | === modified file 'debian/changelog' |
32 | --- debian/changelog 2014-11-20 18:33:08 +0000 |
33 | +++ debian/changelog 2014-11-25 10:52:42 +0000 |
34 | @@ -1,3 +1,9 @@ |
35 | +media-hub (3.0.0) UNRELEASED; urgency=medium |
36 | + |
37 | + * Refactor client-facing interfaces to pull out explicit dependency on hybris-based media layer. |
38 | + |
39 | + -- Thomas Voss <thomas.voss@canonical.com> Tue, 11 Nov 2014 17:15:52 +0100 |
40 | + |
41 | media-hub (2.0.0+15.04.20141120.1-0ubuntu1) vivid; urgency=low |
42 | |
43 | [ Jim Hodapp ] |
44 | |
45 | === modified file 'debian/control' |
46 | --- debian/control 2014-11-12 19:10:24 +0000 |
47 | +++ debian/control 2014-11-25 10:52:42 +0000 |
48 | @@ -22,7 +22,7 @@ |
49 | libdbus-1-dev, |
50 | libdbus-cpp-dev (>= 4.3.0), |
51 | libgoogle-glog-dev, |
52 | - libhybris-dev (>=0.1.0+git20131207+e452e83-0ubuntu30), |
53 | + libhybris-dev (>=0.1.0+git20131207+e452e83-0ubuntu30) [!arm64 !ppc64el !powerpc], |
54 | libprocess-cpp-dev, |
55 | libproperties-cpp-dev, |
56 | gstreamer1.0-libav, |
57 | @@ -42,8 +42,8 @@ |
58 | Architecture: any |
59 | Multi-Arch: same |
60 | Pre-Depends: dpkg (>= 1.15.6~) |
61 | -Depends: libmedia-hub-common2 (= ${binary:Version}), |
62 | - libmedia-hub-client2 (= ${binary:Version}), |
63 | +Depends: libmedia-hub-common3 (= ${binary:Version}), |
64 | + libmedia-hub-client3 (= ${binary:Version}), |
65 | ${misc:Depends}, |
66 | libproperties-cpp-dev, |
67 | Suggests: libmedia-hub-doc |
68 | @@ -65,7 +65,7 @@ |
69 | . |
70 | This package contains the runtime. |
71 | |
72 | -Package: libmedia-hub-common2 |
73 | +Package: libmedia-hub-common3 |
74 | Architecture: any |
75 | Multi-Arch: same |
76 | Pre-Depends: dpkg (>= 1.15.6~) |
77 | @@ -77,7 +77,7 @@ |
78 | . |
79 | This package contains the common libraries. |
80 | |
81 | -Package: libmedia-hub-client2 |
82 | +Package: libmedia-hub-client3 |
83 | Architecture: any |
84 | Multi-Arch: same |
85 | Pre-Depends: dpkg (>= 1.15.6~) |
86 | |
87 | === renamed file 'debian/libmedia-hub-client2.install' => 'debian/libmedia-hub-client3.install' |
88 | === renamed file 'debian/libmedia-hub-common2.install' => 'debian/libmedia-hub-common3.install' |
89 | === renamed file 'debian/libmedia-hub-common2.symbols' => 'debian/libmedia-hub-common3.symbols' |
90 | --- debian/libmedia-hub-common2.symbols 2014-09-10 21:11:00 +0000 |
91 | +++ debian/libmedia-hub-common3.symbols 2014-11-25 10:52:42 +0000 |
92 | @@ -1,2 +1,2 @@ |
93 | -libmedia-hub-common.so.2 libmedia-hub-common2 #MINVER# |
94 | +libmedia-hub-common.so.3 libmedia-hub-common3 #MINVER# |
95 | (c++)"core::ubuntu::media::the_session_bus()@Base" 2.0.0+14.10.20140910.2 |
96 | |
97 | === modified file 'include/core/media/player.h' |
98 | --- include/core/media/player.h 2014-10-14 20:05:20 +0000 |
99 | +++ include/core/media/player.h 2014-11-25 10:52:42 +0000 |
100 | @@ -21,6 +21,9 @@ |
101 | |
102 | #include <core/media/track.h> |
103 | |
104 | +#include <core/media/video/dimensions.h> |
105 | +#include <core/media/video/sink.h> |
106 | + |
107 | #include <core/property.h> |
108 | |
109 | #include <chrono> |
110 | @@ -43,10 +46,15 @@ |
111 | typedef uint32_t PlayerKey; |
112 | typedef void* GLConsumerWrapperHybris; |
113 | |
114 | - /** Used to set a callback function to be called when a frame is ready to be rendered **/ |
115 | - typedef void (*FrameAvailableCbHybris)(GLConsumerWrapperHybris wrapper, void *context); |
116 | - typedef void (*FrameAvailableCb)(void *context); |
117 | - typedef void (*PlaybackCompleteCb)(void *context); |
118 | + struct Error |
119 | + { |
120 | + Error() = delete; |
121 | + |
122 | + struct OutOfProcessBufferStreamingNotSupported : public std::runtime_error |
123 | + { |
124 | + OutOfProcessBufferStreamingNotSupported(); |
125 | + }; |
126 | + }; |
127 | |
128 | struct Configuration; |
129 | |
130 | @@ -103,9 +111,9 @@ |
131 | virtual std::shared_ptr<TrackList> track_list() = 0; |
132 | virtual PlayerKey key() const = 0; |
133 | |
134 | + virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id) = 0; |
135 | + |
136 | virtual bool open_uri(const Track::UriType& uri) = 0; |
137 | - virtual void create_video_sink(uint32_t texture_id) = 0; |
138 | - virtual GLConsumerWrapperHybris gl_consumer() const = 0; |
139 | virtual void next() = 0; |
140 | virtual void previous() = 0; |
141 | virtual void play() = 0; |
142 | @@ -113,10 +121,6 @@ |
143 | virtual void stop() = 0; |
144 | virtual void seek_to(const std::chrono::microseconds& offset) = 0; |
145 | |
146 | - // TODO: Convert this to be a signal |
147 | - virtual void set_frame_available_callback(FrameAvailableCb cb, void *context) = 0; |
148 | - virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context) = 0; |
149 | - |
150 | virtual const core::Property<bool>& can_play() const = 0; |
151 | virtual const core::Property<bool>& can_pause() const = 0; |
152 | virtual const core::Property<bool>& can_seek() const = 0; |
153 | @@ -146,11 +150,7 @@ |
154 | virtual const core::Signal<int64_t>& seeked_to() const = 0; |
155 | virtual const core::Signal<void>& end_of_stream() const = 0; |
156 | virtual core::Signal<PlaybackStatus>& playback_status_changed() = 0; |
157 | - /** |
158 | - * Called when the video height/width change. Passes height and width as a bitmask with |
159 | - * height in the upper 32 bits and width in the lower 32 bits (both unsigned values) |
160 | - */ |
161 | - virtual const core::Signal<uint64_t>& video_dimension_changed() const = 0; |
162 | + virtual const core::Signal<video::Dimensions>& video_dimension_changed() const = 0; |
163 | protected: |
164 | Player(); |
165 | |
166 | |
167 | === added directory 'include/core/media/video' |
168 | === added file 'include/core/media/video/dimensions.h' |
169 | --- include/core/media/video/dimensions.h 1970-01-01 00:00:00 +0000 |
170 | +++ include/core/media/video/dimensions.h 2014-11-25 10:52:42 +0000 |
171 | @@ -0,0 +1,115 @@ |
172 | +/* |
173 | + * Copyright © 2014 Canonical Ltd. |
174 | + * |
175 | + * This program is free software: you can redistribute it and/or modify it |
176 | + * under the terms of the GNU Lesser General Public License version 3, |
177 | + * as published by the Free Software Foundation. |
178 | + * |
179 | + * This program is distributed in the hope that it will be useful, |
180 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
181 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
182 | + * GNU Lesser General Public License for more details. |
183 | + * |
184 | + * You should have received a copy of the GNU Lesser General Public License |
185 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
186 | + * |
187 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
188 | + */ |
189 | +#ifndef CORE_UBUNTU_MEDIA_VIDEO_DIMENSIONS_H_ |
190 | +#define CORE_UBUNTU_MEDIA_VIDEO_DIMENSIONS_H_ |
191 | + |
192 | +#include <cstdint> |
193 | + |
194 | +#include <tuple> |
195 | + |
196 | +namespace core |
197 | +{ |
198 | +namespace ubuntu |
199 | +{ |
200 | +namespace media |
201 | +{ |
202 | +namespace video |
203 | +{ |
204 | +namespace detail |
205 | +{ |
206 | +enum class DimensionTag { width, height }; |
207 | + |
208 | +template<DimensionTag Tag, typename IntegerType> |
209 | +class IntWrapper |
210 | +{ |
211 | +public: |
212 | + static_assert(std::is_integral<IntegerType>::value, "IntWrapper<> only supports integral types."); |
213 | + typedef IntegerType ValueType; |
214 | + |
215 | + IntWrapper() : value{0} {} |
216 | + template<typename AnyInteger> |
217 | + explicit IntWrapper(AnyInteger value) : value{static_cast<ValueType>(value)} {} |
218 | + |
219 | + template<typename T = IntegerType> |
220 | + T as() const |
221 | + { |
222 | + static_assert(std::is_arithmetic<T>::value, "as() only supports arithmetic types."); |
223 | + return static_cast<T>(value); |
224 | + } |
225 | + |
226 | +private: |
227 | + ValueType value; |
228 | +}; |
229 | + |
230 | +template<DimensionTag Tag, typename IntegerType> |
231 | +std::ostream& operator<<(std::ostream& out, IntWrapper<Tag, IntegerType> const& value) |
232 | +{ |
233 | + out << value.template as<>(); |
234 | + return out; |
235 | +} |
236 | + |
237 | +template<DimensionTag Tag, typename IntegerType> |
238 | +inline bool operator == (IntWrapper<Tag, IntegerType> const& lhs, IntWrapper<Tag, IntegerType> const& rhs) |
239 | +{ |
240 | + return lhs.template as<>() == rhs.template as<>(); |
241 | +} |
242 | + |
243 | +template<DimensionTag Tag, typename IntegerType> |
244 | +inline bool operator != (IntWrapper<Tag, IntegerType> const& lhs, IntWrapper<Tag, IntegerType> const& rhs) |
245 | +{ |
246 | + return lhs.template as<>() != rhs.template as<>(); |
247 | +} |
248 | + |
249 | +template<DimensionTag Tag, typename IntegerType> |
250 | +inline bool operator <= (IntWrapper<Tag, IntegerType> const& lhs, IntWrapper<Tag, IntegerType> const& rhs) |
251 | +{ |
252 | + return lhs.template as<>() <= rhs.template as<>(); |
253 | +} |
254 | + |
255 | +template<DimensionTag Tag, typename IntegerType> |
256 | +inline bool operator >= (IntWrapper<Tag, IntegerType> const& lhs, IntWrapper<Tag, IntegerType> const& rhs) |
257 | +{ |
258 | + return lhs.template as<>() >= rhs.template as<>(); |
259 | +} |
260 | + |
261 | +template<DimensionTag Tag, typename IntegerType> |
262 | +inline bool operator < (IntWrapper<Tag, IntegerType> const& lhs, IntWrapper<Tag, IntegerType> const& rhs) |
263 | +{ |
264 | + return lhs.template as<>() < rhs.template as<>(); |
265 | +} |
266 | + |
267 | +template<DimensionTag Tag, typename IntegerType> |
268 | +inline bool operator > (IntWrapper<Tag, IntegerType> const& lhs, IntWrapper<Tag, IntegerType> const& rhs) |
269 | +{ |
270 | + return lhs.template as<>() > rhs.template as<>(); |
271 | +} |
272 | +} // namespace detail |
273 | + |
274 | +/** @brief The integer Height of a video. */ |
275 | +typedef detail::IntWrapper<detail::DimensionTag::height, std::uint32_t> Height; |
276 | +/** @brief The integer Width of a video. */ |
277 | +typedef detail::IntWrapper<detail::DimensionTag::width, std::uint32_t> Width; |
278 | + |
279 | +/** @brief Height and Width of a video. */ |
280 | +typedef std::tuple<Height, Width> Dimensions; |
281 | +} |
282 | +} |
283 | +} |
284 | +} |
285 | + |
286 | +#endif // CORE_UBUNTU_MEDIA_VIDEO_DIMENSIONS_H_ |
287 | |
288 | === added file 'include/core/media/video/sink.h' |
289 | --- include/core/media/video/sink.h 1970-01-01 00:00:00 +0000 |
290 | +++ include/core/media/video/sink.h 2014-11-25 10:52:42 +0000 |
291 | @@ -0,0 +1,145 @@ |
292 | +/* |
293 | + * Copyright © 2014 Canonical Ltd. |
294 | + * |
295 | + * This program is free software: you can redistribute it and/or modify it |
296 | + * under the terms of the GNU Lesser General Public License version 3, |
297 | + * as published by the Free Software Foundation. |
298 | + * |
299 | + * This program is distributed in the hope that it will be useful, |
300 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
301 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
302 | + * GNU Lesser General Public License for more details. |
303 | + * |
304 | + * You should have received a copy of the GNU Lesser General Public License |
305 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
306 | + * |
307 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
308 | + */ |
309 | +#ifndef CORE_UBUNTU_MEDIA_VIDEO_SINK_H_ |
310 | +#define CORE_UBUNTU_MEDIA_VIDEO_SINK_H_ |
311 | + |
312 | +#include <core/signal.h> |
313 | + |
314 | +#include <memory> |
315 | + |
316 | +namespace core |
317 | +{ |
318 | +namespace ubuntu |
319 | +{ |
320 | +namespace media |
321 | +{ |
322 | +namespace video |
323 | +{ |
324 | +/** @brief A transformation matrix, providing a view on raw float values. */ |
325 | +template<std::size_t rows, std::size_t columns> |
326 | +class MatrixView |
327 | +{ |
328 | +public: |
329 | + /** |
330 | + * @brief Constructs a new matrix instance for the given |
331 | + * raw float array with at least 3*3 members. |
332 | + */ |
333 | + inline constexpr explicit MatrixView(float* raw) |
334 | + : begin{raw}, |
335 | + end{begin + height() * width()} |
336 | + { |
337 | + } |
338 | + |
339 | + // We disallow all copy operations. |
340 | + MatrixView(const MatrixView&) = delete; |
341 | + MatrixView& operator=(const MatrixView&) = delete; |
342 | + |
343 | + /** @brief Returns the height of the matrix in #rows. */ |
344 | + inline constexpr std::size_t height() const |
345 | + { |
346 | + return rows; |
347 | + } |
348 | + |
349 | + /** @brief Returns the width of the matrix in #columns. */ |
350 | + inline constexpr std::size_t width() const |
351 | + { |
352 | + return columns; |
353 | + } |
354 | + |
355 | + /** |
356 | + * @brief Returns a mutable reference to M(i,j). |
357 | + * @throws std::out_of_range if the bounds of the matrix are exceeded. |
358 | + */ |
359 | + inline float& operator()(std::size_t row, std::size_t col) |
360 | + { |
361 | + auto offset = row * width() + col; |
362 | + if ((begin + offset) >= end) throw std::out_of_range |
363 | + { |
364 | + "[" + std::to_string(row) + "," + std::to_string(col) + "] exceeds array boundaries" |
365 | + }; |
366 | + return begin[offset]; |
367 | + } |
368 | + |
369 | + /** |
370 | + * @brief Returns a non-mutable reference to M(i,j). |
371 | + * @throws std::out_of_range if the bounds of the matrix are exceeded. |
372 | + */ |
373 | + inline constexpr const float& operator()(std::size_t row, std::size_t col) const |
374 | + { |
375 | + auto offset = row * width() + col; |
376 | + if ((begin + offset) >= end) throw std::out_of_range |
377 | + { |
378 | + "[" + std::to_string(row) + "," + std::to_string(col) + "] exceeds array boundaries" |
379 | + }; |
380 | + return begin[row * width() + col]; |
381 | + } |
382 | + |
383 | + /** @brief Provides access to the underlying, raw float pointer. */ |
384 | + inline constexpr float* to_float() const |
385 | + { |
386 | + return begin; |
387 | + } |
388 | + |
389 | +private: |
390 | + // The raw floating point values in a linear array. |
391 | + float* begin; |
392 | + float* end; |
393 | +}; |
394 | + |
395 | +/** @brief A video sink abstracts a queue of buffers, that receives |
396 | + * a stream of decoded video buffers from an arbitrary source. |
397 | + */ |
398 | +struct Sink |
399 | +{ |
400 | + /** @brief To save us some typing. */ |
401 | + typedef std::shared_ptr<Sink> Ptr; |
402 | + |
403 | + /** @cond */ |
404 | + Sink() = default; |
405 | + Sink(const Sink&) = delete; |
406 | + virtual ~Sink() = default; |
407 | + |
408 | + Sink& operator=(const Sink&) = delete; |
409 | + /** @endcond */ |
410 | + |
411 | + /** |
412 | + * @brief The signal is emitted whenever a new frame is available and a subsequent |
413 | + * call to swap_buffers will not block and return true. |
414 | + */ |
415 | + virtual const core::Signal<void>& frame_available() const = 0; |
416 | + |
417 | + /** |
418 | + * @brief Queries the transformation matrix for the current frame, placing the data into 'matrix'. |
419 | + * @returns true iff the data has been set. Returns false and leaves 'matrix' unchanged in case of issues. |
420 | + */ |
421 | + virtual bool transformation_matrix(MatrixView<4,4>& matrix) const = 0; |
422 | + |
423 | + /** |
424 | + * @brief Releases the current buffer, and consumes the next buffer in the queue, |
425 | + * making it available for consumption by consumers of this API in an |
426 | + * implementation-specific way. Clients will usually rely on a GL texture |
427 | + * to receive the latest buffer. |
428 | + */ |
429 | + virtual bool swap_buffers() const = 0; |
430 | +}; |
431 | +} |
432 | +} |
433 | +} |
434 | +} |
435 | + |
436 | +#endif // CORE_UBUNTU_MEDIA_VIDEO_SINK_H_ |
437 | |
438 | === modified file 'src/core/media/CMakeLists.txt' |
439 | --- src/core/media/CMakeLists.txt 2014-11-12 19:10:24 +0000 |
440 | +++ src/core/media/CMakeLists.txt 2014-11-25 10:52:42 +0000 |
441 | @@ -6,7 +6,10 @@ |
442 | # out all symbols that are not in core::ubuntu::media* |
443 | set(symbol_map "${CMAKE_SOURCE_DIR}/symbols.map") |
444 | |
445 | -file(GLOB MPRIS_HEADERS mpris/ *.h) |
446 | +file(GLOB_RECURSE MEDIA_HUB_HEADERS ${CMAKE_SOURCE_DIR}/include/*.h) |
447 | +file(GLOB MPRIS_HEADERS mpris/*.h) |
448 | + |
449 | +message(STATUS ${MEDIA_HUB_HEADERS}) |
450 | |
451 | add_subdirectory(call-monitor) |
452 | |
453 | @@ -36,6 +39,8 @@ |
454 | add_library( |
455 | media-hub-client SHARED |
456 | |
457 | + ${MEDIA_HUB_HEADERS} |
458 | + |
459 | player.cpp |
460 | service.cpp |
461 | track.cpp |
462 | @@ -44,6 +49,9 @@ |
463 | player_stub.cpp |
464 | service_stub.cpp |
465 | track_list_stub.cpp |
466 | + |
467 | + video/hybris_gl_sink.cpp |
468 | + video/platform_default_sink.cpp |
469 | ) |
470 | |
471 | set_target_properties( |
472 | @@ -75,11 +83,17 @@ |
473 | add_library( |
474 | media-hub-service |
475 | |
476 | + ${MEDIA_HUB_HEADERS} |
477 | ${MPRIS_HEADERS} |
478 | |
479 | + client_death_observer.cpp |
480 | + hybris_client_death_observer.cpp |
481 | cover_art_resolver.cpp |
482 | engine.cpp |
483 | + recorder_observer.cpp |
484 | + hybris_recorder_observer.cpp |
485 | gstreamer/engine.cpp |
486 | + gstreamer/playbin.cpp |
487 | |
488 | player_skeleton.cpp |
489 | player_implementation.cpp |
490 | |
491 | === added file 'src/core/media/client_death_observer.cpp' |
492 | --- src/core/media/client_death_observer.cpp 1970-01-01 00:00:00 +0000 |
493 | +++ src/core/media/client_death_observer.cpp 2014-11-25 10:52:42 +0000 |
494 | @@ -0,0 +1,42 @@ |
495 | +/* |
496 | + * Copyright © 2014 Canonical Ltd. |
497 | + * |
498 | + * This program is free software: you can redistribute it and/or modify it |
499 | + * under the terms of the GNU Lesser General Public License version 3, |
500 | + * as published by the Free Software Foundation. |
501 | + * |
502 | + * This program is distributed in the hope that it will be useful, |
503 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
504 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
505 | + * GNU Lesser General Public License for more details. |
506 | + * |
507 | + * You should have received a copy of the GNU Lesser General Public License |
508 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
509 | + * |
510 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
511 | + */ |
512 | + |
513 | +#include <core/media/client_death_observer.h> |
514 | + |
515 | +namespace media = core::ubuntu::media; |
516 | + |
517 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
518 | +#include <core/media/hybris_client_death_observer.h> |
519 | + |
520 | +// Accesses the default client death observer implementation for the platform. |
521 | +media::ClientDeathObserver::Ptr media::platform_default_client_death_observer() |
522 | +{ |
523 | + return media::HybrisClientDeathObserver::create(); |
524 | +} |
525 | +#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
526 | +// Just throws a std::logic_error as we have not yet defined a default way to |
527 | +// identify client death changes. One possible way of implementing the interface |
528 | +// would be to listen to dbus name changes and react accordingly. |
529 | +media::ClientDeathObserver::Ptr media::platform_default_client_death_observer() |
530 | +{ |
531 | + throw std::logic_error |
532 | + { |
533 | + "No platform-specific death observer implementation known." |
534 | + }; |
535 | +} |
536 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
537 | |
538 | === added file 'src/core/media/client_death_observer.h' |
539 | --- src/core/media/client_death_observer.h 1970-01-01 00:00:00 +0000 |
540 | +++ src/core/media/client_death_observer.h 2014-11-25 10:52:42 +0000 |
541 | @@ -0,0 +1,62 @@ |
542 | +/* |
543 | + * Copyright © 2014 Canonical Ltd. |
544 | + * |
545 | + * This program is free software: you can redistribute it and/or modify it |
546 | + * under the terms of the GNU Lesser General Public License version 3, |
547 | + * as published by the Free Software Foundation. |
548 | + * |
549 | + * This program is distributed in the hope that it will be useful, |
550 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
551 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
552 | + * GNU Lesser General Public License for more details. |
553 | + * |
554 | + * You should have received a copy of the GNU Lesser General Public License |
555 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
556 | + * |
557 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
558 | + */ |
559 | + |
560 | +#ifndef CORE_UBUNTU_MEDIA_CLIENT_DEATH_OBSERVER_H_ |
561 | +#define CORE_UBUNTU_MEDIA_CLIENT_DEATH_OBSERVER_H_ |
562 | + |
563 | +#include <core/media/player.h> |
564 | + |
565 | +#include <core/signal.h> |
566 | + |
567 | +#include <memory> |
568 | + |
569 | +namespace core |
570 | +{ |
571 | +namespace ubuntu |
572 | +{ |
573 | +namespace media |
574 | +{ |
575 | +// Models functionality to be notified whenever a client |
576 | +// of the service goes away, and thus allows us to clean |
577 | +// up in that case. |
578 | +struct ClientDeathObserver |
579 | +{ |
580 | + // To save us some typing. |
581 | + typedef std::shared_ptr<ClientDeathObserver> Ptr; |
582 | + |
583 | + ClientDeathObserver() = default; |
584 | + ClientDeathObserver(const ClientDeathObserver&) = delete; |
585 | + virtual ~ClientDeathObserver() = default; |
586 | + |
587 | + ClientDeathObserver& operator=(const ClientDeathObserver&) = delete; |
588 | + |
589 | + // Registers the client with the given key for death notifications. |
590 | + virtual void register_for_death_notifications_with_key(const Player::PlayerKey&) = 0; |
591 | + |
592 | + // Emitted whenver a client dies, reporting the key under which the |
593 | + // respective client was known. |
594 | + virtual const core::Signal<Player::PlayerKey>& on_client_with_key_died() const = 0; |
595 | +}; |
596 | + |
597 | +// Accesses the default client death observer implementation for the platform. |
598 | +ClientDeathObserver::Ptr platform_default_client_death_observer(); |
599 | +} |
600 | +} |
601 | +} |
602 | + |
603 | +#endif // CORE_UBUNTU_MEDIA_CLIENT_DEATH_OBSERVER_H_ |
604 | |
605 | === modified file 'src/core/media/codec.h' |
606 | --- src/core/media/codec.h 2014-10-10 01:24:43 +0000 |
607 | +++ src/core/media/codec.h 2014-11-25 10:52:42 +0000 |
608 | @@ -230,6 +230,46 @@ |
609 | } |
610 | }; |
611 | |
612 | +namespace helper |
613 | +{ |
614 | +template<core::ubuntu::media::video::detail::DimensionTag tag, typename IntegerType> |
615 | +struct TypeMapper<core::ubuntu::media::video::detail::IntWrapper<tag, IntegerType>> |
616 | +{ |
617 | + constexpr static ArgumentType type_value() |
618 | + { |
619 | + return core::dbus::ArgumentType::uint32; |
620 | + } |
621 | + constexpr static bool is_basic_type() |
622 | + { |
623 | + return true; |
624 | + } |
625 | + constexpr static bool requires_signature() |
626 | + { |
627 | + return false; |
628 | + } |
629 | + |
630 | + static std::string signature() |
631 | + { |
632 | + static const std::string s = TypeMapper<std::uint32_t>::signature(); |
633 | + return s; |
634 | + } |
635 | +}; |
636 | +} |
637 | + |
638 | +template<core::ubuntu::media::video::detail::DimensionTag tag, typename IntegerType> |
639 | +struct Codec<core::ubuntu::media::video::detail::IntWrapper<tag, IntegerType>> |
640 | +{ |
641 | + static void encode_argument(core::dbus::Message::Writer& out, const core::ubuntu::media::video::detail::IntWrapper<tag, IntegerType>& in) |
642 | + { |
643 | + out.push_uint32(in.template as<std::uint32_t>()); |
644 | + } |
645 | + |
646 | + static void decode_argument(core::dbus::Message::Reader& out, core::ubuntu::media::video::detail::IntWrapper<tag, IntegerType>& in) |
647 | + { |
648 | + in = core::ubuntu::media::video::detail::IntWrapper<tag, IntegerType>{out.pop_uint32()}; |
649 | + } |
650 | +}; |
651 | + |
652 | } |
653 | } |
654 | |
655 | |
656 | === modified file 'src/core/media/engine.h' |
657 | --- src/core/media/engine.h 2014-11-03 18:00:48 +0000 |
658 | +++ src/core/media/engine.h 2014-11-25 10:52:42 +0000 |
659 | @@ -76,6 +76,8 @@ |
660 | virtual const core::Property<State>& state() const = 0; |
661 | |
662 | virtual bool open_resource_for_uri(const Track::UriType& uri) = 0; |
663 | + // Throws core::ubuntu::media::Player::Error::OutOfProcessBufferStreamingNotSupported if the implementation does not |
664 | + // support this feature. |
665 | virtual void create_video_sink(uint32_t texture_id) = 0; |
666 | |
667 | virtual bool play() = 0; |
668 | @@ -104,7 +106,7 @@ |
669 | virtual const core::Signal<void>& client_disconnected_signal() const = 0; |
670 | virtual const core::Signal<void>& end_of_stream_signal() const = 0; |
671 | virtual const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const = 0; |
672 | - virtual const core::Signal<uint32_t, uint32_t>& video_dimension_changed_signal() const = 0; |
673 | + virtual const core::Signal<video::Dimensions>& video_dimension_changed_signal() const = 0; |
674 | |
675 | virtual void reset() = 0; |
676 | }; |
677 | |
678 | === modified file 'src/core/media/gstreamer/engine.cpp' |
679 | --- src/core/media/gstreamer/engine.cpp 2014-11-03 18:00:48 +0000 |
680 | +++ src/core/media/gstreamer/engine.cpp 2014-11-25 10:52:42 +0000 |
681 | @@ -100,9 +100,9 @@ |
682 | end_of_stream(); |
683 | } |
684 | |
685 | - void on_video_dimension_changed(uint32_t height, uint32_t width) |
686 | + void on_video_dimension_changed(const media::video::Dimensions& dimensions) |
687 | { |
688 | - video_dimension_changed(height, width); |
689 | + video_dimension_changed(dimensions); |
690 | } |
691 | |
692 | Private() |
693 | @@ -163,12 +163,11 @@ |
694 | &Private::on_end_of_stream, |
695 | this))), |
696 | on_video_dimension_changed_connection( |
697 | - playbin.signals.on_add_frame_dimension.connect( |
698 | + playbin.signals.on_video_dimensions_changed.connect( |
699 | std::bind( |
700 | &Private::on_video_dimension_changed, |
701 | this, |
702 | - std::placeholders::_1, |
703 | - std::placeholders::_2))) |
704 | + std::placeholders::_1))) |
705 | { |
706 | } |
707 | |
708 | @@ -203,7 +202,7 @@ |
709 | core::Signal<void> client_disconnected; |
710 | core::Signal<void> end_of_stream; |
711 | core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
712 | - core::Signal<uint32_t, uint32_t> video_dimension_changed; |
713 | + core::Signal<core::ubuntu::media::video::Dimensions> video_dimension_changed; |
714 | }; |
715 | |
716 | gstreamer::Engine::Engine() : d(new Private{}) |
717 | @@ -379,7 +378,7 @@ |
718 | return d->playback_status_changed; |
719 | } |
720 | |
721 | -const core::Signal<uint32_t, uint32_t>& gstreamer::Engine::video_dimension_changed_signal() const |
722 | +const core::Signal<core::ubuntu::media::video::Dimensions>& gstreamer::Engine::video_dimension_changed_signal() const |
723 | { |
724 | return d->video_dimension_changed; |
725 | } |
726 | |
727 | === modified file 'src/core/media/gstreamer/engine.h' |
728 | --- src/core/media/gstreamer/engine.h 2014-11-03 18:00:48 +0000 |
729 | +++ src/core/media/gstreamer/engine.h 2014-11-25 10:52:42 +0000 |
730 | @@ -62,7 +62,7 @@ |
731 | const core::Signal<void>& client_disconnected_signal() const; |
732 | const core::Signal<void>& end_of_stream_signal() const; |
733 | const core::Signal<core::ubuntu::media::Player::PlaybackStatus>& playback_status_changed_signal() const; |
734 | - const core::Signal<uint32_t, uint32_t>& video_dimension_changed_signal() const; |
735 | + const core::Signal<core::ubuntu::media::video::Dimensions>& video_dimension_changed_signal() const; |
736 | |
737 | void reset(); |
738 | |
739 | |
740 | === added file 'src/core/media/gstreamer/playbin.cpp' |
741 | --- src/core/media/gstreamer/playbin.cpp 1970-01-01 00:00:00 +0000 |
742 | +++ src/core/media/gstreamer/playbin.cpp 2014-11-25 10:52:42 +0000 |
743 | @@ -0,0 +1,501 @@ |
744 | +/* |
745 | + * Copyright © 2013 Canonical Ltd. |
746 | + * |
747 | + * This program is free software: you can redistribute it and/or modify it |
748 | + * under the terms of the GNU Lesser General Public License version 3, |
749 | + * as published by the Free Software Foundation. |
750 | + * |
751 | + * This program is distributed in the hope that it will be useful, |
752 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
753 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
754 | + * GNU Lesser General Public License for more details. |
755 | + * |
756 | + * You should have received a copy of the GNU Lesser General Public License |
757 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
758 | + * |
759 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
760 | + */ |
761 | + |
762 | +#include <core/media/gstreamer/playbin.h> |
763 | + |
764 | +#include <core/media/gstreamer/engine.h> |
765 | + |
766 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
767 | +#include <hybris/media/surface_texture_client_hybris.h> |
768 | +#include <hybris/media/media_codec_layer.h> |
769 | + |
770 | +namespace |
771 | +{ |
772 | +void setup_video_sink_for_buffer_streaming(GstElement* video_sink) |
773 | +{ |
774 | + // Get the service-side BufferQueue (IGraphicBufferProducer) and associate it with |
775 | + // the SurfaceTextureClientHybris instance |
776 | + IGBPWrapperHybris igbp = decoding_service_get_igraphicbufferproducer(); |
777 | + SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp); |
778 | + // Because mirsink is being loaded, we are definitely doing * hardware rendering. |
779 | + surface_texture_client_set_hardware_rendering (stc, TRUE); |
780 | + g_object_set (G_OBJECT (video_sink), "surface", static_cast<gpointer>(stc), static_cast<char*>(NULL)); |
781 | +} |
782 | +} |
783 | +#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
784 | +namespace |
785 | +{ |
786 | +void setup_video_sink_for_buffer_streaming(GstElement*) |
787 | +{ |
788 | + throw core::ubuntu::media::Player::Error::OutOfProcessBufferStreamingNotSupported{}; |
789 | +} |
790 | +} |
791 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
792 | + |
793 | +namespace |
794 | +{ |
795 | +bool is_mir_video_sink() |
796 | +{ |
797 | + return g_strcmp0(::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), "mirsink") == 0; |
798 | +} |
799 | +} |
800 | +// Uncomment to generate a dot file at the time that the pipeline |
801 | +// goes to the PLAYING state. Make sure to export GST_DEBUG_DUMP_DOT_DIR |
802 | +// before starting media-hub-server. To convert the dot file to something |
803 | +// other image format, use: dot pipeline.dot -Tpng -o pipeline.png |
804 | +//#define DEBUG_GST_PIPELINE |
805 | + |
806 | +namespace media = core::ubuntu::media; |
807 | +namespace video = core::ubuntu::media::video; |
808 | + |
809 | +const std::string& gstreamer::Playbin::pipeline_name() |
810 | +{ |
811 | + static const std::string s{"playbin"}; |
812 | + return s; |
813 | +} |
814 | + |
815 | +void gstreamer::Playbin::about_to_finish(GstElement*, gpointer user_data) |
816 | +{ |
817 | + auto thiz = static_cast<Playbin*>(user_data); |
818 | + thiz->signals.about_to_finish(); |
819 | +} |
820 | + |
821 | +gstreamer::Playbin::Playbin() |
822 | + : pipeline(gst_element_factory_make("playbin", pipeline_name().c_str())), |
823 | + bus{gst_element_get_bus(pipeline)}, |
824 | + file_type(MEDIA_FILE_TYPE_NONE), |
825 | + video_sink(nullptr), |
826 | + video_height(0), |
827 | + video_width(0), |
828 | + on_new_message_connection( |
829 | + bus.on_new_message.connect( |
830 | + std::bind( |
831 | + &Playbin::on_new_message, |
832 | + this, |
833 | + std::placeholders::_1))), |
834 | + is_seeking(false) |
835 | +{ |
836 | + if (!pipeline) |
837 | + throw std::runtime_error("Could not create pipeline for playbin."); |
838 | + |
839 | + // Add audio and/or video sink elements depending on environment variables |
840 | + // being set or not set |
841 | + setup_pipeline_for_audio_video(); |
842 | + |
843 | + g_signal_connect( |
844 | + pipeline, |
845 | + "about-to-finish", |
846 | + G_CALLBACK(about_to_finish), |
847 | + this |
848 | + ); |
849 | +} |
850 | + |
851 | +gstreamer::Playbin::~Playbin() |
852 | +{ |
853 | + if (pipeline) |
854 | + gst_object_unref(pipeline); |
855 | +} |
856 | + |
857 | +void gstreamer::Playbin::reset() |
858 | +{ |
859 | + std::cout << "Client died, resetting pipeline" << std::endl; |
860 | + // When the client dies, tear down the current pipeline and get it |
861 | + // in a state that is ready for the next client that connects to the |
862 | + // service |
863 | + reset_pipeline(); |
864 | + // Signal to the Player class that the client side has disconnected |
865 | + signals.client_disconnected(); |
866 | +} |
867 | + |
868 | +void gstreamer::Playbin::reset_pipeline() |
869 | +{ |
870 | + std::cout << __PRETTY_FUNCTION__ << std::endl; |
871 | + auto ret = gst_element_set_state(pipeline, GST_STATE_NULL); |
872 | + switch(ret) |
873 | + { |
874 | + case GST_STATE_CHANGE_FAILURE: |
875 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
876 | + break; |
877 | + case GST_STATE_CHANGE_NO_PREROLL: |
878 | + case GST_STATE_CHANGE_SUCCESS: |
879 | + case GST_STATE_CHANGE_ASYNC: |
880 | + break; |
881 | + default: |
882 | + std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
883 | + } |
884 | + file_type = MEDIA_FILE_TYPE_NONE; |
885 | +} |
886 | + |
887 | +void gstreamer::Playbin::on_new_message(const Bus::Message& message) |
888 | +{ |
889 | + switch(message.type) |
890 | + { |
891 | + case GST_MESSAGE_ERROR: |
892 | + signals.on_error(message.detail.error_warning_info); |
893 | + break; |
894 | + case GST_MESSAGE_WARNING: |
895 | + signals.on_warning(message.detail.error_warning_info); |
896 | + break; |
897 | + case GST_MESSAGE_INFO: |
898 | + signals.on_info(message.detail.error_warning_info); |
899 | + break; |
900 | + case GST_MESSAGE_TAG: |
901 | + { |
902 | + gchar *orientation; |
903 | + if (gst_tag_list_get_string(message.detail.tag.tag_list, "image-orientation", &orientation)) |
904 | + { |
905 | + // If the image-orientation tag is in the GstTagList, signal the Engine |
906 | + signals.on_orientation_changed(orientation_lut(orientation)); |
907 | + g_free (orientation); |
908 | + } |
909 | + |
910 | + signals.on_tag_available(message.detail.tag); |
911 | + } |
912 | + break; |
913 | + case GST_MESSAGE_STATE_CHANGED: |
914 | + signals.on_state_changed(message.detail.state_changed); |
915 | + break; |
916 | + case GST_MESSAGE_ASYNC_DONE: |
917 | + if (is_seeking) |
918 | + { |
919 | + // FIXME: Pass the actual playback time position to the signal call |
920 | + signals.on_seeked_to(0); |
921 | + is_seeking = false; |
922 | + } |
923 | + break; |
924 | + case GST_MESSAGE_EOS: |
925 | + signals.on_end_of_stream(); |
926 | + default: |
927 | + break; |
928 | + } |
929 | +} |
930 | + |
931 | +gstreamer::Bus& gstreamer::Playbin::message_bus() |
932 | +{ |
933 | + return bus; |
934 | +} |
935 | + |
936 | +void gstreamer::Playbin::setup_pipeline_for_audio_video() |
937 | +{ |
938 | + gint flags; |
939 | + g_object_get (pipeline, "flags", &flags, nullptr); |
940 | + flags |= GST_PLAY_FLAG_AUDIO; |
941 | + flags |= GST_PLAY_FLAG_VIDEO; |
942 | + flags &= ~GST_PLAY_FLAG_TEXT; |
943 | + g_object_set (pipeline, "flags", flags, nullptr); |
944 | + |
945 | + if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") != nullptr) |
946 | + { |
947 | + auto audio_sink = gst_element_factory_make ( |
948 | + ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"), |
949 | + "audio-sink"); |
950 | + |
951 | + std::cout << "audio_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") << std::endl; |
952 | + |
953 | + g_object_set ( |
954 | + pipeline, |
955 | + "audio-sink", |
956 | + audio_sink, |
957 | + NULL); |
958 | + } |
959 | + |
960 | + if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
961 | + { |
962 | + video_sink = gst_element_factory_make ( |
963 | + ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
964 | + "video-sink"); |
965 | + |
966 | + std::cout << "video_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") << std::endl; |
967 | + |
968 | + g_object_set ( |
969 | + pipeline, |
970 | + "video-sink", |
971 | + video_sink, |
972 | + NULL); |
973 | + } |
974 | +} |
975 | + |
976 | +void gstreamer::Playbin::create_video_sink(uint32_t) |
977 | +{ |
978 | + if (not video_sink) throw std::logic_error |
979 | + { |
980 | + "No video sink configured for the current pipeline" |
981 | + }; |
982 | + |
983 | + setup_video_sink_for_buffer_streaming(video_sink); |
984 | +} |
985 | + |
986 | +void gstreamer::Playbin::set_volume(double new_volume) |
987 | +{ |
988 | + g_object_set (pipeline, "volume", new_volume, NULL); |
989 | +} |
990 | + |
991 | +/** Translate the AudioStreamRole enum into a string */ |
992 | +std::string gstreamer::Playbin::get_audio_role_str(media::Player::AudioStreamRole audio_role) |
993 | +{ |
994 | + switch (audio_role) |
995 | + { |
996 | + case media::Player::AudioStreamRole::alarm: |
997 | + return "alarm"; |
998 | + break; |
999 | + case media::Player::AudioStreamRole::alert: |
1000 | + return "alert"; |
1001 | + break; |
1002 | + case media::Player::AudioStreamRole::multimedia: |
1003 | + return "multimedia"; |
1004 | + break; |
1005 | + case media::Player::AudioStreamRole::phone: |
1006 | + return "phone"; |
1007 | + break; |
1008 | + default: |
1009 | + return "multimedia"; |
1010 | + break; |
1011 | + } |
1012 | +} |
1013 | + |
1014 | +media::Player::Orientation gstreamer::Playbin::orientation_lut(const gchar *orientation) |
1015 | +{ |
1016 | + if (g_strcmp0(orientation, "rotate-0") == 0) |
1017 | + return media::Player::Orientation::rotate0; |
1018 | + else if (g_strcmp0(orientation, "rotate-90") == 0) |
1019 | + return media::Player::Orientation::rotate90; |
1020 | + else if (g_strcmp0(orientation, "rotate-180") == 0) |
1021 | + return media::Player::Orientation::rotate180; |
1022 | + else if (g_strcmp0(orientation, "rotate-270") == 0) |
1023 | + return media::Player::Orientation::rotate270; |
1024 | + else |
1025 | + return media::Player::Orientation::rotate0; |
1026 | +} |
1027 | + |
1028 | +/** Sets the new audio stream role on the pulsesink in playbin */ |
1029 | +void gstreamer::Playbin::set_audio_stream_role(media::Player::AudioStreamRole new_audio_role) |
1030 | +{ |
1031 | + GstElement *audio_sink = NULL; |
1032 | + g_object_get (pipeline, "audio-sink", &audio_sink, NULL); |
1033 | + |
1034 | + std::string role_str("props,media.role=" + get_audio_role_str(new_audio_role)); |
1035 | + std::cout << "Audio stream role: " << role_str << std::endl; |
1036 | + |
1037 | + GstStructure *props = gst_structure_from_string (role_str.c_str(), NULL); |
1038 | + if (audio_sink != nullptr && props != nullptr) |
1039 | + g_object_set (audio_sink, "stream-properties", props, NULL); |
1040 | + else |
1041 | + { |
1042 | + std::cerr << |
1043 | + "Warning: couldn't set audio stream role - couldn't get audio_sink from pipeline" << |
1044 | + std::endl; |
1045 | + } |
1046 | + |
1047 | + gst_structure_free (props); |
1048 | +} |
1049 | + |
1050 | +uint64_t gstreamer::Playbin::position() const |
1051 | +{ |
1052 | + int64_t pos = 0; |
1053 | + gst_element_query_position (pipeline, GST_FORMAT_TIME, &pos); |
1054 | + |
1055 | + // FIXME: this should be int64_t, but dbus-cpp doesn't seem to handle it correctly |
1056 | + return static_cast<uint64_t>(pos); |
1057 | +} |
1058 | + |
1059 | +uint64_t gstreamer::Playbin::duration() const |
1060 | +{ |
1061 | + int64_t dur = 0; |
1062 | + gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur); |
1063 | + |
1064 | + // FIXME: this should be int64_t, but dbus-cpp doesn't seem to handle it correctly |
1065 | + return static_cast<uint64_t>(dur); |
1066 | +} |
1067 | + |
1068 | +void gstreamer::Playbin::set_uri(const std::string& uri) |
1069 | +{ |
1070 | + g_object_set(pipeline, "uri", uri.c_str(), NULL); |
1071 | + if (is_video_file(uri)) |
1072 | + file_type = MEDIA_FILE_TYPE_VIDEO; |
1073 | + else if (is_audio_file(uri)) |
1074 | + file_type = MEDIA_FILE_TYPE_AUDIO; |
1075 | +} |
1076 | + |
1077 | +std::string gstreamer::Playbin::uri() const |
1078 | +{ |
1079 | + gchar* data = nullptr; |
1080 | + g_object_get(pipeline, "current-uri", &data, nullptr); |
1081 | + |
1082 | + std::string result((data == nullptr ? "" : data)); |
1083 | + g_free(data); |
1084 | + |
1085 | + return result; |
1086 | +} |
1087 | + |
1088 | +bool gstreamer::Playbin::set_state_and_wait(GstState new_state) |
1089 | +{ |
1090 | + static const std::chrono::nanoseconds state_change_timeout |
1091 | + { |
1092 | + // We choose a quite high value here as tests are run under valgrind |
1093 | + // and gstreamer pipeline setup/state changes take longer in that scenario. |
1094 | + // The value does not negatively impact runtime performance. |
1095 | + std::chrono::milliseconds{5000} |
1096 | + }; |
1097 | + |
1098 | + auto ret = gst_element_set_state(pipeline, new_state); |
1099 | + bool result = false; GstState current, pending; |
1100 | + switch(ret) |
1101 | + { |
1102 | + case GST_STATE_CHANGE_FAILURE: |
1103 | + result = false; break; |
1104 | + case GST_STATE_CHANGE_NO_PREROLL: |
1105 | + case GST_STATE_CHANGE_SUCCESS: |
1106 | + result = true; break; |
1107 | + case GST_STATE_CHANGE_ASYNC: |
1108 | + result = GST_STATE_CHANGE_SUCCESS == gst_element_get_state( |
1109 | + pipeline, |
1110 | + ¤t, |
1111 | + &pending, |
1112 | + state_change_timeout.count()); |
1113 | + |
1114 | + if (new_state == GST_STATE_PLAYING) |
1115 | + { |
1116 | + // Get the video height/width from the video sink |
1117 | + try |
1118 | + { |
1119 | + signals.on_video_dimensions_changed(get_video_dimensions()); |
1120 | + } |
1121 | + catch (const std::exception& e) |
1122 | + { |
1123 | + std::cerr << "Problem querying video dimensions: " << e.what() << std::endl; |
1124 | + } |
1125 | + catch (...) |
1126 | + { |
1127 | + std::cerr << "Problem querying video dimensions." << std::endl; |
1128 | + } |
1129 | + |
1130 | +#ifdef DEBUG_GST_PIPELINE |
1131 | + std::cout << "Dumping pipeline dot file" << std::endl; |
1132 | + GST_DEBUG_BIN_TO_DOT_FILE((GstBin*)pipeline, GST_DEBUG_GRAPH_SHOW_ALL, "pipeline"); |
1133 | +#endif |
1134 | + } |
1135 | + break; |
1136 | + } |
1137 | + |
1138 | + return result; |
1139 | +} |
1140 | + |
1141 | +bool gstreamer::Playbin::seek(const std::chrono::microseconds& ms) |
1142 | +{ |
1143 | + is_seeking = true; |
1144 | + return gst_element_seek_simple( |
1145 | + pipeline, |
1146 | + GST_FORMAT_TIME, |
1147 | + (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), |
1148 | + ms.count() * 1000); |
1149 | +} |
1150 | + |
1151 | +core::ubuntu::media::video::Dimensions gstreamer::Playbin::get_video_dimensions() const |
1152 | +{ |
1153 | + if (not video_sink || not is_mir_video_sink()) |
1154 | + throw std::runtime_error |
1155 | + { |
1156 | + "Missing video sink or video sink does not support query of width and height." |
1157 | + }; |
1158 | + |
1159 | + // Initialize to default value prior to querying actual values from the sink. |
1160 | + video_width = video_height = 0; |
1161 | + g_object_get (video_sink, "height", &video_height, nullptr); |
1162 | + g_object_get (video_sink, "width", &video_width, nullptr); |
1163 | + // TODO(tvoss): We should probably check here if width and height are valid. |
1164 | + return core::ubuntu::media::video::Dimensions |
1165 | + { |
1166 | + core::ubuntu::media::video::Height{video_height}, |
1167 | + core::ubuntu::media::video::Width{video_width} |
1168 | + }; |
1169 | +} |
1170 | + |
1171 | +std::string gstreamer::Playbin::get_file_content_type(const std::string& uri) const |
1172 | +{ |
1173 | + if (uri.empty()) |
1174 | + return std::string(); |
1175 | + |
1176 | + std::string filename(uri); |
1177 | + std::cout << "filename: " << filename << std::endl; |
1178 | + size_t pos = uri.find("file://"); |
1179 | + if (pos != std::string::npos) |
1180 | + filename = uri.substr(pos + 7, std::string::npos); |
1181 | + else |
1182 | + // Anything other than a file, for now claim that the type |
1183 | + // is both audio and video. |
1184 | + // FIXME: implement true net stream sampling and get the type from GstCaps |
1185 | + return std::string("audio/video/"); |
1186 | + |
1187 | + |
1188 | + GError *error = nullptr; |
1189 | + std::unique_ptr<GFile, void(*)(void *)> file( |
1190 | + g_file_new_for_path(filename.c_str()), g_object_unref); |
1191 | + std::unique_ptr<GFileInfo, void(*)(void *)> info( |
1192 | + g_file_query_info( |
1193 | + file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE "," |
1194 | + G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE, |
1195 | + /* cancellable */ NULL, &error), |
1196 | + g_object_unref); |
1197 | + if (!info) |
1198 | + { |
1199 | + std::string error_str(error->message); |
1200 | + g_error_free(error); |
1201 | + |
1202 | + std::cout << "Failed to query the URI for the presence of video content: " |
1203 | + << error_str << std::endl; |
1204 | + return std::string(); |
1205 | + } |
1206 | + |
1207 | + std::string content_type(g_file_info_get_attribute_string( |
1208 | + info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE)); |
1209 | + |
1210 | + return content_type; |
1211 | +} |
1212 | + |
1213 | +bool gstreamer::Playbin::is_audio_file(const std::string& uri) const |
1214 | +{ |
1215 | + if (uri.empty()) |
1216 | + return false; |
1217 | + |
1218 | + if (get_file_content_type(uri).find("audio/") == 0) |
1219 | + { |
1220 | + std::cout << "Found audio content" << std::endl; |
1221 | + return true; |
1222 | + } |
1223 | + |
1224 | + return false; |
1225 | +} |
1226 | + |
1227 | +bool gstreamer::Playbin::is_video_file(const std::string& uri) const |
1228 | +{ |
1229 | + if (uri.empty()) |
1230 | + return false; |
1231 | + |
1232 | + if (get_file_content_type(uri).find("video/") == 0) |
1233 | + { |
1234 | + std::cout << "Found video content" << std::endl; |
1235 | + return true; |
1236 | + } |
1237 | + |
1238 | + return false; |
1239 | +} |
1240 | + |
1241 | +gstreamer::Playbin::MediaFileType gstreamer::Playbin::media_file_type() const |
1242 | +{ |
1243 | + return file_type; |
1244 | +} |
1245 | |
1246 | === modified file 'src/core/media/gstreamer/playbin.h' |
1247 | --- src/core/media/gstreamer/playbin.h 2014-11-03 18:00:48 +0000 |
1248 | +++ src/core/media/gstreamer/playbin.h 2014-11-25 10:52:42 +0000 |
1249 | @@ -22,9 +22,6 @@ |
1250 | #include "bus.h" |
1251 | #include "../mpris/player.h" |
1252 | |
1253 | -#include <hybris/media/surface_texture_client_hybris.h> |
1254 | -#include <hybris/media/media_codec_layer.h> |
1255 | - |
1256 | #include <gio/gio.h> |
1257 | #include <gst/gst.h> |
1258 | |
1259 | @@ -37,8 +34,6 @@ |
1260 | // other image format, use: dot pipeline.dot -Tpng -o pipeline.png |
1261 | //#define DEBUG_GST_PIPELINE |
1262 | |
1263 | -namespace media = core::ubuntu::media; |
1264 | - |
1265 | namespace gstreamer |
1266 | { |
1267 | struct Playbin |
1268 | @@ -57,450 +52,57 @@ |
1269 | MEDIA_FILE_TYPE_VIDEO |
1270 | }; |
1271 | |
1272 | - static const std::string& pipeline_name() |
1273 | - { |
1274 | - static const std::string s{"playbin"}; |
1275 | - return s; |
1276 | - } |
1277 | - |
1278 | - static void about_to_finish(GstElement*, |
1279 | - gpointer user_data) |
1280 | - { |
1281 | - auto thiz = static_cast<Playbin*>(user_data); |
1282 | - thiz->signals.about_to_finish(); |
1283 | - } |
1284 | - |
1285 | - Playbin() |
1286 | - : pipeline(gst_element_factory_make("playbin", pipeline_name().c_str())), |
1287 | - bus{gst_element_get_bus(pipeline)}, |
1288 | - file_type(MEDIA_FILE_TYPE_NONE), |
1289 | - video_sink(nullptr), |
1290 | - video_height(0), |
1291 | - video_width(0), |
1292 | - on_new_message_connection( |
1293 | - bus.on_new_message.connect( |
1294 | - std::bind( |
1295 | - &Playbin::on_new_message, |
1296 | - this, |
1297 | - std::placeholders::_1))), |
1298 | - is_seeking(false) |
1299 | - { |
1300 | - if (!pipeline) |
1301 | - throw std::runtime_error("Could not create pipeline for playbin."); |
1302 | - |
1303 | - // Add audio and/or video sink elements depending on environment variables |
1304 | - // being set or not set |
1305 | - setup_pipeline_for_audio_video(); |
1306 | - |
1307 | - g_signal_connect( |
1308 | - pipeline, |
1309 | - "about-to-finish", |
1310 | - G_CALLBACK(about_to_finish), |
1311 | - this |
1312 | - ); |
1313 | - } |
1314 | - |
1315 | - ~Playbin() |
1316 | - { |
1317 | - if (pipeline) |
1318 | - gst_object_unref(pipeline); |
1319 | - } |
1320 | - |
1321 | - void reset() |
1322 | - { |
1323 | - std::cout << "Client died, resetting pipeline" << std::endl; |
1324 | - // When the client dies, tear down the current pipeline and get it |
1325 | - // in a state that is ready for the next client that connects to the |
1326 | - // service |
1327 | - reset_pipeline(); |
1328 | - // Signal to the Player class that the client side has disconnected |
1329 | - signals.client_disconnected(); |
1330 | - } |
1331 | - |
1332 | - void reset_pipeline() |
1333 | - { |
1334 | - std::cout << __PRETTY_FUNCTION__ << std::endl; |
1335 | - auto ret = gst_element_set_state(pipeline, GST_STATE_NULL); |
1336 | - switch(ret) |
1337 | - { |
1338 | - case GST_STATE_CHANGE_FAILURE: |
1339 | - std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
1340 | - break; |
1341 | - case GST_STATE_CHANGE_NO_PREROLL: |
1342 | - case GST_STATE_CHANGE_SUCCESS: |
1343 | - case GST_STATE_CHANGE_ASYNC: |
1344 | - break; |
1345 | - default: |
1346 | - std::cout << "Failed to reset the pipeline state. Client reconnect may not function properly." << std::endl; |
1347 | - } |
1348 | - file_type = MEDIA_FILE_TYPE_NONE; |
1349 | - } |
1350 | - |
1351 | - void on_new_message(const Bus::Message& message) |
1352 | - { |
1353 | - switch(message.type) |
1354 | - { |
1355 | - case GST_MESSAGE_ERROR: |
1356 | - signals.on_error(message.detail.error_warning_info); |
1357 | - break; |
1358 | - case GST_MESSAGE_WARNING: |
1359 | - signals.on_warning(message.detail.error_warning_info); |
1360 | - break; |
1361 | - case GST_MESSAGE_INFO: |
1362 | - signals.on_info(message.detail.error_warning_info); |
1363 | - break; |
1364 | - case GST_MESSAGE_TAG: |
1365 | - { |
1366 | - gchar *orientation; |
1367 | - if (gst_tag_list_get_string(message.detail.tag.tag_list, "image-orientation", &orientation)) |
1368 | - { |
1369 | - // If the image-orientation tag is in the GstTagList, signal the Engine |
1370 | - signals.on_orientation_changed(orientation_lut(orientation)); |
1371 | - g_free (orientation); |
1372 | - } |
1373 | - |
1374 | - signals.on_tag_available(message.detail.tag); |
1375 | - } |
1376 | - break; |
1377 | - case GST_MESSAGE_STATE_CHANGED: |
1378 | - signals.on_state_changed(message.detail.state_changed); |
1379 | - break; |
1380 | - case GST_MESSAGE_ASYNC_DONE: |
1381 | - if (is_seeking) |
1382 | - { |
1383 | - // FIXME: Pass the actual playback time position to the signal call |
1384 | - signals.on_seeked_to(0); |
1385 | - is_seeking = false; |
1386 | - } |
1387 | - break; |
1388 | - case GST_MESSAGE_EOS: |
1389 | - signals.on_end_of_stream(); |
1390 | - default: |
1391 | - break; |
1392 | - } |
1393 | - } |
1394 | - |
1395 | - gstreamer::Bus& message_bus() |
1396 | - { |
1397 | - return bus; |
1398 | - } |
1399 | - |
1400 | - void setup_pipeline_for_audio_video() |
1401 | - { |
1402 | - gint flags; |
1403 | - g_object_get (pipeline, "flags", &flags, nullptr); |
1404 | - flags |= GST_PLAY_FLAG_AUDIO; |
1405 | - flags |= GST_PLAY_FLAG_VIDEO; |
1406 | - flags &= ~GST_PLAY_FLAG_TEXT; |
1407 | - g_object_set (pipeline, "flags", flags, nullptr); |
1408 | - |
1409 | - if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") != nullptr) |
1410 | - { |
1411 | - auto audio_sink = gst_element_factory_make ( |
1412 | - ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME"), |
1413 | - "audio-sink"); |
1414 | - |
1415 | - std::cout << "audio_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_AUDIO_SINK_NAME") << std::endl; |
1416 | - |
1417 | - g_object_set ( |
1418 | - pipeline, |
1419 | - "audio-sink", |
1420 | - audio_sink, |
1421 | - NULL); |
1422 | - } |
1423 | - |
1424 | - if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
1425 | - { |
1426 | - video_sink = gst_element_factory_make ( |
1427 | - ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), |
1428 | - "video-sink"); |
1429 | - |
1430 | - std::cout << "video_sink: " << ::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") << std::endl; |
1431 | - |
1432 | - g_object_set ( |
1433 | - pipeline, |
1434 | - "video-sink", |
1435 | - video_sink, |
1436 | - NULL); |
1437 | - } |
1438 | - } |
1439 | - |
1440 | - void create_video_sink(uint32_t texture_id) |
1441 | - { |
1442 | - std::cout << "Creating video sink for texture_id: " << texture_id << std::endl; |
1443 | - |
1444 | - if (::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME") != nullptr) |
1445 | - { |
1446 | - g_object_get (pipeline, "video_sink", &video_sink, NULL); |
1447 | - |
1448 | - // Get the service-side BufferQueue (IGraphicBufferProducer) and associate it with |
1449 | - // the SurfaceTextureClientHybris instance |
1450 | - IGBPWrapperHybris igbp = decoding_service_get_igraphicbufferproducer(); |
1451 | - SurfaceTextureClientHybris stc = surface_texture_client_create_by_igbp(igbp); |
1452 | - // Because mirsink is being loaded, we are definitely doing * hardware rendering. |
1453 | - surface_texture_client_set_hardware_rendering (stc, TRUE); |
1454 | - g_object_set (G_OBJECT (video_sink), "surface", static_cast<gpointer>(stc), static_cast<char*>(NULL)); |
1455 | - } |
1456 | - } |
1457 | - |
1458 | - void set_volume(double new_volume) |
1459 | - { |
1460 | - g_object_set (pipeline, "volume", new_volume, NULL); |
1461 | - } |
1462 | - |
1463 | - /** Translate the AudioStreamRole enum into a string */ |
1464 | - static std::string get_audio_role_str(media::Player::AudioStreamRole audio_role) |
1465 | - { |
1466 | - switch (audio_role) |
1467 | - { |
1468 | - case media::Player::AudioStreamRole::alarm: |
1469 | - return "alarm"; |
1470 | - break; |
1471 | - case media::Player::AudioStreamRole::alert: |
1472 | - return "alert"; |
1473 | - break; |
1474 | - case media::Player::AudioStreamRole::multimedia: |
1475 | - return "multimedia"; |
1476 | - break; |
1477 | - case media::Player::AudioStreamRole::phone: |
1478 | - return "phone"; |
1479 | - break; |
1480 | - default: |
1481 | - return "multimedia"; |
1482 | - break; |
1483 | - } |
1484 | - } |
1485 | - |
1486 | - media::Player::Orientation orientation_lut(const gchar *orientation) |
1487 | - { |
1488 | - if (g_strcmp0(orientation, "rotate-0") == 0) |
1489 | - return media::Player::Orientation::rotate0; |
1490 | - else if (g_strcmp0(orientation, "rotate-90") == 0) |
1491 | - return media::Player::Orientation::rotate90; |
1492 | - else if (g_strcmp0(orientation, "rotate-180") == 0) |
1493 | - return media::Player::Orientation::rotate180; |
1494 | - else if (g_strcmp0(orientation, "rotate-270") == 0) |
1495 | - return media::Player::Orientation::rotate270; |
1496 | - else |
1497 | - return media::Player::Orientation::rotate0; |
1498 | - } |
1499 | + static std::string get_audio_role_str(core::ubuntu::media::Player::AudioStreamRole audio_role); |
1500 | + |
1501 | + static const std::string& pipeline_name(); |
1502 | + |
1503 | + static void about_to_finish(GstElement*, gpointer user_data); |
1504 | + |
1505 | + Playbin(); |
1506 | + ~Playbin(); |
1507 | + |
1508 | + void reset(); |
1509 | + void reset_pipeline(); |
1510 | + |
1511 | + void on_new_message(const Bus::Message& message); |
1512 | + |
1513 | + gstreamer::Bus& message_bus(); |
1514 | + |
1515 | + void setup_pipeline_for_audio_video(); |
1516 | + |
1517 | + void create_video_sink(uint32_t texture_id); |
1518 | + |
1519 | + void set_volume(double new_volume); |
1520 | + |
1521 | + core::ubuntu::media::Player::Orientation orientation_lut(const gchar *orientation); |
1522 | |
1523 | /** Sets the new audio stream role on the pulsesink in playbin */ |
1524 | - void set_audio_stream_role(media::Player::AudioStreamRole new_audio_role) |
1525 | - { |
1526 | - GstElement *audio_sink = NULL; |
1527 | - g_object_get (pipeline, "audio-sink", &audio_sink, NULL); |
1528 | - |
1529 | - std::string role_str("props,media.role=" + get_audio_role_str(new_audio_role)); |
1530 | - std::cout << "Audio stream role: " << role_str << std::endl; |
1531 | - |
1532 | - GstStructure *props = gst_structure_from_string (role_str.c_str(), NULL); |
1533 | - if (audio_sink != nullptr && props != nullptr) |
1534 | - g_object_set (audio_sink, "stream-properties", props, NULL); |
1535 | - else |
1536 | - { |
1537 | - std::cerr << |
1538 | - "Warning: couldn't set audio stream role - couldn't get audio_sink from pipeline" << |
1539 | - std::endl; |
1540 | - } |
1541 | - |
1542 | - gst_structure_free (props); |
1543 | - } |
1544 | - |
1545 | - uint64_t position() const |
1546 | - { |
1547 | - int64_t pos = 0; |
1548 | - gst_element_query_position (pipeline, GST_FORMAT_TIME, &pos); |
1549 | - |
1550 | - // FIXME: this should be int64_t, but dbus-cpp doesn't seem to handle it correctly |
1551 | - return static_cast<uint64_t>(pos); |
1552 | - } |
1553 | - |
1554 | - uint64_t duration() const |
1555 | - { |
1556 | - int64_t dur = 0; |
1557 | - gst_element_query_duration (pipeline, GST_FORMAT_TIME, &dur); |
1558 | - |
1559 | - // FIXME: this should be int64_t, but dbus-cpp doesn't seem to handle it correctly |
1560 | - return static_cast<uint64_t>(dur); |
1561 | - } |
1562 | - |
1563 | - void set_uri(const std::string& uri) |
1564 | - { |
1565 | - g_object_set(pipeline, "uri", uri.c_str(), NULL); |
1566 | - if (is_video_file(uri)) |
1567 | - file_type = MEDIA_FILE_TYPE_VIDEO; |
1568 | - else if (is_audio_file(uri)) |
1569 | - file_type = MEDIA_FILE_TYPE_AUDIO; |
1570 | - } |
1571 | - |
1572 | - std::string uri() const |
1573 | - { |
1574 | - gchar* data = nullptr; |
1575 | - g_object_get(pipeline, "current-uri", &data, nullptr); |
1576 | - |
1577 | - std::string result((data == nullptr ? "" : data)); |
1578 | - g_free(data); |
1579 | - |
1580 | - return result; |
1581 | - } |
1582 | - |
1583 | - bool set_state_and_wait(GstState new_state) |
1584 | - { |
1585 | - static const std::chrono::nanoseconds state_change_timeout |
1586 | - { |
1587 | - // We choose a quite high value here as tests are run under valgrind |
1588 | - // and gstreamer pipeline setup/state changes take longer in that scenario. |
1589 | - // The value does not negatively impact runtime performance. |
1590 | - std::chrono::milliseconds{5000} |
1591 | - }; |
1592 | - |
1593 | - auto ret = gst_element_set_state(pipeline, new_state); |
1594 | - bool result = false; GstState current, pending; |
1595 | - switch(ret) |
1596 | - { |
1597 | - case GST_STATE_CHANGE_FAILURE: |
1598 | - result = false; break; |
1599 | - case GST_STATE_CHANGE_NO_PREROLL: |
1600 | - case GST_STATE_CHANGE_SUCCESS: |
1601 | - result = true; break; |
1602 | - case GST_STATE_CHANGE_ASYNC: |
1603 | - result = GST_STATE_CHANGE_SUCCESS == gst_element_get_state( |
1604 | - pipeline, |
1605 | - ¤t, |
1606 | - &pending, |
1607 | - state_change_timeout.count()); |
1608 | - |
1609 | - if (new_state == GST_STATE_PLAYING) |
1610 | - { |
1611 | - // Get the video height/width from the video sink |
1612 | - get_video_dimensions(); |
1613 | -#ifdef DEBUG_GST_PIPELINE |
1614 | - std::cout << "Dumping pipeline dot file" << std::endl; |
1615 | - GST_DEBUG_BIN_TO_DOT_FILE((GstBin*)pipeline, GST_DEBUG_GRAPH_SHOW_ALL, "pipeline"); |
1616 | -#endif |
1617 | - } |
1618 | - break; |
1619 | - } |
1620 | - |
1621 | - return result; |
1622 | - } |
1623 | - |
1624 | - bool seek(const std::chrono::microseconds& ms) |
1625 | - { |
1626 | - is_seeking = true; |
1627 | - return gst_element_seek_simple( |
1628 | - pipeline, |
1629 | - GST_FORMAT_TIME, |
1630 | - (GstSeekFlags)(GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_KEY_UNIT), |
1631 | - ms.count() * 1000); |
1632 | - } |
1633 | - |
1634 | - void get_video_dimensions() |
1635 | - { |
1636 | - if (video_sink != nullptr && g_strcmp0(::getenv("CORE_UBUNTU_MEDIA_SERVICE_VIDEO_SINK_NAME"), "mirsink") == 0) |
1637 | - { |
1638 | - g_object_get (video_sink, "height", &video_height, nullptr); |
1639 | - g_object_get (video_sink, "width", &video_width, nullptr); |
1640 | - std::cout << "video_height: " << video_height << ", video_width: " << video_width << std::endl; |
1641 | - signals.on_add_frame_dimension(video_height, video_width); |
1642 | - } |
1643 | - else |
1644 | - std::cerr << "Could not get the height/width of each video frame" << std::endl; |
1645 | - } |
1646 | - |
1647 | - int get_video_height() const |
1648 | - { |
1649 | - return video_height; |
1650 | - } |
1651 | - |
1652 | - int get_video_width() const |
1653 | - { |
1654 | - return video_width; |
1655 | - } |
1656 | - |
1657 | - std::string get_file_content_type(const std::string& uri) const |
1658 | - { |
1659 | - if (uri.empty()) |
1660 | - return std::string(); |
1661 | - |
1662 | - std::string filename(uri); |
1663 | - std::cout << "filename: " << filename << std::endl; |
1664 | - size_t pos = uri.find("file://"); |
1665 | - if (pos != std::string::npos) |
1666 | - filename = uri.substr(pos + 7, std::string::npos); |
1667 | - else |
1668 | - // Anything other than a file, for now claim that the type |
1669 | - // is both audio and video. |
1670 | - // FIXME: implement true net stream sampling and get the type from GstCaps |
1671 | - return std::string("audio/video/"); |
1672 | - |
1673 | - |
1674 | - GError *error = nullptr; |
1675 | - std::unique_ptr<GFile, void(*)(void *)> file( |
1676 | - g_file_new_for_path(filename.c_str()), g_object_unref); |
1677 | - std::unique_ptr<GFileInfo, void(*)(void *)> info( |
1678 | - g_file_query_info( |
1679 | - file.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE "," |
1680 | - G_FILE_ATTRIBUTE_ETAG_VALUE, G_FILE_QUERY_INFO_NONE, |
1681 | - /* cancellable */ NULL, &error), |
1682 | - g_object_unref); |
1683 | - if (!info) |
1684 | - { |
1685 | - std::string error_str(error->message); |
1686 | - g_error_free(error); |
1687 | - |
1688 | - std::cout << "Failed to query the URI for the presence of video content: " |
1689 | - << error_str << std::endl; |
1690 | - return std::string(); |
1691 | - } |
1692 | - |
1693 | - std::string content_type(g_file_info_get_attribute_string( |
1694 | - info.get(), G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE)); |
1695 | - |
1696 | - return content_type; |
1697 | - } |
1698 | - |
1699 | - bool is_audio_file(const std::string& uri) const |
1700 | - { |
1701 | - if (uri.empty()) |
1702 | - return false; |
1703 | - |
1704 | - if (get_file_content_type(uri).find("audio/") == 0) |
1705 | - { |
1706 | - std::cout << "Found audio content" << std::endl; |
1707 | - return true; |
1708 | - } |
1709 | - |
1710 | - return false; |
1711 | - } |
1712 | - |
1713 | - bool is_video_file(const std::string& uri) const |
1714 | - { |
1715 | - if (uri.empty()) |
1716 | - return false; |
1717 | - |
1718 | - if (get_file_content_type(uri).find("video/") == 0) |
1719 | - { |
1720 | - std::cout << "Found video content" << std::endl; |
1721 | - return true; |
1722 | - } |
1723 | - |
1724 | - return false; |
1725 | - } |
1726 | - |
1727 | - MediaFileType media_file_type() const |
1728 | - { |
1729 | - return file_type; |
1730 | - } |
1731 | + void set_audio_stream_role(core::ubuntu::media::Player::AudioStreamRole new_audio_role); |
1732 | + |
1733 | + uint64_t position() const; |
1734 | + uint64_t duration() const; |
1735 | + |
1736 | + void set_uri(const std::string& uri); |
1737 | + std::string uri() const; |
1738 | + |
1739 | + bool set_state_and_wait(GstState new_state); |
1740 | + bool seek(const std::chrono::microseconds& ms); |
1741 | + |
1742 | + core::ubuntu::media::video::Dimensions get_video_dimensions() const; |
1743 | + |
1744 | + std::string get_file_content_type(const std::string& uri) const; |
1745 | + |
1746 | + bool is_audio_file(const std::string& uri) const; |
1747 | + bool is_video_file(const std::string& uri) const; |
1748 | + |
1749 | + MediaFileType media_file_type() const; |
1750 | |
1751 | GstElement* pipeline; |
1752 | gstreamer::Bus bus; |
1753 | MediaFileType file_type; |
1754 | - SurfaceTextureClientHybris stc_hybris; |
1755 | GstElement* video_sink; |
1756 | - uint32_t video_height; |
1757 | - uint32_t video_width; |
1758 | + mutable uint32_t video_height; |
1759 | + mutable uint32_t video_width; |
1760 | core::Connection on_new_message_connection; |
1761 | bool is_seeking; |
1762 | struct |
1763 | @@ -513,9 +115,9 @@ |
1764 | core::Signal<Bus::Message::Detail::StateChanged> on_state_changed; |
1765 | core::Signal<uint64_t> on_seeked_to; |
1766 | core::Signal<void> on_end_of_stream; |
1767 | - core::Signal<media::Player::PlaybackStatus> on_playback_status_changed; |
1768 | - core::Signal<media::Player::Orientation> on_orientation_changed; |
1769 | - core::Signal<uint32_t, uint32_t> on_add_frame_dimension; |
1770 | + core::Signal<core::ubuntu::media::Player::PlaybackStatus> on_playback_status_changed; |
1771 | + core::Signal<core::ubuntu::media::Player::Orientation> on_orientation_changed; |
1772 | + core::Signal<core::ubuntu::media::video::Dimensions> on_video_dimensions_changed; |
1773 | core::Signal<void> client_disconnected; |
1774 | } signals; |
1775 | }; |
1776 | |
1777 | === added file 'src/core/media/hybris_client_death_observer.cpp' |
1778 | --- src/core/media/hybris_client_death_observer.cpp 1970-01-01 00:00:00 +0000 |
1779 | +++ src/core/media/hybris_client_death_observer.cpp 2014-11-25 10:52:42 +0000 |
1780 | @@ -0,0 +1,84 @@ |
1781 | +/* |
1782 | + * Copyright © 2014 Canonical Ltd. |
1783 | + * |
1784 | + * This program is free software: you can redistribute it and/or modify it |
1785 | + * under the terms of the GNU Lesser General Public License version 3, |
1786 | + * as published by the Free Software Foundation. |
1787 | + * |
1788 | + * This program is distributed in the hope that it will be useful, |
1789 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1790 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1791 | + * GNU Lesser General Public License for more details. |
1792 | + * |
1793 | + * You should have received a copy of the GNU Lesser General Public License |
1794 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1795 | + * |
1796 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1797 | + */ |
1798 | + |
1799 | +#include <core/media/hybris_client_death_observer.h> |
1800 | + |
1801 | +namespace media = core::ubuntu::media; |
1802 | + |
1803 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
1804 | +#include <hybris/media/media_codec_layer.h> |
1805 | + |
1806 | +namespace |
1807 | +{ |
1808 | +typedef std::pair<media::Player::PlayerKey, std::weak_ptr<media::HybrisClientDeathObserver>> Holder; |
1809 | +} |
1810 | + |
1811 | +void media::HybrisClientDeathObserver::on_client_died_cb(void* context) |
1812 | +{ |
1813 | + auto holder = static_cast<Holder*>(context); |
1814 | + |
1815 | + if (not holder) |
1816 | + return; |
1817 | + |
1818 | + // We check if we are still alive or if we already got killed. |
1819 | + if (auto sp = holder->second.lock()) |
1820 | + { |
1821 | + sp->client_with_key_died(holder->first); |
1822 | + } |
1823 | + |
1824 | + // And with that, we have reached end of life for our holder object. |
1825 | + delete holder; |
1826 | +} |
1827 | + |
1828 | +// Creates an instance of the HybrisClientDeathObserver or throws |
1829 | +// if the underlying platform does not support it. |
1830 | +media::ClientDeathObserver::Ptr media::HybrisClientDeathObserver::create() |
1831 | +{ |
1832 | + return media::ClientDeathObserver::Ptr{new media::HybrisClientDeathObserver{}}; |
1833 | +} |
1834 | + |
1835 | +media::HybrisClientDeathObserver::HybrisClientDeathObserver() |
1836 | +{ |
1837 | +} |
1838 | + |
1839 | +media::HybrisClientDeathObserver::~HybrisClientDeathObserver() |
1840 | +{ |
1841 | +} |
1842 | + |
1843 | +void media::HybrisClientDeathObserver::register_for_death_notifications_with_key(const media::Player::PlayerKey& key) |
1844 | +{ |
1845 | + decoding_service_set_client_death_cb(&media::HybrisClientDeathObserver::on_client_died_cb, key, new Holder{key, shared_from_this()}); |
1846 | +} |
1847 | + |
1848 | +const core::Signal<media::Player::PlayerKey>& media::HybrisClientDeathObserver::on_client_with_key_died() const |
1849 | +{ |
1850 | + return client_with_key_died; |
1851 | +} |
1852 | +#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
1853 | +// Creates an instance of the HybrisClientDeathObserver or throws |
1854 | +// if the underlying platform does not support it. |
1855 | +media::ClientDeathObserver::Ptr media::HybrisClientDeathObserver::create() |
1856 | +{ |
1857 | + throw std::logic_error |
1858 | + { |
1859 | + "Hybris-based death observer implementation not supported on this platform." |
1860 | + }; |
1861 | +} |
1862 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
1863 | + |
1864 | + |
1865 | |
1866 | === added file 'src/core/media/hybris_client_death_observer.h' |
1867 | --- src/core/media/hybris_client_death_observer.h 1970-01-01 00:00:00 +0000 |
1868 | +++ src/core/media/hybris_client_death_observer.h 2014-11-25 10:52:42 +0000 |
1869 | @@ -0,0 +1,63 @@ |
1870 | +/* |
1871 | + * Copyright © 2014 Canonical Ltd. |
1872 | + * |
1873 | + * This program is free software: you can redistribute it and/or modify it |
1874 | + * under the terms of the GNU Lesser General Public License version 3, |
1875 | + * as published by the Free Software Foundation. |
1876 | + * |
1877 | + * This program is distributed in the hope that it will be useful, |
1878 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1879 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1880 | + * GNU Lesser General Public License for more details. |
1881 | + * |
1882 | + * You should have received a copy of the GNU Lesser General Public License |
1883 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1884 | + * |
1885 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1886 | + */ |
1887 | + |
1888 | +#ifndef CORE_UBUNTU_MEDIA_HYBRIS_CLIENT_DEATH_OBSERVER_H_ |
1889 | +#define CORE_UBUNTU_MEDIA_HYBRIS_CLIENT_DEATH_OBSERVER_H_ |
1890 | + |
1891 | +#include <core/media/client_death_observer.h> |
1892 | + |
1893 | +namespace core |
1894 | +{ |
1895 | +namespace ubuntu |
1896 | +{ |
1897 | +namespace media |
1898 | +{ |
1899 | +// Models functionality to be notified whenever a client |
1900 | +// of the service goes away, and thus allows us to clean |
1901 | +// up in that case. |
1902 | +class HybrisClientDeathObserver : public ClientDeathObserver, |
1903 | + public std::enable_shared_from_this<HybrisClientDeathObserver> |
1904 | +{ |
1905 | +public: |
1906 | + // Our static callback that we inject to the hybris world. |
1907 | + static void on_client_died_cb(void* context); |
1908 | + |
1909 | + // Creates an instance of the HybrisClientDeathObserver or throws |
1910 | + // if the underlying platform does not support it. |
1911 | + static ClientDeathObserver::Ptr create(); |
1912 | + |
1913 | + // Make std::unique_ptr happy for forward declared Private internals. |
1914 | + ~HybrisClientDeathObserver(); |
1915 | + |
1916 | + // Registers the client with the given key for death notifications. |
1917 | + void register_for_death_notifications_with_key(const Player::PlayerKey&) override; |
1918 | + |
1919 | + // Emitted whenver a client dies, reporting the key under which the |
1920 | + // respective client was known. |
1921 | + const core::Signal<Player::PlayerKey>& on_client_with_key_died() const override; |
1922 | + |
1923 | +private: |
1924 | + HybrisClientDeathObserver(); |
1925 | + |
1926 | + core::Signal<media::Player::PlayerKey> client_with_key_died; |
1927 | +}; |
1928 | +} |
1929 | +} |
1930 | +} |
1931 | + |
1932 | +#endif // CORE_UBUNTU_MEDIA_HYBRIS_CLIENT_DEATH_OBSERVER_H_ |
1933 | |
1934 | === added file 'src/core/media/hybris_recorder_observer.cpp' |
1935 | --- src/core/media/hybris_recorder_observer.cpp 1970-01-01 00:00:00 +0000 |
1936 | +++ src/core/media/hybris_recorder_observer.cpp 2014-11-25 10:52:42 +0000 |
1937 | @@ -0,0 +1,99 @@ |
1938 | +/* |
1939 | + * Copyright © 2014 Canonical Ltd. |
1940 | + * |
1941 | + * This program is free software: you can redistribute it and/or modify it |
1942 | + * under the terms of the GNU Lesser General Public License version 3, |
1943 | + * as published by the Free Software Foundation. |
1944 | + * |
1945 | + * This program is distributed in the hope that it will be useful, |
1946 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1947 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1948 | + * GNU Lesser General Public License for more details. |
1949 | + * |
1950 | + * You should have received a copy of the GNU Lesser General Public License |
1951 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1952 | + * |
1953 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
1954 | + */ |
1955 | + |
1956 | +#include <core/media/hybris_recorder_observer.h> |
1957 | + |
1958 | +namespace media = core::ubuntu::media; |
1959 | + |
1960 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
1961 | +#include <hybris/media/media_recorder_layer.h> |
1962 | + |
1963 | +struct media::HybrisRecorderObserver::Private |
1964 | +{ |
1965 | + struct Holder |
1966 | + { |
1967 | + std::weak_ptr<media::HybrisRecorderObserver::Private> wp; |
1968 | + }; |
1969 | + |
1970 | + // The fringe that we hand over to hybris. |
1971 | + static void on_media_recording_state_changed(bool started, void* context) |
1972 | + { |
1973 | + if (auto holder = static_cast<Holder*>(context)) |
1974 | + { |
1975 | + if (auto sp = holder->wp.lock()) |
1976 | + { |
1977 | + sp->recording_state = started ? media::RecordingState::started : media::RecordingState::stopped; |
1978 | + } |
1979 | + } |
1980 | + } |
1981 | + |
1982 | + // TODO: We have no way of freeing the observer and thus leak |
1983 | + // an instance here. |
1984 | + MediaRecorderObserver* observer |
1985 | + { |
1986 | + android_media_recorder_observer_new() |
1987 | + }; |
1988 | + |
1989 | + core::Property<media::RecordingState> recording_state |
1990 | + { |
1991 | + media::RecordingState::stopped |
1992 | + }; |
1993 | + |
1994 | + Holder* holder |
1995 | + { |
1996 | + nullptr |
1997 | + }; |
1998 | +}; |
1999 | + |
2000 | +media::HybrisRecorderObserver::HybrisRecorderObserver() : d{new Private{}} |
2001 | +{ |
2002 | + android_media_recorder_observer_set_cb( |
2003 | + d->observer, |
2004 | + &Private::on_media_recording_state_changed, |
2005 | + d->holder = new Private::Holder{d}); |
2006 | +} |
2007 | + |
2008 | +media::HybrisRecorderObserver::~HybrisRecorderObserver() |
2009 | +{ |
2010 | + // We first reset the context of the callback. |
2011 | + android_media_recorder_observer_set_cb( |
2012 | + d->observer, |
2013 | + &Private::on_media_recording_state_changed, |
2014 | + nullptr); |
2015 | + |
2016 | + delete d->holder; |
2017 | +} |
2018 | + |
2019 | +const core::Property<media::RecordingState>& media::HybrisRecorderObserver::recording_state() const |
2020 | +{ |
2021 | + return d->recording_state; |
2022 | +} |
2023 | + |
2024 | +media::RecorderObserver::Ptr media::HybrisRecorderObserver::create() |
2025 | +{ |
2026 | + return media::RecorderObserver::Ptr{new media::HybrisRecorderObserver{}}; |
2027 | +} |
2028 | +#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
2029 | +media::RecorderObserver::Ptr media::HybrisRecorderObserver::create() |
2030 | +{ |
2031 | + throw std::logic_error |
2032 | + { |
2033 | + "Hybris-based recorder observer implementation not supported on this platform." |
2034 | + }; |
2035 | +} |
2036 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
2037 | |
2038 | === added file 'src/core/media/hybris_recorder_observer.h' |
2039 | --- src/core/media/hybris_recorder_observer.h 1970-01-01 00:00:00 +0000 |
2040 | +++ src/core/media/hybris_recorder_observer.h 2014-11-25 10:52:42 +0000 |
2041 | @@ -0,0 +1,52 @@ |
2042 | +/* |
2043 | + * Copyright © 2014 Canonical Ltd. |
2044 | + * |
2045 | + * This program is free software: you can redistribute it and/or modify it |
2046 | + * under the terms of the GNU Lesser General Public License version 3, |
2047 | + * as published by the Free Software Foundation. |
2048 | + * |
2049 | + * This program is distributed in the hope that it will be useful, |
2050 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2051 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2052 | + * GNU Lesser General Public License for more details. |
2053 | + * |
2054 | + * You should have received a copy of the GNU Lesser General Public License |
2055 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2056 | + * |
2057 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
2058 | + */ |
2059 | + |
2060 | +#ifndef CORE_UBUNTU_MEDIA_HYBRIS_RECORDER_OBSERVER_H_ |
2061 | +#define CORE_UBUNTU_MEDIA_HYBRIS_RECORDER_OBSERVER_H_ |
2062 | + |
2063 | +#include <core/media/recorder_observer.h> |
2064 | + |
2065 | +namespace core |
2066 | +{ |
2067 | +namespace ubuntu |
2068 | +{ |
2069 | +namespace media |
2070 | +{ |
2071 | +class HybrisRecorderObserver : public RecorderObserver |
2072 | +{ |
2073 | +public: |
2074 | + // Creates a new instance of the HybrisRecorderObserver or throws |
2075 | + // if hybris is not available. |
2076 | + static RecorderObserver::Ptr create(); |
2077 | + |
2078 | + ~HybrisRecorderObserver(); |
2079 | + |
2080 | + // Getable/observable property describing the recording state of the system. |
2081 | + const core::Property<RecordingState>& recording_state() const override; |
2082 | + |
2083 | +private: |
2084 | + struct Private; |
2085 | + |
2086 | + HybrisRecorderObserver(); |
2087 | + std::shared_ptr<Private> d; |
2088 | +}; |
2089 | +} |
2090 | +} |
2091 | +} |
2092 | + |
2093 | +#endif // CORE_UBUNTU_MEDIA_HYBRIS_RECORDER_OBSERVER_H_ |
2094 | |
2095 | === modified file 'src/core/media/mpris/player.h' |
2096 | --- src/core/media/mpris/player.h 2014-10-14 20:05:20 +0000 |
2097 | +++ src/core/media/mpris/player.h 2014-11-25 10:52:42 +0000 |
2098 | @@ -34,12 +34,16 @@ |
2099 | #include <core/dbus/types/object_path.h> |
2100 | #include <core/dbus/types/variant.h> |
2101 | |
2102 | +#include <core/dbus/types/stl/tuple.h> |
2103 | + |
2104 | #include <boost/utility/identity_type.hpp> |
2105 | |
2106 | #include <string> |
2107 | #include <tuple> |
2108 | #include <vector> |
2109 | |
2110 | +#include <cstdint> |
2111 | + |
2112 | namespace dbus = core::dbus; |
2113 | |
2114 | namespace mpris |
2115 | @@ -103,6 +107,17 @@ |
2116 | static constexpr const char* stopped{"Stopped"}; |
2117 | }; |
2118 | |
2119 | + struct Error |
2120 | + { |
2121 | + struct OutOfProcessBufferStreamingNotSupported |
2122 | + { |
2123 | + static constexpr const char* name |
2124 | + { |
2125 | + "mpris.Player.Error.OutOfProcessBufferStreamingNotSupported" |
2126 | + }; |
2127 | + }; |
2128 | + }; |
2129 | + |
2130 | typedef std::map<std::string, core::dbus::types::Variant> Dictionary; |
2131 | |
2132 | DBUS_CPP_METHOD_DEF(Next, Player) |
2133 | @@ -122,7 +137,7 @@ |
2134 | DBUS_CPP_SIGNAL_DEF(Seeked, Player, std::int64_t) |
2135 | DBUS_CPP_SIGNAL_DEF(EndOfStream, Player, void) |
2136 | DBUS_CPP_SIGNAL_DEF(PlaybackStatusChanged, Player, core::ubuntu::media::Player::PlaybackStatus) |
2137 | - DBUS_CPP_SIGNAL_DEF(VideoDimensionChanged, Player, std::uint64_t) |
2138 | + DBUS_CPP_SIGNAL_DEF(VideoDimensionChanged, Player, core::ubuntu::media::video::Dimensions) |
2139 | }; |
2140 | |
2141 | struct Properties |
2142 | |
2143 | === modified file 'src/core/media/player.cpp' |
2144 | --- src/core/media/player.cpp 2014-09-09 10:28:32 +0000 |
2145 | +++ src/core/media/player.cpp 2014-11-25 10:52:42 +0000 |
2146 | @@ -22,6 +22,11 @@ |
2147 | |
2148 | namespace media = core::ubuntu::media; |
2149 | |
2150 | +media::Player::Error::OutOfProcessBufferStreamingNotSupported::OutOfProcessBufferStreamingNotSupported() |
2151 | + : std::runtime_error{"Implementation does not support out-of-process buffer streaming"} |
2152 | +{ |
2153 | +} |
2154 | + |
2155 | const media::Player::Configuration& media::Player::Client::default_configuration() |
2156 | { |
2157 | static const media::Player::Configuration config |
2158 | |
2159 | === modified file 'src/core/media/player_implementation.cpp' |
2160 | --- src/core/media/player_implementation.cpp 2014-11-03 18:00:48 +0000 |
2161 | +++ src/core/media/player_implementation.cpp 2014-11-25 10:52:42 +0000 |
2162 | @@ -21,10 +21,10 @@ |
2163 | |
2164 | #include <unistd.h> |
2165 | |
2166 | +#include "client_death_observer.h" |
2167 | #include "engine.h" |
2168 | #include "track_list_implementation.h" |
2169 | |
2170 | -#include <hybris/media/media_codec_layer.h> |
2171 | #include "powerd_service.h" |
2172 | #include "unity_screen_service.h" |
2173 | #include "gstreamer/engine.h" |
2174 | @@ -81,7 +81,16 @@ |
2175 | auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name()); |
2176 | uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen")); |
2177 | |
2178 | - decoding_service_set_client_death_cb(&Private::on_client_died_cb, key, static_cast<void*>(this)); |
2179 | + auto client_death_observer = media::platform_default_client_death_observer(); |
2180 | + |
2181 | + client_death_observer->register_for_death_notifications_with_key(key); |
2182 | + client_death_observer->on_client_with_key_died().connect([this](const media::Player::PlayerKey& died) |
2183 | + { |
2184 | + if (died != this->key) |
2185 | + return; |
2186 | + |
2187 | + on_client_died(); |
2188 | + }); |
2189 | } |
2190 | |
2191 | ~Private() |
2192 | @@ -261,15 +270,6 @@ |
2193 | }; |
2194 | } |
2195 | |
2196 | - static void on_client_died_cb(void *context) |
2197 | - { |
2198 | - if (context) |
2199 | - { |
2200 | - Private *p = static_cast<Private*>(context); |
2201 | - p->on_client_died(); |
2202 | - } |
2203 | - } |
2204 | - |
2205 | void on_client_died() |
2206 | { |
2207 | engine->reset(); |
2208 | @@ -408,12 +408,9 @@ |
2209 | playback_status_changed()(status); |
2210 | }); |
2211 | |
2212 | - d->engine->video_dimension_changed_signal().connect([this](uint32_t height, uint32_t width) |
2213 | + d->engine->video_dimension_changed_signal().connect([this](const media::video::Dimensions& dimensions) |
2214 | { |
2215 | - uint64_t mask = 0; |
2216 | - // Left most 32 bits are for height, right most 32 bits are for width |
2217 | - mask = (static_cast<uint64_t>(height) << 32) | static_cast<uint64_t>(width); |
2218 | - video_dimension_changed()(mask); |
2219 | + video_dimension_changed()(dimensions); |
2220 | }); |
2221 | } |
2222 | |
2223 | @@ -458,22 +455,17 @@ |
2224 | return d->key; |
2225 | } |
2226 | |
2227 | +media::video::Sink::Ptr media::PlayerImplementation::create_gl_texture_video_sink(std::uint32_t texture_id) |
2228 | +{ |
2229 | + d->engine->create_video_sink(texture_id); |
2230 | + return media::video::Sink::Ptr{}; |
2231 | +} |
2232 | + |
2233 | bool media::PlayerImplementation::open_uri(const Track::UriType& uri) |
2234 | { |
2235 | return d->engine->open_resource_for_uri(uri); |
2236 | } |
2237 | |
2238 | -void media::PlayerImplementation::create_video_sink(uint32_t texture_id) |
2239 | -{ |
2240 | - d->engine->create_video_sink(texture_id); |
2241 | -} |
2242 | - |
2243 | -media::Player::GLConsumerWrapperHybris media::PlayerImplementation::gl_consumer() const |
2244 | -{ |
2245 | - // This method is client-side only and is simply a no-op for the service side |
2246 | - return NULL; |
2247 | -} |
2248 | - |
2249 | void media::PlayerImplementation::next() |
2250 | { |
2251 | } |
2252 | @@ -498,18 +490,6 @@ |
2253 | d->engine->stop(); |
2254 | } |
2255 | |
2256 | -void media::PlayerImplementation::set_frame_available_callback( |
2257 | - UNUSED FrameAvailableCb cb, UNUSED void *context) |
2258 | -{ |
2259 | - // This method is client-side only and is simply a no-op for the service side |
2260 | -} |
2261 | - |
2262 | -void media::PlayerImplementation::set_playback_complete_callback( |
2263 | - UNUSED PlaybackCompleteCb cb, UNUSED void *context) |
2264 | -{ |
2265 | - // This method is client-side only and is simply a no-op for the service side |
2266 | -} |
2267 | - |
2268 | void media::PlayerImplementation::seek_to(const std::chrono::microseconds& ms) |
2269 | { |
2270 | d->engine->seek_to(ms); |
2271 | |
2272 | === modified file 'src/core/media/player_implementation.h' |
2273 | --- src/core/media/player_implementation.h 2014-09-25 04:35:46 +0000 |
2274 | +++ src/core/media/player_implementation.h 2014-11-25 10:52:42 +0000 |
2275 | @@ -46,16 +46,14 @@ |
2276 | virtual std::shared_ptr<TrackList> track_list(); |
2277 | virtual PlayerKey key() const; |
2278 | |
2279 | + virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id); |
2280 | + |
2281 | virtual bool open_uri(const Track::UriType& uri); |
2282 | - virtual void create_video_sink(uint32_t texture_id); |
2283 | - virtual GLConsumerWrapperHybris gl_consumer() const; |
2284 | virtual void next(); |
2285 | virtual void previous(); |
2286 | virtual void play(); |
2287 | virtual void pause(); |
2288 | virtual void stop(); |
2289 | - virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
2290 | - virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context); |
2291 | virtual void seek_to(const std::chrono::microseconds& offset); |
2292 | |
2293 | const core::Signal<>& on_client_disconnected() const; |
2294 | |
2295 | === modified file 'src/core/media/player_skeleton.cpp' |
2296 | --- src/core/media/player_skeleton.cpp 2014-10-14 20:15:56 +0000 |
2297 | +++ src/core/media/player_skeleton.cpp 2014-11-25 10:52:42 +0000 |
2298 | @@ -19,6 +19,7 @@ |
2299 | |
2300 | #include "apparmor.h" |
2301 | #include "codec.h" |
2302 | +#include "engine.h" |
2303 | #include "player_skeleton.h" |
2304 | #include "player_traits.h" |
2305 | #include "property_stub.h" |
2306 | @@ -135,9 +136,29 @@ |
2307 | { |
2308 | uint32_t texture_id; |
2309 | in->reader() >> texture_id; |
2310 | - impl->create_video_sink(texture_id); |
2311 | - |
2312 | - auto reply = dbus::Message::make_method_return(in); |
2313 | + |
2314 | + core::dbus::Message::Ptr reply; |
2315 | + |
2316 | + try |
2317 | + { |
2318 | + impl->create_gl_texture_video_sink(texture_id); |
2319 | + reply = dbus::Message::make_method_return(in); |
2320 | + } |
2321 | + catch (const media::Player::Error::OutOfProcessBufferStreamingNotSupported& e) |
2322 | + { |
2323 | + reply = dbus::Message::make_error( |
2324 | + in, |
2325 | + mpris::Player::Error::OutOfProcessBufferStreamingNotSupported::name, |
2326 | + e.what()); |
2327 | + } |
2328 | + catch (...) |
2329 | + { |
2330 | + reply = dbus::Message::make_error( |
2331 | + in, |
2332 | + mpris::Player::Error::OutOfProcessBufferStreamingNotSupported::name, |
2333 | + std::string{}); |
2334 | + } |
2335 | + |
2336 | bus->send(reply); |
2337 | } |
2338 | |
2339 | @@ -298,7 +319,7 @@ |
2340 | remote_playback_status_changed->emit(status); |
2341 | }); |
2342 | |
2343 | - video_dimension_changed.connect([remote_video_dimension_changed](uint64_t mask) |
2344 | + video_dimension_changed.connect([remote_video_dimension_changed](const media::video::Dimensions& mask) |
2345 | { |
2346 | remote_video_dimension_changed->emit(mask); |
2347 | }); |
2348 | @@ -307,7 +328,7 @@ |
2349 | core::Signal<int64_t> seeked_to; |
2350 | core::Signal<void> end_of_stream; |
2351 | core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
2352 | - core::Signal<uint64_t> video_dimension_changed; |
2353 | + core::Signal<media::video::Dimensions> video_dimension_changed; |
2354 | } signals; |
2355 | |
2356 | }; |
2357 | @@ -587,12 +608,12 @@ |
2358 | return d->signals.playback_status_changed; |
2359 | } |
2360 | |
2361 | -const core::Signal<uint64_t>& media::PlayerSkeleton::video_dimension_changed() const |
2362 | +const core::Signal<media::video::Dimensions>& media::PlayerSkeleton::video_dimension_changed() const |
2363 | { |
2364 | return d->signals.video_dimension_changed; |
2365 | } |
2366 | |
2367 | -core::Signal<uint64_t>& media::PlayerSkeleton::video_dimension_changed() |
2368 | +core::Signal<media::video::Dimensions>& media::PlayerSkeleton::video_dimension_changed() |
2369 | { |
2370 | return d->signals.video_dimension_changed; |
2371 | } |
2372 | |
2373 | === modified file 'src/core/media/player_skeleton.h' |
2374 | --- src/core/media/player_skeleton.h 2014-10-14 20:05:20 +0000 |
2375 | +++ src/core/media/player_skeleton.h 2014-11-25 10:52:42 +0000 |
2376 | @@ -73,7 +73,7 @@ |
2377 | virtual const core::Signal<int64_t>& seeked_to() const; |
2378 | virtual const core::Signal<void>& end_of_stream() const; |
2379 | virtual core::Signal<PlaybackStatus>& playback_status_changed(); |
2380 | - virtual const core::Signal<uint64_t>& video_dimension_changed() const; |
2381 | + virtual const core::Signal<video::Dimensions>& video_dimension_changed() const; |
2382 | |
2383 | protected: |
2384 | // All creation time arguments go here. |
2385 | @@ -109,7 +109,7 @@ |
2386 | |
2387 | virtual core::Signal<int64_t>& seeked_to(); |
2388 | virtual core::Signal<void>& end_of_stream(); |
2389 | - virtual core::Signal<uint64_t>& video_dimension_changed(); |
2390 | + virtual core::Signal<video::Dimensions>& video_dimension_changed(); |
2391 | |
2392 | private: |
2393 | struct Private; |
2394 | |
2395 | === modified file 'src/core/media/player_stub.cpp' |
2396 | --- src/core/media/player_stub.cpp 2014-11-05 20:41:03 +0000 |
2397 | +++ src/core/media/player_stub.cpp 2014-11-25 10:52:42 +0000 |
2398 | @@ -29,13 +29,11 @@ |
2399 | |
2400 | #include "mpris/player.h" |
2401 | |
2402 | +#include "video/platform_default_sink.h" |
2403 | + |
2404 | #include <core/dbus/property.h> |
2405 | #include <core/dbus/types/object_path.h> |
2406 | |
2407 | -// Hybris |
2408 | -#include <hybris/media/media_codec_layer.h> |
2409 | -#include <hybris/media/surface_texture_client_hybris.h> |
2410 | - |
2411 | #include <limits> |
2412 | |
2413 | #define UNUSED __attribute__((unused)) |
2414 | @@ -48,13 +46,8 @@ |
2415 | Private(const std::shared_ptr<Service>& parent, |
2416 | const std::shared_ptr<core::dbus::Object>& object |
2417 | ) : parent(parent), |
2418 | - texture_id(0), |
2419 | - igbc_wrapper(nullptr), |
2420 | - glc_wrapper(nullptr), |
2421 | - decoding_session(nullptr), |
2422 | - frame_available_cb(nullptr), |
2423 | - frame_available_context(nullptr), |
2424 | object(object), |
2425 | + key(object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>().value()), |
2426 | properties |
2427 | { |
2428 | // Link the properties from the server side to the client side over the bus |
2429 | @@ -87,64 +80,19 @@ |
2430 | object->get_signal<mpris::Player::Signals::VideoDimensionChanged>() |
2431 | } |
2432 | { |
2433 | - auto op = object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>(); |
2434 | - decoding_session = decoding_service_create_session(op.value()); |
2435 | } |
2436 | |
2437 | ~Private() |
2438 | { |
2439 | } |
2440 | |
2441 | - static void on_frame_available_cb(UNUSED GLConsumerWrapperHybris wrapper, void *context) |
2442 | - { |
2443 | - if (context != nullptr) { |
2444 | - Private *p = static_cast<Private*>(context); |
2445 | - p->on_frame_available(); |
2446 | - } |
2447 | - else |
2448 | - std::cerr << "context is nullptr, can't call on_frame_available()" << std::endl; |
2449 | - } |
2450 | - |
2451 | - void on_frame_available() |
2452 | - { |
2453 | - if (frame_available_cb != nullptr) { |
2454 | - frame_available_cb(frame_available_context); |
2455 | - } |
2456 | - else |
2457 | - std::cerr << "frame_available_cb is nullptr, can't call frame_available_cb()" << std::endl; |
2458 | - } |
2459 | - |
2460 | - void set_frame_available_cb(FrameAvailableCb cb, void *context) |
2461 | - { |
2462 | - frame_available_cb = cb; |
2463 | - frame_available_context = context; |
2464 | - |
2465 | - gl_consumer_set_frame_available_cb(glc_wrapper, &Private::on_frame_available_cb, static_cast<void*>(this)); |
2466 | - } |
2467 | - |
2468 | - /** We need a GLConsumerHybris instance for doing texture streaming over the |
2469 | - * process boundary **/ |
2470 | - void get_gl_consumer() |
2471 | - { |
2472 | - igbc_wrapper = decoding_service_get_igraphicbufferconsumer(); |
2473 | - glc_wrapper = gl_consumer_create_by_id_with_igbc(texture_id, igbc_wrapper); |
2474 | - |
2475 | - } |
2476 | - |
2477 | std::shared_ptr<Service> parent; |
2478 | std::shared_ptr<TrackList> track_list; |
2479 | |
2480 | - uint32_t texture_id; |
2481 | - IGBCWrapperHybris igbc_wrapper; |
2482 | - GLConsumerWrapperHybris glc_wrapper; |
2483 | - |
2484 | - DSSessionWrapperHybris decoding_session; |
2485 | - |
2486 | - FrameAvailableCb frame_available_cb; |
2487 | - void *frame_available_context; |
2488 | - |
2489 | dbus::Object::Ptr object; |
2490 | |
2491 | + media::Player::PlayerKey key; |
2492 | + |
2493 | struct |
2494 | { |
2495 | std::shared_ptr<core::dbus::Property<mpris::Player::Properties::CanPlay>> can_play; |
2496 | @@ -181,9 +129,7 @@ |
2497 | const std::shared_ptr<DBusEndOfStreamSignal>& eos, |
2498 | const std::shared_ptr<DBusPlaybackStatusChangedSignal>& status, |
2499 | const std::shared_ptr<DBusVideoDimensionChangedSignal>& d) |
2500 | - : playback_complete_cb(nullptr), |
2501 | - playback_complete_context(nullptr), |
2502 | - seeked_to(), |
2503 | + : seeked_to(), |
2504 | end_of_stream(), |
2505 | playback_status_changed(), |
2506 | video_dimension_changed(), |
2507 | @@ -204,8 +150,6 @@ |
2508 | dbus.end_of_stream->connect([this]() |
2509 | { |
2510 | std::cout << "EndOfStream signal arrived via the bus." << std::endl; |
2511 | - if (playback_complete_cb) |
2512 | - playback_complete_cb(playback_complete_context); |
2513 | end_of_stream(); |
2514 | }); |
2515 | |
2516 | @@ -215,25 +159,17 @@ |
2517 | playback_status_changed(status); |
2518 | }); |
2519 | |
2520 | - dbus.video_dimension_changed->connect([this](uint64_t mask) |
2521 | + dbus.video_dimension_changed->connect([this](const media::video::Dimensions dimensions) |
2522 | { |
2523 | std::cout << "VideoDimensionChanged signal arrived via the bus." << std::endl; |
2524 | - video_dimension_changed(mask); |
2525 | + video_dimension_changed(dimensions); |
2526 | }); |
2527 | - } |
2528 | - |
2529 | - void set_playback_complete_cb(PlaybackCompleteCb cb, void *context) |
2530 | - { |
2531 | - playback_complete_cb = cb; |
2532 | - playback_complete_context = context; |
2533 | } |
2534 | |
2535 | - PlaybackCompleteCb playback_complete_cb; |
2536 | - void *playback_complete_context; |
2537 | core::Signal<int64_t> seeked_to; |
2538 | core::Signal<void> end_of_stream; |
2539 | core::Signal<media::Player::PlaybackStatus> playback_status_changed; |
2540 | - core::Signal<uint64_t> video_dimension_changed; |
2541 | + core::Signal<media::video::Dimensions> video_dimension_changed; |
2542 | |
2543 | struct DBus |
2544 | { |
2545 | @@ -269,9 +205,7 @@ |
2546 | |
2547 | media::Player::PlayerKey media::PlayerStub::key() const |
2548 | { |
2549 | - auto op = d->object->invoke_method_synchronously<mpris::Player::Key, media::Player::PlayerKey>(); |
2550 | - |
2551 | - return op.value(); |
2552 | + return d->key; |
2553 | } |
2554 | |
2555 | bool media::PlayerStub::open_uri(const media::Track::UriType& uri) |
2556 | @@ -281,19 +215,19 @@ |
2557 | return op.value(); |
2558 | } |
2559 | |
2560 | -void media::PlayerStub::create_video_sink(uint32_t texture_id) |
2561 | +media::video::Sink::Ptr media::PlayerStub::create_gl_texture_video_sink(std::uint32_t texture_id) |
2562 | { |
2563 | auto op = d->object->invoke_method_synchronously<mpris::Player::CreateVideoSink, void>(texture_id); |
2564 | - d->texture_id = texture_id; |
2565 | - d->get_gl_consumer(); |
2566 | |
2567 | if (op.is_error()) |
2568 | - throw std::runtime_error("Problem creating new video sink instance on remote object"); |
2569 | -} |
2570 | + { |
2571 | + if (op.error().name() == mpris::Player::Error::OutOfProcessBufferStreamingNotSupported::name) |
2572 | + throw media::Player::Error::OutOfProcessBufferStreamingNotSupported{}; |
2573 | + else |
2574 | + throw std::runtime_error{op.error().print()}; |
2575 | + } |
2576 | |
2577 | -GLConsumerWrapperHybris media::PlayerStub::gl_consumer() const |
2578 | -{ |
2579 | - return d->glc_wrapper; |
2580 | + return media::video::make_platform_default_sink(texture_id, d->key); |
2581 | } |
2582 | |
2583 | void media::PlayerStub::next() |
2584 | @@ -344,16 +278,6 @@ |
2585 | throw std::runtime_error("Problem stopping playback on remote object"); |
2586 | } |
2587 | |
2588 | -void media::PlayerStub::set_frame_available_callback(FrameAvailableCb cb, void *context) |
2589 | -{ |
2590 | - d->set_frame_available_cb(cb, context); |
2591 | -} |
2592 | - |
2593 | -void media::PlayerStub::set_playback_complete_callback(PlaybackCompleteCb cb, void *context) |
2594 | -{ |
2595 | - d->signals.set_playback_complete_cb(cb, context); |
2596 | -} |
2597 | - |
2598 | const core::Property<bool>& media::PlayerStub::can_play() const |
2599 | { |
2600 | return *d->properties.can_play; |
2601 | @@ -489,7 +413,7 @@ |
2602 | return d->signals.playback_status_changed; |
2603 | } |
2604 | |
2605 | -const core::Signal<uint64_t>& media::PlayerStub::video_dimension_changed() const |
2606 | +const core::Signal<media::video::Dimensions>& media::PlayerStub::video_dimension_changed() const |
2607 | { |
2608 | return d->signals.video_dimension_changed; |
2609 | } |
2610 | |
2611 | === modified file 'src/core/media/player_stub.h' |
2612 | --- src/core/media/player_stub.h 2014-10-22 20:08:22 +0000 |
2613 | +++ src/core/media/player_stub.h 2014-11-25 10:52:42 +0000 |
2614 | @@ -46,9 +46,9 @@ |
2615 | virtual std::shared_ptr<TrackList> track_list(); |
2616 | virtual PlayerKey key() const; |
2617 | |
2618 | - virtual bool open_uri(const Track::UriType& uri); |
2619 | - virtual void create_video_sink(uint32_t texture_id); |
2620 | - virtual GLConsumerWrapperHybris gl_consumer() const; |
2621 | + virtual video::Sink::Ptr create_gl_texture_video_sink(std::uint32_t texture_id); |
2622 | + |
2623 | + virtual bool open_uri(const Track::UriType& uri); |
2624 | virtual void next(); |
2625 | virtual void previous(); |
2626 | virtual void play(); |
2627 | @@ -56,9 +56,6 @@ |
2628 | virtual void seek_to(const std::chrono::microseconds& offset); |
2629 | virtual void stop(); |
2630 | |
2631 | - virtual void set_frame_available_callback(FrameAvailableCb cb, void *context); |
2632 | - virtual void set_playback_complete_callback(PlaybackCompleteCb cb, void *context); |
2633 | - |
2634 | virtual const core::Property<bool>& can_play() const; |
2635 | virtual const core::Property<bool>& can_pause() const; |
2636 | virtual const core::Property<bool>& can_seek() const; |
2637 | @@ -88,7 +85,7 @@ |
2638 | virtual const core::Signal<int64_t>& seeked_to() const; |
2639 | virtual const core::Signal<void>& end_of_stream() const; |
2640 | virtual core::Signal<PlaybackStatus>& playback_status_changed(); |
2641 | - virtual const core::Signal<uint64_t>& video_dimension_changed() const; |
2642 | + virtual const core::Signal<video::Dimensions>& video_dimension_changed() const; |
2643 | |
2644 | private: |
2645 | struct Private; |
2646 | |
2647 | === added file 'src/core/media/recorder_observer.cpp' |
2648 | --- src/core/media/recorder_observer.cpp 1970-01-01 00:00:00 +0000 |
2649 | +++ src/core/media/recorder_observer.cpp 2014-11-25 10:52:42 +0000 |
2650 | @@ -0,0 +1,28 @@ |
2651 | +/* |
2652 | + * Copyright © 2014 Canonical Ltd. |
2653 | + * |
2654 | + * This program is free software: you can redistribute it and/or modify it |
2655 | + * under the terms of the GNU Lesser General Public License version 3, |
2656 | + * as published by the Free Software Foundation. |
2657 | + * |
2658 | + * This program is distributed in the hope that it will be useful, |
2659 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2660 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2661 | + * GNU Lesser General Public License for more details. |
2662 | + * |
2663 | + * You should have received a copy of the GNU Lesser General Public License |
2664 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2665 | + * |
2666 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
2667 | + */ |
2668 | + |
2669 | +#include <core/media/recorder_observer.h> |
2670 | + |
2671 | +#include <core/media/hybris_recorder_observer.h> |
2672 | + |
2673 | +namespace media = core::ubuntu::media; |
2674 | + |
2675 | +media::RecorderObserver::Ptr media::make_platform_default_recorder_observer() |
2676 | +{ |
2677 | + return media::HybrisRecorderObserver::create(); |
2678 | +} |
2679 | |
2680 | === added file 'src/core/media/recorder_observer.h' |
2681 | --- src/core/media/recorder_observer.h 1970-01-01 00:00:00 +0000 |
2682 | +++ src/core/media/recorder_observer.h 2014-11-25 10:52:42 +0000 |
2683 | @@ -0,0 +1,64 @@ |
2684 | +/* |
2685 | + * Copyright © 2014 Canonical Ltd. |
2686 | + * |
2687 | + * This program is free software: you can redistribute it and/or modify it |
2688 | + * under the terms of the GNU Lesser General Public License version 3, |
2689 | + * as published by the Free Software Foundation. |
2690 | + * |
2691 | + * This program is distributed in the hope that it will be useful, |
2692 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2693 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2694 | + * GNU Lesser General Public License for more details. |
2695 | + * |
2696 | + * You should have received a copy of the GNU Lesser General Public License |
2697 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2698 | + * |
2699 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
2700 | + */ |
2701 | + |
2702 | +#ifndef CORE_UBUNTU_MEDIA_RECORDER_OBSERVER_H_ |
2703 | +#define CORE_UBUNTU_MEDIA_RECORDER_OBSERVER_H_ |
2704 | + |
2705 | +#include <core/property.h> |
2706 | + |
2707 | +#include <memory> |
2708 | + |
2709 | +namespace core |
2710 | +{ |
2711 | +namespace ubuntu |
2712 | +{ |
2713 | +namespace media |
2714 | +{ |
2715 | +// All known states of the recorder |
2716 | +enum class RecordingState |
2717 | +{ |
2718 | + // No active recording |
2719 | + stopped, |
2720 | + // We have an active recording session |
2721 | + started |
2722 | +}; |
2723 | + |
2724 | +// A RecorderObserver allows for monitoring the recording state |
2725 | +// of the service. |
2726 | +struct RecorderObserver |
2727 | +{ |
2728 | + // To save us some typing. |
2729 | + typedef std::shared_ptr<RecorderObserver> Ptr; |
2730 | + |
2731 | + RecorderObserver() = default; |
2732 | + RecorderObserver(const RecorderObserver&) = delete; |
2733 | + virtual ~RecorderObserver() = default; |
2734 | + RecorderObserver& operator=(const RecorderObserver&) = delete; |
2735 | + |
2736 | + // Getable/observable property describing the recording state of the system. |
2737 | + virtual const core::Property<RecordingState>& recording_state() const = 0; |
2738 | +}; |
2739 | + |
2740 | +// Creates an instance of interface RecorderObserver relying on |
2741 | +// default services offered by the platform we are currently running on. |
2742 | +RecorderObserver::Ptr make_platform_default_recorder_observer(); |
2743 | +} |
2744 | +} |
2745 | +} |
2746 | + |
2747 | +#endif // CORE_UBUNTU_MEDIA_RECORDER_OBSERVER_H_ |
2748 | |
2749 | === modified file 'src/core/media/server/server.cpp' |
2750 | --- src/core/media/server/server.cpp 2014-04-04 14:31:43 +0000 |
2751 | +++ src/core/media/server/server.cpp 2014-11-25 10:52:42 +0000 |
2752 | @@ -20,8 +20,6 @@ |
2753 | #include <core/media/player.h> |
2754 | #include <core/media/track_list.h> |
2755 | |
2756 | -#include <hybris/media/media_codec_layer.h> |
2757 | - |
2758 | #include "core/media/service_implementation.h" |
2759 | |
2760 | #include <iostream> |
2761 | @@ -30,10 +28,32 @@ |
2762 | |
2763 | using namespace std; |
2764 | |
2765 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
2766 | +#include <hybris/media/media_codec_layer.h> |
2767 | + |
2768 | +namespace |
2769 | +{ |
2770 | +// All platform-specific initialization routines go here. |
2771 | +void platform_init() |
2772 | +{ |
2773 | + decoding_service_init(); |
2774 | +} |
2775 | +} |
2776 | +#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
2777 | +namespace |
2778 | +{ |
2779 | +// All platform-specific initialization routines go here. |
2780 | +void platform_init() |
2781 | +{ |
2782 | + // Consciously left empty |
2783 | +} |
2784 | +} |
2785 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
2786 | + |
2787 | int main() |
2788 | { |
2789 | - // Init hybris-level DecodingService |
2790 | - decoding_service_init(); |
2791 | + platform_init(); |
2792 | + |
2793 | cout << "Starting DecodingService..." << endl; |
2794 | |
2795 | auto service = std::make_shared<media::ServiceImplementation>(); |
2796 | |
2797 | === modified file 'src/core/media/service_implementation.cpp' |
2798 | --- src/core/media/service_implementation.cpp 2014-11-20 18:31:40 +0000 |
2799 | +++ src/core/media/service_implementation.cpp 2014-11-25 10:52:42 +0000 |
2800 | @@ -26,6 +26,7 @@ |
2801 | #include "call-monitor/call_monitor.h" |
2802 | #include "player_configuration.h" |
2803 | #include "player_implementation.h" |
2804 | +#include "recorder_observer.h" |
2805 | |
2806 | #include <boost/asio.hpp> |
2807 | |
2808 | @@ -40,7 +41,6 @@ |
2809 | |
2810 | #include "util/timeout.h" |
2811 | #include "unity_screen_service.h" |
2812 | -#include <hybris/media/media_recorder_layer.h> |
2813 | |
2814 | namespace media = core::ubuntu::media; |
2815 | |
2816 | @@ -141,8 +141,11 @@ |
2817 | auto uscreen_stub_service = dbus::Service::use_service(bus, dbus::traits::Service<core::UScreen>::interface_name()); |
2818 | uscreen_session = uscreen_stub_service->object_for_path(dbus::types::ObjectPath("/com/canonical/Unity/Screen")); |
2819 | |
2820 | - observer = android_media_recorder_observer_new(); |
2821 | - android_media_recorder_observer_set_cb(observer, &Private::media_recording_started_callback, this); |
2822 | + recorder_observer = media::make_platform_default_recorder_observer(); |
2823 | + recorder_observer->recording_state().changed().connect([this](media::RecordingState state) |
2824 | + { |
2825 | + media_recording_state_changed(state); |
2826 | + }); |
2827 | } |
2828 | |
2829 | ~Private() |
2830 | @@ -165,12 +168,12 @@ |
2831 | pulse_worker.join(); |
2832 | } |
2833 | |
2834 | - void media_recording_started(bool started) |
2835 | + void media_recording_state_changed(media::RecordingState state) |
2836 | { |
2837 | if (uscreen_session == nullptr) |
2838 | return; |
2839 | |
2840 | - if (started) |
2841 | + if (state == media::RecordingState::started) |
2842 | { |
2843 | if (disp_cookie > 0) |
2844 | return; |
2845 | @@ -180,7 +183,7 @@ |
2846 | throw std::runtime_error(result.error().print()); |
2847 | disp_cookie = result.value(); |
2848 | } |
2849 | - else |
2850 | + else if (state == media::RecordingState::stopped) |
2851 | { |
2852 | if (disp_cookie != -1) |
2853 | { |
2854 | @@ -192,15 +195,6 @@ |
2855 | } |
2856 | } |
2857 | |
2858 | - static void media_recording_started_callback(bool started, void *context) |
2859 | - { |
2860 | - if (context == nullptr) |
2861 | - return; |
2862 | - |
2863 | - auto p = static_cast<Private*>(context); |
2864 | - p->media_recording_started(started); |
2865 | - } |
2866 | - |
2867 | pa_threaded_mainloop *mainloop() |
2868 | { |
2869 | return pulse_mainloop; |
2870 | @@ -456,8 +450,7 @@ |
2871 | std::shared_ptr<core::dbus::Property<core::IndicatorPower::IsWarning>> is_warning; |
2872 | int disp_cookie; |
2873 | std::shared_ptr<dbus::Object> uscreen_session; |
2874 | - MediaRecorderObserver *observer; |
2875 | - |
2876 | + media::RecorderObserver::Ptr recorder_observer; |
2877 | // Pulse-specific |
2878 | pa_mainloop_api *pulse_mainloop_api; |
2879 | pa_threaded_mainloop *pulse_mainloop; |
2880 | |
2881 | === added directory 'src/core/media/video' |
2882 | === added file 'src/core/media/video/hybris_gl_sink.cpp' |
2883 | --- src/core/media/video/hybris_gl_sink.cpp 1970-01-01 00:00:00 +0000 |
2884 | +++ src/core/media/video/hybris_gl_sink.cpp 2014-11-25 10:52:42 +0000 |
2885 | @@ -0,0 +1,116 @@ |
2886 | +/* |
2887 | + * Copyright © 2014 Canonical Ltd. |
2888 | + * |
2889 | + * This program is free software: you can redistribute it and/or modify it |
2890 | + * under the terms of the GNU Lesser General Public License version 3, |
2891 | + * as published by the Free Software Foundation. |
2892 | + * |
2893 | + * This program is distributed in the hope that it will be useful, |
2894 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2895 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2896 | + * GNU Lesser General Public License for more details. |
2897 | + * |
2898 | + * You should have received a copy of the GNU Lesser General Public License |
2899 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2900 | + * |
2901 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
2902 | + */ |
2903 | + |
2904 | +#include <core/media/video/hybris_gl_sink.h> |
2905 | + |
2906 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
2907 | +// Hybris |
2908 | +#include <hybris/media/media_codec_layer.h> |
2909 | +#include <hybris/media/surface_texture_client_hybris.h> |
2910 | + |
2911 | +namespace media = core::ubuntu::media; |
2912 | +namespace video = core::ubuntu::media::video; |
2913 | + |
2914 | +struct video::HybrisGlSink::Private |
2915 | +{ |
2916 | + static void on_frame_available_callback(GLConsumerWrapperHybris, void* context) |
2917 | + { |
2918 | + if (not context) |
2919 | + return; |
2920 | + |
2921 | + auto thiz = static_cast<Private*>(context); |
2922 | + |
2923 | + thiz->frame_available(); |
2924 | + } |
2925 | + |
2926 | + Private(std::uint32_t gl_texture, const media::Player::PlayerKey& player_key) |
2927 | + : gl_texture{gl_texture}, |
2928 | + player_key{player_key}, |
2929 | + decoding_service_session{decoding_service_create_session(player_key)}, |
2930 | + graphics_buffer_consumer{decoding_service_get_igraphicbufferconsumer()}, |
2931 | + gl_texture_consumer{gl_consumer_create_by_id_with_igbc(gl_texture, graphics_buffer_consumer)} |
2932 | + { |
2933 | + if (not decoding_service_session) throw std::runtime_error |
2934 | + { |
2935 | + "video::HybrisGlSink: Could not connect to the remote decoding service and establish a session." |
2936 | + }; |
2937 | + |
2938 | + if (not graphics_buffer_consumer) throw std::runtime_error |
2939 | + { |
2940 | + "video::HybrisGlSink: Could not connect to remote buffer queue." |
2941 | + }; |
2942 | + |
2943 | + if (not gl_texture_consumer) throw std::runtime_error |
2944 | + { |
2945 | + "video::HybrisGlSink: Could not associate local texture id with remote buffer streak." |
2946 | + }; |
2947 | + |
2948 | + gl_consumer_set_frame_available_cb(gl_texture_consumer, Private::on_frame_available_callback, this); |
2949 | + } |
2950 | + |
2951 | + ~Private() |
2952 | + { |
2953 | + gl_consumer_set_frame_available_cb(gl_texture_consumer, Private::on_frame_available_callback, nullptr); |
2954 | + } |
2955 | + |
2956 | + std::uint32_t gl_texture; |
2957 | + media::Player::PlayerKey player_key; |
2958 | + core::Signal<void> frame_available; |
2959 | + DSSessionWrapperHybris decoding_service_session; |
2960 | + IGBCWrapperHybris graphics_buffer_consumer; |
2961 | + GLConsumerWrapperHybris gl_texture_consumer; |
2962 | +}; |
2963 | + |
2964 | +// Creates a new instance for the given gl texture or throws |
2965 | +// in case of issues. |
2966 | +video::HybrisGlSink::HybrisGlSink(std::uint32_t gl_texture, const media::Player::PlayerKey& key) : d{new Private{gl_texture, key}} |
2967 | +{ |
2968 | +} |
2969 | + |
2970 | +video::HybrisGlSink::~HybrisGlSink() |
2971 | +{ |
2972 | +} |
2973 | + |
2974 | +// The signal is emitted whenever a new frame is available and a subsequent |
2975 | +// call to swap_buffers will not block and return true. |
2976 | +const core::Signal<void>& video::HybrisGlSink::frame_available() const |
2977 | +{ |
2978 | + return d->frame_available; |
2979 | +} |
2980 | + |
2981 | +// Queries the transformation matrix for the current frame, placing the data into 'matrix' |
2982 | +// and returns true or returns false and leaves 'matrix' unchanged in case |
2983 | +// of issues. |
2984 | +bool video::HybrisGlSink::transformation_matrix(video::MatrixView<4,4>& matrix) const |
2985 | +{ |
2986 | + // TODO: The underlying API really should tell us if everything is ok. |
2987 | + gl_consumer_get_transformation_matrix(d->gl_texture_consumer, matrix.to_float()); |
2988 | + return true; |
2989 | +} |
2990 | + |
2991 | +// Releases the current buffer, and consumes the next buffer in the queue, |
2992 | +// making it available for consumption by consumers of this API in an |
2993 | +// implementation-specific way. Clients will usually rely on a GL texture |
2994 | +// to receive the latest buffer. |
2995 | +bool video::HybrisGlSink::swap_buffers() const |
2996 | +{ |
2997 | + // TODO: The underlying API really should tell us if everything is ok. |
2998 | + gl_consumer_update_texture(d->gl_texture_consumer); |
2999 | + return true; |
3000 | +} |
3001 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
3002 | |
3003 | === added file 'src/core/media/video/hybris_gl_sink.h' |
3004 | --- src/core/media/video/hybris_gl_sink.h 1970-01-01 00:00:00 +0000 |
3005 | +++ src/core/media/video/hybris_gl_sink.h 2014-11-25 10:52:42 +0000 |
3006 | @@ -0,0 +1,67 @@ |
3007 | +/* |
3008 | + * Copyright © 2014 Canonical Ltd. |
3009 | + * |
3010 | + * This program is free software: you can redistribute it and/or modify it |
3011 | + * under the terms of the GNU Lesser General Public License version 3, |
3012 | + * as published by the Free Software Foundation. |
3013 | + * |
3014 | + * This program is distributed in the hope that it will be useful, |
3015 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3016 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3017 | + * GNU Lesser General Public License for more details. |
3018 | + * |
3019 | + * You should have received a copy of the GNU Lesser General Public License |
3020 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3021 | + * |
3022 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
3023 | + */ |
3024 | +#ifndef CORE_UBUNTU_MEDIA_VIDEO_HYBRIS_GL_SINK_H_ |
3025 | +#define CORE_UBUNTU_MEDIA_VIDEO_HYBRIS_GL_SINK_H_ |
3026 | + |
3027 | +#include <core/media/video/sink.h> |
3028 | + |
3029 | +#include <core/media/player.h> |
3030 | + |
3031 | +namespace core |
3032 | +{ |
3033 | +namespace ubuntu |
3034 | +{ |
3035 | +namespace media |
3036 | +{ |
3037 | +namespace video |
3038 | +{ |
3039 | +class HybrisGlSink : public video::Sink |
3040 | +{ |
3041 | +public: |
3042 | + // Creates a new instance for the given gl texture, connecting to the remote part known |
3043 | + // under the given key or throw in case of issues. |
3044 | + HybrisGlSink(std::uint32_t gl_texture, const media::Player::PlayerKey& key); |
3045 | + |
3046 | + // Need this to avoid std::unique_ptr complaining about forward-declared Private. |
3047 | + ~HybrisGlSink(); |
3048 | + |
3049 | + // The signal is emitted whenever a new frame is available and a subsequent |
3050 | + // call to swap_buffers will not block and return true. |
3051 | + const core::Signal<void>& frame_available() const override; |
3052 | + |
3053 | + // Queries the transformation matrix for the current frame, placing the data into 'matrix' |
3054 | + // and returns true or returns false and leaves 'matrix' unchanged in case |
3055 | + // of issues. |
3056 | + bool transformation_matrix(MatrixView<4,4>& matrix) const override; |
3057 | + |
3058 | + // Releases the current buffer, and consumes the next buffer in the queue, |
3059 | + // making it available for consumption by consumers of this API in an |
3060 | + // implementation-specific way. Clients will usually rely on a GL texture |
3061 | + // to receive the latest buffer. |
3062 | + bool swap_buffers() const override; |
3063 | + |
3064 | +private: |
3065 | + struct Private; |
3066 | + std::unique_ptr<Private> d; |
3067 | +}; |
3068 | +} |
3069 | +} |
3070 | +} |
3071 | +} |
3072 | + |
3073 | +#endif // CORE_UBUNTU_MEDIA_VIDEO_HYBRIS_GL_SINK_H_ |
3074 | |
3075 | === added file 'src/core/media/video/platform_default_sink.cpp' |
3076 | --- src/core/media/video/platform_default_sink.cpp 1970-01-01 00:00:00 +0000 |
3077 | +++ src/core/media/video/platform_default_sink.cpp 2014-11-25 10:52:42 +0000 |
3078 | @@ -0,0 +1,67 @@ |
3079 | +/* |
3080 | + * Copyright © 2014 Canonical Ltd. |
3081 | + * |
3082 | + * This program is free software: you can redistribute it and/or modify it |
3083 | + * under the terms of the GNU Lesser General Public License version 3, |
3084 | + * as published by the Free Software Foundation. |
3085 | + * |
3086 | + * This program is distributed in the hope that it will be useful, |
3087 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3088 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3089 | + * GNU Lesser General Public License for more details. |
3090 | + * |
3091 | + * You should have received a copy of the GNU Lesser General Public License |
3092 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3093 | + * |
3094 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
3095 | + */ |
3096 | + |
3097 | +#include <core/media/video/platform_default_sink.h> |
3098 | + |
3099 | +namespace media = core::ubuntu::media; |
3100 | +namespace video = core::ubuntu::media::video; |
3101 | + |
3102 | +namespace |
3103 | +{ |
3104 | +struct NullSink : public video::Sink |
3105 | +{ |
3106 | + // The signal is emitted whenever a new frame is available and a subsequent |
3107 | + // call to swap_buffers will not block and return true. |
3108 | + const core::Signal<void>& frame_available() const; |
3109 | + |
3110 | + // Queries the transformation matrix for the current frame, placing the data into 'matrix' |
3111 | + // and returns true or returns false and leaves 'matrix' unchanged in case |
3112 | + // of issues. |
3113 | + bool transformation_matrix(video::MatrixView<4,4>& matrix) const |
3114 | + { |
3115 | + for (unsigned int i = 0; i < matrix.height(); i++) |
3116 | + for (unsigned int j = 0; j < matrix.width(); j++) |
3117 | + matrix(i, j) = i == j ? 1.f : 0.f; |
3118 | + |
3119 | + return true; |
3120 | + } |
3121 | + |
3122 | + // Releases the current buffer, and consumes the next buffer in the queue, |
3123 | + // making it available for consumption by consumers of this API in an |
3124 | + // implementation-specific way. Clients will usually rely on a GL texture |
3125 | + // to receive the latest buffer. |
3126 | + bool swap_buffers() const |
3127 | + { |
3128 | + return true; |
3129 | + } |
3130 | +}; |
3131 | +} |
3132 | + |
3133 | +#if defined(MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER) |
3134 | +#include <core/media/video/hybris_gl_sink.h> |
3135 | + |
3136 | +video::Sink::Ptr video::make_platform_default_sink(std::uint32_t gl_texture, const media::Player::PlayerKey& key) |
3137 | +{ |
3138 | + return std::make_shared<video::HybrisGlSink>(gl_texture, key); |
3139 | +} |
3140 | +#else // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
3141 | +video::Sink::Ptr video::make_platform_default_sink(std::uint32_t, const media::Player::PlayerKey&) |
3142 | +{ |
3143 | + return std::make_shared<NullSink>(); |
3144 | +} |
3145 | +#endif // MEDIA_HUB_HAVE_HYBRIS_MEDIA_COMPAT_LAYER |
3146 | |
3147 | === added file 'src/core/media/video/platform_default_sink.h' |
3148 | --- src/core/media/video/platform_default_sink.h 1970-01-01 00:00:00 +0000 |
3149 | +++ src/core/media/video/platform_default_sink.h 2014-11-25 10:52:42 +0000 |
3150 | @@ -0,0 +1,41 @@ |
3151 | +/* |
3152 | + * Copyright © 2014 Canonical Ltd. |
3153 | + * |
3154 | + * This program is free software: you can redistribute it and/or modify it |
3155 | + * under the terms of the GNU Lesser General Public License version 3, |
3156 | + * as published by the Free Software Foundation. |
3157 | + * |
3158 | + * This program is distributed in the hope that it will be useful, |
3159 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3160 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3161 | + * GNU Lesser General Public License for more details. |
3162 | + * |
3163 | + * You should have received a copy of the GNU Lesser General Public License |
3164 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3165 | + * |
3166 | + * Authored by: Thomas Voß <thomas.voss@canonical.com> |
3167 | + */ |
3168 | +#ifndef CORE_UBUNTU_MEDIA_VIDEO_PLATFORM_DEFAULT_SINK_H_ |
3169 | +#define CORE_UBUNTU_MEDIA_VIDEO_PLATFORM_DEFAULT_SINK_H_ |
3170 | + |
3171 | +#include <core/media/video/sink.h> |
3172 | + |
3173 | +#include <core/media/player.h> |
3174 | + |
3175 | +namespace core |
3176 | +{ |
3177 | +namespace ubuntu |
3178 | +{ |
3179 | +namespace media |
3180 | +{ |
3181 | +namespace video |
3182 | +{ |
3183 | +// Returns the platform default video sink for the given parameters. Never returns null, but |
3184 | +// throws in case of issues. |
3185 | +Sink::Ptr make_platform_default_sink(std::uint32_t gl_texture, const Player::PlayerKey& key); |
3186 | +} |
3187 | +} |
3188 | +} |
3189 | +} |
3190 | + |
3191 | +#endif // CORE_UBUNTU_MEDIA_VIDEO_PLATFORM_DEFAULT_SINK_H_ |
3192 | |
3193 | === modified file 'tests/unit-tests/CMakeLists.txt' |
3194 | --- tests/unit-tests/CMakeLists.txt 2014-11-12 19:10:24 +0000 |
3195 | +++ tests/unit-tests/CMakeLists.txt 2014-11-25 10:52:42 +0000 |
3196 | @@ -7,12 +7,16 @@ |
3197 | add_executable( |
3198 | test-gstreamer-engine |
3199 | |
3200 | - libmedia-mock.cpp |
3201 | + ${CMAKE_SOURCE_DIR}/src/core/media/client_death_observer.cpp |
3202 | + ${CMAKE_SOURCE_DIR}/src/core/media/hybris_client_death_observer.cpp |
3203 | ${CMAKE_SOURCE_DIR}/src/core/media/cover_art_resolver.cpp |
3204 | ${CMAKE_SOURCE_DIR}/src/core/media/engine.cpp |
3205 | ${CMAKE_SOURCE_DIR}/src/core/media/gstreamer/engine.cpp |
3206 | + ${CMAKE_SOURCE_DIR}/src/core/media/gstreamer/playbin.cpp |
3207 | ${CMAKE_SOURCE_DIR}/src/core/media/player_skeleton.cpp |
3208 | ${CMAKE_SOURCE_DIR}/src/core/media/player_implementation.cpp |
3209 | + ${CMAKE_SOURCE_DIR}/src/core/media/recorder_observer.cpp |
3210 | + ${CMAKE_SOURCE_DIR}/src/core/media/hybris_recorder_observer.cpp |
3211 | ${CMAKE_SOURCE_DIR}/src/core/media/service_skeleton.cpp |
3212 | ${CMAKE_SOURCE_DIR}/src/core/media/service_implementation.cpp |
3213 | ${CMAKE_SOURCE_DIR}/src/core/media/track_list_skeleton.cpp |
3214 | |
3215 | === removed file 'tests/unit-tests/libmedia-mock.cpp' |
3216 | --- tests/unit-tests/libmedia-mock.cpp 2014-11-03 18:00:48 +0000 |
3217 | +++ tests/unit-tests/libmedia-mock.cpp 1970-01-01 00:00:00 +0000 |
3218 | @@ -1,26 +0,0 @@ |
3219 | -/* |
3220 | - * Copyright © 2013-2014 Canonical Ltd. |
3221 | - * |
3222 | - * This program is free software: you can redistribute it and/or modify it |
3223 | - * under the terms of the GNU Lesser General Public License version 3, |
3224 | - * as published by the Free Software Foundation. |
3225 | - * |
3226 | - * This program is distributed in the hope that it will be useful, |
3227 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3228 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3229 | - * GNU Lesser General Public License for more details. |
3230 | - * |
3231 | - * You should have received a copy of the GNU Lesser General Public License |
3232 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3233 | - * |
3234 | - * Authored by: Jim Hodapp <jim.hodapp@canonical.com> |
3235 | - */ |
3236 | - |
3237 | -#include <hybris/media/media_codec_layer.h> |
3238 | -#include <hybris/media/surface_texture_client_hybris.h> |
3239 | - |
3240 | -#define UNUSED __attribute__((unused)) |
3241 | - |
3242 | -void decoding_service_set_client_death_cb(UNUSED DecodingClientDeathCbHybris callback, UNUSED uint32_t handle, UNUSED void *context) |
3243 | -{ |
3244 | -} |
Looking good so far. I'd like to see unit tests for HybrisGlSink and a lot of the functionality surrounding it. See my comments inline below.