Merge lp:~thomas-voss/media-hub/refactor-video-sink-interface-to-not-rely-on-hybris-types into lp:media-hub

Proposed by Thomas Voß
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
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.

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

Revision history for this message
Jim Hodapp (jhodapp) wrote :

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.

review: Needs Fixing (code)
Revision history for this message
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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+ &current,
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- &current,
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-}

Subscribers

People subscribed via source and target branches