[Swfdec] configure.ac libswfdec/Makefile.am
libswfdec/swfdec_codec.c libswfdec/swfdec_codec_gst.c
Benjamin Otte
company at kemper.freedesktop.org
Thu Apr 5 07:45:44 PDT 2007
configure.ac | 20 +++
libswfdec/Makefile.am | 10 +
libswfdec/swfdec_codec.c | 9 +
libswfdec/swfdec_codec_gst.c | 260 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 294 insertions(+), 5 deletions(-)
New commits:
diff-tree 9367afafdc43e320b2689237f9f302e52d8fac0e (from 1906bf5a380edbbb4b808543cf3da0e9e836dbf4)
Author: Benjamin Otte <otte at gnome.org>
Date: Thu Apr 5 16:46:57 2007 +0200
implement first try at GStreamer codecs
It's disabled by default since it crashes far too often
diff --git a/configure.ac b/configure.ac
index fdf2a31..899cfef 100644
--- a/configure.ac
+++ b/configure.ac
@@ -204,6 +204,26 @@ else
AC_MSG_WARN([*** ffmpeg support was not enabled. ***])
fi
AM_CONDITIONAL(HAVE_FFMPEG, [test "x$HAVE_FFMPEG" = xyes])
+AC_ARG_ENABLE(gstreamer,
+ AS_HELP_STRING([--enable-gstreamer],
+ [enable GStreamer support (default=no)])],
+ enable_gstreamer=$enableval,
+ enable_gstreamer="no")
+
+if test "$enable_gstreamer" = "yes"; then
+ dnl I used my own version here, it might work with lower versions
+ GST_REQUIRED=0.10.10
+ PKG_CHECK_MODULES(GST, gstreamer-0.10 >= $GST_REQUIRED, HAVE_GST=yes, HAVE_GST=no)
+ if test "x$HAVE_GST" = xyes; then
+ AC_DEFINE(HAVE_GST, 1, [Define if GStreamer is enabled])
+ else
+ AC_MSG_ERROR([Couldn't find GStreamer $GST_REQUIRED.])
+ fi
+else
+ AC_MSG_WARN([*** GStreamer support was not enabled. ***])
+fi
+AM_CONDITIONAL(HAVE_GST, [test "x$HAVE_GST" = xyes])
+
AC_ARG_ENABLE(gnome-vfs,
AS_HELP_STRING([--enable-gnome-vfs],
diff --git a/libswfdec/Makefile.am b/libswfdec/Makefile.am
index f7be47f..0ad15c5 100644
--- a/libswfdec/Makefile.am
+++ b/libswfdec/Makefile.am
@@ -10,6 +10,9 @@ endif
if HAVE_FFMPEG
CODECS += swfdec_codec_ffmpeg.c
endif
+if HAVE_GST
+CODECS += swfdec_codec_gst.c
+endif
lib_LTLIBRARIES = libswfdec- at SWFDEC_MAJORMINOR@.la
@@ -86,13 +89,14 @@ libswfdec_ at SWFDEC_MAJORMINOR@_la_SOURCES
libswfdec_ at SWFDEC_MAJORMINOR@_la_CFLAGS = \
$(GLOBAL_CFLAGS) $(CAIRO_CFLAGS) $(GLIB_CFLAGS) $(PANGO_CFLAGS) \
- -I$(srcdir)/jpeg/ $(js_cflags) $(LIBOIL_CFLAGS) $(FFMPEG_CFLAGS) \
+ -I$(srcdir)/jpeg/ $(js_cflags) $(LIBOIL_CFLAGS) \
+ $(GST_CFLAGS) $(FFMPEG_CFLAGS) $(MAD_CFLAGS) \
-DG_LOG_DOMAIN=\"Swfdec\"
libswfdec_ at SWFDEC_MAJORMINOR@_la_LDFLAGS = \
-version-info $(SWFDEC_LIBVERSION) \
-export-symbols-regex '^(swfdec_.*)' \
- $(CAIRO_LIBS) $(GLIB_LIBS) $(PANGO_LIBS) $(MAD_LIBS) $(FFMPEG_LIBS) \
- $(LIBOIL_LIBS) -lz
+ $(CAIRO_LIBS) $(GLIB_LIBS) $(PANGO_LIBS) $(LIBOIL_LIBS) -lz \
+ $(MAD_LIBS) $(FFMPEG_LIBS) $(GST_LIBS)
public_headers = \
swfdec.h \
diff --git a/libswfdec/swfdec_codec.c b/libswfdec/swfdec_codec.c
index d0f048f..1875572 100644
--- a/libswfdec/swfdec_codec.c
+++ b/libswfdec/swfdec_codec.c
@@ -27,6 +27,7 @@
/*** DECODER LIST ***/
extern const SwfdecAudioCodec swfdec_codec_adpcm;
+extern const SwfdecVideoCodec swfdec_codec_screen;
#ifdef HAVE_MAD
extern const SwfdecAudioCodec swfdec_codec_mad;
@@ -39,7 +40,7 @@ extern const SwfdecVideoCodec swfdec_cod
extern const SwfdecVideoCodec swfdec_codec_ffmpeg_screen;
#endif
-extern const SwfdecVideoCodec swfdec_codec_screen;
+extern const SwfdecVideoCodec swfdec_codec_gst_h263;
/*** UNCOMPRESSED SOUND ***/
@@ -157,12 +158,16 @@ swfdec_codec_get_video (SwfdecVideoForma
SWFDEC_ERROR ("Screen video requires ffmpeg");
return NULL;
case SWFDEC_VIDEO_FORMAT_H263:
+#ifdef HAVE_GST
+ return &swfdec_codec_gst_h263;
+#else
#ifdef HAVE_FFMPEG
return &swfdec_codec_ffmpeg_h263;
#else
- SWFDEC_ERROR ("H263 video requires ffmpeg");
+ SWFDEC_ERROR ("H263 video requires ffmpeg or GStreamer");
return NULL;
#endif
+#endif
default:
SWFDEC_ERROR ("video codec %u not implemented yet", (guint) format);
return NULL;
diff --git a/libswfdec/swfdec_codec_gst.c b/libswfdec/swfdec_codec_gst.c
new file mode 100644
index 0000000..c4313aa
--- /dev/null
+++ b/libswfdec/swfdec_codec_gst.c
@@ -0,0 +1,260 @@
+/* Swfdec
+ * Copyright (C) 2007 Benjamin Otte <otte at gnome.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 Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <gst/gst.h>
+
+#include "swfdec_codec.h"
+#include "swfdec_debug.h"
+
+#define swfdec_cond_wait(cond, mutex) G_STMT_START { \
+ g_print ("waiting at %s\n", G_STRLOC); \
+ g_cond_wait (cond, mutex); \
+ g_print (" done at %s\n", G_STRLOC); \
+}G_STMT_END
+
+typedef struct _SwfdecGstVideo SwfdecGstVideo;
+struct _SwfdecGstVideo {
+ GMutex * mutex; /* mutex that blocks everything below */
+ GCond * cond; /* cond used to signal when stuff below changes */
+ volatile int refcount; /* refcount (d'oh) */
+
+ GstElement * pipeline; /* pipeline that is playing or NULL when done */
+ SwfdecBuffer * in; /* next input buffer or NULL */
+ SwfdecBuffer * out; /* available output or NULL */
+ int width; /* width of last output buffer */
+ int height; /* height of last output buffer */
+ GstCaps * srccaps; /* caps to set on buffers */
+};
+
+static void
+swfdec_gst_video_unref (gpointer data, GObject *unused)
+{
+ SwfdecGstVideo *player = data;
+
+ if (!g_atomic_int_dec_and_test (&player->refcount))
+ return;
+ g_cond_free (player->cond);
+ g_mutex_free (player->mutex);
+ gst_caps_unref (player->srccaps);
+ if (player->in)
+ swfdec_buffer_unref (player->in);
+ if (player->out)
+ swfdec_buffer_unref (player->out);
+ g_slice_free (SwfdecGstVideo, player);
+}
+
+static void
+swfdec_codec_gst_video_finish (gpointer codec_data)
+{
+ SwfdecGstVideo *player = codec_data;
+ GstElement *pipeline;
+
+ g_mutex_lock (player->mutex);
+ pipeline = player->pipeline;
+ player->pipeline = NULL;
+ g_cond_signal (player->cond);
+ g_mutex_unlock (player->mutex);
+ gst_element_set_state (pipeline, GST_STATE_NULL);
+ g_object_unref (pipeline);
+
+ swfdec_gst_video_unref (player, NULL);
+}
+
+static void
+swfdec_codec_gst_fakesrc_handoff (GstElement *fakesrc, GstBuffer *buf,
+ GstPad *pad, SwfdecGstVideo *player)
+{
+ g_mutex_lock (player->mutex);
+ while (player->pipeline != NULL && player->in == NULL)
+ swfdec_cond_wait (player->cond, player->mutex);
+ if (player->pipeline == NULL) {
+ g_mutex_unlock (player->mutex);
+ return;
+ }
+ buf->data = g_memdup (player->in->data, player->in->length);
+ buf->size = player->in->length;
+ gst_buffer_set_caps (buf, player->srccaps);
+ player->in = NULL;
+ g_cond_signal (player->cond);
+ g_mutex_unlock (player->mutex);
+}
+
+static void
+swfdec_codec_gst_fakesink_handoff (GstElement *fakesrc, GstBuffer *buf,
+ GstPad *pad, SwfdecGstVideo *player)
+{
+ GstCaps *caps;
+
+ g_mutex_lock (player->mutex);
+ caps = gst_buffer_get_caps (buf);
+ if (caps) {
+ GstStructure *structure = gst_caps_get_structure (caps, 0);
+ if (!gst_structure_get_int (structure, "width", &player->width) ||
+ !gst_structure_get_int (structure, "height", &player->height)) {
+ player->width = 0;
+ player->height = 0;
+ }
+ gst_caps_unref (caps);
+ }
+ while (player->pipeline != NULL && player->out != NULL)
+ swfdec_cond_wait (player->cond, player->mutex);
+ if (player->pipeline == NULL)
+ return;
+ player->out = swfdec_buffer_new ();
+ player->out->data = g_memdup (buf->data, buf->size);
+ player->out->length = buf->size;
+ g_cond_signal (player->cond);
+ g_mutex_unlock (player->mutex);
+}
+
+static void
+do_the_link (GstElement *src, GstPad *pad, GstElement *sink)
+{
+ if (!gst_element_link (src, sink)) {
+ SWFDEC_ERROR ("no delayed link");
+ }
+}
+
+static gpointer
+swfdec_codec_gst_h263_init (void)
+{
+ SwfdecGstVideo *player;
+ GstElement *fakesrc, *fakesink, *decoder, *csp;
+ GstCaps *sinkcaps;
+
+ if (!gst_init_check (NULL, NULL, NULL))
+ return FALSE;
+
+ player = g_slice_new0 (SwfdecGstVideo);
+ player->pipeline = gst_pipeline_new ("pipeline");
+ player->refcount = 1;
+ g_assert (player->pipeline);
+ player->mutex = g_mutex_new ();
+ player->cond = g_cond_new ();
+ player->srccaps = gst_caps_from_string ("video/x-flash-video");
+ g_assert (player->srccaps);
+ fakesrc = gst_element_factory_make ("fakesrc", NULL);
+ if (fakesrc == NULL) {
+ SWFDEC_ERROR ("failed to create fakesrc");
+ swfdec_codec_gst_video_finish (player);
+ return NULL;
+ }
+ g_object_set (fakesrc, "signal-handoffs", TRUE,
+ "can-activate-pull", FALSE, NULL);
+ g_signal_connect (fakesrc, "handoff",
+ G_CALLBACK (swfdec_codec_gst_fakesrc_handoff), player);
+ g_atomic_int_inc (&player->refcount);
+ g_object_weak_ref (G_OBJECT (fakesrc), swfdec_gst_video_unref, player);
+ gst_bin_add (GST_BIN (player->pipeline), fakesrc);
+ fakesink = gst_element_factory_make ("fakesink", NULL);
+ if (fakesink == NULL) {
+ SWFDEC_ERROR ("failed to create fakesink");
+ swfdec_codec_gst_video_finish (player);
+ return NULL;
+ }
+ g_object_set (fakesink, "signal-handoffs", TRUE, NULL);
+ g_signal_connect (fakesink, "handoff",
+ G_CALLBACK (swfdec_codec_gst_fakesink_handoff), player);
+ g_atomic_int_inc (&player->refcount);
+ g_object_weak_ref (G_OBJECT (fakesink), swfdec_gst_video_unref, player);
+ gst_bin_add (GST_BIN (player->pipeline), fakesink);
+ decoder = gst_element_factory_make ("decodebin", NULL);
+ if (decoder == NULL) {
+ SWFDEC_ERROR ("failed to create decoder");
+ swfdec_codec_gst_video_finish (player);
+ return NULL;
+ }
+ gst_bin_add (GST_BIN (player->pipeline), decoder);
+ csp = gst_element_factory_make ("ffmpegcolorspace", NULL);
+ if (csp == NULL) {
+ SWFDEC_ERROR ("failed to create colorspace");
+ swfdec_codec_gst_video_finish (player);
+ return NULL;
+ }
+ gst_bin_add (GST_BIN (player->pipeline), csp);
+ g_signal_connect (decoder, "pad-added", G_CALLBACK (do_the_link), csp);
+
+ sinkcaps = gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
+ "red_mask=16711680, green_mask=65280, blue_mask=255");
+ g_assert (sinkcaps);
+ if (!gst_element_link_filtered (fakesrc, decoder, player->srccaps) ||
+#if 0
+ !gst_element_link (decoder, csp) ||
+#endif
+ !gst_element_link_filtered (csp, fakesink, sinkcaps)) {
+ SWFDEC_ERROR ("linking failed");
+ swfdec_codec_gst_video_finish (player);
+ return NULL;
+ }
+ gst_caps_unref (sinkcaps);
+ if (gst_element_set_state (player->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+ SWFDEC_ERROR ("failed to change sate");
+ swfdec_codec_gst_video_finish (player);
+ return NULL;
+ }
+
+ return player;
+}
+
+static gboolean
+swfdec_codec_gst_video_get_size (gpointer codec_data,
+ guint *width, guint *height)
+{
+ SwfdecGstVideo *player = codec_data;
+
+ g_mutex_lock (player->mutex);
+ if (player->width == 0 || player->height == 0) {
+ g_mutex_unlock (player->mutex);
+ return FALSE;
+ }
+ *width = player->width;
+ *height = player->height;
+ g_mutex_unlock (player->mutex);
+ return TRUE;
+}
+
+SwfdecBuffer *
+swfdec_codec_gst_video_decode (gpointer codec_data, SwfdecBuffer *buffer)
+{
+ SwfdecGstVideo *player = codec_data;
+
+ g_mutex_lock (player->mutex);
+ g_assert (player->in == NULL);
+ player->in = buffer;
+ while (player->out == NULL) {
+ swfdec_cond_wait (player->cond, player->mutex);
+ }
+ g_print ("processing buffer\n");
+ buffer = player->out;
+ player->out = NULL;
+ g_mutex_unlock (player->mutex);
+ return buffer;
+}
+
+const SwfdecVideoCodec swfdec_codec_gst_h263 = {
+ swfdec_codec_gst_h263_init,
+ swfdec_codec_gst_video_get_size,
+ swfdec_codec_gst_video_decode,
+ swfdec_codec_gst_video_finish
+};
+
More information about the Swfdec
mailing list