[rygel/wip/gst-1.0: 2/2] WIP
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rygel/wip/gst-1.0: 2/2] WIP
- Date: Mon, 5 Nov 2012 10:11:06 +0000 (UTC)
commit dd3a25ea52ab4ac6aae6d3edb59afabb5f3e6249
Author: Jens Georg <jensg openismus com>
Date: Sat Nov 3 20:23:45 2012 +0100
WIP
autogen.sh | 2 +-
configure.ac | 47 +++--
src/media-engines/Makefile.am | 4 +
src/media-engines/gstreamer-1.0/Makefile.am | 45 ++++
.../gstreamer-1.0/rygel-aac-transcoder.vala | 35 +++
.../gstreamer-1.0/rygel-audio-transcoder.vala | 119 +++++++++
.../gstreamer-1.0/rygel-avc-transcoder.vala | 67 +++++
.../gstreamer-1.0/rygel-gst-data-source.vala | 262 ++++++++++++++++++++
.../gstreamer-1.0/rygel-gst-media-engine.vala | 118 +++++++++
.../gstreamer-1.0/rygel-gst-sink.vala | 150 +++++++++++
.../gstreamer-1.0/rygel-gst-transcoder.vala | 166 +++++++++++++
.../gstreamer-1.0/rygel-gst-utils.vala | 117 +++++++++
.../gstreamer-1.0/rygel-l16-transcoder.vala | 97 +++++++
.../gstreamer-1.0/rygel-mp2ts-transcoder.vala | 112 +++++++++
.../gstreamer-1.0/rygel-mp3-transcoder.vala | 42 +++
.../gstreamer-1.0/rygel-video-transcoder.vala | 108 ++++++++
.../gstreamer-1.0/rygel-wmv-transcoder.vala | 39 +++
17 files changed, 1512 insertions(+), 18 deletions(-)
---
diff --git a/autogen.sh b/autogen.sh
index a2348ce..815f5df 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -40,4 +40,4 @@ bash gnome-autogen.sh --enable-vala --enable-valadoc --enable-maintainer-mode --
--enable-tests --enable-test-plugin \
--enable-example-plugins \
--enable-mediathek-plugin --enable-gst-launch-plugin \
- --enable-strict-valac "$@"
+ --enble-strict-valac "$@"
diff --git a/configure.ac b/configure.ac
index 2566073..5e917ef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -29,7 +29,7 @@ LT_INIT([dlopen disable-static])
dnl Required versions of library packages
GLIB_REQUIRED=2.31.13
-VALA_REQUIRED=0.16.1
+VALA_REQUIRED=0.18.0
VALADOC_REQUIRED=0.2
GSSDP_REQUIRED=0.13.0
GUPNP_REQUIRED=0.19.0
@@ -72,12 +72,12 @@ AC_ARG_ENABLE([media_engine_gst_0.10],
[enable_media_engine_gst_0_10="$enableval"],
[enable_media_engine_gst_0_10="yes"])
-dnl AC_ARG_ENABLE([media_engine_gst_1.0],
-dnl AS_HELP_STRING(
-dnl [--enable-media-engine-gst-1.0],
-dnl [Compile with GStreamer 1.0 media engine]),
-dnl [enable_media_engine_gst_1_0="$enableval"],
-dnl [enable_media_engine_gst_1_0="yes"])
+AC_ARG_ENABLE([media_engine_gst_1.0],
+ AS_HELP_STRING(
+ [--enable-media-engine-gst-1.0],
+ [Compile with GStreamer 1.0 media engine]),
+ [enable_media_engine_gst_1_0="$enableval"],
+ [enable_media_engine_gst_1_0="yes"])
AC_ARG_ENABLE([media_engine_simple],
AS_HELP_STRING(
@@ -86,13 +86,6 @@ AC_ARG_ENABLE([media_engine_simple],
[enable_media_engine_simple="$enableval"],
[enable_media_engine_simple="yes"])
-dnl AC_ARG_WITH([media_engine],
-dnl AS_HELP_STRING(
-dnl [--with-media-engine=@<:@gstreamer|none@:>@],
-dnl [Media Engine to use]),
-dnl [with_media_engine="$withval"],
-dnl [with_media_engine="gstreamer"])
-
AS_IF([test "x$enable_media_engine_gst_0_10" = "xyes"],
[
PKG_CHECK_MODULES(LIBGUPNP_DLNA, gupnp-dlna-1.0 >= $GUPNP_DLNA_REQUIRED)
@@ -101,9 +94,24 @@ AS_IF([test "x$enable_media_engine_gst_0_10" = "xyes"],
PKG_CHECK_MODULES(GST_PBU, gstreamer-pbutils-0.10 >= $GSTPBU_REQUIRED)
enable_gstreamer="yes"
BUILT_ENGINES="$BUILT_ENGINES;librygel-media-engine-gst"
+ RYGEL_ADD_STAMP([src/media-engines/gstreamer/librygel_media_engine_gst_la_vala.stamp])
],
[enable_gstreamer="no"])
AM_CONDITIONAL([HAVE_GSTREAMER],[test "x$enable_gstreamer" = "xyes"])
+
+AS_IF([test "x$enable_media_engine_gst_1_0" = "xyes"],
+ [
+ PKG_CHECK_MODULES(LIBGUPNP_DLNA_1_1, gupnp-dlna-1.1 >= $GUPNP_DLNA_REQUIRED)
+ PKG_CHECK_MODULES(LIBGSTREAMER_1_0, gstreamer-1.0 >= $GSTREAMER_REQUIRED)
+ PKG_CHECK_MODULES(GSTREAMER_BASE_1_0, gstreamer-base-1.0 >= $GSTREAMER_REQUIRED)
+ PKG_CHECK_MODULES(GST_PBU_1_0, gstreamer-pbutils-1.0 >= $GSTPBU_REQUIRED)
+ enable_gstreamer_1_0="yes"
+ BUILT_ENGINES="$BUILT_ENGINES;librygel-media-engine-gst-1.0"
+ RYGEL_ADD_STAMP([src/media-engines/gstreamer/librygel_media_engine_gst_1_0_la_vala.stamp])
+ ],
+ [enable_gstreamer_1_0="no"])
+AM_CONDITIONAL([HAVE_GSTREAMER_1_0],[test "x$enable_gstreamer_1_0" = "xyes"])
+
AC_SUBST([BUILT_ENGINES])
dnl Add plugins
@@ -117,7 +125,6 @@ AS_IF([test "x$enable_gstreamer" = "xyes"],
RYGEL_ADD_PLUGIN([playbin],[GStreamer playbin],[yes])
RYGEL_ADD_PLUGIN([media-export],[MediaExport],[yes])
RYGEL_ADD_PLUGIN([gst-launch],[GStreamer launchline],[no])
- RYGEL_ADD_STAMP([src/media-engines/gstreamer/librygel_media_engine_gst_la_vala.stamp])
RYGEL_ADD_STAMP([src/librygel-renderer-gst/librygel_renderer_gst_2_0_la_vala.stamp])
],
[
@@ -125,8 +132,8 @@ AS_IF([test "x$enable_gstreamer" = "xyes"],
RYGEL_DISABLE_PLUGIN([media-export])
RYGEL_DISABLE_PLUGIN([gst-launch])
])
-
-dnl Example plugins:
+
+dnl Example plugins:
AC_ARG_ENABLE([example-plugins],
AS_HELP_STRING([--enable-example-plugins],[enable example plugins]),,
enable_example_plugins=no)
@@ -152,6 +159,11 @@ AS_IF([test "x$enable_gstreamer" = "xyes"],
RYGEL_CHECK_PACKAGES([gupnp-dlna-1.0 gstreamer-0.10 gstreamer-pbutils-0.10])
])
+AS_IF([test "x$enable_gstreamer_1_0" = "xyes"],
+ [
+ RYGEL_CHECK_PACKAGES([gupnp-dlna-1.1 gstreamer-1.0 gstreamer-pbutils-1.0])
+ ])
+
dnl Debugging
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],[enable debugging]),,
@@ -303,6 +315,7 @@ src/rygel/Makefile
src/ui/Makefile
src/media-engines/Makefile
src/media-engines/gstreamer/Makefile
+src/media-engines/gstreamer-1.0/Makefile
src/media-engines/simple/Makefile
src/plugins/Makefile
data/Makefile
diff --git a/src/media-engines/Makefile.am b/src/media-engines/Makefile.am
index ed2f101..7bd9979 100644
--- a/src/media-engines/Makefile.am
+++ b/src/media-engines/Makefile.am
@@ -3,3 +3,7 @@ SUBDIRS=simple
if HAVE_GSTREAMER
SUBDIRS += gstreamer
endif
+
+if HAVE_GSTREAMER_1_0
+SUBDIRS += gstreamer-1.0
+endif
diff --git a/src/media-engines/gstreamer-1.0/Makefile.am b/src/media-engines/gstreamer-1.0/Makefile.am
new file mode 100644
index 0000000..269372a
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/Makefile.am
@@ -0,0 +1,45 @@
+include $(top_srcdir)/common.am
+
+engine_LTLIBRARIES = librygel-media-engine-gst-1.0.la
+
+AM_CFLAGS += -DG_LOG_DOMAIN='"MediaEngine-GStreamer-1.0"' \
+ $(GST_PBU_1_0_CFLAGS) \
+ $(LIBGUPNP_DLNA_1_1_CFLAGS)
+
+librygel_media_engine_gst_1_0_la_SOURCES = \
+ rygel-aac-transcoder.vala \
+ rygel-audio-transcoder.vala \
+ rygel-avc-transcoder.vala \
+ rygel-gst-data-source.vala \
+ rygel-gst-media-engine.vala \
+ rygel-gst-sink.vala \
+ rygel-gst-transcoder.vala \
+ rygel-gst-utils.vala \
+ rygel-l16-transcoder.vala \
+ rygel-mp2ts-transcoder.vala \
+ rygel-mp3-transcoder.vala \
+ rygel-video-transcoder.vala \
+ rygel-wmv-transcoder.vala
+
+librygel_media_engine_gst_1_0_la_VALAFLAGS = \
+ --enable-experimental \
+ --pkg gstreamer-base-1.0 \
+ --pkg gstreamer-pbutils-1.0 \
+ --pkg gupnp-dlna-1.1 \
+ --library rygel-media-engine-gst \
+ --use-header \
+ --header=rygel-media-engine-gst.h \
+ $(RYGEL_COMMON_SERVER_PLUGIN_VALAFLAGS)
+
+rygel-media-engine-gst.h rygel-media-engine-gstreamer.vapi: librygel_media_engine_gst_1_0_la_vala.stamp
+
+librygel_media_engine_gst_1_0_la_LIBADD = \
+ $(GST_PBU_1_0_LIBS) \
+ $(LIBGUPNP_DLNA_1_1_LIBS) \
+ $(RYGEL_COMMON_SERVER_LIBS)
+
+librygel_media_engine_gst_1_0_la_LDFLAGS = $(RYGEL_PLUGIN_LINKER_FLAGS)
+
+EXTRA_DIST = \
+ rygel-media-engine-gst.vapi \
+ rygel-media-engine-gst.h
diff --git a/src/media-engines/gstreamer-1.0/rygel-aac-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-aac-transcoder.vala
new file mode 100644
index 0000000..c92df8a
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-aac-transcoder.vala
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation.
+ *
+ * Author: Luis de Bethencourt <luis debethencourt collabora com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/**
+ * Transcoder for 3GP stream containing MPEG4 audio (AAC).
+ */
+internal class Rygel.AACTranscoder : Rygel.AudioTranscoder {
+ private const int BITRATE = 256;
+ private const string CODEC = "audio/mpeg,mpegversion=4," +
+ "stream-format=adts,rate=44100,base-profile=lc";
+
+ public AACTranscoder () {
+ base ("audio/vnd.dlna.adts", "AAC_ADTS_320", BITRATE, null, CODEC, "adts");
+ this.preset = "Rygel AAC_ADTS_320 preset";
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-audio-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-audio-transcoder.vala
new file mode 100644
index 0000000..76a503c
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-audio-transcoder.vala
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Author: Jens Georg <jensg openismus com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+using Gst;
+using Gst.PbUtils;
+using GUPnP;
+
+/**
+ * Base class for all transcoders that handle audio.
+ */
+internal class Rygel.AudioTranscoder : Rygel.GstTranscoder {
+ protected int audio_bitrate;
+ protected Caps container_format = null;
+ protected Caps audio_codec_format = null;
+
+ public const string NO_CONTAINER = null;
+
+ public AudioTranscoder (string content_type,
+ string dlna_profile,
+ int audio_bitrate,
+ string? container_caps,
+ string audio_codec_caps,
+ string extension) {
+ base (content_type, dlna_profile, AudioItem.UPNP_CLASS, extension);
+
+ this.audio_bitrate = audio_bitrate;
+ if (container_caps != null) {
+ this.container_format = Caps.from_string (container_caps);
+ }
+
+ this.audio_codec_format = Caps.from_string (audio_codec_caps);
+ }
+
+ public AudioTranscoder.with_class (string content_type,
+ string dlna_profile,
+ string upnp_class,
+ int audio_bitrate,
+ string? container_caps,
+ string audio_codec_caps,
+ string extension) {
+ base (content_type, dlna_profile, upnp_class, extension);
+
+ this.audio_bitrate = audio_bitrate;
+ if (container_caps != null) {
+ this.container_format = Caps.from_string (container_caps);
+ }
+
+ this.audio_codec_format = Caps.from_string (audio_codec_caps);
+ }
+
+
+ public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item,
+ MediaItem item,
+ TranscodeManager manager)
+ throws Error {
+ var resource = base.add_resource (didl_item, item, manager);
+ if (resource == null) {
+ return null;
+ }
+
+ resource.bitrate = (this.audio_bitrate * 1000) / 8;
+
+ return resource;
+ }
+
+ public override uint get_distance (MediaItem item) {
+ if (!(item is AudioItem) || item is VideoItem) {
+ return uint.MAX;
+ }
+
+ var audio_item = item as AudioItem;
+ var distance = uint.MIN;
+
+ if (audio_item.bitrate > 0) {
+ distance += (audio_item.bitrate - this.audio_bitrate).abs ();
+ }
+
+ return distance;
+ }
+
+ protected override EncodingProfile get_encoding_profile () {
+ var enc_audio_profile = new EncodingAudioProfile (audio_codec_format,
+ this.preset,
+ null,
+ 1);
+ enc_audio_profile.set_name ("audio");
+
+ if (this.container_format != null) {
+ var enc_container_profile = new EncodingContainerProfile ("container",
+ null,
+ container_format,
+ this.preset);
+ enc_container_profile.add_profile (enc_audio_profile);
+
+ return enc_container_profile;
+ }
+
+ return enc_audio_profile;
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-avc-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-avc-transcoder.vala
new file mode 100644
index 0000000..3e48efc
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-avc-transcoder.vala
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation.
+ *
+ * Author: Luis de Bethencourt <luis debethencourt collabora com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+using Gst;
+using GUPnP;
+
+/**
+ * Transcoder for H.264 in MP4 conforming to DLNA profile
+ * AVC_MP4_BL_CIF15_AAC_520 (15 fps, CIF resolution)
+ */
+internal class Rygel.AVCTranscoder : Rygel.VideoTranscoder {
+ private const int VIDEO_BITRATE = 1200;
+ private const int AUDIO_BITRATE = 64;
+ private const string CONTAINER = "video/quicktime,variant=iso";
+ private const string AUDIO_CAPS = "audio/mpeg,mpegversion=4";
+ private const string VIDEO_CAPS =
+ "video/x-h264,stream-format=avc";
+
+ private const string RESTRICTIONS =
+ "framerate=(fraction)15/1,width=352,height=288";
+
+ public AVCTranscoder () {
+ base ("video/mp4",
+ "AVC_MP4_BL_CIF15_AAC_520",
+ AUDIO_BITRATE,
+ VIDEO_BITRATE,
+ CONTAINER,
+ AUDIO_CAPS,
+ VIDEO_CAPS,
+ "mp4",
+ RESTRICTIONS);
+ this.preset = "Rygel AVC_MP4_BL_CIF15_AAC_520 preset";
+ }
+
+ public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item,
+ MediaItem item,
+ TranscodeManager manager)
+ throws Error {
+ var resource = base.add_resource (didl_item, item, manager);
+ if (resource == null) {
+ return null;
+ }
+
+ resource.width = 352;
+ resource.height = 288;
+
+ return resource;
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-gst-data-source.vala b/src/media-engines/gstreamer-1.0/rygel-gst-data-source.vala
new file mode 100644
index 0000000..1e536f6
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-gst-data-source.vala
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Author: Jens Georg <jensg openismus com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Gst;
+
+internal errordomain Rygel.GstDataSourceError {
+ NOT_COMPATIBLE
+}
+
+internal class Rygel.GstDataSource : Rygel.DataSource, GLib.Object {
+ internal dynamic Element src;
+ private Pipeline pipeline;
+ private HTTPSeek seek = null;
+ private GstSink sink;
+ private uint bus_watch_id;
+
+ public GstDataSource (string uri) throws Error {
+ this.src = GstUtils.create_source_for_uri (uri);
+ if (this.src == null) {
+ var msg = _("Could not create GstElement for URI %s");
+
+ throw new GstDataSourceError.NOT_COMPATIBLE (msg, uri);
+ }
+ }
+
+ ~GstDataSource () {
+ if (this.sink != null) {
+ this.sink.cancellable.cancel ();
+ }
+
+ if (this.pipeline != null) {
+ this.pipeline.set_state (State.NULL);
+ }
+ }
+
+ public GstDataSource.from_element (Element element) {
+ this.src = element;
+ }
+
+ public void start (HTTPSeek? offsets) throws Error {
+ this.seek = offsets;
+ this.prepare_pipeline ("RygelGstDataSource", this.src);
+ if (this.seek != null) {
+ this.pipeline.set_state (State.PAUSED);
+ } else {
+ this.pipeline.set_state (State.PLAYING);
+ }
+ }
+
+ public void freeze () {
+ this.sink.freeze ();
+ }
+
+ public void thaw () {
+ this.sink.thaw ();
+ }
+
+ public void stop () {
+ // Unlock eventually frozen sink
+ this.sink.cancellable.cancel ();
+ this.pipeline.set_state (State.NULL);
+ Source.remove (this.bus_watch_id);
+ Idle.add ( () => { this.done (); return false; });
+ }
+
+ private void prepare_pipeline (string name,
+ Element src) throws Error {
+ this.sink = new GstSink (this, this.seek);
+
+ this.pipeline = new Pipeline (name);
+ if (pipeline == null) {
+ throw new DataSourceError.GENERAL
+ (_("Failed to create pipeline"));
+ }
+
+ this.pipeline.add_many (src, sink);
+
+ if (src.numsrcpads == 0) {
+ // Seems source uses dynamic pads, link when pad available
+ src.pad_added.connect (this.src_pad_added);
+ } else {
+ // static pads? easy!
+ if (!src.link (sink)) {
+ throw new GstError.LINK (_("Failed to link %s to %s"),
+ src.name,
+ sink.name);
+ }
+ }
+
+ // Bus handler
+ var bus = this.pipeline.get_bus ();
+ this.bus_watch_id = bus.add_watch (Priority.DEFAULT, this.bus_handler);
+ }
+
+ private void src_pad_added (Element src, Pad src_pad) {
+ var caps = src_pad.query_caps (null);
+
+ var sink = this.pipeline.get_by_name (GstSink.NAME);
+ Pad sink_pad;
+
+ dynamic Element depay = GstUtils.get_rtp_depayloader (caps);
+ if (depay != null) {
+ this.pipeline.add (depay);
+ if (!depay.link (sink)) {
+ critical (_("Failed to link %s to %s"),
+ depay.name,
+ sink.name);
+ this.done ();
+
+ return;
+ }
+
+ sink_pad = depay.get_compatible_pad (src_pad, caps);
+ } else {
+ sink_pad = sink.get_compatible_pad (src_pad, caps);
+ }
+
+ if (src_pad.link (sink_pad) != PadLinkReturn.OK) {
+ critical (_("Failed to link pad %s to %s"),
+ src_pad.name,
+ sink_pad.name);
+ this.done ();
+
+ return;
+ }
+
+ if (depay != null) {
+ depay.sync_state_with_parent ();
+ }
+ }
+
+ private bool bus_handler (Gst.Bus bus, Gst.Message message) {
+ bool ret = true;
+
+ if (message.type == MessageType.EOS) {
+ ret = false;
+ } else if (message.type == MessageType.STATE_CHANGED) {
+ if (message.src != this.pipeline) {
+ return true;
+ }
+
+ State old_state;
+ State new_state;
+
+ message.parse_state_changed (out old_state,
+ out new_state,
+ null);
+
+ if (old_state == State.NULL && new_state == State.READY) {
+ dynamic Element element = this.pipeline.get_by_name ("muxer");
+ if (element != null) {
+ var name = element.get_factory ().get_name ();
+ // Awesome gross hack, really.
+ if (name == "mp4mux") {
+ element.streamable = true;
+ element.fragment_duration = 1000;
+ }
+ }
+ }
+
+ if (this.seek != null) {
+ if (old_state == State.READY && new_state == State.PAUSED) {
+ if (this.perform_seek ()) {
+ this.pipeline.set_state (State.PLAYING);
+ }
+ }
+ }
+ } else {
+ GLib.Error err;
+ string err_msg;
+
+ if (message.type == MessageType.ERROR) {
+ message.parse_error (out err, out err_msg);
+ critical (_("Error from pipeline %s: %s"),
+ this.pipeline.name,
+ err_msg);
+
+ ret = false;
+ } else if (message.type == MessageType.WARNING) {
+ message.parse_warning (out err, out err_msg);
+ warning (_("Warning from pipeline %s: %s"),
+ this.pipeline.name,
+ err_msg);
+ }
+ }
+
+ if (!ret) {
+ Idle.add_full (Priority.DEFAULT, () => {
+ this.done ();
+
+ return false;
+ });
+ }
+
+ return ret;
+ }
+
+ private bool perform_seek () {
+ if (this.seek != null &&
+ this.seek.length >= this.seek.total_length) {
+ return true;
+ }
+
+ var stop_type = Gst.SeekType.NONE;
+ Format format;
+ var flags = SeekFlags.FLUSH;
+ int64 start, stop;
+
+ if (this.seek.seek_type == HTTPSeekType.TIME) {
+ format = Format.TIME;
+ flags |= SeekFlags.KEY_UNIT;
+ start = (this.seek.start) * Gst.USECOND;
+ stop = (this.seek.stop) * Gst.USECOND;
+ } else {
+ format = Format.BYTES;
+ flags |= SeekFlags.ACCURATE;
+ start = this.seek.start;
+ stop = this.seek.stop;
+ }
+
+ if (this.seek.stop > 0) {
+ stop_type = Gst.SeekType.SET;
+ }
+
+ if (!this.pipeline.seek (1.0,
+ format,
+ flags,
+ Gst.SeekType.SET,
+ start,
+ stop_type,
+ stop + 1)) {
+ warning (_("Failed to seek to offsets %lld:%lld"),
+ this.seek.start,
+ this.seek.stop);
+
+ this.error (new DataSourceError.SEEK_FAILED (_("Failed to seek")));
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-gst-media-engine.vala b/src/media-engines/gstreamer-1.0/rygel-gst-media-engine.vala
new file mode 100644
index 0000000..867b9c2
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-gst-media-engine.vala
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Author: Jens Georg <jensg openismus com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Gst;
+using Gee;
+
+// Remove for GStreamer 1.0
+[CCode (cname = "PRESET_DIR")]
+internal extern static const string PRESET_DIR;
+
+[CCode (cname="gst_preset_set_app_dir")]
+extern bool gst_preset_set_app_dir (string app_dir);
+
+public class Rygel.GstMediaEngine : Rygel.MediaEngine {
+ private GLib.List<DLNAProfile> dlna_profiles = null;
+ private GLib.List<Transcoder> transcoders = null;
+
+ public GstMediaEngine () {
+ unowned string[] args = null;
+
+ Gst.init (ref args);
+ gst_preset_set_app_dir (PRESET_DIR);
+
+ var discoverer = new GUPnPDLNA.Discoverer ((ClockTime) SECOND,
+ true,
+ false);
+ foreach (var profile in discoverer.list_profiles ()) {
+ var p = new DLNAProfile (profile.name, profile.mime);
+ this.dlna_profiles.prepend (p);
+ }
+
+ this.dlna_profiles.reverse ();
+
+ var transcoding = true;
+ var transcoder_list = new ArrayList<string> ();
+
+ var config = MetaConfig.get_default ();
+ try {
+ transcoding = config.get_transcoding ();
+ transcoder_list = config.get_string_list ("MediaEngine",
+ "transcoders");
+ } catch (Error err) {}
+
+ if (transcoding) {
+ foreach (var transcoder in transcoder_list) {
+ switch (transcoder) {
+ case "lpcm":
+ this.transcoders.prepend (new L16Transcoder ());
+ break;
+ case "mp3":
+ this.transcoders.prepend (new MP3Transcoder ());
+ break;
+ case "mp2ts":
+ this.transcoders.prepend (new MP2TSTranscoder(MP2TSProfile.SD));
+ this.transcoders.prepend (new MP2TSTranscoder(MP2TSProfile.HD));
+ break;
+ case "wmv":
+ this.transcoders.prepend (new WMVTranscoder ());
+ break;
+ case "aac":
+ this.transcoders.prepend (new AACTranscoder ());
+ break;
+ case "avc":
+ this.transcoders.prepend (new AVCTranscoder ());
+ break;
+ default:
+ debug ("Unsupported transcoder \"%s\"", transcoder);
+ break;
+ }
+ }
+
+ this.transcoders.reverse ();
+ }
+ }
+
+ public override unowned GLib.List<DLNAProfile> get_dlna_profiles () {
+ return this.dlna_profiles;
+ }
+
+ public override unowned GLib.List<Transcoder>? get_transcoders () {
+ return this.transcoders;
+ }
+
+ public override DataSource? create_data_source (string uri) {
+ try {
+ return new GstDataSource (uri);
+ } catch (Error error) {
+ return null;
+ }
+ }
+
+ public DataSource create_data_source_from_element (Element element) {
+ return new GstDataSource.from_element (element);
+ }
+}
+
+public static Rygel.MediaEngine module_get_instance () {
+ return new Rygel.GstMediaEngine ();
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-gst-sink.vala b/src/media-engines/gstreamer-1.0/rygel-gst-sink.vala
new file mode 100644
index 0000000..67e582d
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-gst-sink.vala
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ * <zeeshan ali nokia com>
+ * Jens Georg <jensg openismus com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Gst;
+using Gst.Base;
+
+internal class Rygel.GstSink : Sink {
+ public const string NAME = "http-gst-sink";
+ public const string PAD_NAME = "sink";
+ // High and low threshold for number of buffered chunks
+ private const uint MAX_BUFFERED_CHUNKS = 32;
+ private const uint MIN_BUFFERED_CHUNKS = 4;
+
+ public Cancellable cancellable;
+
+ private int priority;
+
+ private int64 chunks_buffered;
+ private int64 bytes_sent;
+ private int64 max_bytes;
+
+ private Mutex buffer_mutex = Mutex ();
+ private Cond buffer_condition = Cond ();
+ private unowned DataSource source;
+ private HTTPSeek offsets;
+
+ private bool frozen;
+
+ static construct {
+ var caps = new Caps.any ();
+ var template = new PadTemplate (PAD_NAME,
+ PadDirection.SINK,
+ PadPresence.ALWAYS,
+ caps);
+ add_pad_template (template);
+ }
+
+ public GstSink (DataSource source, HTTPSeek? offsets) {
+ this.chunks_buffered = 0;
+ this.bytes_sent = 0;
+ this.max_bytes = int64.MAX;
+ this.source = source;
+ this.offsets = offsets;
+
+ this.cancellable = new Cancellable ();
+
+ this.sync = false;
+ this.name = NAME;
+ this.frozen = false;
+
+ if (this.offsets != null) {
+ if (this.offsets.seek_type == HTTPSeekType.BYTE) {
+ this.max_bytes = this.offsets.length;
+ }
+ }
+
+ this.cancellable.cancelled.connect (this.on_cancelled);
+ }
+
+ public void freeze () {
+ if (this.frozen) {
+ return;
+ }
+
+ this.buffer_mutex.lock ();
+ this.frozen = true;
+ this.buffer_mutex.unlock ();
+ }
+
+ public void thaw () {
+ if (!this.frozen) {
+ return;
+ }
+
+ this.buffer_mutex.lock ();
+ this.frozen = false;
+ this.buffer_condition.broadcast ();
+ this.buffer_mutex.unlock ();
+ }
+
+ public override FlowReturn render (Buffer buffer) {
+ this.buffer_mutex.lock ();
+ while (!this.cancellable.is_cancelled () &&
+ this.frozen) {
+ // Client is either not reading (Paused) or not fast enough
+ this.buffer_condition.wait (this.buffer_mutex);
+ }
+ this.buffer_mutex.unlock ();
+
+ if (this.cancellable.is_cancelled ()) {
+ return FlowReturn.OK;
+ }
+
+ Idle.add_full (this.priority, () => {
+ return this.push_data (buffer);
+ });
+
+ return FlowReturn.OK;
+ }
+
+ // Runs in application thread
+ public bool push_data (Buffer buffer) {
+ var left = this.max_bytes - this.bytes_sent;
+
+ if (this.cancellable.is_cancelled () || left <= 0) {
+ return false;
+ }
+
+ var bufsize = buffer.get_size ();
+ var to_send = int64.min (bufsize, left);
+ MapInfo info;
+
+ buffer.map (out info, MapFlags.READ);
+
+ this.source.data_available (info.data[0:to_send]);
+ this.chunks_buffered++;
+ this.bytes_sent += to_send;
+ buffer.unmap (info);
+
+ return false;
+ }
+
+ private void on_cancelled () {
+ this.buffer_mutex.lock ();
+ this.buffer_condition.broadcast ();
+ this.buffer_mutex.unlock ();
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-gst-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-gst-transcoder.vala
new file mode 100644
index 0000000..70ccf61
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-gst-transcoder.vala
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2009-2012 Nokia Corporation.
+ * Copyright (C) 2012 Intel Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ * <zeeshan ali nokia com>
+ * Jens Georg <jensg openismus com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Gst;
+using Gst.PbUtils;
+using GUPnP;
+
+/**
+ * The base Transcoder class. Each implementation derives from it and must
+ * implement get_distance and get_encoding_profile methods.
+ */
+internal abstract class Rygel.GstTranscoder : Rygel.Transcoder {
+ public string preset { get;
+ protected set;
+ default = DEFAULT_ENCODING_PRESET; }
+
+ private const string DECODE_BIN = "decodebin";
+ private const string ENCODE_BIN = "encodebin";
+ private const string DEFAULT_ENCODING_PRESET = "Rygel DLNA preset";
+
+ dynamic Element decoder;
+ dynamic Element encoder;
+
+ private bool link_failed;
+
+ public GstTranscoder (string mime_type,
+ string dlna_profile,
+ string upnp_class,
+ string extension) {
+ this.mime_type = mime_type;
+ this.dlna_profile = dlna_profile;
+ this.link_failed = true;
+ this.extension = extension;
+ }
+
+ /**
+ * Creates a transcoding source.
+ *
+ * @param src the media item to create the transcoding source for
+ * @param src the original (non-transcoding) source
+ *
+ * @return the new transcoding source
+ */
+ public override DataSource create_source (MediaItem item,
+ DataSource src) throws Error {
+ // We can only link GStreamer data sources together
+ assert (src is GstDataSource);
+
+ var orig_source = src as GstDataSource;
+
+ this.decoder = GstUtils.create_element (DECODE_BIN,
+ DECODE_BIN);
+ this.encoder = GstUtils.create_element (ENCODE_BIN,
+ ENCODE_BIN);
+
+ encoder.profile = this.get_encoding_profile ();
+ debug ("%s using the following encoding profile:",
+ this.get_class ().get_type ().name ());
+ GstUtils.dump_encoding_profile (encoder.profile);
+
+ var bin = new Bin ("transcoder-source");
+ bin.add_many (orig_source.src, decoder, encoder);
+
+ orig_source.src.link (decoder);
+
+ decoder.pad_added.connect (this.on_decoder_pad_added);
+ decoder.autoplug_continue.connect (this.on_autoplug_continue);
+ decoder.no_more_pads.connect (this.on_no_more_pads);
+
+ var pad = encoder.get_static_pad ("src");
+ var ghost = new GhostPad (null, pad);
+ bin.add_pad (ghost);
+
+ return new GstDataSource.from_element (bin);
+ }
+
+ /**
+ * Gets the Gst.EncodingProfile for this transcoder.
+ *
+ * @return the Gst.EncodingProfile for this transcoder.
+ */
+ protected abstract EncodingProfile get_encoding_profile ();
+
+ private bool on_autoplug_continue (Element decodebin,
+ Pad new_pad,
+ Caps caps) {
+ Gst.Pad sinkpad = null;
+
+ Signal.emit_by_name (this.encoder, "request-pad", caps, out sinkpad);
+ if (sinkpad == null) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private void on_decoder_pad_added (Element decodebin, Pad new_pad) {
+ Gst.Pad sinkpad;
+
+ sinkpad = this.encoder.get_compatible_pad (new_pad, null);
+
+ if (sinkpad == null) {
+ var caps = new_pad.query_caps (null);
+ Signal.emit_by_name (this.encoder, "request-pad", caps, out sinkpad);
+ }
+
+ if (sinkpad == null) {
+ debug ("No compatible encodebin pad found for pad '%s', ignoring..",
+ new_pad.name);
+
+ return;
+ }
+
+ var pad_link_ok = (new_pad.link (sinkpad) == PadLinkReturn.OK);
+ if (!pad_link_ok) {
+ warning ("Failed to link pad '%s' to '%s'",
+ new_pad.name,
+ sinkpad.name);
+ } else {
+ this.link_failed = false;
+ }
+
+ return;
+ }
+
+ private const string DESCRIPTION = "Encoder and decoder are not " +
+ "compatible";
+
+ private void on_no_more_pads (Element decodebin) {
+ // We haven't found any pads we could link
+ if (this.link_failed) {
+ // Signalize that error
+ var bin = this.encoder.get_parent () as Bin;
+ var error = new IOError.FAILED ("Could not link");
+ var message = new Message.error (bin,
+ error,
+ DESCRIPTION);
+
+
+ var bus = bin.get_bus ();
+ bus.post (message);
+ }
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-gst-utils.vala b/src/media-engines/gstreamer-1.0/rygel-gst-utils.vala
new file mode 100644
index 0000000..4a440b3
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-gst-utils.vala
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ * <zeeshan ali nokia com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+using Gst;
+using Gst.PbUtils;
+
+internal errordomain Rygel.GstError {
+ MISSING_PLUGIN,
+ LINK
+}
+
+internal abstract class Rygel.GstUtils {
+ public static Element create_element (string factoryname,
+ string? name)
+ throws Error {
+ Element element = ElementFactory.make (factoryname, name);
+ if (element == null) {
+ throw new GstError.MISSING_PLUGIN
+ (_("Required element %s missing"),
+ factoryname);
+ }
+
+ return element;
+ }
+
+ public static Element? create_source_for_uri (string uri) {
+ try {
+ dynamic Element src = Element.make_from_uri (URIType.SRC, uri, null);
+
+ if (src.get_class ().find_property ("blocksize") != null) {
+ // The default is usually 4KiB which is not really big enough
+ // for most cases so we set this to 65KiB.
+ src.blocksize = (long) 65536;
+ }
+
+ if (src.get_class ().find_property ("tcp-timeout") != null) {
+ // For rtspsrc since some RTSP sources takes a while to start
+ // transmitting
+ src.tcp_timeout = (int64) 60000000;
+ }
+
+ return src;
+ } catch (Error error) {
+ return null;
+ }
+ }
+
+ public static void dump_encoding_profile (EncodingProfile profile,
+ int indent = 2) {
+ var indent_s = string.nfill (indent, ' ');
+ debug (indent_s + "%s:", profile.get_name ());
+ debug (indent_s + " Format: %s", profile.get_format ().to_string ());
+ if (profile.get_restriction () != null) {
+ debug (indent_s + " Restriction: %s",
+ profile.get_restriction ().to_string ());
+ }
+
+ if (profile is EncodingContainerProfile) {
+ var container = profile as EncodingContainerProfile;
+ foreach (var subprofile in container.get_profiles ()) {
+ dump_encoding_profile (subprofile, indent + 4);
+ }
+ }
+ }
+
+ public static dynamic Element? get_rtp_depayloader (Caps caps) {
+ if (!need_rtp_depayloader (caps)) {
+ return null;
+ }
+
+ var features = ElementFactory.list_get_elements
+ (ElementFactoryType.DEPAYLOADER,
+ Rank.NONE);
+ features = ElementFactory.list_filter (features,
+ caps,
+ PadDirection.SINK,
+ false);
+
+ // If most "fitting" depayloader was rtpdepay skip it because it is
+ // just some kind of proxy.
+ if (features.data.get_name () == "rtpdepay") {
+ if (features.next != null) {
+ return features.next.data.create (null);
+ }
+
+ return null;
+ } else {
+ return features.data.create (null);
+ }
+ }
+
+ private static bool need_rtp_depayloader (Caps caps) {
+ var structure = caps.get_structure (0);
+
+ return structure.get_name () == "application/x-rtp";
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-l16-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-l16-transcoder.vala
new file mode 100644
index 0000000..538d405
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-l16-transcoder.vala
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ * <zeeshan ali nokia com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+using Gst;
+using GUPnP;
+using Gee;
+
+/**
+ * Transcoder for linear PCM audio (LPCM).
+ */
+internal class Rygel.L16Transcoder : Rygel.AudioTranscoder {
+ private const int CHANNELS = 2;
+ private const int FREQUENCY = 44100;
+ private const int WIDTH = 16;
+ private const int DEPTH = 16;
+ private const bool SIGNED = true;
+ private const int ENDIANNESS = ByteOrder.BIG_ENDIAN;
+
+ public L16Transcoder () {
+ var mime_type = "audio/L" + L16Transcoder.WIDTH.to_string () +
+ ";rate=" + L16Transcoder.FREQUENCY.to_string () +
+ ";channels=" + L16Transcoder.CHANNELS.to_string ();
+
+ var caps_str = "audio/x-raw,format=S16BE" +
+ ",channels=" + CHANNELS.to_string () +
+ ",rate=" + FREQUENCY.to_string ();
+
+ base (mime_type,
+ "LPCM",
+ 0,
+ AudioTranscoder.NO_CONTAINER,
+ caps_str,
+ "lpcm");
+ }
+
+ public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item,
+ MediaItem item,
+ TranscodeManager manager)
+ throws Error {
+ var resource = base.add_resource (didl_item, item, manager);
+ if (resource == null) {
+ return null;
+ }
+
+ resource.sample_freq = L16Transcoder.FREQUENCY;
+ resource.audio_channels = L16Transcoder.CHANNELS;
+ resource.bits_per_sample = L16Transcoder.WIDTH;
+ // Set bitrate in bytes/second
+ resource.bitrate = L16Transcoder.FREQUENCY *
+ L16Transcoder.CHANNELS *
+ L16Transcoder.WIDTH / 8;
+
+ return resource;
+ }
+
+ public override uint get_distance (MediaItem item) {
+ if (!(item is AudioItem) || item is VideoItem) {
+ return uint.MAX;
+ }
+
+ var audio_item = item as AudioItem;
+ var distance = uint.MIN;
+
+ if (audio_item.sample_freq > 0) {
+ distance += (audio_item.sample_freq - FREQUENCY).abs ();
+ }
+
+ if (audio_item.channels > 0) {
+ distance += (audio_item.channels - CHANNELS).abs ();
+ }
+
+ if (audio_item.bits_per_sample > 0) {
+ distance += (audio_item.bits_per_sample - WIDTH).abs ();
+ }
+
+ return distance;
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-mp2ts-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-mp2ts-transcoder.vala
new file mode 100644
index 0000000..da59e92
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-mp2ts-transcoder.vala
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ * <zeeshan ali nokia com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+using Gst;
+using GUPnP;
+
+internal enum Rygel.MP2TSProfile {
+ SD = 0,
+ HD
+}
+
+/**
+ * Transcoder for mpeg transport stream containing mpeg 2 video and mp2 audio.
+ */
+internal class Rygel.MP2TSTranscoder : Rygel.VideoTranscoder {
+ private const int VIDEO_BITRATE = 1500;
+ private const int AUDIO_BITRATE = 192;
+
+ // HD
+ private const int[] WIDTH = {720, 1280};
+ private const int[] HEIGHT = {576, 720};
+ private const int[] FRAME_RATE = {25, 30};
+ private const string[] PROFILES = {"MPEG_TS_SD_EU_ISO", "MPEG_TS_HD_NA_ISO"};
+
+ private const string CONTAINER =
+ "video/mpegts,systemstream=true,packetsize=188";
+
+ private const string AUDIO_FORMAT =
+ "audio/mpeg,mpegversion=1,layer=2";
+
+ private const string BASE_VIDEO_FORMAT =
+ "video/mpeg,mpegversion=2,systemstream=false";
+
+ private const string RESTRICTION_TEMPLATE =
+ "framerate=(fraction)%d/1,width=%d,height=%d";
+
+ private MP2TSProfile profile;
+
+ public MP2TSTranscoder (MP2TSProfile profile) {
+ base ("video/mpeg",
+ PROFILES[profile],
+ AUDIO_BITRATE,
+ VIDEO_BITRATE,
+ CONTAINER,
+ AUDIO_FORMAT,
+ BASE_VIDEO_FORMAT,
+ "mpg",
+ RESTRICTION_TEMPLATE.printf (FRAME_RATE[profile],
+ WIDTH[profile],
+ HEIGHT[profile]));
+
+ this.profile = profile;
+ }
+
+ public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item,
+ MediaItem item,
+ TranscodeManager manager)
+ throws Error {
+ var resource = base.add_resource (didl_item, item, manager);
+ if (resource == null) {
+ return null;
+ }
+
+ resource.width = WIDTH[this.profile];
+ resource.height = HEIGHT[this.profile];
+ resource.bitrate = (VIDEO_BITRATE + AUDIO_BITRATE) * 1000 / 8;
+
+ return resource;
+ }
+
+ public override uint get_distance (MediaItem item) {
+ if (!(item is VideoItem)) {
+ return uint.MAX;
+ }
+
+ var video_item = item as VideoItem;
+ var distance = base.get_distance (item);
+
+ if (video_item.bitrate > 0) {
+ distance += (video_item.bitrate - VIDEO_BITRATE).abs ();
+ }
+
+ if (video_item.width > 0) {
+ distance += (video_item.width - WIDTH[this.profile]).abs ();
+ }
+
+ if (video_item.height > 0) {
+ distance += (video_item.height - HEIGHT[this.profile]).abs ();
+ }
+
+ return distance;
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-mp3-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-mp3-transcoder.vala
new file mode 100644
index 0000000..ecbdd45
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-mp3-transcoder.vala
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Author: Zeeshan Ali (Khattak) <zeeshanak gnome org>
+ * <zeeshan ali nokia com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+using Gst;
+using GUPnP;
+using Gee;
+
+/**
+ * Transcoder for mpeg 1 layer 3 audio.
+ */
+internal class Rygel.MP3Transcoder : Rygel.AudioTranscoder {
+ public const int BITRATE = 128;
+ private const string FORMAT = "audio/mpeg,mpegversion=1,layer=3";
+
+ public MP3Transcoder () {
+ base ("audio/mpeg",
+ "MP3",
+ BITRATE,
+ AudioTranscoder.NO_CONTAINER,
+ FORMAT,
+ "mp3");
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-video-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-video-transcoder.vala
new file mode 100644
index 0000000..7589ded
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-video-transcoder.vala
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 Nokia Corporation.
+ *
+ * Author: Jens Georg <jensg openismus com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+using Gst;
+using Gst.PbUtils;
+using GUPnP;
+
+/**
+ * Base class for all transcoders that handle video.
+ */
+internal class Rygel.VideoTranscoder : Rygel.AudioTranscoder {
+ private int video_bitrate;
+ private Caps video_codec_format;
+ private Caps video_restrictions = null;
+
+ public VideoTranscoder (string content_type,
+ string dlna_profile,
+ int audio_bitrate,
+ int video_bitrate,
+ string container_caps,
+ string audio_codec_caps,
+ string video_codec_caps,
+ string extension,
+ string? restrictions = null) {
+
+ base.with_class (content_type,
+ dlna_profile,
+ VideoItem.UPNP_CLASS,
+ audio_bitrate,
+ container_caps,
+ audio_codec_caps,
+ extension);
+
+ this.video_bitrate = video_bitrate;
+ this.video_codec_format = Caps.from_string (video_codec_caps);
+
+ if (restrictions != null) {
+ this.video_restrictions = Caps.from_string (restrictions);
+ }
+ }
+
+ public override DIDLLiteResource? add_resource (DIDLLiteItem didl_item,
+ MediaItem item,
+ TranscodeManager manager)
+ throws Error {
+ var resource = base.add_resource (didl_item, item, manager);
+ if (resource == null) {
+ return null;
+ }
+
+ var video_item = item as VideoItem;
+
+ resource.width = video_item.width;
+ resource.height = video_item.height;
+ resource.bitrate = (this.video_bitrate + this.audio_bitrate) * 1000 / 8;
+
+ return resource;
+ }
+
+ public override uint get_distance (MediaItem item) {
+ if (!(item is VideoItem)) {
+ return uint.MAX;
+ }
+
+ var video_item = item as VideoItem;
+ var distance = uint.MIN;
+
+ if (video_item.bitrate > 0) {
+ distance += (video_item.bitrate - this.video_bitrate).abs ();
+ }
+
+ return distance;
+ }
+
+ protected override EncodingProfile get_encoding_profile () {
+ var enc_container_profile = base.get_encoding_profile () as
+ EncodingContainerProfile;
+
+ var enc_video_profile = new EncodingVideoProfile
+ (this.video_codec_format,
+ this.preset,
+ this.video_restrictions,
+ 1);
+ enc_video_profile.set_name ("video");
+
+ enc_container_profile.add_profile (enc_video_profile);
+
+ return enc_container_profile;
+ }
+}
diff --git a/src/media-engines/gstreamer-1.0/rygel-wmv-transcoder.vala b/src/media-engines/gstreamer-1.0/rygel-wmv-transcoder.vala
new file mode 100644
index 0000000..947ee04
--- /dev/null
+++ b/src/media-engines/gstreamer-1.0/rygel-wmv-transcoder.vala
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 Jens Georg <mail jensge org>.
+ *
+ * Author: Jens Georg <mail jensge org>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+using Gst;
+using GUPnP;
+
+internal class Rygel.WMVTranscoder : Rygel.VideoTranscoder {
+ private const int VIDEO_BITRATE = 1200;
+ private const int AUDIO_BITRATE = 64;
+
+ public WMVTranscoder () {
+ base ("video/x-ms-wmv",
+ "WMVHIGH_FULL",
+ AUDIO_BITRATE,
+ VIDEO_BITRATE,
+ "video/x-ms-asf,parsed=true",
+ "audio/x-wma,channels=2,wmaversion=1",
+ "video/x-wmv,wmvversion=1",
+ "wmv");
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]