diff options
Diffstat (limited to 'gst/playondemand/gstplayondemand.c')
-rw-r--r-- | gst/playondemand/gstplayondemand.c | 242 |
1 files changed, 109 insertions, 133 deletions
diff --git a/gst/playondemand/gstplayondemand.c b/gst/playondemand/gstplayondemand.c index b108bec2..2d883234 100644 --- a/gst/playondemand/gstplayondemand.c +++ b/gst/playondemand/gstplayondemand.c @@ -24,11 +24,14 @@ #include "gstplayondemand.h" +/* in these files, a 'tick' is a discrete unit of time, usually around the 1ms + * range. a tick is not divisible into smaller units of time. 1ms is probably + * way beyond what a real computer can actually keep track of, but hey ... */ /* some default values */ #define GST_POD_MAX_PLAYS 100 /* maximum simultaneous plays */ #define GST_POD_BUFFER_TIME 5.0 /* buffer length in seconds */ -#define GST_POD_CLOCK_SPEED 1e-8 /* 0.1 sec/tick default */ +#define GST_POD_TICK_RATE 1e-6 /* ticks per second */ /* buffer pool fallback values ... use if no buffer pool is available */ #define GST_POD_BUFPOOL_SIZE 4096 @@ -88,6 +91,7 @@ static void play_on_demand_class_init (GstPlayOnDemandClass *klass); static void play_on_demand_init (GstPlayOnDemand *filter); static void play_on_demand_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void play_on_demand_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); +static void play_on_demand_dispose (GObject *object); /* GStreamer functionality */ static GstBufferPool* play_on_demand_get_bufferpool (GstPad *pad); @@ -144,9 +148,9 @@ enum { PROP_MUTE, PROP_BUFFER_TIME, PROP_MAX_PLAYS, - PROP_CLOCK_SPEED, + PROP_TICK_RATE, PROP_TOTAL_TICKS, - PROP_TICK_LIST, + PROP_TICKS, }; static guint gst_pod_filter_signals[LAST_SIGNAL] = { 0 }; @@ -163,40 +167,24 @@ play_on_demand_class_init (GstPlayOnDemandClass *klass) gstelement_class = (GstElementClass *) klass; gst_pod_filter_signals[PLAYED_SIGNAL] = - g_signal_new("played", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, + g_signal_new("played", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GstPlayOnDemandClass, played), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gst_pod_filter_signals[PLAY_SIGNAL] = - g_signal_new("play", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, + g_signal_new("play", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GstPlayOnDemandClass, play), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gst_pod_filter_signals[CLEAR_SIGNAL] = - g_signal_new("clear", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, + g_signal_new("clear", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GstPlayOnDemandClass, clear), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); gst_pod_filter_signals[RESET_SIGNAL] = - g_signal_new("reset", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, + g_signal_new("reset", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GstPlayOnDemandClass, reset), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); klass->play = play_on_demand_play_handler; klass->clear = play_on_demand_clear_handler; @@ -206,45 +194,33 @@ play_on_demand_class_init (GstPlayOnDemandClass *klass) gobject_class->set_property = play_on_demand_set_property; gobject_class->get_property = play_on_demand_get_property; + gobject_class->dispose = play_on_demand_dispose; gstelement_class->set_clock = play_on_demand_set_clock; g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_MUTE, - g_param_spec_boolean("mute", "Silence output", - "Do not output any sound", - FALSE, G_PARAM_READWRITE)); - + g_param_spec_boolean("mute", "Silence output", "Do not output any sound", + FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_BUFFER_TIME, - g_param_spec_float("buffer-time", "Buffer length in seconds", - "Number of seconds of audio the buffer holds", - 0.0, G_MAXUINT - 2, GST_POD_BUFFER_TIME, G_PARAM_READWRITE)); - + g_param_spec_float("buffer-time", "Buffer length in seconds", "Number of seconds of audio the buffer holds", + 0.0, G_MAXUINT / GST_AUDIO_MAX_RATE - 10, GST_POD_BUFFER_TIME, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_MAX_PLAYS, - g_param_spec_uint("plays", "Maximum simultaneous playback", - "Maximum allowed number of simultaneous plays from the buffer", - 1, G_MAXUINT, GST_POD_MAX_PLAYS, G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_CLOCK_SPEED, - g_param_spec_float("clock-speed", "Clock speed (ticks/second)", - "The relative speed of a musical tick", - 0, G_MAXFLOAT, 1, G_PARAM_READWRITE)); - + g_param_spec_uint("max-plays", "Maximum simultaneous playbacks", "Maximum allowed number of simultaneous plays from the buffer", + 1, G_MAXUINT, GST_POD_MAX_PLAYS, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TICK_RATE, + g_param_spec_float("tick-rate", "Tick rate (ticks/second)", "The rate of musical ticks, the smallest time unit in a song", + 0, G_MAXFLOAT, GST_POD_TICK_RATE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TOTAL_TICKS, - g_param_spec_uint("total-ticks", "Total number of ticks", - "Total number of ticks (only relevant for tick lists)", - 1, G_MAXUINT, 1, G_PARAM_READWRITE)); - - g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TICK_LIST, - g_param_spec_pointer("tick-list", "List of ticks to play", - "A list of ticks (musical times) at which to play the sample", - G_PARAM_WRITABLE)); + g_param_spec_uint("total-ticks", "Total number of ticks", "Total number of ticks in the tick array", + 1, G_MAXUINT, 1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_TICKS, + g_param_spec_pointer("ticks", "Ticks to play sample on", "An array of ticks (musical times) at which to play the sample", + G_PARAM_READWRITE)); } static void play_on_demand_init (GstPlayOnDemand *filter) { - guint i; - filter->srcpad = gst_pad_new_from_template(play_on_demand_src_factory(), "src"); filter->sinkpad = gst_pad_new_from_template(play_on_demand_sink_factory(), "sink"); @@ -258,23 +234,14 @@ play_on_demand_init (GstPlayOnDemand *filter) filter->clock = NULL; - /* filter properties */ - filter->mute = FALSE; - filter->buffer_time = GST_POD_BUFFER_TIME; - filter->max_plays = GST_POD_MAX_PLAYS; - filter->clock_speed = GST_POD_CLOCK_SPEED; - filter->total_ticks = 1; - filter->tick_list = NULL; + filter->rate = 0; - /* internal buffer stuff */ - play_on_demand_resize_buffer(filter); - filter->eos = FALSE; + filter->ticks = g_new(guint32, filter->total_ticks / 32 + 1); + filter->plays = g_new(guint, filter->max_plays); - /* play pointers, stored as an array of buffer offsets */ - filter->write = 0; - filter->plays = g_new(guint, filter->max_plays); - for (i = 0; i < filter->max_plays; i++) - filter->plays[i] = G_MAXUINT; + play_on_demand_resize_buffer(filter); + play_on_demand_clear_handler(GST_ELEMENT(filter)); + play_on_demand_reset_handler(GST_ELEMENT(filter)); } static void @@ -284,6 +251,7 @@ play_on_demand_set_property (GObject *object, guint prop_id, GstPlayOnDemand *filter; register guint i; guint new_size, min_size, *new_plays; + guint *new_ticks; g_return_if_fail(GST_IS_PLAYONDEMAND(object)); filter = GST_PLAYONDEMAND(object); @@ -296,10 +264,9 @@ play_on_demand_set_property (GObject *object, guint prop_id, filter->buffer_time = g_value_get_float(value); play_on_demand_resize_buffer(filter); - /* clear out now-invalid play pointers, if there are any. */ + /* clear out now-invalid play pointers */ for (i = 0; i < filter->max_plays; i++) - if (filter->plays[i] > filter->buffer_bytes) - filter->plays[i] = G_MAXUINT; + filter->plays[i] = G_MAXUINT; break; case PROP_MAX_PLAYS: @@ -308,21 +275,35 @@ play_on_demand_set_property (GObject *object, guint prop_id, new_plays = g_new(guint, new_size); for (i = 0; i < min_size; i++) new_plays[i] = filter->plays[i]; - for (i = min_size; i < filter->max_plays; i++) new_plays[i] = G_MAXUINT; + for (i = min_size; i < new_size; i++) new_plays[i] = G_MAXUINT; g_free(filter->plays); filter->plays = new_plays; filter->max_plays = new_size; break; - case PROP_CLOCK_SPEED: - filter->clock_speed = g_value_get_float(value); + case PROP_TICK_RATE: + filter->tick_rate = g_value_get_float(value); break; case PROP_TOTAL_TICKS: - filter->total_ticks = g_value_get_uint(value); + new_size = g_value_get_uint(value); + min_size = (new_size < filter->total_ticks) ? new_size : filter->total_ticks; + + new_ticks = g_new(guint32, new_size / 32 + 1); + for (i = 0; i <= min_size / 32; i++) new_ticks[i] = filter->ticks[i]; + for (i = min_size / 32 + 1; i <= new_size / 32; i++) new_ticks[i] = 0; + + g_free(filter->ticks); + filter->ticks = new_ticks; + filter->total_ticks = new_size; + break; - case PROP_TICK_LIST: - filter->tick_list = (GSList *) g_value_get_pointer(value); + case PROP_TICKS: + new_ticks = (guint *) g_value_get_pointer(value); + if (new_ticks) { + g_free(filter->ticks); + filter->ticks = new_ticks; + } break; default: break; @@ -348,18 +329,33 @@ play_on_demand_get_property (GObject *object, guint prop_id, case PROP_MAX_PLAYS: g_value_set_uint(value, filter->max_plays); break; - case PROP_CLOCK_SPEED: - g_value_set_float(value, filter->clock_speed); + case PROP_TICK_RATE: + g_value_set_float(value, filter->tick_rate); break; case PROP_TOTAL_TICKS: g_value_set_uint(value, filter->total_ticks); break; + case PROP_TICKS: + g_value_set_pointer(value, (gpointer) filter->ticks); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } +static void +play_on_demand_dispose (GObject *object) +{ + GstPlayOnDemand *filter = GST_PLAYONDEMAND (object); + + G_OBJECT_CLASS (parent_class)->dispose (object); + + g_free (filter->ticks); + g_free (filter->plays); + g_free (filter->buffer); +} + static GstBufferPool* play_on_demand_get_bufferpool (GstPad *pad) { @@ -380,7 +376,7 @@ play_on_demand_pad_link (GstPad *pad, GstCaps *caps) filter = GST_PLAYONDEMAND(GST_PAD_PARENT(pad)); gst_caps_get_string(caps, "format", &format); - gst_caps_get_int(caps, "rate", &filter->rate); + gst_caps_get_int(caps, "rate", &filter->rate); gst_caps_get_int(caps, "channels", &filter->channels); if (strcmp(format, "int") == 0) { @@ -397,21 +393,22 @@ play_on_demand_pad_link (GstPad *pad, GstCaps *caps) return GST_PAD_LINK_DELAYED; } -/* clock check macros. in these macros, - f == filter - t == tick in question - c == current tick (from the clock) - l == last tick (last tick when clock was checked) - dt == ticks between c and t */ -#define GST_POD_SAMPLE_OFFSET(f, dt) \ - ((guint) (dt * (f)->rate / (f)->clock_speed)) - -/* play a sample if the tick in question came between the last time we checked - the clock and the current clock time. only looks complicated because the last - clock time could have been at the end of the total_ticks, so the clock might - have wrapped around ... */ -#define GST_POD_TICK_ELAPSED(t, c, l) \ - (((l < c) && (l < t) && (t < c)) || ((l > c) && ((l < t) || (t < c)))) +inline static void +play_on_demand_add_play_pointer (GstPlayOnDemand *filter, guint pos) +{ + register guint i; + + if (filter->rate && ((filter->buffer_time * filter->rate) > pos)) { + for (i = 0; i < filter->max_plays; i++) { + if (filter->plays[i] == G_MAXUINT) { + filter->plays[i] = pos; + /* emit a signal to indicate a sample being played */ + g_signal_emit(filter, gst_pod_filter_signals[PLAYED_SIGNAL], 0); + break; + } + } + } +} static void play_on_demand_loop (GstElement *elem) @@ -419,37 +416,30 @@ play_on_demand_loop (GstElement *elem) GstPlayOnDemand *filter = GST_PLAYONDEMAND(elem); guint num_in, num_out, num_filter; GstBuffer *in, *out; - register guint j, k, t; - guint w, offset; - - /* variables for clock check. */ static guint last_tick = 0; - GSList *tick_list; - guint tick, current_tick; g_return_if_fail(filter != NULL); g_return_if_fail(GST_IS_PLAYONDEMAND(filter)); filter->bufpool = gst_pad_get_bufferpool(filter->srcpad); - if (filter->bufpool == NULL) { + if (filter->bufpool == NULL) filter->bufpool = gst_buffer_pool_get_default(GST_POD_BUFPOOL_SIZE, GST_POD_BUFPOOL_NUM); - } in = gst_pad_pull(filter->sinkpad); if (filter->format == GST_PLAYONDEMAND_FORMAT_INT) { if (filter->width == 16) { - gint16 min = -32768; - gint16 max = 32767; + gint16 min = 0xffff; + gint16 max = 0x7fff; gint16 zero = 0; #define _TYPE_ gint16 #include "filter.func" #undef _TYPE_ } else if (filter->width == 8) { - gint8 min = -128; - gint8 max = 127; + gint8 min = 0xff; + gint8 max = 0x7f; gint8 zero = 0; #define _TYPE_ gint8 #include "filter.func" @@ -493,6 +483,7 @@ static void play_on_demand_clear_handler (GstElement *elem) { GstPlayOnDemand *filter; + register guint i; g_return_if_fail(elem != NULL); g_return_if_fail(GST_IS_PLAYONDEMAND(elem)); @@ -500,6 +491,9 @@ play_on_demand_clear_handler (GstElement *elem) filter->write = 0; filter->eos = FALSE; + + for (i = 0; i < filter->max_plays; i++) filter->plays[i] = G_MAXUINT; + for (i = 0; i < filter->buffer_bytes; i++) filter->buffer[i] = 0; } static void @@ -508,39 +502,21 @@ play_on_demand_reset_handler (GstElement *elem) GstPlayOnDemand *filter; register guint i; + play_on_demand_clear_handler (elem); + g_return_if_fail(elem != NULL); g_return_if_fail(GST_IS_PLAYONDEMAND(elem)); filter = GST_PLAYONDEMAND(elem); - for (i = 0; i < filter->max_plays; i++) { - filter->plays[i] = G_MAXUINT; - } - - filter->write = 0; - filter->eos = FALSE; -} - -static void -play_on_demand_add_play_pointer (GstPlayOnDemand *filter, guint pos) -{ - register guint i; - - if (filter->rate && ((filter->buffer_time * filter->rate) > pos)) - for (i = 0; i < filter->max_plays; i++) - if (filter->plays[i] == G_MAXUINT) { - filter->plays[i] = pos; - /* emit a signal to indicate a sample being played */ - g_signal_emit(filter, gst_pod_filter_signals[PLAYED_SIGNAL], 0); - return; - } + for (i = 0; i <= filter->total_ticks / 32; i++) filter->ticks[i] = 0; } static void play_on_demand_resize_buffer (GstPlayOnDemand *filter) { - register guint i; - guint new_size, min_size; - gchar *new_buffer; + register guint i; + guint new_size, min_size; + gchar *new_buffer; /* use a default sample rate of 44100, 1 channel, 1 byte per sample if caps haven't been set yet */ @@ -557,7 +533,7 @@ play_on_demand_resize_buffer (GstPlayOnDemand *filter) new_buffer = g_new(gchar, new_size); for (i = 0; i < min_size; i++) new_buffer[i] = filter->buffer[i]; - for (i = min_size; i < filter->buffer_bytes; i++) new_buffer[i] = 0; + for (i = min_size; i < new_size; i++) new_buffer[i] = 0; g_free(filter->buffer); filter->buffer = new_buffer; |