[libdmapsharing] Update transcoders and add (still broken) QuickTime transcoder



commit 4caf1556bda4b3260263d90575040c64be3a717c
Author: W. Michael Petullo <mike flyn org>
Date:   Mon Jun 24 20:10:32 2013 -0500

    Update transcoders and add (still broken) QuickTime transcoder
    
    Signed-off-by: W. Michael Petullo <mike flyn org>

 libdmapsharing/Makefile.am                 |    2 +
 libdmapsharing/daap-share.c                |    8 +-
 libdmapsharing/dmap-gst-input-stream.c     |    3 +
 libdmapsharing/dmap-gst-mp3-input-stream.c |   34 +++---
 libdmapsharing/dmap-gst-qt-input-stream.c  |  192 ++++++++++++++++++++++++++++
 libdmapsharing/dmap-gst-qt-input-stream.h  |   66 ++++++++++
 libdmapsharing/dmap-gst-wav-input-stream.c |   41 +++---
 7 files changed, 308 insertions(+), 38 deletions(-)
---
diff --git a/libdmapsharing/Makefile.am b/libdmapsharing/Makefile.am
index 5cc3fc2..f461991 100644
--- a/libdmapsharing/Makefile.am
+++ b/libdmapsharing/Makefile.am
@@ -44,6 +44,7 @@ if USE_GSTREAMERAPP
 libdmapsharing_3_0_la_SOURCES += \
        dmap-gst-input-stream.c \
        dmap-gst-mp3-input-stream.c \
+       dmap-gst-qt-input-stream.c \
        dmap-gst-wav-input-stream.c \
        gst-util.c
 endif
@@ -100,6 +101,7 @@ noinst_HEADERS = \
        dmap-mdns-avahi.h \
        dmap-utils.h \
        dmap-gst-mp3-input-stream.h \
+       dmap-gst-qt-input-stream.h \
        dmap-gst-wav-input-stream.h \
        gst-util.h
 
diff --git a/libdmapsharing/daap-share.c b/libdmapsharing/daap-share.c
index d676afa..9e9a8c9 100644
--- a/libdmapsharing/daap-share.c
+++ b/libdmapsharing/daap-share.c
@@ -163,6 +163,8 @@ mime_to_format (const gchar * transcode_mimetype)
                return g_strdup ("wav");
        } else if (!strcmp (transcode_mimetype, "audio/mp3")) {
                return g_strdup ("mp3");
+       } else if (!strcmp (transcode_mimetype, "video/quicktime")) {
+               return g_strdup ("mp4");
        } else
                return NULL;
 }
@@ -418,8 +420,10 @@ send_chunked_file (SoupServer * server, SoupMessage * message,
 
        g_object_get (record, "format", &format, NULL);
        // Not presently transcoding videos (see also same comments elsewhere).
-       if (has_video || transcode_mimetype == NULL
-           || !strcmp (format, mime_to_format (transcode_mimetype))) {
+       char *format2 = NULL;
+       if (has_video 
+           || transcode_mimetype == NULL
+           || (format2 = mime_to_format (transcode_mimetype)) && !strcmp (format, format2)) {
                g_debug ("Not transcoding");
                cd->stream = stream;
 #ifdef HAVE_GSTREAMERAPP
diff --git a/libdmapsharing/dmap-gst-input-stream.c b/libdmapsharing/dmap-gst-input-stream.c
index 793d150..ecb07af 100644
--- a/libdmapsharing/dmap-gst-input-stream.c
+++ b/libdmapsharing/dmap-gst-input-stream.c
@@ -276,6 +276,9 @@ dmap_gst_input_stream_new (const gchar * transcode_mimetype,
        } else if (!strcmp (transcode_mimetype, "audio/wav")) {
                stream = G_INPUT_STREAM (dmap_gst_wav_input_stream_new
                                         (src_stream));
+       } else if (!strcmp (transcode_mimetype, "video/quicktime")) {
+               stream = G_INPUT_STREAM (dmap_gst_qt_input_stream_new
+                                        (src_stream));
        } else {
                g_warning ("Transcode format %s not supported",
                           transcode_mimetype);
diff --git a/libdmapsharing/dmap-gst-mp3-input-stream.c b/libdmapsharing/dmap-gst-mp3-input-stream.c
index 0ca4dcf..dc60af2 100644
--- a/libdmapsharing/dmap-gst-mp3-input-stream.c
+++ b/libdmapsharing/dmap-gst-mp3-input-stream.c
@@ -34,7 +34,7 @@ struct DMAPGstMP3InputStreamPrivate
        GstElement *src;
        GstElement *decode;
        GstElement *convert;
-       GstElement *encode;
+       GstElement *audio_encode;
        GstElement *sink;
 };
 
@@ -59,13 +59,6 @@ pad_added_cb (GstElement * element,
                           (stream->priv->convert, "sink")));
 
                gst_pad_link (pad, conv_pad);
-
-               if (gst_element_link_many (stream->priv->convert,
-                                          stream->priv->encode,
-                                          stream->priv->sink,
-                                          NULL) == FALSE) {
-                       g_warning ("Error linking convert and sink elements");
-               }
        } else {
                g_warning ("Could not link GStreamer pipeline.");
        }
@@ -95,8 +88,8 @@ dmap_gst_mp3_input_stream_new (GInputStream * src_stream)
                gst_element_factory_make ("audioconvert", "convert");
        g_assert (GST_IS_ELEMENT (stream->priv->convert));
 
-       stream->priv->encode = gst_element_factory_make ("lamemp3enc", "encode");
-       g_assert (GST_IS_ELEMENT (stream->priv->encode));
+       stream->priv->audio_encode = gst_element_factory_make ("lamemp3enc", "audioencode");
+       g_assert (GST_IS_ELEMENT (stream->priv->audio_encode));
 
        stream->priv->sink = gst_element_factory_make ("appsink", "sink");
        g_assert (GST_IS_ELEMENT (stream->priv->sink));
@@ -105,22 +98,31 @@ dmap_gst_mp3_input_stream_new (GInputStream * src_stream)
                          stream->priv->src,
                          stream->priv->decode,
                          stream->priv->convert,
-                         stream->priv->encode, stream->priv->sink, NULL);
+                         stream->priv->audio_encode,
+                         stream->priv->sink,
+                         NULL);
 
-       if (gst_element_link (stream->priv->src, stream->priv->decode) ==
-           FALSE) {
+       if (gst_element_link (stream->priv->src,
+                             stream->priv->decode) == FALSE) {
                g_warning ("Error linking source and decode elements");
        }
 
+       if (gst_element_link_many (stream->priv->convert,
+                                  stream->priv->audio_encode,
+                                  stream->priv->sink,
+                                  NULL) == FALSE) {
+               g_warning ("Error linking convert through sink elements");
+       }
+
        g_assert (G_IS_INPUT_STREAM (src_stream));
        g_object_set (G_OBJECT (stream->priv->src), "stream", src_stream,
                      NULL);
 
        /* quality=9 is important for fast, realtime transcoding: */
        // FIXME: Causes crash; why?
-       // g_object_set (G_OBJECT (stream->priv->encode), "quality", 9, NULL);
-       g_object_set (G_OBJECT (stream->priv->encode), "bitrate", 128, NULL);
-       g_object_set (G_OBJECT (stream->priv->encode), "vbr", 0, NULL);
+       // g_object_set (G_OBJECT (stream->priv->audio_encode), "quality", 9, NULL);
+       g_object_set (G_OBJECT (stream->priv->audio_encode), "bitrate", 128, NULL);
+       g_object_set (G_OBJECT (stream->priv->audio_encode), "vbr", 0, NULL);
        g_signal_connect (stream->priv->decode, "pad-added",
                          G_CALLBACK (pad_added_cb), stream);
 
diff --git a/libdmapsharing/dmap-gst-qt-input-stream.c b/libdmapsharing/dmap-gst-qt-input-stream.c
new file mode 100644
index 0000000..eff4253
--- /dev/null
+++ b/libdmapsharing/dmap-gst-qt-input-stream.c
@@ -0,0 +1,192 @@
+/*
+ * DMAPGstQtInputStream class: Open a URI using dmap_gst_qt_input_stream_new ().
+ * Data is decoded using GStreamer and is then reencoded as a QuickTime video
+ * stream by the class's read operations.
+ *
+ * Copyright (C) 2009 W. Michael Petullo <mike flyn org>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <gst/gst.h>
+#include <gst/app/gstappsink.h>
+
+#include "dmap-gst-qt-input-stream.h"
+#include "gst-util.h"
+
+#define GST_APP_MAX_BUFFERS 1024
+
+struct DMAPGstQtInputStreamPrivate
+{
+       GstElement *pipeline;
+       GstElement *src;
+       GstElement *decode;
+       GstElement *convert;
+       GstElement *audio_encode;
+       GstElement *mux;
+       GstElement *sink;
+};
+
+/* FIXME: See note in dmap-gst-input-stream.h */
+void dmap_gst_input_stream_new_buffer_cb (GstElement * element,
+                                         DMAPGstInputStream * stream);
+
+static void
+pad_added_cb (GstElement * element,
+              GstPad * pad,
+              DMAPGstQtInputStream * stream)
+{
+       /* Link remaining pad after decodebin2 does its magic. */
+       GstPad *conv_pad;
+
+       conv_pad = gst_element_get_static_pad (stream->priv->convert, "sink");
+       g_assert (conv_pad != NULL);
+
+       if (pads_compatible (pad, conv_pad)) {
+               g_assert (!GST_PAD_IS_LINKED
+                         (gst_element_get_static_pad
+                          (stream->priv->convert, "sink")));
+
+               gst_pad_link (pad, conv_pad);
+       } else {
+               g_warning ("Could not link GStreamer pipeline.");
+       }
+}
+
+GInputStream *
+dmap_gst_qt_input_stream_new (GInputStream * src_stream)
+{
+       GstStateChangeReturn sret;
+       GstState state;
+       DMAPGstQtInputStream *stream;
+
+       stream = DMAP_GST_QT_INPUT_STREAM (g_object_new
+                                           (DMAP_TYPE_GST_QT_INPUT_STREAM,
+                                            NULL));
+
+       stream->priv->pipeline = gst_pipeline_new ("pipeline");
+
+       stream->priv->src = gst_element_factory_make ("giostreamsrc", "src");
+       g_assert (GST_IS_ELEMENT (stream->priv->src));
+
+       stream->priv->decode =
+               gst_element_factory_make ("decodebin", "decode");
+       g_assert (GST_IS_ELEMENT (stream->priv->decode));
+
+       stream->priv->convert =
+               gst_element_factory_make ("audioconvert", "convert");
+       g_assert (GST_IS_ELEMENT (stream->priv->convert));
+
+       stream->priv->audio_encode = gst_element_factory_make ("avenc_aac", "audioencode");
+       g_assert (GST_IS_ELEMENT (stream->priv->audio_encode));
+
+       stream->priv->mux = gst_element_factory_make ("qtmux", "mux");
+       g_assert (GST_IS_ELEMENT (stream->priv->mux));
+
+       stream->priv->sink = gst_element_factory_make ("appsink", "sink");
+       g_assert (GST_IS_ELEMENT (stream->priv->sink));
+
+       gst_bin_add_many (GST_BIN (stream->priv->pipeline),
+                         stream->priv->src,
+                         stream->priv->decode,
+                         stream->priv->convert,
+                         stream->priv->audio_encode,
+                         stream->priv->mux,
+                         stream->priv->sink,
+                         NULL);
+
+       if (gst_element_link (stream->priv->src,
+                             stream->priv->decode) == FALSE) {
+               g_warning ("Error linking source and decode elements");
+       }
+
+       if (gst_element_link_many (stream->priv->convert,
+                                  stream->priv->audio_encode,
+                                  stream->priv->mux,
+                                  stream->priv->sink,
+                                  NULL) == FALSE) {
+               g_warning ("Error linking convert through sink elements");
+       }
+
+       g_assert (G_IS_INPUT_STREAM (src_stream));
+       g_object_set (G_OBJECT (stream->priv->src), "stream", src_stream,
+                     NULL);
+
+       g_signal_connect (stream->priv->decode, "pad-added",
+                         G_CALLBACK (pad_added_cb), stream);
+
+       g_object_set (G_OBJECT (stream->priv->sink), "emit-signals", TRUE,
+                     "sync", FALSE, NULL);
+       gst_app_sink_set_max_buffers (GST_APP_SINK (stream->priv->sink),
+                                     GST_APP_MAX_BUFFERS);
+       gst_app_sink_set_drop (GST_APP_SINK (stream->priv->sink), FALSE);
+
+       g_signal_connect (stream->priv->sink, "new-sample",
+                         G_CALLBACK (dmap_gst_input_stream_new_buffer_cb),
+                         stream);
+
+       /* FIXME: this technique is shared with dmapd-daap-share.c */
+       sret = gst_element_set_state (stream->priv->pipeline,
+                                     GST_STATE_PLAYING);
+       if (GST_STATE_CHANGE_ASYNC == sret) {
+               if (GST_STATE_CHANGE_SUCCESS !=
+                   gst_element_get_state (GST_ELEMENT
+                                          (stream->priv->pipeline), &state,
+                                          NULL, 5 * GST_SECOND)) {
+                       g_warning ("State change failed for stream.");
+               }
+       } else if (sret != GST_STATE_CHANGE_SUCCESS) {
+               g_warning ("Could not read stream.");
+       }
+
+       g_assert (G_IS_SEEKABLE (stream));
+       return G_INPUT_STREAM (stream);
+}
+
+static void
+dmap_gst_qt_input_stream_kill_pipeline (DMAPGstInputStream * stream)
+{
+       DMAPGstQtInputStream *qt_stream =
+               DMAP_GST_QT_INPUT_STREAM (stream);
+
+       // FIXME: It seems that I need to send an EOS, because QuickTime writes
+       // its headers after encoding the streams, but this does not yet work.
+       gst_element_send_event(qt_stream->priv->pipeline, gst_event_new_eos());
+       
+       gst_element_set_state (qt_stream->priv->pipeline, GST_STATE_NULL);
+       gst_object_unref (GST_OBJECT (qt_stream->priv->pipeline));
+}
+
+G_DEFINE_TYPE (DMAPGstQtInputStream, dmap_gst_qt_input_stream,
+              DMAP_TYPE_GST_INPUT_STREAM);
+
+static void
+dmap_gst_qt_input_stream_class_init (DMAPGstQtInputStreamClass * klass)
+{
+       DMAPGstInputStreamClass *parent_class =
+               DMAP_GST_INPUT_STREAM_CLASS (klass);
+
+       g_type_class_add_private (klass,
+                                 sizeof (DMAPGstQtInputStreamPrivate));
+
+       parent_class->kill_pipeline = dmap_gst_qt_input_stream_kill_pipeline;
+}
+
+static void
+dmap_gst_qt_input_stream_init (DMAPGstQtInputStream * stream)
+{
+       stream->priv = DMAP_GST_QT_INPUT_STREAM_GET_PRIVATE (stream);
+
+}
diff --git a/libdmapsharing/dmap-gst-qt-input-stream.h b/libdmapsharing/dmap-gst-qt-input-stream.h
new file mode 100644
index 0000000..8e2bda6
--- /dev/null
+++ b/libdmapsharing/dmap-gst-qt-input-stream.h
@@ -0,0 +1,66 @@
+/*
+ * DMAPGstQtInputStream class: Open a URI using dmap_gst_qt_input_stream_new ().
+ * Data is decoded using GStreamer and is then reencoded as a QuickTime video
+ * stream by the class's read operations.
+ *
+ * Copyright (C) 2008 W. Michael Petullo <mike flyn org>
+ *
+ * This library 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.1 of the License, or (at your option) any later version.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __DMAP_GST_QT_INPUT_STREAM
+#define __DMAP_GST_QT_INPUT_STREAM
+
+#include <gio/gio.h>
+
+#include "dmap-gst-input-stream.h"
+
+G_BEGIN_DECLS
+#define DMAP_TYPE_GST_QT_INPUT_STREAM         (dmap_gst_qt_input_stream_get_type ())
+#define DMAP_GST_QT_INPUT_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), \
+                                              DMAP_TYPE_GST_QT_INPUT_STREAM, \
+                                              DMAPGstQtInputStream))
+#define DMAP_GST_QT_INPUT_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), \
+                                              DMAP_TYPE_GST_QT_INPUT_STREAM, \
+                                              DMAPGstQtInputStreamClass))
+#define IS_DMAP_GST_QT_INPUT_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), \
+                                              DMAP_TYPE_GST_QT_INPUT_STREAM))
+#define IS_DMAP_GST_QT_INPUT_STREAM_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), \
+                                              DMAP_TYPE_GST_QT_INPUT_STREAM_CLASS))
+#define DMAP_GST_QT_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), \
+                                              DMAP_TYPE_GST_QT_INPUT_STREAM, \
+                                              DMAPGstQtInputStreamClass))
+#define DMAP_GST_QT_INPUT_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
+                                          DMAP_TYPE_GST_QT_INPUT_STREAM, \
+                                          DMAPGstQtInputStreamPrivate))
+typedef struct DMAPGstQtInputStreamPrivate DMAPGstQtInputStreamPrivate;
+
+typedef struct
+{
+       DMAPGstInputStream parent;
+       DMAPGstQtInputStreamPrivate *priv;
+} DMAPGstQtInputStream;
+
+typedef struct
+{
+       DMAPGstInputStreamClass parent;
+} DMAPGstQtInputStreamClass;
+
+GType dmap_gst_qt_input_stream_get_type (void);
+
+GInputStream *dmap_gst_qt_input_stream_new (GInputStream * stream);
+
+G_END_DECLS
+#endif /* __DMAP_GST_QT_INPUT_STREAM */
diff --git a/libdmapsharing/dmap-gst-wav-input-stream.c b/libdmapsharing/dmap-gst-wav-input-stream.c
index 8f8afd8..c7817ba 100644
--- a/libdmapsharing/dmap-gst-wav-input-stream.c
+++ b/libdmapsharing/dmap-gst-wav-input-stream.c
@@ -35,7 +35,7 @@ struct DMAPGstWAVInputStreamPrivate
        GstElement *decode;
        GstElement *convert;
        GstCaps *filter;
-       GstElement *encode;
+       GstElement *audio_encode;
        GstElement *sink;
 };
 
@@ -60,18 +60,6 @@ pad_added_cb (GstElement * element,
                           (stream->priv->convert, "sink")));
 
                gst_pad_link (pad, conv_pad);
-
-               if (gst_element_link_filtered (stream->priv->convert,
-                                              stream->priv->encode,
-                                              stream->priv->filter) ==
-                   FALSE) {
-                       g_warning
-                               ("Error linking convert and encode elements");
-               }
-               if (gst_element_link (stream->priv->encode,
-                                     stream->priv->sink) == FALSE) {
-                       g_warning ("Error linking encode and sink elements");
-               }
        } else {
                g_warning ("Could not link GStreamer pipeline.");
        }
@@ -94,7 +82,7 @@ dmap_gst_wav_input_stream_new (GInputStream * src_stream)
        g_assert (GST_IS_ELEMENT (stream->priv->src));
 
        stream->priv->decode =
-               gst_element_factory_make ("decodebin2", "decode");
+               gst_element_factory_make ("decodebin", "decode");
        g_assert (GST_IS_ELEMENT (stream->priv->decode));
 
        stream->priv->convert =
@@ -107,8 +95,8 @@ dmap_gst_wav_input_stream_new (GInputStream * src_stream)
                                                    "width", G_TYPE_INT, 16,
                                                    "depth", G_TYPE_INT, 16,
                                                    NULL);
-       stream->priv->encode = gst_element_factory_make ("wavenc", "encode");
-       g_assert (GST_IS_ELEMENT (stream->priv->encode));
+       stream->priv->audio_encode = gst_element_factory_make ("wavenc", "audioencode");
+       g_assert (GST_IS_ELEMENT (stream->priv->audio_encode));
 
        stream->priv->sink = gst_element_factory_make ("appsink", "sink");
        g_assert (GST_IS_ELEMENT (stream->priv->sink));
@@ -117,11 +105,24 @@ dmap_gst_wav_input_stream_new (GInputStream * src_stream)
                          stream->priv->src,
                          stream->priv->decode,
                          stream->priv->convert,
-                         stream->priv->encode, stream->priv->sink, NULL);
+                         stream->priv->audio_encode,
+                         stream->priv->sink,
+                         NULL);
+
+       if (gst_element_link (stream->priv->src, 
+                             stream->priv->decode) == FALSE) {
+               g_warning ("Error linking source through decode elements");
+       }
+
+       if (gst_element_link_filtered (stream->priv->convert,
+                                      stream->priv->audio_encode,
+                                      stream->priv->filter) == FALSE) {
+               g_warning ("Error linking convert and audioencode elements");
+       }
 
-       if (gst_element_link (stream->priv->src, stream->priv->decode) ==
-           FALSE) {
-               g_warning ("Error linking source and decode elements");
+       if (gst_element_link (stream->priv->audio_encode,
+                             stream->priv->sink) == FALSE) {
+               g_warning ("Error linking audioencode and sink elements");
        }
 
        g_object_set (G_OBJECT (stream->priv->src), "stream", src_stream,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]