From 47d2a13d48e1b227e0566be9386a0864a27dfdfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Wang?= Date: Thu, 12 Mar 2015 11:29:00 +0000 Subject: [PATCH] acm: Port ACM MP3 decoder and encoders to GStreamer 1.x https://bugzilla.gnome.org/show_bug.cgi?id=744047 --- configure.ac | 2 +- sys/acmenc/acmenc.c | 58 ++++++++++++++++++++++------------ sys/acmmp3dec/acmmp3dec.c | 65 ++++++++++++++++++++++++--------------- 3 files changed, 79 insertions(+), 46 deletions(-) diff --git a/configure.ac b/configure.ac index 18c4472feb..184e9b2f69 100644 --- a/configure.ac +++ b/configure.ac @@ -426,7 +426,7 @@ GST_PLUGINS_NONPORTED=" cdxaparse \ apexsink dc1394 \ gsettings \ musepack nas sdl timidity \ - acm wininet \ + wininet \ xvid lv2 sndio libvisual" AC_SUBST(GST_PLUGINS_NONPORTED) diff --git a/sys/acmenc/acmenc.c b/sys/acmenc/acmenc.c index 67f5efb347..601c93750c 100644 --- a/sys/acmenc/acmenc.c +++ b/sys/acmenc/acmenc.c @@ -50,7 +50,7 @@ GST_DEBUG_CATEGORY_STATIC (acmenc_debug); static GstStaticPadTemplate acmenc_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw-int, " + GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("audio/x-raw, " "depth = (int)16, " "width = (int)16, " "endianness = (int)" G_STRINGIFY (G_BYTE_ORDER) ", " @@ -106,7 +106,7 @@ static GstCaps * acmenc_caps_from_format (WAVEFORMATEX * fmt) { return gst_riff_create_audio_caps (fmt->wFormatTag, NULL, - (gst_riff_strf_auds *) fmt, NULL, NULL, NULL); + (gst_riff_strf_auds *) fmt, NULL, NULL, NULL, NULL); } static gboolean @@ -298,8 +298,18 @@ acmenc_push_output (ACMEnc * enc) GstFlowReturn ret = GST_FLOW_OK; if (enc->header.cbDstLengthUsed > 0) { GstBuffer *outbuf = gst_buffer_new_and_alloc (enc->header.cbDstLengthUsed); - memcpy (GST_BUFFER_DATA (outbuf), enc->header.pbDst, - enc->header.cbDstLengthUsed); + if (!outbuf) { + GST_WARNING_OBJECT (enc, "cannot allocate a new GstBuffer"); + goto done_push_output; + } + + if (gst_buffer_fill (outbuf, 0, enc->header.pbDst, + enc->header.cbDstLengthUsed) != enc->header.cbDstLengthUsed) { + gst_buffer_unref (outbuf); + GST_WARNING_OBJECT (enc, "unable to fill output buffer"); + goto done_push_output; + } + if (enc->outfmt->nAvgBytesPerSec > 0) { /* We have a bitrate, so we can create a timestamp, hopefully */ @@ -312,18 +322,24 @@ acmenc_push_output (ACMEnc * enc) enc->header.cbDstLengthUsed); ret = gst_pad_push (enc->srcpad, outbuf); } + +done_push_output: return ret; } static GstFlowReturn -acmenc_chain (GstPad * pad, GstBuffer * buf) +acmenc_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { MMRESULT res; ACMEnc *enc = (ACMEnc *) GST_PAD_PARENT (pad); - guchar *data = GST_BUFFER_DATA (buf); - gint len = GST_BUFFER_SIZE (buf); + GstMapInfo map; + guchar *data; + gint len; int chunklen; GstFlowReturn ret = GST_FLOW_OK; + gst_buffer_map (buf, &map, GST_MAP_READ); + len = map.size; + data = map.data; while (len) { chunklen = MIN (len, ACM_BUFFER_SIZE - enc->offset); memcpy (enc->header.pbSrc + enc->offset, data, chunklen); @@ -356,6 +372,7 @@ acmenc_chain (GstPad * pad, GstBuffer * buf) /* Write out any data produced */ acmenc_push_output (enc); } + gst_buffer_unmap (buf, &map); return ret; } @@ -381,11 +398,17 @@ acmenc_finish_stream (ACMEnc * enc) } static gboolean -acmenc_sink_event (GstPad * pad, GstEvent * event) +acmenc_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { ACMEnc *enc = (ACMEnc *) GST_PAD_PARENT (pad); gboolean res; switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS:{ + GstCaps *caps; + gst_event_parse_caps (event, &caps); + return acmenc_sink_setcaps (pad, caps); + break; + } case GST_EVENT_EOS: acmenc_finish_stream (enc); res = gst_pad_push_event (enc->srcpad, event); @@ -409,8 +432,6 @@ acmenc_init (ACMEnc * enc) { enc->sinkpad = gst_pad_new_from_static_template (&acmenc_sink_template, "sink"); - gst_pad_set_setcaps_function (enc->sinkpad, - GST_DEBUG_FUNCPTR (acmenc_sink_setcaps)); gst_pad_set_chain_function (enc->sinkpad, GST_DEBUG_FUNCPTR (acmenc_chain)); gst_pad_set_event_function (enc->sinkpad, GST_DEBUG_FUNCPTR (acmenc_sink_event)); @@ -451,6 +472,12 @@ static void acmenc_class_init (ACMEncClass * klass) { GObjectClass *gobjectclass = (GObjectClass *) klass; + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + ACMEncParams *params; + ACMDRIVERDETAILS driverdetails; + gchar *shortname, *longname, *detail, *description; + MMRESULT res; + parent_class = (GstElementClass *) g_type_class_peek_parent (klass); gobjectclass->dispose = acmenc_dispose; gobjectclass->set_property = acmenc_set_property; @@ -458,15 +485,6 @@ acmenc_class_init (ACMEncClass * klass) g_object_class_install_property (gobjectclass, ARG_BITRATE, g_param_spec_int ("bitrate", "Bitrate", "Bitrate to encode at (in bps)", 0, 1000000, DEFAULT_BITRATE, G_PARAM_READWRITE)); -} static void - -acmenc_base_init (ACMEncClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - ACMEncParams *params; - ACMDRIVERDETAILS driverdetails; - gchar *shortname, *longname, *detail, *description; - MMRESULT res; gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&acmenc_sink_template)); @@ -545,7 +563,7 @@ acmenc_register_file (GstPlugin * plugin, wchar_t * filename) GType type; GTypeInfo typeinfo = { sizeof (ACMEncClass), - (GBaseInitFunc) acmenc_base_init, NULL, + NULL, NULL, (GClassInitFunc) acmenc_class_init, NULL, NULL, sizeof (ACMEnc), 0, (GInstanceInitFunc) acmenc_init, }; diff --git a/sys/acmmp3dec/acmmp3dec.c b/sys/acmmp3dec/acmmp3dec.c index 737d4a001d..a0b9c36a67 100644 --- a/sys/acmmp3dec/acmmp3dec.c +++ b/sys/acmmp3dec/acmmp3dec.c @@ -36,6 +36,12 @@ (acmmp3dec_get_type()) #define GST_ACM_MP3_DEC(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ACM_MP3_DEC,ACMMP3Dec)) +#define GST_ACM_MP3_DEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ACM_MP3_DEC,ACMMP3DecClass)) +#define GST_IS_ACM_MP3_DEC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ACM_MP3_DEC)) +#define GST_IS_ACM_MP3_DEC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ACM_MP3_DEC)) #define GST_CAT_DEFAULT acmmp3dec_debug GST_DEBUG_CATEGORY_STATIC (acmmp3dec_debug); @@ -44,7 +50,7 @@ static GstStaticPadTemplate acmmp3dec_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " + GST_STATIC_CAPS ("audio/x-raw, " "depth = (int)16, " "width = (int)16, " "endianness = (int)" G_STRINGIFY (G_BYTE_ORDER) ", " @@ -96,13 +102,14 @@ typedef struct _ACMMP3Dec GType acmmp3dec_get_type (void); -GST_BOILERPLATE (ACMMP3Dec, acmmp3dec, GstElement, GST_TYPE_ELEMENT); +#define acmmp3dec_parent_class parent_class +G_DEFINE_TYPE (ACMMP3Dec, acmmp3dec, GST_TYPE_ELEMENT); static GstCaps * acmmp3dec_caps_from_format (WAVEFORMATEX * fmt) { return gst_riff_create_audio_caps (fmt->wFormatTag, - NULL, (gst_riff_strf_auds *) fmt, NULL, NULL, NULL); + NULL, (gst_riff_strf_auds *) fmt, NULL, NULL, NULL, NULL); } static gboolean @@ -239,21 +246,28 @@ acmmp3dec_push_output (ACMMP3Dec * dec) if (dec->header.cbDstLengthUsed > 0) { GstBuffer *outbuf = gst_buffer_new_and_alloc (dec->header.cbDstLengthUsed); - memcpy (GST_BUFFER_DATA (outbuf), dec->header.pbDst, - dec->header.cbDstLengthUsed); + if (!outbuf) { + GST_WARNING_OBJECT (dec, "cannot allocate a new GstBuffer"); + goto done_push_output; + } + + if (gst_buffer_fill (outbuf, 0, dec->header.pbDst, + dec->header.cbDstLengthUsed) != dec->header.cbDstLengthUsed) { + gst_buffer_unref (outbuf); + GST_WARNING_OBJECT (dec, "unable to fill output buffer"); + goto done_push_output; + } if (dec->timestamp != GST_CLOCK_TIME_NONE) GST_BUFFER_TIMESTAMP (outbuf) = dec->timestamp; GST_BUFFER_DURATION (outbuf) = - gst_util_uint64_scale_int (GST_BUFFER_SIZE (outbuf), GST_SECOND, + gst_util_uint64_scale_int (dec->header.cbDstLengthUsed, GST_SECOND, dec->rate * dec->channels * 2); GST_DEBUG_OBJECT (dec, "decoded buffer has ts %d, duration %d", (int) (GST_BUFFER_TIMESTAMP (outbuf)), (int) (GST_BUFFER_DURATION (outbuf))); - gst_buffer_set_caps (outbuf, dec->output_caps); - if (dec->timestamp != GST_CLOCK_TIME_NONE) dec->timestamp += GST_BUFFER_DURATION (outbuf); @@ -263,20 +277,21 @@ acmmp3dec_push_output (ACMMP3Dec * dec) } else GST_DEBUG_OBJECT (dec, "Not pushing decoded buffer, no output"); - +done_push_output: return ret; } static GstFlowReturn -acmmp3dec_chain (GstPad * pad, GstBuffer * buf) +acmmp3dec_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) { MMRESULT res; ACMMP3Dec *dec = (ACMMP3Dec *) GST_PAD_PARENT (pad); - guchar *data = GST_BUFFER_DATA (buf); - gint len = GST_BUFFER_SIZE (buf); + GstMapInfo map; GstFlowReturn ret = GST_FLOW_OK; - if (len > ACM_BUFFER_SIZE) { + gst_buffer_map (buf, &map, GST_MAP_READ); + + if (map.size > ACM_BUFFER_SIZE) { GST_WARNING_OBJECT (dec, "Impossibly large mp3 frame!"); ret = GST_FLOW_ERROR; goto done; @@ -288,8 +303,8 @@ acmmp3dec_chain (GstPad * pad, GstBuffer * buf) dec->timestamp = GST_BUFFER_TIMESTAMP (buf); } - memcpy (dec->header.pbSrc, data, len); - dec->header.cbSrcLength = len; + memcpy (dec->header.pbSrc, map.data, map.size); + dec->header.cbSrcLength = map.size; /* Now we have a buffer ready to go */ res = acmStreamConvert (dec->stream, &dec->header, @@ -314,6 +329,7 @@ acmmp3dec_chain (GstPad * pad, GstBuffer * buf) } done: + gst_buffer_unmap (buf, &map); gst_buffer_unref (buf); return ret; @@ -340,11 +356,17 @@ acmmp3dec_finish_stream (ACMMP3Dec * dec) } static gboolean -acmmp3dec_sink_event (GstPad * pad, GstEvent * event) +acmmp3dec_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { ACMMP3Dec *dec = (ACMMP3Dec *) GST_PAD_PARENT (pad); switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS:{ + GstCaps *caps; + gst_event_parse_caps (event, &caps); + return acmmp3dec_sink_setcaps (pad, caps); + break; + } case GST_EVENT_EOS: acmmp3dec_finish_stream (dec); break; @@ -373,12 +395,10 @@ acmmp3dec_dispose (GObject * obj) } static void -acmmp3dec_init (ACMMP3Dec * dec, ACMMP3DecClass * decclass) +acmmp3dec_init (ACMMP3Dec * dec) { dec->sinkpad = gst_pad_new_from_static_template (&acmmp3dec_sink_template, "sink"); - gst_pad_set_setcaps_function (dec->sinkpad, - GST_DEBUG_FUNCPTR (acmmp3dec_sink_setcaps)); gst_pad_set_chain_function (dec->sinkpad, GST_DEBUG_FUNCPTR (acmmp3dec_chain)); gst_pad_set_event_function (dec->sinkpad, @@ -395,13 +415,8 @@ static void acmmp3dec_class_init (ACMMP3DecClass * klass) { GObjectClass *gobjectclass = (GObjectClass *) klass; - gobjectclass->dispose = acmmp3dec_dispose; -} - -static void -acmmp3dec_base_init (gpointer klass) -{ GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + gobjectclass->dispose = acmmp3dec_dispose; gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&acmmp3dec_sink_template));