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.
This commit is contained in:
parent
2127cf3e8c
commit
53f654150b
@ -83,7 +83,9 @@ enum
|
|||||||
|
|
||||||
static void gst_wildmidi_base_init (gpointer g_class);
|
static void gst_wildmidi_base_init (gpointer g_class);
|
||||||
static void gst_wildmidi_class_init (GstWildmidiClass * klass);
|
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 gboolean gst_wildmidi_src_event (GstPad * pad, GstEvent * event);
|
||||||
|
|
||||||
static GstStateChangeReturn gst_wildmidi_change_state (GstElement * element,
|
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 gboolean gst_wildmidi_activatepull (GstPad * pad, gboolean active);
|
||||||
|
|
||||||
static void gst_wildmidi_loop (GstPad * sinkpad);
|
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);
|
static gboolean gst_wildmidi_src_query (GstPad * pad, GstQuery * query);
|
||||||
|
|
||||||
@ -230,7 +233,7 @@ gst_wildmidi_class_init (GstWildmidiClass * klass)
|
|||||||
gobject_class = (GObjectClass *) klass;
|
gobject_class = (GObjectClass *) klass;
|
||||||
gstelement_class = (GstElementClass *) 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->set_property = gst_wildmidi_set_property;
|
||||||
gobject_class->get_property = gst_wildmidi_get_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_object_class_install_property (gobject_class, ARG_HIGH_QUALITY,
|
||||||
g_param_spec_boolean ("high-quality", "High Quality",
|
g_param_spec_boolean ("high-quality", "High Quality",
|
||||||
"High Quality", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
"High Quality", TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
|
|
||||||
|
gstelement_class->change_state = gst_wildmidi_change_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* initialize the new element
|
/* initialize the new element
|
||||||
@ -260,6 +265,8 @@ gst_wildmidi_init (GstWildmidi * filter, GstWildmidiClass * g_class)
|
|||||||
gst_pad_set_activatepull_function (filter->sinkpad,
|
gst_pad_set_activatepull_function (filter->sinkpad,
|
||||||
gst_wildmidi_activatepull);
|
gst_wildmidi_activatepull);
|
||||||
gst_pad_set_activate_function (filter->sinkpad, gst_wildmidi_activate);
|
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);
|
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
|
||||||
|
|
||||||
filter->srcpad =
|
filter->srcpad =
|
||||||
@ -274,10 +281,18 @@ gst_wildmidi_init (GstWildmidi * filter, GstWildmidiClass * g_class)
|
|||||||
|
|
||||||
gst_segment_init (filter->o_segment, GST_FORMAT_DEFAULT);
|
gst_segment_init (filter->o_segment, GST_FORMAT_DEFAULT);
|
||||||
|
|
||||||
|
filter->adapter = gst_adapter_new ();
|
||||||
|
|
||||||
filter->bytes_per_frame = WILDMIDI_BPS;
|
filter->bytes_per_frame = WILDMIDI_BPS;
|
||||||
filter->time_per_frame = GST_SECOND / WILDMIDI_RATE;
|
filter->time_per_frame = GST_SECOND / WILDMIDI_RATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_wildmidi_finalize (GObject * object)
|
||||||
|
{
|
||||||
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_wildmidi_src_convert (GstWildmidi * wildmidi,
|
gst_wildmidi_src_convert (GstWildmidi * wildmidi,
|
||||||
GstFormat src_format, gint64 src_value,
|
GstFormat src_format, gint64 src_value,
|
||||||
@ -381,20 +396,6 @@ gst_wildmidi_src_query (GstPad * pad, GstQuery * query)
|
|||||||
return res;
|
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 *
|
static GstSegment *
|
||||||
gst_wildmidi_get_segment (GstWildmidi * wildmidi, GstFormat format,
|
gst_wildmidi_get_segment (GstWildmidi * wildmidi, GstFormat format,
|
||||||
gboolean update)
|
gboolean update)
|
||||||
@ -521,6 +522,7 @@ gst_wildmidi_src_event (GstPad * pad, GstEvent * event)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_wildmidi_activate (GstPad * sinkpad)
|
gst_wildmidi_activate (GstPad * sinkpad)
|
||||||
{
|
{
|
||||||
@ -643,73 +645,26 @@ gst_wildmidi_get_buffer (GstWildmidi * wildmidi)
|
|||||||
return gst_wildmidi_clip_buffer (wildmidi, out);
|
return gst_wildmidi_clip_buffer (wildmidi, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
gst_wildmidi_loop (GstPad * sinkpad)
|
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;
|
struct _WM_Info *info;
|
||||||
|
GstCaps *outcaps;
|
||||||
|
guint8 *data;
|
||||||
|
guint size;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (wildmidi, "Parsing song");
|
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 */
|
/* this method takes our memory block */
|
||||||
wildmidi->song =
|
wildmidi->song = WildMidi_OpenBuffer (data, size);
|
||||||
WildMidi_OpenBuffer ((unsigned char *) wildmidi->mididata,
|
|
||||||
wildmidi->mididata_size);
|
|
||||||
wildmidi->mididata_size = 0;
|
|
||||||
wildmidi->mididata = NULL;
|
|
||||||
|
|
||||||
if (!wildmidi->song) {
|
if (!wildmidi->song) {
|
||||||
GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
|
GST_ELEMENT_ERROR (wildmidi, STREAM, DECODE, (NULL),
|
||||||
("Unable to parse midi"));
|
("Unable to parse midi"));
|
||||||
goto paused;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
WildMidi_LoadSamples (wildmidi->song);
|
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_wildmidi_get_new_segment_event (wildmidi, GST_FORMAT_TIME, FALSE));
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (wildmidi, "Parsing song done");
|
GST_DEBUG_OBJECT (wildmidi, "Parsing song done");
|
||||||
return;
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wildmidi->o_segment_changed) {
|
static GstFlowReturn
|
||||||
GstSegment *segment;
|
gst_wildmidi_do_play (GstWildmidi * wildmidi)
|
||||||
|
{
|
||||||
GST_DEBUG_OBJECT (wildmidi, "segment changed");
|
GstBuffer *out;
|
||||||
|
GstFlowReturn ret;
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_segment_free (segment);
|
|
||||||
wildmidi->o_segment_changed = FALSE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wildmidi->o_seek) {
|
if (wildmidi->o_seek) {
|
||||||
unsigned long int sample;
|
unsigned long int sample;
|
||||||
@ -781,7 +718,7 @@ gst_wildmidi_loop (GstPad * sinkpad)
|
|||||||
GST_LOG_OBJECT (wildmidi, "Song ended, generating eos");
|
GST_LOG_OBJECT (wildmidi, "Song ended, generating eos");
|
||||||
gst_pad_push_event (wildmidi->srcpad, gst_event_new_eos ());
|
gst_pad_push_event (wildmidi->srcpad, gst_event_new_eos ());
|
||||||
wildmidi->o_seek = FALSE;
|
wildmidi->o_seek = FALSE;
|
||||||
goto paused;
|
return GST_FLOW_UNEXPECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wildmidi->o_seek) {
|
if (wildmidi->o_seek) {
|
||||||
@ -792,9 +729,94 @@ gst_wildmidi_loop (GstPad * sinkpad)
|
|||||||
gst_buffer_set_caps (out, GST_PAD_CAPS (wildmidi->srcpad));
|
gst_buffer_set_caps (out, GST_PAD_CAPS (wildmidi->srcpad));
|
||||||
ret = gst_pad_push (wildmidi->srcpad, out);
|
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)
|
if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED)
|
||||||
goto error;
|
goto error;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
paused:
|
paused:
|
||||||
@ -821,10 +843,10 @@ gst_wildmidi_change_state (GstElement * element, GstStateChange transition)
|
|||||||
|
|
||||||
switch (transition) {
|
switch (transition) {
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||||
wildmidi->mididata = NULL;
|
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||||
wildmidi->mididata_size = 0;
|
wildmidi->offset = 0;
|
||||||
|
wildmidi->state = GST_WILDMIDI_STATE_LOAD;
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||||
break;
|
break;
|
||||||
@ -841,9 +863,7 @@ gst_wildmidi_change_state (GstElement * element, GstStateChange transition)
|
|||||||
if (wildmidi->song)
|
if (wildmidi->song)
|
||||||
WildMidi_Close (wildmidi->song);
|
WildMidi_Close (wildmidi->song);
|
||||||
wildmidi->song = NULL;
|
wildmidi->song = NULL;
|
||||||
if (wildmidi->mididata)
|
gst_adapter_clear (wildmidi->adapter);
|
||||||
free (wildmidi->mididata);
|
|
||||||
wildmidi->mididata = NULL;
|
|
||||||
break;
|
break;
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -47,6 +47,12 @@ G_BEGIN_DECLS
|
|||||||
typedef struct _GstWildmidi GstWildmidi;
|
typedef struct _GstWildmidi GstWildmidi;
|
||||||
typedef struct _GstWildmidiClass GstWildmidiClass;
|
typedef struct _GstWildmidiClass GstWildmidiClass;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GST_WILDMIDI_STATE_LOAD,
|
||||||
|
GST_WILDMIDI_STATE_PARSE,
|
||||||
|
GST_WILDMIDI_STATE_PLAY
|
||||||
|
} GstWildmidiState;
|
||||||
|
|
||||||
struct _GstWildmidi
|
struct _GstWildmidi
|
||||||
{
|
{
|
||||||
GstElement element;
|
GstElement element;
|
||||||
@ -54,14 +60,13 @@ struct _GstWildmidi
|
|||||||
GstPad *sinkpad, *srcpad;
|
GstPad *sinkpad, *srcpad;
|
||||||
|
|
||||||
/* input stream properties */
|
/* input stream properties */
|
||||||
gint64 mididata_size, mididata_offset;
|
GstWildmidiState state;
|
||||||
gchar *mididata;
|
GstAdapter *adapter;
|
||||||
gboolean mididata_filled;
|
|
||||||
|
|
||||||
midi *song;
|
midi *song;
|
||||||
|
guint64 offset;
|
||||||
|
|
||||||
/* output data */
|
/* output data */
|
||||||
gboolean o_new_segment, o_segment_changed, o_seek;
|
gboolean o_new_segment, o_seek;
|
||||||
GstSegment o_segment[1];
|
GstSegment o_segment[1];
|
||||||
gint64 o_len;
|
gint64 o_len;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user