From 4a44dc5ecfe7b5d375ef7df6ff418b82812f688e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 19 Mar 2013 10:14:05 +0100 Subject: [PATCH] port wildmidi Fixes https://bugzilla.gnome.org/show_bug.cgi?id=696041 --- configure.ac | 2 +- ext/timidity/gstwildmidi.c | 236 ++++++++++++++++++++----------------- 2 files changed, 129 insertions(+), 109 deletions(-) diff --git a/configure.ac b/configure.ac index 68a439b28b..62cfc88635 100644 --- a/configure.ac +++ b/configure.ac @@ -328,7 +328,7 @@ GST_PLUGINS_NONPORTED=" aiff \ gsettings ladspa \ musepack musicbrainz nas neon ofa openal rsvg sdl sndfile timidity \ directdraw direct3d9 acm wininet \ - wildmidi xvid lv2 teletextdec sndio wasapi" + xvid lv2 teletextdec sndio wasapi" AC_SUBST(GST_PLUGINS_NONPORTED) dnl these are all the gst plug-ins, compilable without additional libs diff --git a/ext/timidity/gstwildmidi.c b/ext/timidity/gstwildmidi.c index 1ae642b809..5efc0675c8 100644 --- a/ext/timidity/gstwildmidi.c +++ b/ext/timidity/gstwildmidi.c @@ -32,16 +32,12 @@ * * Example pipeline * |[ - * gst-launch filesrc location=song.mid ! wildmidi ! alsasink + * gst-launch-1.0 filesrc location=song.mid ! wildmidi ! alsasink * ]| This example pipeline will parse the midi and render to raw audio which is * played via alsa. * */ -/* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex - * with newer GLib versions (>= 2.31.0) */ -#define GLIB_DISABLE_DEPRECATION_WARNINGS - #ifdef HAVE_CONFIG_H # include #endif @@ -84,18 +80,23 @@ enum static void gst_wildmidi_finalize (GObject * object); -static gboolean gst_wildmidi_sink_event (GstPad * pad, GstEvent * event); -static gboolean gst_wildmidi_src_event (GstPad * pad, GstEvent * event); +static gboolean gst_wildmidi_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); +static gboolean gst_wildmidi_src_event (GstPad * pad, GstObject * parent, + GstEvent * event); static GstStateChangeReturn gst_wildmidi_change_state (GstElement * element, GstStateChange transition); -static gboolean gst_wildmidi_activate (GstPad * pad); -static gboolean gst_wildmidi_activatepull (GstPad * pad, gboolean active); +static gboolean gst_wildmidi_activate (GstPad * pad, GstObject * parent); +static gboolean gst_wildmidi_activatemode (GstPad * pad, GstObject * parent, + GstPadMode mode, gboolean active); static void gst_wildmidi_loop (GstPad * sinkpad); -static GstFlowReturn gst_wildmidi_chain (GstPad * sinkpad, GstBuffer * buffer); +static GstFlowReturn gst_wildmidi_chain (GstPad * sinkpad, GstObject * parent, + GstBuffer * buffer); -static gboolean gst_wildmidi_src_query (GstPad * pad, GstQuery * query); +static gboolean gst_wildmidi_src_query (GstPad * pad, GstObject * parent, + GstQuery * query); static void gst_wildmidi_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); @@ -111,27 +112,13 @@ static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("audio/x-raw-int, " + GST_STATIC_CAPS ("audio/x-raw, " + "format = (string) S16LE, " "rate = (int) 44100, " - "channels = (int) 2, " - "endianness = (int) LITTLE_ENDIAN, " - "width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true")); + "channels = (int) 2, " "layout = (string) interleaved")); -GST_BOILERPLATE (GstWildmidi, gst_wildmidi, GstElement, GST_TYPE_ELEMENT); - -static void -gst_wildmidi_base_init (gpointer gclass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); - - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&src_factory)); - gst_element_class_add_pad_template (element_class, - gst_static_pad_template_get (&sink_factory)); - gst_element_class_set_static_metadata (element_class, "WildMidi", - "Codec/Decoder/Audio", - "Midi Synthesizer Element", "Wouter Paesen "); -} +#define parent_class gst_wildmidi_parent_class +G_DEFINE_TYPE (GstWildmidi, gst_wildmidi, GST_TYPE_ELEMENT); static gboolean wildmidi_open_config (void) @@ -252,6 +239,14 @@ gst_wildmidi_class_init (GstWildmidiClass * klass) "High Quality", DEFAULT_HIGH_QUALITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_factory)); + gst_element_class_set_static_metadata (gstelement_class, "WildMidi", + "Codec/Decoder/Audio", + "Midi Synthesizer Element", "Wouter Paesen "); + gstelement_class->change_state = gst_wildmidi_change_state; } @@ -261,24 +256,18 @@ gst_wildmidi_class_init (GstWildmidiClass * klass) * initialize structure */ static void -gst_wildmidi_init (GstWildmidi * filter, GstWildmidiClass * g_class) +gst_wildmidi_init (GstWildmidi * filter) { - GstElementClass *klass = GST_ELEMENT_GET_CLASS (filter); + filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); - filter->sinkpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "sink"), "sink"); - - gst_pad_set_activatepull_function (filter->sinkpad, - gst_wildmidi_activatepull); + gst_pad_set_activatemode_function (filter->sinkpad, + gst_wildmidi_activatemode); gst_pad_set_activate_function (filter->sinkpad, gst_wildmidi_activate); gst_pad_set_event_function (filter->sinkpad, gst_wildmidi_sink_event); gst_pad_set_chain_function (filter->sinkpad, gst_wildmidi_chain); gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); - filter->srcpad = - gst_pad_new_from_template (gst_element_class_get_pad_template (klass, - "src"), "src"); + filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); gst_pad_set_query_function (filter->srcpad, gst_wildmidi_src_query); gst_pad_set_event_function (filter->srcpad, gst_wildmidi_src_event); @@ -357,17 +346,15 @@ done: } static gboolean -gst_wildmidi_src_query (GstPad * pad, GstQuery * query) +gst_wildmidi_src_query (GstPad * pad, GstObject * parent, GstQuery * query) { gboolean res = TRUE; - GstWildmidi *wildmidi = GST_WILDMIDI (gst_pad_get_parent (pad)); + GstWildmidi *wildmidi = GST_WILDMIDI (parent); GstFormat src_format, dst_format; gint64 src_value, dst_value; - if (!wildmidi->song) { - gst_object_unref (wildmidi); + if (!wildmidi->song) return FALSE; - } switch (GST_QUERY_TYPE (query)) { case GST_QUERY_DURATION: @@ -377,7 +364,7 @@ gst_wildmidi_src_query (GstPad * pad, GstQuery * query) break; case GST_QUERY_POSITION: gst_query_set_position (query, GST_FORMAT_TIME, - gst_util_uint64_scale_int (wildmidi->o_segment->last_stop, GST_SECOND, + gst_util_uint64_scale_int (wildmidi->o_segment->position, GST_SECOND, WILDMIDI_RATE)); break; case GST_QUERY_CONVERT: @@ -410,7 +397,6 @@ gst_wildmidi_src_query (GstPad * pad, GstQuery * query) break; } - gst_object_unref (wildmidi); return res; } @@ -418,12 +404,13 @@ static GstEvent * gst_wildmidi_get_new_segment_event (GstWildmidi * wildmidi, GstFormat format) { gint64 start, stop, time; - GstSegment *segment; + GstSegment *segment, newseg; GstEvent *event; GstFormat src_format; segment = wildmidi->o_segment; src_format = segment->format; + newseg = *segment; /* convert the segment values to the target format */ gst_wildmidi_src_convert (wildmidi, src_format, segment->start, &format, @@ -433,8 +420,12 @@ gst_wildmidi_get_new_segment_event (GstWildmidi * wildmidi, GstFormat format) gst_wildmidi_src_convert (wildmidi, src_format, segment->time, &format, &time); - event = gst_event_new_new_segment_full (FALSE, - segment->rate, segment->applied_rate, format, start, stop, time); + newseg.format = format; + newseg.start = start; + newseg.stop = stop; + newseg.time = time; + + event = gst_event_new_segment (&newseg); return event; } @@ -495,15 +486,15 @@ gst_wildmidi_do_seek (GstWildmidi * wildmidi, GstEvent * event) GST_PAD_STREAM_LOCK (wildmidi->sinkpad); if (flush) { - gst_pad_push_event (wildmidi->srcpad, gst_event_new_flush_stop ()); + gst_pad_push_event (wildmidi->srcpad, gst_event_new_flush_stop (TRUE)); } /* update the segment now */ - gst_segment_set_seek (segment, rate, dst_format, flags, + gst_segment_do_seek (segment, rate, dst_format, flags, start_type, start, stop_type, stop, &update); - /* we need to seek to last_stop in the segment now, sample will be updated */ - sample = segment->last_stop; + /* we need to seek to position in the segment now, sample will be updated */ + sample = segment->position; GST_OBJECT_LOCK (wildmidi); #ifdef HAVE_WILDMIDI_0_2_2 @@ -518,7 +509,7 @@ gst_wildmidi_do_seek (GstWildmidi * wildmidi, GstEvent * event) GST_OBJECT_UNLOCK (wildmidi); - segment->start = segment->time = segment->last_stop = sample; + segment->start = segment->time = segment->position = sample; gst_pad_push_event (wildmidi->srcpad, gst_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME)); @@ -534,10 +525,10 @@ gst_wildmidi_do_seek (GstWildmidi * wildmidi, GstEvent * event) } static gboolean -gst_wildmidi_src_event (GstPad * pad, GstEvent * event) +gst_wildmidi_src_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = FALSE; - GstWildmidi *wildmidi = GST_WILDMIDI (gst_pad_get_parent (pad)); + GstWildmidi *wildmidi = GST_WILDMIDI (parent); GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event)); @@ -549,38 +540,71 @@ gst_wildmidi_src_event (GstPad * pad, GstEvent * event) break; } - g_object_unref (wildmidi); return res; } static gboolean -gst_wildmidi_activate (GstPad * sinkpad) +gst_wildmidi_activate (GstPad * sinkpad, GstObject * parent) { - if (gst_pad_check_pull_range (sinkpad)) - return gst_pad_activate_pull (sinkpad, TRUE); + GstQuery *query; + gboolean pull_mode; - return gst_pad_activate_push (sinkpad, TRUE); + query = gst_query_new_scheduling (); + + if (!gst_pad_peer_query (sinkpad, query)) { + gst_query_unref (query); + goto activate_push; + } + + pull_mode = gst_query_has_scheduling_mode_with_flags (query, + GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE); + gst_query_unref (query); + + if (!pull_mode) + goto activate_push; + + GST_DEBUG_OBJECT (sinkpad, "activating pull"); + return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE); + +activate_push: + { + GST_DEBUG_OBJECT (sinkpad, "activating push"); + return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE); + } } static gboolean -gst_wildmidi_activatepull (GstPad * pad, gboolean active) +gst_wildmidi_activatemode (GstPad * pad, GstObject * parent, + GstPadMode mode, gboolean active) { - if (active) { - return gst_pad_start_task (pad, (GstTaskFunction) gst_wildmidi_loop, pad, - NULL); - } else { - return gst_pad_stop_task (pad); + gboolean res; + + switch (mode) { + case GST_PAD_MODE_PUSH: + res = TRUE; + break; + case GST_PAD_MODE_PULL: + if (active) { + res = gst_pad_start_task (pad, (GstTaskFunction) gst_wildmidi_loop, + pad, NULL); + } else { + res = gst_pad_stop_task (pad); + } + break; + default: + res = FALSE; + break; } + return res; } static GstBuffer * gst_wildmidi_clip_buffer (GstWildmidi * wildmidi, GstBuffer * buffer) { - gint64 start, stop; - gint64 new_start, new_stop; + guint64 start, stop; + guint64 new_start, new_stop; gint64 offset, length; - GstBuffer *out; guint64 bpf; /* clipping disabled for now */ @@ -603,65 +627,64 @@ gst_wildmidi_clip_buffer (GstWildmidi * wildmidi, GstBuffer * buffer) length = new_stop - new_start; bpf = wildmidi->bytes_per_frame; - out = gst_buffer_create_sub (buffer, offset * bpf, length * bpf); + buffer = gst_buffer_make_writable (buffer); + gst_buffer_resize (buffer, offset * bpf, length * bpf); - GST_BUFFER_OFFSET (out) = new_start; - GST_BUFFER_OFFSET_END (out) = new_stop; - GST_BUFFER_TIMESTAMP (out) = + GST_BUFFER_OFFSET (buffer) = new_start; + GST_BUFFER_OFFSET_END (buffer) = new_stop; + GST_BUFFER_TIMESTAMP (buffer) = gst_util_uint64_scale_int (new_start, GST_SECOND, WILDMIDI_RATE); - GST_BUFFER_DURATION (out) = + GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (new_stop, GST_SECOND, WILDMIDI_RATE) - - GST_BUFFER_TIMESTAMP (out); + GST_BUFFER_TIMESTAMP (buffer); - gst_buffer_unref (buffer); - - return out; + return buffer; } /* generate audio data and advance internal timers */ static GstBuffer * gst_wildmidi_get_buffer (GstWildmidi * wildmidi) { - size_t bytes_read; + size_t size; gint64 samples; GstBuffer *buffer; GstSegment *segment; - guint8 *data; - guint size; + GstMapInfo info; guint bpf; bpf = wildmidi->bytes_per_frame; buffer = gst_buffer_new_and_alloc (256 * bpf); - data = GST_BUFFER_DATA (buffer); - size = GST_BUFFER_SIZE (buffer); + gst_buffer_map (buffer, &info, GST_MAP_READWRITE); GST_OBJECT_LOCK (wildmidi); - bytes_read = WildMidi_GetOutput (wildmidi->song, (char *) data, - (unsigned long int) size); + size = WildMidi_GetOutput (wildmidi->song, (char *) info.data, + (unsigned long int) info.size); GST_OBJECT_UNLOCK (wildmidi); - if (bytes_read == 0) { + gst_buffer_unmap (buffer, &info); + + if (size == 0) { gst_buffer_unref (buffer); return NULL; } /* adjust buffer size */ - size = GST_BUFFER_SIZE (buffer) = bytes_read; + gst_buffer_resize (buffer, 0, size); segment = wildmidi->o_segment; - GST_BUFFER_OFFSET (buffer) = segment->last_stop; + GST_BUFFER_OFFSET (buffer) = segment->position; GST_BUFFER_TIMESTAMP (buffer) = - gst_util_uint64_scale_int (segment->last_stop, GST_SECOND, WILDMIDI_RATE); + gst_util_uint64_scale_int (segment->position, GST_SECOND, WILDMIDI_RATE); samples = size / bpf; - segment->last_stop += samples; + segment->position += samples; - GST_BUFFER_OFFSET_END (buffer) = segment->last_stop; + GST_BUFFER_OFFSET_END (buffer) = segment->position; GST_BUFFER_DURATION (buffer) = - gst_util_uint64_scale_int (segment->last_stop, GST_SECOND, + gst_util_uint64_scale_int (segment->position, GST_SECOND, WILDMIDI_RATE) - GST_BUFFER_TIMESTAMP (buffer); GST_DEBUG_OBJECT (wildmidi, "buffer ts: %" GST_TIME_FORMAT ", " @@ -718,8 +741,7 @@ gst_wildmidi_parse_song (GstWildmidi * wildmidi) gst_caps_unref (outcaps); /* we keep an internal segment in samples */ - gst_segment_set_newsegment (wildmidi->o_segment, FALSE, 1.0, - GST_FORMAT_DEFAULT, 0, GST_CLOCK_TIME_NONE, 0); + gst_segment_init (wildmidi->o_segment, GST_FORMAT_DEFAULT); gst_pad_push_event (wildmidi->srcpad, gst_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME)); @@ -752,7 +774,6 @@ gst_wildmidi_do_play (GstWildmidi * wildmidi) wildmidi->discont = FALSE; } - gst_buffer_set_caps (out, GST_PAD_CAPS (wildmidi->srcpad)); ret = gst_pad_push (wildmidi->srcpad, out); return ret; @@ -761,15 +782,15 @@ gst_wildmidi_do_play (GstWildmidi * wildmidi) eos: { GST_LOG_OBJECT (wildmidi, "Song ended"); - return GST_FLOW_UNEXPECTED; + return GST_FLOW_EOS; } } static gboolean -gst_wildmidi_sink_event (GstPad * pad, GstEvent * event) +gst_wildmidi_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { gboolean res = FALSE; - GstWildmidi *wildmidi = GST_WILDMIDI (gst_pad_get_parent (pad)); + GstWildmidi *wildmidi = GST_WILDMIDI (parent); GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event)); @@ -787,16 +808,15 @@ gst_wildmidi_sink_event (GstPad * pad, GstEvent * event) break; } - gst_object_unref (wildmidi); return res; } static GstFlowReturn -gst_wildmidi_chain (GstPad * sinkpad, GstBuffer * buffer) +gst_wildmidi_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * buffer) { GstWildmidi *wildmidi; - wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad)); + wildmidi = GST_WILDMIDI (parent); /* push stuff in the adapter, we will start doing something in the sink event * handler when we get EOS */ @@ -821,7 +841,7 @@ gst_wildmidi_loop (GstPad * sinkpad) ret = gst_pad_pull_range (wildmidi->sinkpad, wildmidi->offset, -1, &buffer); - if (ret == GST_FLOW_UNEXPECTED) { + if (ret == GST_FLOW_EOS) { GST_DEBUG_OBJECT (wildmidi, "Song loaded"); wildmidi->state = GST_WILDMIDI_STATE_PARSE; } else if (ret != GST_FLOW_OK) { @@ -831,7 +851,7 @@ gst_wildmidi_loop (GstPad * sinkpad) } else { GST_DEBUG_OBJECT (wildmidi, "pushing buffer"); gst_adapter_push (wildmidi->adapter, buffer); - wildmidi->offset += GST_BUFFER_SIZE (buffer); + wildmidi->offset += gst_buffer_get_size (buffer); } break; } @@ -858,11 +878,11 @@ pause: GST_DEBUG_OBJECT (wildmidi, "pausing task, reason %s", reason); gst_pad_pause_task (sinkpad); - if (ret == GST_FLOW_UNEXPECTED) { + if (ret == GST_FLOW_EOS) { /* perform EOS logic */ event = gst_event_new_eos (); gst_pad_push_event (wildmidi->srcpad, event); - } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_UNEXPECTED) { + } else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) { event = gst_event_new_eos (); /* for fatal errors we post an error message, post the error * first so the app knows about the error first. */