[rygel/wip/gst-1.0: 2/2] WIP



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]