Benjamin Otte
2007-Apr-08 03:32 UTC
[Swfdec] libswfdec/swfdec_codec_audio.c libswfdec/swfdec_codec_gst.c
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@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, "
Maybe Matching Threads
- 6 commits - configure.ac libswfdec/swfdec_codec_audio.c libswfdec/swfdec_codec_gst.c libswfdec/swfdec_codec_video.c player/swfplay.c
- configure.ac libswfdec/Makefile.am libswfdec/swfdec_codec.c libswfdec/swfdec_codec_gst.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
- 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