Benjamin Otte
2007-Apr-05 07:45 UTC
[Swfdec] configure.ac libswfdec/Makefile.am libswfdec/swfdec_codec.c libswfdec/swfdec_codec_gst.c
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@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-@SWFDEC_MAJORMINOR@.la @@ -86,13 +89,14 @@ libswfdec_@SWFDEC_MAJORMINOR@_la_SOURCES libswfdec_@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_@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@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 +}; +
Possibly Parallel Threads
- 3 commits - libswfdec-gtk/swfdec_gtk_loader.c libswfdec/Makefile.am libswfdec/swfdec_codec.c libswfdec/swfdec_codec_ffmpeg.c libswfdec/swfdec_codec_gst.c libswfdec/swfdec_codec.h libswfdec/swfdec_codec_screen.c libswfdec/swfdec_codec_video.c
- 4 commits - libswfdec/swfdec_audio_flv.c libswfdec/swfdec_audio_stream.c libswfdec/swfdec_codec_adpcm.c libswfdec/swfdec_codec.c libswfdec/swfdec_codec_ffmpeg.c libswfdec/swfdec_codec_gst.c libswfdec/swfdec_codec.h libswfdec/swfdec_codec_mad.c
- libswfdec/swfdec_codec_audio.c libswfdec/swfdec_codec_gst.c
- 6 commits - configure.ac libswfdec/swfdec_codec_audio.c libswfdec/swfdec_codec_gst.c libswfdec/swfdec_codec_video.c player/swfplay.c
- 9 commits - libswfdec/swfdec_as_context.c libswfdec/swfdec_as_frame.c libswfdec/swfdec_as_frame_internal.h libswfdec/swfdec_as_object.c libswfdec/swfdec_codec_gst.c test/trace