From: Benjamin O. <co...@us...> - 2002-03-14 00:03:18
|
CVS Root: /cvsroot/gstreamer Module: gst-plugins Changes by: company Date: Wed Mar 13 2002 16:03:18 PST Log message: First commit to new branch. The only stuff that is known to compile are: - the ext/mad dir - the gst/mpegaudioparse dir - the sys/oss dir Why these? - because I hacked them up to do seeking in Mp3's with the player - The changes are not supposed to stay there. At least the osssink hack is ugly, but I wanted easy output :) Modified files: ext/mad : gstmad.c sys/oss : gstosssink.c gstosssink.h Links: http://cvs.sf.net/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/ext/mad/gstmad.c.diff?r1=1.13&r2=1.13.4.1 http://cvs.sf.net/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/sys/oss/gstosssink.c.diff?r1=1.10&r2=1.10.4.1 http://cvs.sf.net/cgi-bin/viewcvs.cgi/gstreamer/gst-plugins/sys/oss/gstosssink.h.diff?r1=1.2&r2=1.2.4.1 ====Begin Diffs==== Index: gstmad.c =================================================================== RCS file: /cvsroot/gstreamer/gst-plugins/ext/mad/gstmad.c,v retrieving revision 1.13 retrieving revision 1.13.4.1 diff -u -d -r1.13 -r1.13.4.1 --- gstmad.c 3 Mar 2002 00:53:24 -0000 1.13 +++ gstmad.c 14 Mar 2002 00:03:05 -0000 1.13.4.1 @@ -32,6 +32,9 @@ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MAD)) #define GST_IS_MAD_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MAD)) + +/* some defines wrt VBRs */ +#define GST_MAD_CHECK_LENGTH 300 /* check length every many frames */ typedef struct _GstMad GstMad; typedef struct _GstMadClass GstMadClass; @@ -48,7 +51,7 @@ struct mad_synth synth; guchar *tempbuffer; glong tempsize; - gboolean need_sync; + gboolean need_flush; guint64 last_time; guint64 framestamp; /* timestamp-like, but counted in frames */ guint64 sync_point; @@ -61,6 +64,9 @@ guint framecount; gint vbr_average; /* average bitrate */ gulong vbr_rate; /* average * framecount */ + + /* length */ + GstEventLength *length; /* caps */ gboolean caps_set; @@ -138,11 +144,12 @@ static void gst_mad_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void gst_mad_chain (GstPad *pad, GstBuffer *buffer); +static void gst_mad_chain (GstPad *pad, GstData *data); static GstElementStateReturn - gst_mad_change_state (GstElement *element); - + gst_mad_change_state (GstElement *element); +static gpointer gst_mad_srcpad_event (GstPad *pad, GstData *event); +static GstEventLength * gst_mad_new_length_event (GstEventLength *length); static GstElementClass *parent_class = NULL; /* static guint gst_mad_signals[LAST_SIGNAL] = { 0 }; */ @@ -228,10 +235,11 @@ mad->srcpad = gst_pad_new_from_template( GST_PADTEMPLATE_GET (mad_src_template_factory), "src"); gst_element_add_pad(GST_ELEMENT(mad),mad->srcpad); + gst_pad_set_event_function (mad->srcpad, gst_mad_srcpad_event); mad->tempbuffer = g_malloc (MAD_BUFFER_MDLEN * 3); mad->tempsize = 0; - mad->need_sync = TRUE; + mad->need_flush = FALSE; mad->last_time = 0; mad->framestamp = 0; mad->total_samples = 0; @@ -240,6 +248,10 @@ mad->framecount = 0; mad->vbr_average = 0; mad->vbr_rate = 0; + mad->length = NULL; + + /* hey, we can handle events */ + GST_FLAG_SET (mad, GST_ELEMENT_EVENT_AWARE); } static void @@ -247,9 +259,12 @@ { GstMad *mad = GST_MAD (object); + g_free (mad->tempbuffer); + if (mad->length != NULL) + gst_data_unref (GST_DATA (mad->length)); + G_OBJECT_CLASS (parent_class)->dispose (object); - g_free (mad->tempbuffer); } static inline signed int @@ -322,6 +337,7 @@ break; } } +/* must only be called from the chain function, this function calls gst_pad_push */ static void gst_mad_update_info (GstMad *mad, struct mad_header const *header) { @@ -365,24 +381,133 @@ g_object_thaw_notify (G_OBJECT (mad)); + /* see if we shoould update the length */ + if (((mad->framecount % GST_MAD_CHECK_LENGTH) == 0 || mad->framecount == 1) && mad->length && mad->length->accuracy[GST_OFFSET_TIME] != GST_ACCURACY_SURE) + { + GstEventLength *temp = gst_mad_new_length_event (mad->length); + gst_data_unref (GST_DATA (mad->length)); + mad->length = temp; + mad->length->length[GST_OFFSET_TIME] = mad->length->length[GST_OFFSET_BYTES] * 8000000 / mad->vbr_average; + mad->length->accuracy[GST_OFFSET_TIME] = (header->bitrate == mad->vbr_average) ? GST_ACCURACY_SURE : GST_ACCURACY_WILD_GUESS; + if (GST_PAD_IS_CONNECTED (mad->srcpad)) + { + gst_data_ref (GST_DATA (mad->length)); + gst_pad_push (mad->srcpad, GST_DATA (mad->length)); + } + } + #undef CHECK_HEADER } - static void -gst_mad_chain (GstPad *pad, GstBuffer *buffer) +gst_mad_instream_event (GstMad *mad, GstData *event) +{ + GstEventLength *length; + + switch (GST_DATA_TYPE (event)) + { + case GST_EVENT_NEWMEDIA: + /* reset everything */ + mad->last_time = 0; + mad->framestamp = 0; + mad->total_samples = 0; + mad->sync_point = 0; + mad->new_header = TRUE; + mad->framecount = 0; + mad->vbr_average = 0; + mad->vbr_rate = 0; + mad->tempsize = 0; + if (mad->length) + { + gst_data_unref (GST_DATA (mad->length)); + mad->length = NULL; + } + break; + case GST_EVENT_DISCONTINUOUS: + /* reset some stuff */ + mad->tempsize = 0; + mad->total_samples = 0; + if (event->offset[GST_OFFSET_TIME] > 0) + { + mad->sync_point = event->offset[GST_OFFSET_TIME]; + } else { + GstEventDiscontinuous *new_event = gst_event_new_discontinuous (); + mad->sync_point = event->offset[GST_OFFSET_BYTES] * 8000000 / (mad->vbr_average > 0 ? mad->vbr_average : 1); + gst_event_copy_discontinuous (new_event, event); + GST_DATA (new_event)->offset[GST_OFFSET_TIME] = mad->sync_point; + gst_data_unref (event); + event = GST_DATA (new_event); + } + break; + case GST_EVENT_LENGTH: + length = GST_EVENT_LENGTH (event); + if (mad->length == NULL || length->accuracy[GST_OFFSET_BYTES] > mad->length->accuracy[GST_OFFSET_BYTES]) + { + if (mad->length != NULL) + gst_data_unref (GST_DATA (mad->length)); + + /* if the event knows the length, we gladly accept that, else we compute our own */ + if (length->accuracy[GST_OFFSET_TIME] != GST_ACCURACY_SURE && mad->vbr_average > 0) + { + /* create new event with better time info */ + GstEventLength *new_length = gst_mad_new_length_event (length); + new_length->length[GST_OFFSET_TIME] = mad->length->length[GST_OFFSET_BYTES] * 8000000 / mad->vbr_average; + new_length->accuracy[GST_OFFSET_TIME] = ((mad->vbr_average == mad->header.bitrate) && (mad->framecount >= GST_MAD_CHECK_LENGTH) + ? GST_ACCURACY_SURE : GST_ACCURACY_WILD_GUESS); + + gst_data_ref (GST_DATA (new_length)); + mad->length = new_length; + gst_data_unref (event); + } else { + gst_data_ref (GST_DATA (length)); + mad->length = length; + } + event = GST_DATA (mad->length); + } + break; + case GST_EVENT_EOS: + gst_element_set_eos (GST_ELEMENT (mad)); + break; + default: + break; + } + + if (GST_PAD_IS_CONNECTED (mad->srcpad)) + gst_pad_push (mad->srcpad, event); + else + gst_data_unref (event); +} +static void +gst_mad_chain (GstPad *pad, GstData *dat) { GstMad *mad; gchar *data; glong size; + GstBuffer *buffer; mad = GST_MAD (gst_pad_get_parent (pad)); - + buffer = GST_BUFFER (dat); + + /* need to flush? */ + if (mad->need_flush) + { + mad->tempsize = 0; + mad->need_flush = FALSE; + } + /* end of new bit */ data = GST_BUFFER_DATA (buffer); size = GST_BUFFER_SIZE (buffer); - if (!GST_PAD_IS_CONNECTED (mad->srcpad)) { - gst_buffer_unref (buffer); + /* is this an event? */ + if (GST_IS_EVENT (dat)) + { + gst_mad_instream_event (mad, dat); + return; + } + + if (!GST_PAD_IS_CONNECTED (mad->srcpad)) + { + gst_data_unref (dat); return; } @@ -444,9 +569,10 @@ mad->sync_point = GST_BUFFER_TIMESTAMP (buffer); mad->total_samples = 0; } + } else { + GST_BUFFER_TIMESTAMP (outbuffer) = mad->sync_point + + mad->total_samples * 1000000LL / mad->frame.header.samplerate; } - GST_BUFFER_TIMESTAMP (outbuffer) = mad->sync_point + - mad->total_samples * 1000000LL / mad->frame.header.samplerate; /* end of new bit */ while (nsamples--) { @@ -481,7 +607,12 @@ mad->caps_set = TRUE; } - gst_pad_push (mad->srcpad, outbuffer); + gst_pad_push (mad->srcpad, GST_DATA (outbuffer)); + if (mad->need_flush) + { + gst_data_unref (dat); + return; + } next: /* figure out how many bytes mad consumed */ consumed = mad->stream.next_frame - mad_input_buffer; @@ -493,7 +624,7 @@ memmove (mad->tempbuffer, mad_input_buffer, mad->tempsize); } - gst_buffer_unref (buffer); + gst_data_unref (dat); } static GstElementStateReturn @@ -529,6 +660,66 @@ parent_class->change_state (element); return GST_STATE_SUCCESS; +} + +static gpointer +gst_mad_srcpad_event (GstPad *pad, GstData *event) +{ + GstEventSeek *seek; + gpointer ret = NULL; + GstMad *mad = GST_MAD (GST_PAD_PARENT (pad)); + GstPad *nextpad = GST_PAD_CAST (GST_RPAD_PEER (mad->sinkpad)); + + switch (GST_DATA_TYPE (event)) + { + case GST_EVENT_SEEK: + seek = (GstEventSeek *) event; + /* check if we can provide better seek info than the event */ + if (seek->accuracy[GST_OFFSET_TIME] > GST_ACCURACY_NONE && seek->accuracy[GST_OFFSET_BYTES] != GST_ACCURACY_SURE) + { + GstEventSeek *new_event = NULL; + if ((new_event = gst_event_new_seek (seek->type, seek->original, 0, seek->flush)) == NULL) + { + gst_data_unref (event); + g_warning ("couldn't create seek event, skipping seek - out of memory?\n"); + return NULL; + } + /* copy all info from the old event */ + gst_event_copy_seek (new_event, seek); + /* set the info from ourselves */ + new_event->accuracy[GST_OFFSET_BYTES] = ((mad->vbr_average == mad->header.bitrate) && (mad->framecount >= GST_MAD_CHECK_LENGTH) + ? GST_ACCURACY_SURE : GST_ACCURACY_GUESS); + new_event->offset[GST_OFFSET_BYTES] = seek->offset[GST_OFFSET_TIME] * mad->vbr_average / 8000000; + if ((ret = gst_pad_send_event (nextpad, GST_DATA (new_event))) != NULL) + { + mad->need_flush |= seek->flush; + } + gst_data_unref (event); + return ret; + } + break; + case GST_EVENT_FLUSH: + if ((ret = gst_pad_send_event (nextpad, event)) == NULL) + { + return NULL; + } + mad->need_flush = TRUE; + return ret; + break; + default: + break; + } + + return gst_pad_send_event (nextpad, event); +} + +static GstEventLength * +gst_mad_new_length_event (GstEventLength *length) +{ + GstEventLength *ret = gst_event_new_length (length->original, 0, 0); + gst_event_copy_length (ret, length); + + return ret; } static gboolean Index: gstosssink.c =================================================================== RCS file: /cvsroot/gstreamer/gst-plugins/sys/oss/gstosssink.c,v retrieving revision 1.10 retrieving revision 1.10.4.1 diff -u -d -r1.10 -r1.10.4.1 --- gstosssink.c 21 Feb 2002 13:49:11 -0000 1.10 +++ gstosssink.c 14 Mar 2002 00:03:05 -0000 1.10.4.1 @@ -58,7 +58,7 @@ static void gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); -static void gst_osssink_chain (GstPad *pad,GstBuffer *buf); +static void gst_osssink_chain (GstPad *pad, GstData *data); /* OssSink signals and args */ enum { @@ -74,7 +74,9 @@ ARG_CHANNELS, ARG_FREQUENCY, ARG_FRAGMENT, - ARG_BUFFER_SIZE + ARG_BUFFER_SIZE, + ARG_LENGTH, + ARG_POSITION, /* FILL ME */ }; @@ -203,6 +205,12 @@ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFER_SIZE, g_param_spec_int("buffer_size","buffer_size","buffer_size", 0,G_MAXINT,4096,G_PARAM_READWRITE)); + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_POSITION, + g_param_spec_uint64("position", "Position", "position in the current stream in microseconds", + 0, G_MAXUINT64, 0, G_PARAM_READABLE)); + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_LENGTH, + g_param_spec_uint64("length", "length", "length of the current stream in microseconds", + 0, G_MAXUINT64, 0, G_PARAM_READABLE)); gst_osssink_signals[SIGNAL_HANDOFF] = g_signal_new("handoff",G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, @@ -244,12 +252,15 @@ /* 6 buffers per chunk by default */ osssink->sinkpool = gst_buffer_pool_get_default (osssink->bufsize, 6); + osssink->length = 0; + osssink->provided_clock = GST_CLOCK (gst_oss_clock_new ("OssClock", GST_ELEMENT (osssink))); GST_ELEMENT (osssink)->setclockfunc = gst_osssink_set_clock; GST_ELEMENT (osssink)->getclockfunc = gst_osssink_get_clock; GST_FLAG_SET (osssink, GST_ELEMENT_THREAD_SUGGESTED); + GST_FLAG_SET (osssink, GST_ELEMENT_EVENT_AWARE); } static GstPadConnectReturn @@ -414,22 +425,66 @@ } static void -gst_osssink_chain (GstPad *pad, GstBuffer *buf) +gst_osssink_chain (GstPad *pad, GstData *data) { GstOssSink *osssink; GstClockTime buftime; - + GstBuffer *buf; /* this has to be an audio buffer */ osssink = GST_OSSSINK (gst_pad_get_parent (pad)); + /* handle events */ + if (GST_IS_EVENT (data)) + { + GstEventLength *length; + switch (GST_DATA_TYPE (data)) + { + case GST_EVENT_NEWMEDIA: + /* FIXME */ + osssink->offset = 0; + g_object_notify (G_OBJECT (osssink), "position"); + break; + case GST_EVENT_DISCONTINUOUS: + /* FIXME */ + osssink->offset = data->offset[GST_OFFSET_TIME]; + g_object_notify (G_OBJECT (osssink), "position"); + break; + case GST_EVENT_EOS: + gst_element_set_eos (GST_ELEMENT (osssink)); + break; + case GST_EVENT_LENGTH: + { + length = GST_EVENT_LENGTH (data); + if (length->accuracy[GST_OFFSET_TIME] > GST_ACCURACY_NONE) + { + osssink->length = length->length[GST_OFFSET_TIME]; + g_object_notify (G_OBJECT (osssink), "length"); + } + } + break; + default: + /* g_assert_not_reached () */ + break; + } + gst_data_unref (data); + return; + } + + buf = GST_BUFFER (data); buftime = GST_BUFFER_TIMESTAMP (buf); if (!osssink->bps) { - gst_buffer_unref (buf); + gst_data_unref (data); gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type"); } if (osssink->fd >= 0) { + /* FIXME, NEW_MEDIA/DISCONT?. Try to get our start point */ + if (buftime > osssink->offset) { + /* gst_oss_clock_set_base (GST_OSS_CLOCK (osssink->clock), buftime); */ + osssink->offset = buftime; + } + if (!osssink->mute) { guchar *data = GST_BUFFER_DATA (buf); gint size = GST_BUFFER_SIZE (buf); @@ -442,12 +497,6 @@ audio_buf_info ospace; gint queued; - /* FIXME, NEW_MEDIA/DISCONT?. Try to get our start point */ - if (osssink->offset == 0LL && buftime != -1LL) { - /* gst_oss_clock_set_base (GST_OSS_CLOCK (osssink->clock), buftime); */ - osssink->offset = buftime; - } - ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace); ioctl (osssink->fd, SNDCTL_DSP_GETOPTR, &optr); @@ -484,8 +533,13 @@ } } } + + /* now set the right offset */ + /* FIXME: rounding errors? */ + osssink->offset += GST_BUFFER_SIZE (buf) * 1000000LL / osssink->bps; + g_object_notify (G_OBJECT (osssink), "position"); } - gst_buffer_unref (buf); + gst_data_unref (data); } static void @@ -536,6 +590,7 @@ g_object_notify (object, "buffer_size"); break; default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } @@ -572,7 +627,14 @@ case ARG_BUFFER_SIZE: g_value_set_int (value, osssink->bufsize); break; + case ARG_LENGTH: + g_value_set_uint64 (value, osssink->length); + break; + case ARG_POSITION: + g_value_set_uint64 (value, osssink->offset); + break; default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } Index: gstosssink.h =================================================================== RCS file: /cvsroot/gstreamer/gst-plugins/sys/oss/gstosssink.h,v retrieving revision 1.2 retrieving revision 1.2.4.1 diff -u -d -r1.2 -r1.2.4.1 --- gstosssink.h 3 Feb 2002 20:10:04 -0000 1.2 +++ gstosssink.h 14 Mar 2002 00:03:05 -0000 1.2.4.1 @@ -78,6 +78,9 @@ guint bufsize; guint bps; guint64 offset; + + /* length of the current stream in microseconds */ + guint64 length; guint64 fragment_time; }; |