port wildmidi

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=696041
This commit is contained in:
Wim Taymans 2013-03-19 10:14:05 +01:00
parent 52908193b0
commit 4a44dc5ecf
2 changed files with 129 additions and 109 deletions

View file

@ -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

View file

@ -32,16 +32,12 @@
* <refsect2>
* <title>Example pipeline</title>
* |[
* 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.
* </refsect2>
*/
/* 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 <config.h>
#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 <wouter@blue-gate.be>");
}
#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 <wouter@blue-gate.be>");
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. */