[Swfdec] libswfdec/swfdec_codec_audio.c libswfdec/swfdec_codec_gst.c
Benjamin Otte
company at kemper.freedesktop.org
Sun Apr 8 03:32:48 PDT 2007
libswfdec/swfdec_codec_audio.c | 8 -
libswfdec/swfdec_codec_gst.c | 271 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 270 insertions(+), 9 deletions(-)
New commits:
diff-tree 68a17dfade3397478342d4c88fa9b9e3dc13f329 (from 01bf0e400ee99da0e96707f606d41bb23d5a8b48)
Author: Benjamin Otte <otte at gnome.org>
Date: Sun Apr 8 12:32:39 2007 +0200
make GStreamer do MP3 audio
diff --git a/libswfdec/swfdec_codec_audio.c b/libswfdec/swfdec_codec_audio.c
index b5d00fb..9bd091c 100644
--- a/libswfdec/swfdec_codec_audio.c
+++ b/libswfdec/swfdec_codec_audio.c
@@ -118,6 +118,10 @@ extern SwfdecAudioDecoderNewFunc swfdec_
extern SwfdecAudioDecoderNewFunc swfdec_audio_decoder_ffmpeg_new;
#endif
+#ifdef HAVE_FFMPEG
+extern SwfdecAudioDecoderNewFunc swfdec_audio_decoder_gst_new;
+#endif
+
/*** PUBLIC API ***/
/**
@@ -137,6 +141,7 @@ swfdec_audio_decoder_new (SwfdecAudioFor
ret = swfdec_audio_decoder_uncompressed_new (format, width, data_format);
if (ret == NULL)
ret = swfdec_audio_decoder_adpcm_new (format, width, data_format);
+#if 0
#ifdef HAVE_MAD
if (ret == NULL)
ret = swfdec_audio_decoder_mad_new (format, width, data_format);
@@ -145,12 +150,11 @@ swfdec_audio_decoder_new (SwfdecAudioFor
if (ret == NULL)
ret = swfdec_audio_decoder_ffmpeg_new (format, width, data_format);
#endif
-#if 0
+#endif
#ifdef HAVE_GST
if (ret == NULL)
ret = swfdec_audio_decoder_gst_new (format, width, data_format);
#endif
-#endif
if (ret) {
ret->format = format;
g_return_val_if_fail (ret->out_format != 0, NULL);
diff --git a/libswfdec/swfdec_codec_gst.c b/libswfdec/swfdec_codec_gst.c
index cd4f517..64c335c 100644
--- a/libswfdec/swfdec_codec_gst.c
+++ b/libswfdec/swfdec_codec_gst.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <gst/gst.h>
+#include "swfdec_codec_audio.h"
#include "swfdec_codec_video.h"
#include "swfdec_debug.h"
@@ -36,6 +37,262 @@
#define swfdec_cond_wait g_cond_wait
#endif
+/*** AUDIO ***/
+
+typedef struct _SwfdecGstAudio SwfdecGstAudio;
+struct _SwfdecGstAudio {
+ SwfdecAudioDecoder decoder;
+
+ 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 */
+ SwfdecBufferQueue * out; /* all the stored output buffers */
+ GstCaps * srccaps; /* caps to set on buffers */
+ gboolean eof; /* we've pushed EOF */
+ gboolean done; /* TRUE after decoding stopped (error or EOF) */
+};
+
+static void
+swfdec_gst_audio_unref (gpointer data, GObject *unused)
+{
+ SwfdecGstAudio *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);
+ swfdec_buffer_queue_unref (player->out);
+ g_slice_free (SwfdecGstAudio, player);
+}
+
+static void
+swfdec_audio_decoder_gst_free (SwfdecAudioDecoder *dec)
+{
+ SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
+ 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_audio_unref (player, NULL);
+}
+
+static void
+swfdec_audio_decoder_gst_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
+{
+ SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
+
+ g_mutex_lock (player->mutex);
+ g_return_if_fail (!player->eof);
+ while (player->in != NULL && !player->done) {
+ swfdec_cond_wait (player->cond, player->mutex);
+ }
+ if (buffer) {
+ player->in = buffer;
+ } else {
+ player->eof = TRUE;
+ }
+ g_cond_signal (player->cond);
+ g_mutex_unlock (player->mutex);
+}
+
+static SwfdecBuffer *
+swfdec_audio_decoder_gst_pull (SwfdecAudioDecoder *dec)
+{
+ SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
+ SwfdecBuffer *buffer;
+
+ g_mutex_lock (player->mutex);
+ if (player->eof) {
+ while (!player->done)
+ swfdec_cond_wait (player->cond, player->mutex);
+ }
+ buffer = swfdec_buffer_queue_pull_buffer (player->out);
+ g_mutex_unlock (player->mutex);
+ return buffer;
+}
+
+static void
+swfdec_audio_decoder_gst_fakesrc_handoff (GstElement *fakesrc, GstBuffer *buf,
+ GstPad *pad, SwfdecGstAudio *player)
+{
+ g_mutex_lock (player->mutex);
+ while (player->pipeline != NULL && player->in == NULL && player->eof == FALSE)
+ swfdec_cond_wait (player->cond, player->mutex);
+ if (player->pipeline == NULL) {
+ g_mutex_unlock (player->mutex);
+ return;
+ }
+ if (player->eof) {
+ //doesn't work: g_object_set (fakesrc, "num-buffers", 1, NULL);
+ /* HACK: just tell everyone we're done, that'll probably lose data in the
+ * gst stream, since we can't properly push EOF, but that's life... */
+ player->done = TRUE;
+ }
+ if (player->in) {
+ buf->data = g_memdup (player->in->data, player->in->length);
+ buf->malloc_data = buf->data;
+ 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_audio_decoder_gst_fakesink_handoff (GstElement *fakesrc, GstBuffer *buf,
+ GstPad *pad, SwfdecGstAudio *player)
+{
+ SwfdecBuffer *buffer;
+
+ g_mutex_lock (player->mutex);
+
+ while (player->pipeline == NULL && player->out != NULL)
+ swfdec_cond_wait (player->cond, player->mutex);
+ buffer = swfdec_buffer_new_for_data (
+ g_memdup (buf->data, buf->size), buf->size);
+ swfdec_buffer_queue_push (player->out, buffer);
+ g_cond_signal (player->cond);
+ g_mutex_unlock (player->mutex);
+}
+
+static void
+swfdec_audio_decoder_gst_link (GstElement *src, GstPad *pad, GstElement *sink)
+{
+ if (!gst_element_link (src, sink)) {
+ SWFDEC_ERROR ("no delayed link");
+ }
+}
+
+GstBusSyncReply
+swfdec_audio_decoder_gst_handle_bus (GstBus *bus, GstMessage *message, gpointer data)
+{
+ SwfdecGstAudio *player = data;
+
+ switch (message->type) {
+ case GST_MESSAGE_EOS:
+ case GST_MESSAGE_ERROR:
+ g_mutex_lock (player->mutex);
+ g_cond_signal (player->cond);
+ player->done = TRUE;
+ g_mutex_unlock (player->mutex);
+ break;
+ default:
+ break;
+ }
+ return GST_BUS_PASS;
+}
+
+SwfdecAudioDecoder *
+swfdec_audio_decoder_gst_new (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format)
+{
+ SwfdecGstAudio *player;
+ GstElement *fakesrc, *fakesink, *decoder, *convert;
+ GstBus *bus;
+ GstCaps *caps;
+
+ if (!gst_init_check (NULL, NULL, NULL))
+ return NULL;
+
+ switch (type) {
+ case SWFDEC_AUDIO_FORMAT_MP3:
+ caps = gst_caps_from_string ("audio/mpeg, mpegversion=(int)1, layer=(int)3");
+ break;
+ default:
+ return NULL;
+ }
+ g_assert (caps);
+
+ player = g_slice_new0 (SwfdecGstAudio);
+ player->decoder.out_format = SWFDEC_AUDIO_OUT_STEREO_44100;
+ player->decoder.pull = swfdec_audio_decoder_gst_pull;
+ player->decoder.push = swfdec_audio_decoder_gst_push;
+ player->decoder.free = swfdec_audio_decoder_gst_free;
+ player->pipeline = gst_pipeline_new ("pipeline");
+ player->refcount = 1;
+ g_assert (player->pipeline);
+ bus = gst_element_get_bus (player->pipeline);
+ g_atomic_int_inc (&player->refcount);
+ g_object_weak_ref (G_OBJECT (bus), swfdec_gst_audio_unref, player);
+ gst_bus_set_sync_handler (bus, swfdec_audio_decoder_gst_handle_bus, player);
+ player->mutex = g_mutex_new ();
+ player->cond = g_cond_new ();
+ player->out = swfdec_buffer_queue_new ();
+ player->srccaps = caps;
+ fakesrc = gst_element_factory_make ("fakesrc", NULL);
+ if (fakesrc == NULL) {
+ SWFDEC_ERROR ("failed to create fakesrc");
+ swfdec_audio_decoder_gst_free (&player->decoder);
+ return NULL;
+ }
+ g_object_set (fakesrc, "signal-handoffs", TRUE,
+ "can-activate-pull", FALSE, NULL);
+ g_signal_connect (fakesrc, "handoff",
+ G_CALLBACK (swfdec_audio_decoder_gst_fakesrc_handoff), player);
+ g_atomic_int_inc (&player->refcount);
+ g_object_weak_ref (G_OBJECT (fakesrc), swfdec_gst_audio_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_audio_decoder_gst_free (&player->decoder);
+ return NULL;
+ }
+ g_object_set (fakesink, "signal-handoffs", TRUE, NULL);
+ g_signal_connect (fakesink, "handoff",
+ G_CALLBACK (swfdec_audio_decoder_gst_fakesink_handoff), player);
+ g_atomic_int_inc (&player->refcount);
+ g_object_weak_ref (G_OBJECT (fakesink), swfdec_gst_audio_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_audio_decoder_gst_free (&player->decoder);
+ return NULL;
+ }
+ gst_bin_add (GST_BIN (player->pipeline), decoder);
+ convert = gst_element_factory_make ("audioconvert", NULL);
+ if (convert == NULL) {
+ SWFDEC_ERROR ("failed to create audioconvert");
+ swfdec_audio_decoder_gst_free (&player->decoder);
+ return NULL;
+ }
+ gst_bin_add (GST_BIN (player->pipeline), convert);
+ g_signal_connect (decoder, "pad-added",
+ G_CALLBACK (swfdec_audio_decoder_gst_link), convert);
+
+ caps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, rate=44100, channels=2");
+ g_assert (caps);
+ if (!gst_element_link_filtered (fakesrc, decoder, player->srccaps) ||
+ !gst_element_link_filtered (convert, fakesink, caps)) {
+ SWFDEC_ERROR ("linking failed");
+ swfdec_audio_decoder_gst_free (&player->decoder);
+ return NULL;
+ }
+ gst_caps_unref (caps);
+ if (gst_element_set_state (player->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
+ SWFDEC_ERROR ("failed to change sate");
+ swfdec_audio_decoder_gst_free (&player->decoder);
+ return NULL;
+ }
+
+ return &player->decoder;
+}
+
+/*** VIDEO ***/
+
typedef struct _SwfdecGstVideo SwfdecGstVideo;
struct _SwfdecGstVideo {
SwfdecVideoDecoder decoder;
@@ -88,7 +345,7 @@ swfdec_video_decoder_gst_free (SwfdecVid
swfdec_gst_video_unref (player, NULL);
}
-SwfdecBuffer *
+static SwfdecBuffer *
swfdec_video_decoder_gst_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffer,
guint *width, guint *height, guint *rowstride)
{
@@ -117,7 +374,7 @@ swfdec_video_decoder_gst_decode (SwfdecV
}
static void
-swfdec_codec_gst_fakesrc_handoff (GstElement *fakesrc, GstBuffer *buf,
+swfdec_video_decoder_gst_fakesrc_handoff (GstElement *fakesrc, GstBuffer *buf,
GstPad *pad, SwfdecGstVideo *player)
{
g_mutex_lock (player->mutex);
@@ -144,7 +401,7 @@ swfdec_codec_gst_fakesrc_handoff (GstEle
}
static void
-swfdec_codec_gst_fakesink_handoff (GstElement *fakesrc, GstBuffer *buf,
+swfdec_video_decoder_gst_fakesink_handoff (GstElement *fakesrc, GstBuffer *buf,
GstPad *pad, SwfdecGstVideo *player)
{
GstCaps *caps;
@@ -180,7 +437,7 @@ swfdec_codec_gst_fakesink_handoff (GstEl
}
static void
-swfdec_codec_gst_do_link (GstElement *src, GstPad *pad, GstElement *sink)
+swfdec_video_decoder_gst_link (GstElement *src, GstPad *pad, GstElement *sink)
{
if (!gst_element_link (src, sink)) {
SWFDEC_ERROR ("no delayed link");
@@ -227,7 +484,7 @@ swfdec_video_decoder_gst_new (SwfdecVide
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_CALLBACK (swfdec_video_decoder_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);
@@ -239,7 +496,7 @@ swfdec_video_decoder_gst_new (SwfdecVide
}
g_object_set (fakesink, "signal-handoffs", TRUE, NULL);
g_signal_connect (fakesink, "handoff",
- G_CALLBACK (swfdec_codec_gst_fakesink_handoff), player);
+ G_CALLBACK (swfdec_video_decoder_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);
@@ -258,7 +515,7 @@ swfdec_video_decoder_gst_new (SwfdecVide
}
gst_bin_add (GST_BIN (player->pipeline), csp);
g_signal_connect (decoder, "pad-added",
- G_CALLBACK (swfdec_codec_gst_do_link), csp);
+ G_CALLBACK (swfdec_video_decoder_gst_link), csp);
#if G_BYTE_ORDER == G_BIG_ENDIAN
caps = gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
More information about the Swfdec
mailing list