summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@collabora.co.uk>2009-08-31 18:20:00 +0200
committerWim Taymans <wim.taymans@collabora.co.uk>2009-08-31 18:48:04 +0200
commit53f654150b558ed75ac13f8fabec6217fc72751a (patch)
treeee1e8d3e535eeebc77008574e4e6da1fe00b6799
parent2127cf3e8c61b45efea8babe7378d3ab6beefcda (diff)
wildmidi: use state machine
Use a state machine to keep track of the current state. Add chain function and event function on the sinkpad. Remove some unused code.
-rw-r--r--ext/timidity/gstwildmidi.c226
-rw-r--r--ext/timidity/gstwildmidi.h15
2 files changed, 133 insertions, 108 deletions
diff --git a/ext/timidity/gstwildmidi.c b/ext/timidity/gstwildmidi.c
index 43359d8e3..5a37491fd 100644
--- a/ext/timidity/gstwildmidi.c
+++ b/ext/timidity/gstwildmidi.c
@@ -83,7 +83,9 @@ enum
static void gst_wildmidi_base_init (gpointer g_class);
static void gst_wildmidi_class_init (GstWildmidiClass * klass);
+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 GstStateChangeReturn gst_wildmidi_change_state (GstElement * element,
@@ -92,6 +94,7 @@ static gboolean gst_wildmidi_activate (GstPad * pad);
static gboolean gst_wildmidi_activatepull (GstPad * pad, gboolean active);
static void gst_wildmidi_loop (GstPad * sinkpad);
+static GstFlowReturn gst_wildmidi_chain (GstPad * sinkpad, GstBuffer * buffer);
static gboolean gst_wildmidi_src_query (GstPad * pad, GstQuery * query);
@@ -230,7 +233,7 @@ gst_wildmidi_class_init (GstWildmidiClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
- gstelement_class->change_state = gst_wildmidi_change_state;
+ gobject_class->finalize = gst_wildmidi_finalize;
gobject_class->set_property = gst_wildmidi_set_property;
gobject_class->get_property = gst_wildmidi_get_property;
@@ -241,6 +244,8 @@ gst_wildmidi_class_init (GstWildmidiClass * klass)
g_object_class_install_property (gobject_class, ARG_HIGH_QUALITY,
g_param_spec_boolean ("high-quality", "High Quality",
"High Quality", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+
+ gstelement_class->change_state = gst_wildmidi_change_state;
}
/* initialize the new element
@@ -260,6 +265,8 @@ gst_wildmidi_init (GstWildmidi * filter, GstWildmidiClass * g_class)
gst_pad_set_activatepull_function (filter->sinkpad,
gst_wildmidi_activatepull);
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 =
@@ -274,10 +281,18 @@ gst_wildmidi_init (GstWildmidi * filter, GstWildmidiClass * g_class)
gst_segment_init (filter->o_segment, GST_FORMAT_DEFAULT);
+ filter->adapter = gst_adapter_new ();
+
filter->bytes_per_frame = WILDMIDI_BPS;
filter->time_per_frame = GST_SECOND / WILDMIDI_RATE;
}
+static void
+gst_wildmidi_finalize (GObject * object)
+{
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
static gboolean
gst_wildmidi_src_convert (GstWildmidi * wildmidi,
GstFormat src_format, gint64 src_value,
@@ -381,20 +396,6 @@ gst_wildmidi_src_query (GstPad * pad, GstQuery * query)
return res;
}
-static gboolean
-gst_wildmidi_get_upstream_size (GstWildmidi * wildmidi, gint64 * size)
-{
- GstFormat format = GST_FORMAT_BYTES;
- gboolean res = FALSE;
- GstPad *peer = gst_pad_get_peer (wildmidi->sinkpad);
-
- if (peer != NULL)
- res = gst_pad_query_duration (peer, &format, size) && *size >= 0;
-
- gst_object_unref (peer);
- return res;
-}
-
static GstSegment *
gst_wildmidi_get_segment (GstWildmidi * wildmidi, GstFormat format,
gboolean update)
@@ -521,6 +522,7 @@ gst_wildmidi_src_event (GstPad * pad, GstEvent * event)
return res;
}
+
static gboolean
gst_wildmidi_activate (GstPad * sinkpad)
{
@@ -643,73 +645,26 @@ gst_wildmidi_get_buffer (GstWildmidi * wildmidi)
return gst_wildmidi_clip_buffer (wildmidi, out);
}
-static void
-gst_wildmidi_loop (GstPad * sinkpad)
+static gboolean
+gst_wildmidi_parse_song (GstWildmidi * wildmidi)
{
- GstWildmidi *wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad));
- GstBuffer *out;
- GstFlowReturn ret;
- GstCaps *outcaps;
-
- if (wildmidi->mididata_size == 0) {
- if (!gst_wildmidi_get_upstream_size (wildmidi, &wildmidi->mididata_size)) {
- GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
- ("Unable to get song length"));
- goto paused;
- }
-
- if (wildmidi->mididata)
- free (wildmidi->mididata);
-
- wildmidi->mididata = malloc (wildmidi->mididata_size);
- wildmidi->mididata_offset = 0;
- return;
- }
-
- if (wildmidi->mididata_offset < wildmidi->mididata_size) {
- GstBuffer *buffer;
- gint64 size;
-
- GST_DEBUG_OBJECT (wildmidi, "loading song");
-
- ret =
- gst_pad_pull_range (wildmidi->sinkpad, wildmidi->mididata_offset,
- -1, &buffer);
- if (ret != GST_FLOW_OK) {
- GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
- ("Unable to load song"));
- goto paused;
- }
-
- size = wildmidi->mididata_size - wildmidi->mididata_offset;
- if (GST_BUFFER_SIZE (buffer) < size)
- size = GST_BUFFER_SIZE (buffer);
-
- memmove (wildmidi->mididata + wildmidi->mididata_offset,
- GST_BUFFER_DATA (buffer), size);
- gst_buffer_unref (buffer);
-
- wildmidi->mididata_offset += size;
- GST_DEBUG_OBJECT (wildmidi, "Song loaded");
- return;
- }
-
- if (!wildmidi->song) {
struct _WM_Info *info;
+ GstCaps *outcaps;
+ guint8 *data;
+ guint size;
GST_DEBUG_OBJECT (wildmidi, "Parsing song");
+ size = gst_adapter_available (wildmidi->adapter);
+ data = gst_adapter_take (wildmidi->adapter, size);
+
/* this method takes our memory block */
- wildmidi->song =
- WildMidi_OpenBuffer ((unsigned char *) wildmidi->mididata,
- wildmidi->mididata_size);
- wildmidi->mididata_size = 0;
- wildmidi->mididata = NULL;
+ wildmidi->song = WildMidi_OpenBuffer (data, size);
if (!wildmidi->song) {
GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
("Unable to parse midi"));
- goto paused;
+ return FALSE;
}
WildMidi_LoadSamples (wildmidi->song);
@@ -733,33 +688,15 @@ gst_wildmidi_loop (GstPad * sinkpad)
gst_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME, FALSE));
GST_DEBUG_OBJECT (wildmidi, "Parsing song done");
- return;
- }
-
- if (wildmidi->o_segment_changed) {
- GstSegment *segment;
-
- GST_DEBUG_OBJECT (wildmidi, "segment changed");
-
- segment = gst_wildmidi_get_segment (wildmidi, GST_FORMAT_TIME,
- !wildmidi->o_new_segment);
-
- GST_LOG_OBJECT (wildmidi,
- "sending newsegment from %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT
- ", pos=%" GST_TIME_FORMAT, GST_TIME_ARGS ((guint64) segment->start),
- GST_TIME_ARGS ((guint64) segment->stop),
- GST_TIME_ARGS ((guint64) segment->time));
- if (wildmidi->o_segment->flags & GST_SEEK_FLAG_SEGMENT) {
- gst_element_post_message (GST_ELEMENT (wildmidi),
- gst_message_new_segment_start (GST_OBJECT (wildmidi),
- segment->format, segment->start));
+ return TRUE;
}
- gst_segment_free (segment);
- wildmidi->o_segment_changed = FALSE;
- return;
- }
+static GstFlowReturn
+gst_wildmidi_do_play (GstWildmidi * wildmidi)
+{
+ GstBuffer *out;
+ GstFlowReturn ret;
if (wildmidi->o_seek) {
unsigned long int sample;
@@ -781,7 +718,7 @@ gst_wildmidi_loop (GstPad * sinkpad)
GST_LOG_OBJECT (wildmidi, "Song ended, generating eos");
gst_pad_push_event (wildmidi->srcpad, gst_event_new_eos ());
wildmidi->o_seek = FALSE;
- goto paused;
+ return GST_FLOW_UNEXPECTED;
}
if (wildmidi->o_seek) {
@@ -792,9 +729,94 @@ gst_wildmidi_loop (GstPad * sinkpad)
gst_buffer_set_caps (out, GST_PAD_CAPS (wildmidi->srcpad));
ret = gst_pad_push (wildmidi->srcpad, out);
+ return ret;
+}
+
+static gboolean
+gst_wildmidi_sink_event (GstPad * pad, GstEvent * event)
+{
+ gboolean res = FALSE;
+ GstWildmidi *wildmidi = GST_WILDMIDI (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (pad, "%s event received", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_EOS:
+ wildmidi->state = GST_WILDMIDI_STATE_PARSE;
+ /* now start the parsing task */
+ gst_pad_start_task (wildmidi->sinkpad,
+ (GstTaskFunction) gst_wildmidi_loop, wildmidi->sinkpad);
+ gst_event_unref (event);
+ break;
+ default:
+ res = gst_pad_push_event (wildmidi->srcpad, event);
+ break;
+ }
+ return res;
+}
+
+static GstFlowReturn
+gst_wildmidi_chain (GstPad * sinkpad, GstBuffer * buffer)
+{
+ GstFlowReturn ret;
+ GstWildmidi *wildmidi;
+
+ wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad));
+
+ gst_adapter_push (wildmidi->adapter, buffer);
+
+ ret = GST_FLOW_OK;
+
+ return ret;
+}
+
+static void
+gst_wildmidi_loop (GstPad * sinkpad)
+{
+ GstWildmidi *wildmidi = GST_WILDMIDI (GST_PAD_PARENT (sinkpad));
+ GstFlowReturn ret;
+
+ switch (wildmidi->state) {
+ case GST_WILDMIDI_STATE_LOAD:
+ {
+ GstBuffer *buffer;
+
+ GST_DEBUG_OBJECT (wildmidi, "loading song");
+
+ ret =
+ gst_pad_pull_range (wildmidi->sinkpad, wildmidi->offset, -1, &buffer);
+
+ if (ret == GST_FLOW_UNEXPECTED) {
+ GST_DEBUG_OBJECT (wildmidi, "Song loaded");
+ wildmidi->state = GST_WILDMIDI_STATE_PARSE;
+ } else if (ret != GST_FLOW_OK) {
+ GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
+ ("Unable to load song"));
+ goto paused;
+ } else {
+ GST_DEBUG_OBJECT (wildmidi, "pushing buffer");
+ gst_adapter_push (wildmidi->adapter, buffer);
+ wildmidi->offset += GST_BUFFER_SIZE (buffer);
+ }
+ break;
+ }
+ case GST_WILDMIDI_STATE_PARSE:
+ {
+ if (!wildmidi->song) {
+ if (!gst_wildmidi_parse_song (wildmidi))
+ goto paused;
+ }
+ wildmidi->state = GST_WILDMIDI_STATE_PLAY;
+ break;
+ }
+ case GST_WILDMIDI_STATE_PLAY:
+ ret = gst_wildmidi_do_play (wildmidi);
if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED)
goto error;
-
+ break;
+ default:
+ break;
+ }
return;
paused:
@@ -821,10 +843,10 @@ gst_wildmidi_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
- wildmidi->mididata = NULL;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
- wildmidi->mididata_size = 0;
+ wildmidi->offset = 0;
+ wildmidi->state = GST_WILDMIDI_STATE_LOAD;
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break;
@@ -841,9 +863,7 @@ gst_wildmidi_change_state (GstElement * element, GstStateChange transition)
if (wildmidi->song)
WildMidi_Close (wildmidi->song);
wildmidi->song = NULL;
- if (wildmidi->mididata)
- free (wildmidi->mididata);
- wildmidi->mididata = NULL;
+ gst_adapter_clear (wildmidi->adapter);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
diff --git a/ext/timidity/gstwildmidi.h b/ext/timidity/gstwildmidi.h
index 84802f735..c33f5005e 100644
--- a/ext/timidity/gstwildmidi.h
+++ b/ext/timidity/gstwildmidi.h
@@ -47,6 +47,12 @@ G_BEGIN_DECLS
typedef struct _GstWildmidi GstWildmidi;
typedef struct _GstWildmidiClass GstWildmidiClass;
+typedef enum {
+ GST_WILDMIDI_STATE_LOAD,
+ GST_WILDMIDI_STATE_PARSE,
+ GST_WILDMIDI_STATE_PLAY
+} GstWildmidiState;
+
struct _GstWildmidi
{
GstElement element;
@@ -54,14 +60,13 @@ struct _GstWildmidi
GstPad *sinkpad, *srcpad;
/* input stream properties */
- gint64 mididata_size, mididata_offset;
- gchar *mididata;
- gboolean mididata_filled;
-
+ GstWildmidiState state;
+ GstAdapter *adapter;
midi *song;
+ guint64 offset;
/* output data */
- gboolean o_new_segment, o_segment_changed, o_seek;
+ gboolean o_new_segment, o_seek;
GstSegment o_segment[1];
gint64 o_len;