diff --git a/gst/elements/gstfakesink.c b/gst/elements/gstfakesink.c index a9b1276b56..83a24a60cc 100644 --- a/gst/elements/gstfakesink.c +++ b/gst/elements/gstfakesink.c @@ -149,6 +149,8 @@ gst_fakesink_init (GstFakeSink *fakesink) fakesink->last_message = NULL; GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock; + + GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE); } static void @@ -251,8 +253,26 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf) fakesink = GST_FAKESINK (gst_pad_get_parent (pad)); - if (fakesink->sync) { - gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf)); + if (GST_IS_EVENT (buf)) { + GstEvent *event = GST_EVENT (buf); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_DISCONTINUOUS: + if (fakesink->sync && fakesink->clock) { + gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value; + gst_clock_handle_discont (fakesink->clock, value); + } + default: + gst_pad_event_default (pad, event); + break; + } + + gst_event_free (event); + return; + } + + if (fakesink->sync && fakesink->clock) { + gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf), NULL); } if (!fakesink->silent) { diff --git a/gst/elements/gstfakesrc.c b/gst/elements/gstfakesrc.c index 83474cfeb5..bace80d8ff 100644 --- a/gst/elements/gstfakesrc.c +++ b/gst/elements/gstfakesrc.c @@ -322,7 +322,7 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event) case GST_EVENT_SEEK: src->buffer_count = GST_EVENT_SEEK_OFFSET (event); - if (!GST_EVENT_SEEK_FLUSH (event)) { + if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { gst_event_free (event); break; } diff --git a/gst/elements/gstfilesink.c b/gst/elements/gstfilesink.c index 9b3cd23385..a87e00c159 100644 --- a/gst/elements/gstfilesink.c +++ b/gst/elements/gstfilesink.c @@ -271,24 +271,29 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event) switch (type) { case GST_EVENT_SEEK: /* we need to seek */ - if (GST_EVENT_SEEK_FLUSH(event)) + if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) if (fflush(filesink->file)) gst_element_error(GST_ELEMENT(filesink), "Error flushing the buffer cache of file \'%s\' to disk: %s", gst_filesink_getcurrentfilename(filesink), sys_errlist[errno]); - switch (GST_EVENT_SEEK_TYPE(event)) + + if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { + g_warning("Any other then byte-offset seeking is not supported!\n"); + } + + switch (GST_EVENT_SEEK_METHOD(event)) { - case GST_SEEK_BYTEOFFSET_SET: + case GST_SEEK_METHOD_SET: fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_SET); break; - case GST_SEEK_BYTEOFFSET_CUR: + case GST_SEEK_METHOD_CUR: fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_CUR); break; - case GST_SEEK_BYTEOFFSET_END: + case GST_SEEK_METHOD_END: fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_END); break; default: - g_warning("Any other then byte-offset seeking is not supported!\n"); + g_warning("unkown seek method!\n"); break; } break; diff --git a/gst/elements/gstfilesrc.c b/gst/elements/gstfilesrc.c index 4671033ec6..6b885fb5e9 100644 --- a/gst/elements/gstfilesrc.c +++ b/gst/elements/gstfilesrc.c @@ -110,6 +110,8 @@ static void gst_filesrc_get_property (GObject *object, guint prop_id, static GstBuffer * gst_filesrc_get (GstPad *pad); static gboolean gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event); +static gboolean gst_filesrc_srcpad_query (GstPad *pad, GstPadQueryType type, + GstSeekType *format, gint64 *value); static GstElementStateReturn gst_filesrc_change_state (GstElement *element); @@ -184,8 +186,9 @@ static void gst_filesrc_init (GstFileSrc *src) { src->srcpad = gst_pad_new ("src", GST_PAD_SRC); - gst_pad_set_get_function (src->srcpad,gst_filesrc_get); - gst_pad_set_event_function (src->srcpad,gst_filesrc_srcpad_event); + gst_pad_set_get_function (src->srcpad, gst_filesrc_get); + gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event); + gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query); gst_element_add_pad (GST_ELEMENT (src), src->srcpad); src->pagesize = getpagesize(); @@ -201,7 +204,7 @@ gst_filesrc_init (GstFileSrc *src) src->mapbuf = NULL; src->mapsize = 4 * 1024 * 1024; /* default is 4MB */ - src->map_regions = g_tree_new(gst_filesrc_bufcmp); + src->map_regions = g_tree_new (gst_filesrc_bufcmp); src->map_regions_lock = g_mutex_new(); src->seek_happened = FALSE; @@ -445,12 +448,19 @@ gst_filesrc_get (GstPad *pad) /* check for seek */ if (src->seek_happened) { + GstEvent *event; + src->seek_happened = FALSE; - return GST_BUFFER (gst_event_new (GST_EVENT_DISCONTINUOUS)); + GST_DEBUG (GST_CAT_EVENT, "filesrc sending discont\n"); + event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset, NULL); + GST_EVENT_DISCONT_FLUSH (event) = src->need_flush; + src->need_flush = FALSE; + return GST_BUFFER (event); } /* check for flush */ if (src->need_flush) { src->need_flush = FALSE; + GST_DEBUG (GST_CAT_EVENT, "filesrc sending flush\n"); return GST_BUFFER (gst_event_new_flush ()); } @@ -645,6 +655,7 @@ gst_filesrc_change_state (GstElement *element) case GST_STATE_READY_TO_PAUSED: case GST_STATE_PAUSED_TO_READY: src->curoffset = 0; + src->seek_happened = TRUE; default: break; } @@ -655,21 +666,50 @@ gst_filesrc_change_state (GstElement *element) return GST_STATE_SUCCESS; } +static gboolean +gst_filesrc_srcpad_query (GstPad *pad, GstPadQueryType type, + GstFormat *format, gint64 *value) +{ + GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad)); + + switch (type) { + case GST_PAD_QUERY_TOTAL: + if (*format != GST_FORMAT_BYTES) { + return FALSE; + } + *value = src->filelen; + break; + case GST_PAD_QUERY_POSITION: + if (*format != GST_FORMAT_BYTES) { + return FALSE; + } + *value = src->curoffset; + break; + default: + return FALSE; + break; + } + return TRUE; +} + static gboolean gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event) { - GstFileSrc *src = GST_FILESRC(GST_PAD_PARENT(pad)); + GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: - switch (GST_EVENT_SEEK_TYPE (event)) { - case GST_SEEK_BYTEOFFSET_SET: + if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { + return FALSE; + } + switch (GST_EVENT_SEEK_METHOD (event)) { + case GST_SEEK_METHOD_SET: src->curoffset = (guint64) GST_EVENT_SEEK_OFFSET (event); break; - case GST_SEEK_BYTEOFFSET_CUR: + case GST_SEEK_METHOD_CUR: src->curoffset += GST_EVENT_SEEK_OFFSET (event); break; - case GST_SEEK_BYTEOFFSET_END: + case GST_SEEK_METHOD_END: src->curoffset = src->filelen - ABS (GST_EVENT_SEEK_OFFSET (event)); break; default: @@ -678,9 +718,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event) } g_object_notify (G_OBJECT (src), "offset"); src->seek_happened = TRUE; - src->need_flush = GST_EVENT_SEEK_FLUSH(event); - gst_event_free (event); - /* push a discontinuous event? */ + src->need_flush = GST_EVENT_SEEK_FLAGS(event) & GST_SEEK_FLAG_FLUSH; break; case GST_EVENT_FLUSH: src->need_flush = TRUE; diff --git a/gst/gstclock.c b/gst/gstclock.c index fa72ac2335..b123323a9a 100644 --- a/gst/gstclock.c +++ b/gst/gstclock.c @@ -258,10 +258,12 @@ gst_clock_set_active (GstClock *clock, gboolean active) GST_LOCK (clock); if (active) { - clock->start_time = time - clock->last_time;; + clock->start_time = time - clock->last_time; + clock->accept_discont = TRUE; } else { clock->last_time = time - clock->start_time; + clock->accept_discont = FALSE; } GST_UNLOCK (clock); @@ -286,6 +288,39 @@ gst_clock_is_active (GstClock *clock) return clock->active; } +gboolean +gst_clock_handle_discont (GstClock *clock, guint64 time) +{ + GstClockTime itime = 0LL; + + GST_DEBUG (GST_CAT_CLOCK, "clock discont %llu %llu %d\n", time, clock->start_time, clock->accept_discont); + + GST_LOCK (clock); + if (clock->accept_discont) { + if (CLASS (clock)->get_internal_time) { + itime = CLASS (clock)->get_internal_time (clock); + } + } + else { + GST_UNLOCK (clock); + GST_DEBUG (GST_CAT_CLOCK, "clock discont refused %llu %llu\n", time, clock->start_time); + return FALSE; + } + + clock->start_time = itime - time; + clock->last_time = time; + clock->accept_discont = FALSE; + GST_UNLOCK (clock); + + GST_DEBUG (GST_CAT_CLOCK, "new time %llu\n", gst_clock_get_time (clock)); + + g_mutex_lock (clock->active_mutex); + g_cond_broadcast (clock->active_cond); + g_mutex_unlock (clock->active_mutex); + + return TRUE; +} + /** * gst_clock_get_time * @clock: a #GstClock to query @@ -311,7 +346,7 @@ gst_clock_get_time (GstClock *clock) ret = CLASS (clock)->get_internal_time (clock) - clock->start_time; } /* make sure the time is increasing, else return last_time */ - if (ret < clock->last_time) { + if ((gint64) ret < (gint64) clock->last_time) { ret = clock->last_time; } else { @@ -355,7 +390,7 @@ gst_clock_wait_async_func (GstClock *clock, GstClockTime time, * Returns: the #GstClockReturn result of the operation. */ GstClockReturn -gst_clock_wait (GstClock *clock, GstClockTime time) +gst_clock_wait (GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter) { GstClockID id; GstClockReturn res; @@ -363,7 +398,7 @@ gst_clock_wait (GstClock *clock, GstClockTime time) g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED); id = gst_clock_wait_async_func (clock, time, NULL, NULL); - res = gst_clock_wait_id (clock, id); + res = gst_clock_wait_id (clock, id, jitter); return res; } @@ -460,12 +495,13 @@ gst_clock_unlock_func (GstClock *clock, GstClockTime time, GstClockID id, gpoint * Returns: result of the operation. */ GstClockReturn -gst_clock_wait_id (GstClock *clock, GstClockID id) +gst_clock_wait_id (GstClock *clock, GstClockID id, GstClockTimeDiff *jitter) { GstClockReturn res = GST_CLOCK_TIMEOUT; GstClockEntry *entry = (GstClockEntry *) id; GstClockTime current_real, current, target; GTimeVal timeval; + GstClockTimeDiff this_jitter; g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_ERROR); g_return_val_if_fail (entry, GST_CLOCK_ERROR); @@ -479,16 +515,24 @@ gst_clock_wait_id (GstClock *clock, GstClockID id) entry->func = gst_clock_unlock_func; target = GST_CLOCK_ENTRY_TIME (entry) - current + current_real; - GST_DEBUG (GST_CAT_CLOCK, "%llu %llu %llu\n", target, current, current_real); + GST_DEBUG (GST_CAT_CLOCK, "real_target %llu, current_real %llu, target %llu, now %llu\n", + target, current_real, GST_CLOCK_ENTRY_TIME (entry), current); if (target > current_real) { - timeval.tv_usec = target % 1000000; - timeval.tv_sec = target / 1000000; - + GST_TIME_TO_TIMEVAL (target, timeval); GST_CLOCK_ENTRY_TIMED_WAIT (entry, &timeval); + current = gst_clock_get_time (clock); + this_jitter = current - GST_CLOCK_ENTRY_TIME (entry); + } + else { + res = GST_CLOCK_EARLY; + this_jitter = target - current_real; } GST_CLOCK_ENTRY_UNLOCK (entry); + if (jitter) + *jitter = this_jitter; + gst_clock_free_entry (clock, entry); return res; diff --git a/gst/gstclock.h b/gst/gstclock.h index 97a88a2b8d..9fb6d87583 100644 --- a/gst/gstclock.h +++ b/gst/gstclock.h @@ -45,8 +45,18 @@ typedef guint64 GstClockTime; typedef gint64 GstClockTimeDiff; typedef gpointer GstClockID; -#define GST_CLOCK_DIFF(s, e) (GstClockTimeDiff)((s)-(e)) -#define GST_TIMEVAL_TO_TIME(tv) ((tv).tv_sec * (guint64) G_USEC_PER_SEC + (tv).tv_usec) +#define GST_SECOND ((guint64)G_USEC_PER_SEC) +#define GST_MSECOND ((guint64)GST_SECOND/1000LL) +#define GST_USECOND ((guint64)GST_SECOND/1000000LL) +#define GST_NSECOND ((guint64)GST_SECOND/1000000000LL) + +#define GST_CLOCK_DIFF(s, e) (GstClockTimeDiff)((s)-(e)) +#define GST_TIMEVAL_TO_TIME(tv) ((tv).tv_sec * GST_SECOND + (tv).tv_usec * GST_USECOND) +#define GST_TIME_TO_TIMEVAL(t,tv) \ +G_STMT_START { \ + (tv).tv_sec = (t) / GST_SECOND; \ + (tv).tv_usec = ((t) / GST_USECOND) % GST_SECOND; \ +} G_STMT_END typedef struct _GstClock GstClock; typedef struct _GstClockClass GstClockClass; @@ -66,6 +76,7 @@ struct _GstClock { GstClockTime start_time; GstClockTime last_time; + gboolean accept_discont; gdouble speed; gboolean active; GList *entries; @@ -95,18 +106,19 @@ gdouble gst_clock_get_speed (GstClock *clock); void gst_clock_set_active (GstClock *clock, gboolean active); gboolean gst_clock_is_active (GstClock *clock); void gst_clock_reset (GstClock *clock); +gboolean gst_clock_handle_discont (GstClock *clock, guint64 time); gboolean gst_clock_async_supported (GstClock *clock); GstClockTime gst_clock_get_time (GstClock *clock); -GstClockReturn gst_clock_wait (GstClock *clock, GstClockTime time); +GstClockReturn gst_clock_wait (GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter); GstClockID gst_clock_wait_async (GstClock *clock, GstClockTime time, GstClockCallback func, gpointer user_data); void gst_clock_cancel_wait_async (GstClock *clock, GstClockID id); GstClockID gst_clock_notify_async (GstClock *clock, GstClockTime interval, GstClockCallback func, gpointer user_data); void gst_clock_remove_notify_async (GstClock *clock, GstClockID id); -GstClockReturn gst_clock_wait_id (GstClock *clock, GstClockID id); +GstClockReturn gst_clock_wait_id (GstClock *clock, GstClockID id, GstClockTimeDiff *jitter); GstClockID gst_clock_get_next_id (GstClock *clock); void gst_clock_unlock_id (GstClock *clock, GstClockID id); diff --git a/gst/gstelement.c b/gst/gstelement.c index efb4600fd4..8a4b35183b 100644 --- a/gst/gstelement.c +++ b/gst/gstelement.c @@ -183,6 +183,7 @@ gst_element_init (GstElement *element) element->pads = NULL; element->loopfunc = NULL; element->sched = NULL; + element->clock = NULL; element->sched_private = NULL; element->state_mutex = g_mutex_new (); element->state_cond = g_cond_new (); @@ -223,9 +224,8 @@ gst_element_dispatch_properties_changed (GObject *object, G_OBJECT_CLASS (parent_class)->dispatch_properties_changed (object, n_pspecs, pspecs); /* now let the parent dispatch those, too */ - gst_object = GST_OBJECT (object); - while (gst_object) - { + gst_object = GST_OBJECT_PARENT (object); + while (gst_object) { /* need own category? */ for (i = 0; i < n_pspecs; i++) { GST_DEBUG (GST_CAT_EVENT, "deep notification from %s to %s (%s)", GST_OBJECT_NAME (object), @@ -266,7 +266,7 @@ static void gst_element_threadsafe_properties_pre_run (GstElement *element) { GST_DEBUG (GST_CAT_THREAD, "locking element %s", GST_OBJECT_NAME (element)); - g_mutex_lock (element->property_mutex); + //g_mutex_lock (element->property_mutex); gst_element_set_pending_properties (element); } @@ -274,7 +274,7 @@ static void gst_element_threadsafe_properties_post_run (GstElement *element) { GST_DEBUG (GST_CAT_THREAD, "unlocking element %s", GST_OBJECT_NAME (element)); - g_mutex_unlock (element->property_mutex); + //g_mutex_unlock (element->property_mutex); } void @@ -678,6 +678,8 @@ gst_element_set_clock (GstElement *element, GstClock *clock) if (element->setclockfunc) element->setclockfunc (element, clock); + + element->clock = clock; } /** @@ -711,16 +713,41 @@ gst_element_get_clock (GstElement *element) * Returns: the #GstClockReturn result of the wait operation */ GstClockReturn -gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time) +gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter) { + GstClockReturn res; + g_return_val_if_fail (element != NULL, GST_CLOCK_ERROR); g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR); if (GST_ELEMENT_SCHED (element)) { - return gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, clock, time); + res = gst_scheduler_clock_wait (GST_ELEMENT_SCHED (element), element, clock, time, jitter); } else - return GST_CLOCK_TIMEOUT; + res = GST_CLOCK_TIMEOUT; + + return res; +} + + +/** + * gst_element_release_locks: + * @element: an element + * + * Instruct the element to release all the locks it is holding, ex + * blocking reads, waiting for the clock, ... + * + * Returns: TRUE if the locks could be released. + */ +gboolean +gst_element_release_locks (GstElement *element) +{ + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + + if (CLASS (element)->release_locks) + return CLASS (element)->release_locks (element); + + return TRUE; } /** diff --git a/gst/gstelement.h b/gst/gstelement.h index 73d7ba80e1..1a32317ae9 100644 --- a/gst/gstelement.h +++ b/gst/gstelement.h @@ -130,6 +130,7 @@ struct _GstElement { gpointer sched_private; GstElementSetClockFunction setclockfunc; GstElementGetClockFunction getclockfunc; + GstClock *clock; /* element pads */ guint16 numpads; @@ -169,6 +170,7 @@ struct _GstElementClass { void (*get_property) (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); /* vtable*/ + gboolean (*release_locks) (GstElement *element); /* change the element state */ GstElementStateReturn (*change_state) (GstElement *element); /* request a new pad */ @@ -211,7 +213,10 @@ GstObject* gst_element_get_parent (GstElement *element); GstClock* gst_element_get_clock (GstElement *element); void gst_element_set_clock (GstElement *element, GstClock *clock); -GstClockReturn gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time); +GstClockReturn gst_element_clock_wait (GstElement *element, GstClock *clock, + GstClockTime time, GstClockTimeDiff *jitter); + +gboolean gst_element_release_locks (GstElement *element); void gst_element_yield (GstElement *element); gboolean gst_element_interrupt (GstElement *element); diff --git a/gst/gstevent.c b/gst/gstevent.c index 880dd6890b..5951952a19 100644 --- a/gst/gstevent.c +++ b/gst/gstevent.c @@ -25,6 +25,8 @@ #include "gst/gstevent.h" #include /* memcpy */ +/* #define MEMPROF */ + GType _gst_event_type; static GMemChunk *_gst_event_chunk; @@ -71,9 +73,13 @@ gst_event_new (GstEventType type) { GstEvent *event; +#ifndef MEMPROF g_mutex_lock (_gst_event_chunk_lock); event = g_mem_chunk_alloc (_gst_event_chunk); g_mutex_unlock (_gst_event_chunk_lock); +#else + event = g_new0(GstEvent, 1); +#endif GST_INFO (GST_CAT_EVENT, "creating new event %p", event); GST_DATA_TYPE (event) = _gst_event_type; @@ -97,9 +103,13 @@ gst_event_copy (GstEvent *event) { GstEvent *copy; +#ifndef MEMPROF g_mutex_lock (_gst_event_chunk_lock); copy = g_mem_chunk_alloc (_gst_event_chunk); g_mutex_unlock (_gst_event_chunk_lock); +#else + copy = g_new0(GstEvent, 1); +#endif memcpy (copy, event, sizeof (GstEvent)); @@ -127,7 +137,11 @@ gst_event_free (GstEvent* event) default: break; } +#ifndef MEMPROF g_mem_chunk_free (_gst_event_chunk, event); +#else + g_free (event); +#endif g_mutex_unlock (_gst_event_chunk_lock); } @@ -142,16 +156,65 @@ gst_event_free (GstEvent* event) * Returns: A new seek event. */ GstEvent* -gst_event_new_seek (GstSeekType type, gint64 offset, gboolean flush) +gst_event_new_seek (GstSeekType type, gint64 offset) { GstEvent *event; event = gst_event_new (GST_EVENT_SEEK); GST_EVENT_SEEK_TYPE (event) = type; GST_EVENT_SEEK_OFFSET (event) = offset; - GST_EVENT_SEEK_FLUSH (event) = flush; return event; } +GstEvent* +gst_event_new_discontinuous (gboolean new_media, GstSeekType format1, ...) +{ + va_list var_args; + GstEvent *event; + gint count = 0; + + event = gst_event_new (GST_EVENT_DISCONTINUOUS); + GST_EVENT_DISCONT_NEW_MEDIA (event) = new_media; + + va_start (var_args, format1); + + while (format1) { + + GST_EVENT_DISCONT_OFFSET (event, count).format = format1 & GST_SEEK_FORMAT_MASK; + GST_EVENT_DISCONT_OFFSET (event, count).value = va_arg (var_args, gint64); + + format1 = va_arg (var_args, GstSeekType); + + count++; + } + va_end (var_args); + + GST_EVENT_DISCONT_OFFSET_LEN (event) = count; + + return event; +} + +gboolean +gst_event_discont_get_value (GstEvent *event, GstSeekType type, gint64 *value) +{ + gint i, n; + + g_return_val_if_fail (event, FALSE); + g_return_val_if_fail (value, FALSE); + + n = GST_EVENT_DISCONT_OFFSET_LEN (event); + + for (i = 0; i < n; i++) { + if (GST_EVENT_DISCONT_OFFSET(event,i).format == type) { + *value = GST_EVENT_DISCONT_OFFSET(event,i).value; + return TRUE; + } + } + + return FALSE; +} + + + diff --git a/gst/gstevent.h b/gst/gstevent.h index 46166ffd12..1595b63af3 100644 --- a/gst/gstevent.h +++ b/gst/gstevent.h @@ -25,23 +25,22 @@ #define __GST_EVENT_H__ #include -#include -#include #include #include +#include -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +G_BEGIN_DECLS typedef enum { GST_EVENT_UNKNOWN, GST_EVENT_EOS, GST_EVENT_FLUSH, GST_EVENT_EMPTY, - GST_EVENT_SEEK, GST_EVENT_DISCONTINUOUS, GST_EVENT_NEW_MEDIA, + GST_EVENT_QOS, + GST_EVENT_SEEK, + GST_EVENT_FILLER, } GstEventType; extern GType _gst_event_type; @@ -54,20 +53,45 @@ extern GType _gst_event_type; #define GST_EVENT_TIMESTAMP(event) (GST_EVENT(event)->timestamp) #define GST_EVENT_SRC(event) (GST_EVENT(event)->src) +#define GST_SEEK_FORMAT_SHIFT 0 +#define GST_SEEK_METHOD_SHIFT 16 +#define GST_SEEK_FLAGS_SHIFT 20 +#define GST_SEEK_FORMAT_MASK 0x0000ffff +#define GST_SEEK_METHOD_MASK 0x000f0000 +#define GST_SEEK_FLAGS_MASK 0xfff00000 + /* seek events */ typedef enum { - GST_SEEK_ANY, - GST_SEEK_TIMEOFFSET_CUR, - GST_SEEK_TIMEOFFSET_SET, - GST_SEEK_TIMEOFFSET_END, - GST_SEEK_BYTEOFFSET_SET, - GST_SEEK_BYTEOFFSET_CUR, - GST_SEEK_BYTEOFFSET_END, + GST_SEEK_METHOD_CUR = (1 << GST_SEEK_METHOD_SHIFT), + GST_SEEK_METHOD_SET = (2 << GST_SEEK_METHOD_SHIFT), + GST_SEEK_METHOD_END = (3 << GST_SEEK_METHOD_SHIFT), + + GST_SEEK_FLAG_FLUSH = (1 << (GST_SEEK_FLAGS_SHIFT + 0)), + GST_SEEK_FLAG_ACCURATE = (1 << (GST_SEEK_FLAGS_SHIFT + 1)), } GstSeekType; -#define GST_EVENT_SEEK_TYPE(event) (GST_EVENT(event)->event_data.seek.type) -#define GST_EVENT_SEEK_OFFSET(event) (GST_EVENT(event)->event_data.seek.offset) -#define GST_EVENT_SEEK_FLUSH(event) (GST_EVENT(event)->event_data.seek.flush) +typedef enum { + GST_SEEK_CERTAIN, + GST_SEEK_FUZZY, +} GstSeekAccuracy; + +typedef struct +{ + GstFormat format; + gint64 value; +} GstFormatValue; + +#define GST_EVENT_SEEK_TYPE(event) (GST_EVENT(event)->event_data.seek.type) +#define GST_EVENT_SEEK_FORMAT(event) (GST_EVENT_SEEK_TYPE(event) & GST_SEEK_FORMAT_MASK) +#define GST_EVENT_SEEK_METHOD(event) (GST_EVENT_SEEK_TYPE(event) & GST_SEEK_METHOD_MASK) +#define GST_EVENT_SEEK_FLAGS(event) (GST_EVENT_SEEK_TYPE(event) & GST_SEEK_FLAGS_MASK) +#define GST_EVENT_SEEK_OFFSET(event) (GST_EVENT(event)->event_data.seek.offset) +#define GST_EVENT_SEEK_ACCURACY(event) (GST_EVENT(event)->event_data.seek.accuracy) + +#define GST_EVENT_DISCONT_NEW_MEDIA(event) (GST_EVENT(event)->event_data.discont.new_media) +#define GST_EVENT_DISCONT_FLUSH(event) (GST_EVENT(event)->event_data.discont.flush) +#define GST_EVENT_DISCONT_OFFSET(event,i) (GST_EVENT(event)->event_data.discont.offsets[i]) +#define GST_EVENT_DISCONT_OFFSET_LEN(event) (GST_EVENT(event)->event_data.discont.noffsets) struct _GstEvent { GstData data; @@ -78,27 +102,37 @@ struct _GstEvent { union { struct { - GstSeekType type; - gint64 offset; - gboolean flush; + GstSeekType type; + gint64 offset; + GstSeekAccuracy accuracy; } seek; + struct { + GstFormatValue offsets[8]; + gint noffsets; + gboolean new_media; + gboolean flush; + GstSeekAccuracy accuracy; + } discont; } event_data; }; -void _gst_event_initialize (void); +void _gst_event_initialize (void); -GstEvent* gst_event_new (GstEventType type); -GstEvent* gst_event_copy (GstEvent *event); -void gst_event_free (GstEvent *event); +GstEvent* gst_event_new (GstEventType type); +GstEvent* gst_event_copy (GstEvent *event); +void gst_event_free (GstEvent *event); /* seek events */ -GstEvent* gst_event_new_seek (GstSeekType type, gint64 offset, gboolean flush); +GstEvent* gst_event_new_seek (GstSeekType type, gint64 offset); +GstEvent* gst_event_new_discontinuous (gboolean new_media, + GstFormat format1, ...); +gboolean gst_event_discont_get_value (GstEvent *event, GstFormat format, gint64 *value); + +#define gst_event_new_filler() gst_event_new(GST_EVENT_FILLER) /* flush events */ -#define gst_event_new_flush() gst_event_new(GST_EVENT_FLUSH) +#define gst_event_new_flush() gst_event_new(GST_EVENT_FLUSH) -#ifdef __cplusplus -} -#endif /* __cplusplus */ +G_END_DECLS #endif /* __GST_EVENT_H__ */ diff --git a/gst/gstformat.h b/gst/gstformat.h new file mode 100644 index 0000000000..fbce2aa77a --- /dev/null +++ b/gst/gstformat.h @@ -0,0 +1,49 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstevent.h: Header for GstEvent subsystem + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_FORMAT_H__ +#define __GST_FORMAT_H__ + +#include + +G_BEGIN_DECLS + +typedef enum { + GST_FORMAT_NONE = 0, + GST_FORMAT_DEFAULT = 1, + GST_FORMAT_BYTES = 2, + GST_FORMAT_TIME = 6, + GST_FORMAT_BUFFERS = 7, + GST_FORMAT_PERCENT = 8, + + /* audio related */ + GST_FORMAT_SAMPLES = 3, + + /* video related */ + GST_FORMAT_FRAMES = 4, + GST_FORMAT_FIELDS = 5, +} GstFormat; + +G_END_DECLS + +#endif /* __GST_FORMAT_H__ */ diff --git a/gst/gstpad.c b/gst/gstpad.c index 229f411812..cb1498db68 100644 --- a/gst/gstpad.c +++ b/gst/gstpad.c @@ -31,6 +31,15 @@ #include "gstscheduler.h" #include "gstevent.h" +enum { + TEMPL_PAD_CREATED, + /* FILL ME */ + TEMPL_LAST_SIGNAL +}; + +static GstObject *padtemplate_parent_class = NULL; +static guint gst_pad_template_signals[TEMPL_LAST_SIGNAL] = { 0 }; + GType _gst_pad_type = 0; /***** Start with the base GstPad class *****/ @@ -206,11 +215,9 @@ gst_real_pad_init (GstRealPad *pad) pad->chainfunc = NULL; pad->getfunc = NULL; - pad->getregionfunc = NULL; pad->chainhandler = GST_DEBUG_FUNCPTR (gst_pad_push_func); pad->gethandler = NULL; - pad->pullregionfunc = NULL; pad->bufferpoolfunc = NULL; pad->ghostpads = NULL; @@ -218,6 +225,12 @@ gst_real_pad_init (GstRealPad *pad) pad->connectfunc = NULL; pad->getcapsfunc = NULL; + + pad->convertfunc = gst_pad_convert_default; + pad->eventfunc = gst_pad_event_default; + pad->convertfunc = gst_pad_convert_default; + pad->queryfunc = gst_pad_query_default; + pad->intconnfunc = gst_pad_get_internal_connections_default; } static void @@ -258,6 +271,32 @@ gst_real_pad_get_property (GObject *object, guint prop_id, GValue *value, GParam } +/** + * gst_pad_custom_new: + * @type: the type of the pad + * @name: name of new pad + * @direction: either GST_PAD_SRC or GST_PAD_SINK + * + * Create a new pad with given name from the given type. + * + * Returns: new pad + */ +GstPad* +gst_pad_custom_new (GType type, const gchar *name, + GstPadDirection direction) +{ + GstRealPad *pad; + + g_return_val_if_fail (name != NULL, NULL); + g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL); + + pad = g_object_new (type, NULL); + gst_object_set_name (GST_OBJECT (pad), name); + GST_RPAD_DIRECTION (pad) = direction; + + return GST_PAD (pad); +} + /** * gst_pad_new: * @name: name of new pad @@ -268,19 +307,38 @@ gst_real_pad_get_property (GObject *object, guint prop_id, GValue *value, GParam * Returns: new pad */ GstPad* -gst_pad_new (gchar *name, +gst_pad_new (const gchar *name, GstPadDirection direction) { - GstRealPad *pad; + return gst_pad_custom_new (gst_real_pad_get_type (), name, direction); +} +/** + * gst_pad_custom_new_from_template: + * @type: the custom GType for this pad + * @templ: the pad template to use + * @name: the name of the element + * + * Create a new pad with given name from the given template. + * + * Returns: new pad + */ +GstPad* +gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ, + const gchar *name) +{ + GstPad *pad; g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (direction != GST_PAD_UNKNOWN, NULL); + g_return_val_if_fail (templ != NULL, NULL); - pad = g_object_new (gst_real_pad_get_type (), NULL); - gst_object_set_name (GST_OBJECT (pad), name); - GST_RPAD_DIRECTION (pad) = direction; + pad = gst_pad_new (name, templ->direction); + + gst_object_ref (GST_OBJECT (templ)); + GST_PAD_PAD_TEMPLATE (pad) = templ; - return GST_PAD (pad); + g_signal_emit (G_OBJECT (templ), gst_pad_template_signals[TEMPL_PAD_CREATED], 0, pad); + + return pad; } /** @@ -294,19 +352,9 @@ gst_pad_new (gchar *name, */ GstPad* gst_pad_new_from_template (GstPadTemplate *templ, - gchar *name) + const gchar *name) { - GstPad *pad; - - g_return_val_if_fail (name != NULL, NULL); - g_return_val_if_fail (templ != NULL, NULL); - - pad = gst_pad_new (name, templ->direction); - - gst_object_ref (GST_OBJECT (templ)); - GST_PAD_PAD_TEMPLATE (pad) = templ; - - return pad; + return gst_pad_custom_new_from_template (gst_real_pad_get_type (), templ, name); } /** @@ -418,24 +466,43 @@ gst_pad_set_event_function (GstPad *pad, } /** - * gst_pad_set_getregion_function: - * @pad: the pad to set the getregion function for - * @getregion: the getregion function + * gst_pad_set_convert_function: + * @pad: the pad to set the event handler for + * @convert: the convert function * - * Set the given getregion function for the pad. + * Set the given convert function for the pad. */ void -gst_pad_set_getregion_function (GstPad *pad, - GstPadGetRegionFunction getregion) +gst_pad_set_convert_function (GstPad *pad, + GstPadConvertFunction convert) { g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_REAL_PAD (pad)); - GST_RPAD_GETREGIONFUNC(pad) = getregion; - GST_DEBUG (GST_CAT_PADS, "getregionfunc for %s:%s set to %s", - GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (getregion)); + GST_RPAD_CONVERTFUNC(pad) = convert; + GST_DEBUG (GST_CAT_PADS, "convertfunc for %s:%s set to %s", + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (convert)); } +/** + * gst_pad_set_query_function: + * @pad: the pad to set the event handler for + * @query: the query function + * + * Set the given query function for the pad. + */ +void +gst_pad_set_query_function (GstPad *pad, GstPadQueryFunction query) +{ + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_REAL_PAD (pad)); + + GST_RPAD_QUERYFUNC(pad) = query; + GST_DEBUG (GST_CAT_PADS, "queryfunc for %s:%s set to %s", + GST_DEBUG_PAD_NAME (pad), GST_DEBUG_FUNCPTR_NAME (query)); +} + + /** * gst_pad_set_connect_function: * @pad: the pad to set the connect function for @@ -1832,56 +1899,6 @@ gst_pad_pull (GstPad *pad) } #endif -#ifndef gst_pad_pullregion -/** - * gst_pad_pullregion: - * @pad: the pad to pull the region from - * @type: the regiontype - * @offset: the offset/start of the buffer to pull - * @len: the length of the buffer to pull - * - * Pull a buffer region from the peer pad. The region to pull can be - * specified with a offset/lenght pair or with a start/legnth time - * indicator as specified by the type parameter. - * - * Returns: a new buffer from the peer pad with data in the specified - * region. - */ -GstBuffer* -gst_pad_pullregion (GstPad *pad, GstRegionType type, guint64 offset, guint64 len) -{ - GstRealPad *peer; - GstBuffer *result = NULL; - - g_return_val_if_fail (GST_PAD_DIRECTION (pad) == GST_PAD_SINK, NULL); - - do { - peer = GST_RPAD_PEER(pad); - g_return_val_if_fail (peer != NULL, NULL); - - if (result) - gst_buffer_unref (result); - - GST_DEBUG_ENTER("(%s:%s,%d,%lld,%lld)",GST_DEBUG_PAD_NAME(pad),type,offset,len); - - if (peer->pullregionfunc) { - GST_DEBUG (GST_CAT_DATAFLOW, "calling pullregionfunc &%s of peer pad %s:%s", - GST_DEBUG_FUNCPTR_NAME (peer->pullregionfunc), GST_DEBUG_PAD_NAME(GST_PAD_CAST (peer))); - result = (peer->pullregionfunc) (GST_PAD_CAST (peer), type, offset, len); - } else { - GST_DEBUG (GST_CAT_DATAFLOW,"no pullregionfunc"); - result = NULL; - break; - } - } - /* FIXME */ - while (result && !(GST_BUFFER_OFFSET (result) == offset && - GST_BUFFER_SIZE (result) == len)); - - return result; -} -#endif - /** * gst_pad_peek: * @pad: the pad to peek @@ -1959,15 +1976,6 @@ gst_pad_selectv (GstPad *pad, ...) static void gst_pad_template_class_init (GstPadTemplateClass *klass); static void gst_pad_template_init (GstPadTemplate *templ); -enum { - TEMPL_PAD_CREATED, - /* FILL ME */ - TEMPL_LAST_SIGNAL -}; - -static GstObject *padtemplate_parent_class = NULL; -static guint gst_pad_template_signals[TEMPL_LAST_SIGNAL] = { 0 }; - GType gst_pad_template_get_type (void) { @@ -2238,7 +2246,72 @@ gst_ghost_pad_new (gchar *name, return GST_PAD (ghostpad); } -static void +/** + * gst_pad_get_internal_connections_default: + * @pad: the pad to get the internal connections of + * + * Get a GList of pads that this pad is connected to internally + * to the parent element. + * + * Returns: a GList of pads, g_list_free after use. + */ +GList* +gst_pad_get_internal_connections_default (GstPad *pad) +{ + GList *res = NULL; + GstElement *parent; + GList *parent_pads; + GstPadDirection direction; + GstRealPad *rpad; + + g_return_val_if_fail (GST_IS_PAD (pad), FALSE); + + rpad = GST_PAD_REALIZE (pad); + direction = rpad->direction; + + parent = GST_PAD_PARENT (rpad); + parent_pads = parent->pads; + + while (parent_pads) { + GstRealPad *parent_pad = GST_PAD_REALIZE (parent_pads->data); + + if (parent_pad->direction != direction) { + res = g_list_prepend (res, parent_pad); + } + + parent_pads = g_list_next (parent_pads); + } + + return res; +} + +/** + * gst_pad_get_internal_connections: + * @pad: the pad to get the internal connections of + * + * Get a GList of pads that this pad is connected to internally + * to the parent element. + * + * Returns: a GList of pads, g_list_free after use. + */ +GList* +gst_pad_get_internal_connections (GstPad *pad) +{ + GList *res = NULL; + GstRealPad *rpad; + + g_return_val_if_fail (GST_IS_PAD (pad), NULL); + + rpad = GST_PAD_REALIZE (pad); + + if (GST_RPAD_INTCONNFUNC (rpad)) + res = GST_RPAD_INTCONNFUNC (rpad) (GST_PAD_CAST (rpad)); + + return res; +} + + +static gboolean gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *event) { GList *pads = element->pads; @@ -2255,10 +2328,13 @@ gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *even else { GstPad *peerpad = GST_PAD_CAST (GST_RPAD_PEER (eventpad)); - gst_pad_send_event (peerpad, gst_event_copy (event)); + /* we only send the event on one pad, multi-sinkpad elements should implement + * a handler */ + return gst_pad_send_event (peerpad, event); } } } + return TRUE; } /** @@ -2267,8 +2343,10 @@ gst_pad_event_default_dispatch (GstPad *pad, GstElement *element, GstEvent *even * @event: the event to handle * * Invoke the default event handler for the given pad. + * + * Returns: TRUE if the event was sent succesfully. */ -void +gboolean gst_pad_event_default (GstPad *pad, GstEvent *event) { GstElement *element = GST_PAD_PARENT (pad); @@ -2282,11 +2360,61 @@ gst_pad_event_default (GstPad *pad, GstEvent *event) /* we have to try to schedule another element because this one is disabled */ gst_element_yield (element); break; + case GST_EVENT_DISCONTINUOUS: + { + guint64 time; + + if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &time)) { + if (element->setclockfunc && element->clock) { + gst_clock_handle_discont (element->clock, time); + } + } + } case GST_EVENT_FLUSH: default: - gst_pad_event_default_dispatch (pad, element, event); - break; + return gst_pad_event_default_dispatch (pad, element, event); } + return TRUE; +} + +/** + * gst_pad_dispatcher: + * @pad: the pad to dispatch + * @dispatch: the GstDispatcherFunc to call + * @data: data passed to the dispatcher function. + * + * Invoke the given dispatcher function on all internally connected + * pads of the given pad. The GstPadDispatcherFunc should return + * TRUE when no further pads need to be preocessed. + * + * Returns: TRUE if one of the dispatcher functions returned TRUE. + */ +gboolean +gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunc dispatch, gpointer data) +{ + gboolean res = FALSE; + GList *int_pads, *orig; + + g_return_val_if_fail (pad, FALSE); + g_return_val_if_fail (data, FALSE); + + orig = int_pads = gst_pad_get_internal_connections (pad); + + while (int_pads) { + GstRealPad *int_rpad = GST_PAD_REALIZE (int_pads->data); + GstRealPad *int_peer = GST_RPAD_PEER (int_rpad); + + if (int_peer && GST_PAD_IS_CONNECTED (int_peer)) { + res = dispatch (GST_PAD_CAST (int_peer), data); + if (res) + break; + } + int_pads = g_list_next (int_pads); + } + + g_list_free (orig); + + return res; } /** @@ -2301,10 +2429,13 @@ gst_pad_event_default (GstPad *pad, GstEvent *event) gboolean gst_pad_send_event (GstPad *pad, GstEvent *event) { - gboolean handled = FALSE; + gboolean success = FALSE; g_return_val_if_fail (event, FALSE); + if (!pad || (GST_PAD_IS_SINK (pad) && !GST_PAD_IS_CONNECTED (pad))) + return FALSE; + if (GST_EVENT_SRC (event) == NULL) GST_EVENT_SRC (event) = gst_object_ref (GST_OBJECT (pad)); @@ -2312,17 +2443,166 @@ gst_pad_send_event (GstPad *pad, GstEvent *event) GST_EVENT_TYPE (event), GST_DEBUG_PAD_NAME (pad)); if (GST_RPAD_EVENTFUNC (pad)) - handled = GST_RPAD_EVENTFUNC (pad) (pad, event); + success = GST_RPAD_EVENTFUNC (pad) (pad, event); else { GST_DEBUG(GST_CAT_EVENT, "there's no event function for pad %s:%s", GST_DEBUG_PAD_NAME (pad)); } - if (!handled) { - GST_DEBUG(GST_CAT_EVENT, "proceeding with default event behavior here"); - gst_pad_event_default (pad, event); - handled = TRUE; - } - - return handled; + return success; } +typedef struct +{ + GstFormat src_format; + gint64 src_value; + GstFormat *dest_format; + gint64 *dest_value; +} GstPadConvertData; + +static gboolean +gst_pad_convert_dispatcher (GstPad *pad, GstPadConvertData *data) +{ + return gst_pad_convert (pad, data->src_format, data->src_value, + data->dest_format, data->dest_value); +} + +/** + * gst_pad_convert_default: + * @pad: the pad to invoke the default converter on + * @src_format: the source format + * @src_value: the source value + * @dest_format: a pointer to the destination format + * @dest_value: a pointer to the destination value + * + * Invoke the default converter on a pad. This will forward the + * call to the pad obtained using the internal connection of + * the element. + * + * Returns: TRUE if the conversion could be performed. + */ +gboolean +gst_pad_convert_default (GstPad *pad, + GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value) +{ + GstPadConvertData data; + + g_return_val_if_fail (pad, FALSE); + g_return_val_if_fail (dest_format, FALSE); + g_return_val_if_fail (dest_value, FALSE); + + data.src_format = src_format; + data.src_value = src_value; + data.dest_format = dest_format; + data.dest_value = dest_value; + + return gst_pad_dispatcher (pad, (GstPadDispatcherFunc) gst_pad_convert_dispatcher, &data); +} + +/** + * gst_pad_convert: + * @pad: the pad to invoke the converter on + * @src_format: the source format + * @src_value: the source value + * @dest_format: a pointer to the destination format + * @dest_value: a pointer to the destination value + * + * Invoke a conversion on the pad. + * + * Returns: TRUE if the conversion could be performed. + */ +gboolean +gst_pad_convert (GstPad *pad, + GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value) +{ + GstRealPad *rpad; + + g_return_val_if_fail (pad, FALSE); + g_return_val_if_fail (dest_format, FALSE); + g_return_val_if_fail (dest_value, FALSE); + + rpad = GST_PAD_REALIZE (pad); + + g_return_val_if_fail (rpad, FALSE); + + if (GST_RPAD_CONVERTFUNC (rpad)) { + return GST_RPAD_CONVERTFUNC (rpad) (GST_PAD_CAST (rpad), src_format, src_value, dest_format, dest_value); + } + + return FALSE; +} + +typedef struct +{ + GstPadQueryType type; + GstFormat *format; + gint64 *value; +} GstPadQueryData; + +static gboolean +gst_pad_query_dispatcher (GstPad *pad, GstPadQueryData *data) +{ + return gst_pad_query (pad, data->type, data->format, data->value); +} + +/** + * gst_pad_query_default: + * @pad: the pad to invoke the default query on + * @type: the type of query to perform + * @format: a pointer to the format of the query + * @value: a pointer to the result of the query + * + * Invoke the default query function on a pad. + * + * Returns: TRUE if the query could be performed. + */ +gboolean +gst_pad_query_default (GstPad *pad, GstPadQueryType type, + GstFormat *format, gint64 *value) +{ + GstPadQueryData data; + + g_return_val_if_fail (pad, FALSE); + g_return_val_if_fail (format, FALSE); + g_return_val_if_fail (value, FALSE); + + data.type = type; + data.format = format; + data.value = value; + + return gst_pad_dispatcher (pad, (GstPadDispatcherFunc) gst_pad_query_dispatcher, &data); +} + +/** + * gst_pad_query: + * @pad: the pad to invoke the query on + * @type: the type of query to perform + * @format: a pointer to the format of the query + * @value: a pointer to the result of the query + * + * Query a pad for one of the available GstPadQuery properties. + * + * Returns: TRUE if the query could be performed. + */ +gboolean +gst_pad_query (GstPad *pad, GstPadQueryType type, + GstFormat *format, gint64 *value) +{ + GstRealPad *rpad; + + if (pad == NULL) + return FALSE; + + g_return_val_if_fail (format, FALSE); + g_return_val_if_fail (value, FALSE); + + rpad = GST_PAD_REALIZE (pad); + + g_return_val_if_fail (rpad, FALSE); + + if (GST_RPAD_QUERYFUNC (rpad)) + return GST_RPAD_QUERYFUNC (rpad) (GST_PAD_CAST (pad), type, format, value); + + return FALSE; +} diff --git a/gst/gstpad.h b/gst/gstpad.h index 285a667a5c..c1808c1b97 100644 --- a/gst/gstpad.h +++ b/gst/gstpad.h @@ -111,12 +111,6 @@ typedef struct _GstGhostPadClass GstGhostPadClass; /*typedef struct _GstPadTemplateClass GstPadTemplateClass;*/ -typedef enum { - GST_REGION_VOID, - GST_REGION_OFFSET_LEN, - GST_REGION_TIME_LEN, -} GstRegionType; - typedef enum { GST_PAD_CONNECT_REFUSED = -1, GST_PAD_CONNECT_DELAYED = 0, @@ -124,21 +118,31 @@ typedef enum { GST_PAD_CONNECT_DONE = 2, } GstPadConnectReturn; +typedef enum { + GST_PAD_QUERY_TOTAL, + GST_PAD_QUERY_POSITION, + GST_PAD_QUERY_LATENCY, +} GstPadQueryType; + /* this defines the functions used to chain buffers * pad is the sink pad (so the same chain function can be used for N pads) * buf is the buffer being passed */ typedef void (*GstPadChainFunction) (GstPad *pad,GstBuffer *buf); typedef GstBuffer* (*GstPadGetFunction) (GstPad *pad); typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstEvent *event); +typedef gboolean (*GstPadConvertFunction) (GstPad *pad, + GstSeekType src_format, gint64 src_value, + GstSeekType *dest_format, gint64 *dest_value); +typedef gboolean (*GstPadQueryFunction) (GstPad *pad, GstPadQueryType type, + GstSeekType *format, gint64 *value); +typedef GList* (*GstPadIntConnFunction) (GstPad *pad); -typedef GstBuffer* (*GstPadGetRegionFunction) (GstPad *pad, GstRegionType type, - guint64 offset, guint64 len); -typedef GstBuffer* (*GstPadPullRegionFunction) (GstPad *pad, GstRegionType type, - guint64 offset, guint64 len); typedef GstPadConnectReturn (*GstPadConnectFunction) (GstPad *pad, GstCaps *caps); typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad, GstCaps *caps); typedef GstBufferPool* (*GstPadBufferPoolFunction) (GstPad *pad); +typedef gboolean (*GstPadDispatcherFunc) (GstPad *pad, gpointer data); + typedef enum { GST_PAD_UNKNOWN, GST_PAD_SRC, @@ -178,10 +182,6 @@ struct _GstRealPad { GstRealPad *peer; GstBuffer *bufpen; - /* CR1: FIXME: regiontype should go away */ - GstRegionType regiontype; - guint64 offset; - guint64 len; GstPadChainFunction chainfunc; GstPadChainFunction chainhandler; @@ -190,9 +190,9 @@ struct _GstRealPad { GstPadEventFunction eventfunc; GstPadEventFunction eventhandler; - - GstPadGetRegionFunction getregionfunc; - GstPadPullRegionFunction pullregionfunc; + GstPadConvertFunction convertfunc; + GstPadQueryFunction queryfunc; + GstPadIntConnFunction intconnfunc; GstPadGetCapsFunction getcapsfunc; GstPadConnectFunction connectfunc; @@ -247,18 +247,14 @@ struct _GstGhostPadClass { #define GST_RPAD_GETHANDLER(pad) (((GstRealPad *)(pad))->gethandler) #define GST_RPAD_EVENTFUNC(pad) (((GstRealPad *)(pad))->eventfunc) #define GST_RPAD_EVENTHANDLER(pad) (((GstRealPad *)(pad))->eventhandler) - -#define GST_RPAD_GETREGIONFUNC(pad) (((GstRealPad *)(pad))->getregionfunc) -#define GST_RPAD_PULLREGIONFUNC(pad) (((GstRealPad *)(pad))->pullregionfunc) +#define GST_RPAD_CONVERTFUNC(pad) (((GstRealPad *)(pad))->convertfunc) +#define GST_RPAD_QUERYFUNC(pad) (((GstRealPad *)(pad))->queryfunc) +#define GST_RPAD_INTCONNFUNC(pad) (((GstRealPad *)(pad))->intconnfunc) #define GST_RPAD_CONNECTFUNC(pad) (((GstRealPad *)(pad))->connectfunc) #define GST_RPAD_GETCAPSFUNC(pad) (((GstRealPad *)(pad))->getcapsfunc) #define GST_RPAD_BUFFERPOOLFUNC(pad) (((GstRealPad *)(pad))->bufferpoolfunc) -#define GST_RPAD_REGIONTYPE(pad) (((GstRealPad *)(pad))->regiontype) -#define GST_RPAD_OFFSET(pad) (((GstRealPad *)(pad))->offset) -#define GST_RPAD_LEN(pad) (((GstRealPad *)(pad))->len) - /* GstGhostPad */ #define GST_GPAD_REALPAD(pad) (((GstGhostPad *)(pad))->realpad) @@ -342,17 +338,20 @@ GType gst_pad_get_type (void); GType gst_real_pad_get_type (void); GType gst_ghost_pad_get_type (void); -GstPad* gst_pad_new (gchar *name, GstPadDirection direction); +GstPad* gst_pad_new (const gchar *name, GstPadDirection direction); #define gst_pad_destroy(pad) gst_object_destroy (GST_OBJECT (pad)) -GstPad* gst_pad_new_from_template (GstPadTemplate *templ, gchar *name); +GstPad* gst_pad_new_from_template (GstPadTemplate *templ, const gchar *name); +GstPad* gst_pad_custom_new (GType type, const gchar *name, GstPadDirection direction); +GstPad* gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ, const gchar *name); GstPadDirection gst_pad_get_direction (GstPad *pad); void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain); void gst_pad_set_get_function (GstPad *pad, GstPadGetFunction get); void gst_pad_set_event_function (GstPad *pad, GstPadEventFunction event); - -void gst_pad_set_getregion_function (GstPad *pad, GstPadGetRegionFunction getregion); +void gst_pad_set_convert_function (GstPad *pad, GstPadConvertFunction convert); +void gst_pad_set_query_function (GstPad *pad, GstPadQueryFunction query); +void gst_pad_set_internal_connection_function (GstPad *pad, GstPadIntConnFunction intconn); void gst_pad_set_connect_function (GstPad *pad, GstPadConnectFunction connect); void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps); @@ -411,22 +410,33 @@ void gst_pad_push (GstPad *pad, GstBuffer *buf); #endif #if 1 GstBuffer* gst_pad_pull (GstPad *pad); -GstBuffer* gst_pad_pullregion (GstPad *pad, GstRegionType type, - guint64 offset, guint64 len); #else #define gst_pad_pull(pad) \ ( (((GstRealPad *)(pad))->peer->gethandler) ? \ (((GstRealPad *)(pad))->peer->gethandler)((GstPad *)(((GstRealPad *)(pad))->peer)) : \ NULL ) -#define gst_pad_pullregion(pad,type,offset,len) \ - ( (((GstRealPad *)(pad))->peer->pullregionfunc) ? \ -(((GstRealPad *)(pad))->peer->pullregionfunc)((GstPad *)(((GstRealPad *)(pad))->peer),(type),(offset),(len)) : \ -NULL ) #endif gboolean gst_pad_send_event (GstPad *pad, GstEvent *event); -void gst_pad_event_default (GstPad *pad, GstEvent *event); +gboolean gst_pad_event_default (GstPad *pad, GstEvent *event); +gboolean gst_pad_convert (GstPad *pad, + GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value); +gboolean gst_pad_convert_default (GstPad *pad, + GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value); + +gboolean gst_pad_query (GstPad *pad, GstPadQueryType type, + GstFormat *format, gint64 *value); +gboolean gst_pad_query_default (GstPad *pad, GstPadQueryType type, + GstFormat *format, gint64 *value); + +GList* gst_pad_get_internal_connections (GstPad *pad); +GList* gst_pad_get_internal_connections_default (GstPad *pad); + +gboolean gst_pad_dispatcher (GstPad *pad, GstPadDispatcherFunc dispatch, + gpointer data); GstBuffer* gst_pad_peek (GstPad *pad); diff --git a/gst/gstqueue.c b/gst/gstqueue.c index 11b3e9cdb8..32b6cb402d 100644 --- a/gst/gstqueue.c +++ b/gst/gstqueue.c @@ -82,9 +82,13 @@ static void gst_queue_chain (GstPad *pad, GstBuffer *buf); static GstBuffer * gst_queue_get (GstPad *pad); static GstBufferPool* gst_queue_get_bufferpool (GstPad *pad); -static void gst_queue_locked_flush (GstQueue *queue); +static gboolean gst_queue_handle_src_event (GstPad *pad, GstEvent *event); + + +static void gst_queue_locked_flush (GstQueue *queue); static GstElementStateReturn gst_queue_change_state (GstElement *element); +static gboolean gst_queue_release_locks (GstElement *element); #define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type()) @@ -157,7 +161,8 @@ gst_queue_class_init (GstQueueClass *klass) gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_queue_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_queue_get_property); - gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_queue_change_state); + gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_queue_change_state); + gstelement_class->release_locks = GST_DEBUG_FUNCPTR(gst_queue_release_locks); } static GstPadConnectReturn @@ -207,6 +212,7 @@ gst_queue_init (GstQueue *queue) gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad); gst_pad_set_connect_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_connect)); gst_pad_set_getcaps_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps)); + gst_pad_set_event_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_handle_src_event)); queue->leaky = GST_QUEUE_NO_LEAK; queue->queue = NULL; @@ -301,6 +307,9 @@ restart: GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "eos in on %s %d\n", GST_ELEMENT_NAME (queue), queue->level_buffers); break; + case GST_EVENT_DISCONTINUOUS: + //gst_queue_locked_flush (queue); + break; default: /*gst_pad_event_default (pad, GST_EVENT (buf)); */ break; @@ -350,7 +359,8 @@ restart: while (queue->level_buffers == queue->size_buffers) { /* if there's a pending state change for this queue or its manager, switch */ /* back to iterator so bottom half of state change executes */ - while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + if (queue->interrupt) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!"); g_mutex_unlock (queue->qlock); if (gst_element_interrupt (GST_ELEMENT (queue))) @@ -435,7 +445,8 @@ restart: /* if there's a pending state change for this queue or its manager, switch * back to iterator so bottom half of state change executes */ - while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + if (queue->interrupt) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!"); g_mutex_unlock (queue->qlock); if (gst_element_interrupt (GST_ELEMENT (queue))) @@ -507,6 +518,51 @@ restart: return buf; } + +static gboolean +gst_queue_handle_src_event (GstPad *pad, GstEvent *event) +{ + GstQueue *queue; + + queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); + + g_mutex_lock (queue->qlock); + + if (gst_element_get_state (GST_ELEMENT (queue)) == GST_STATE_PLAYING) { + g_warning ("queue event in playing state"); + } + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH: + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "FLUSH event, flushing queue\n"); + gst_queue_locked_flush (queue); + break; + case GST_EVENT_SEEK: + gst_queue_locked_flush (queue); + default: + gst_pad_event_default (pad, event); + break; + } + g_mutex_unlock (queue->qlock); + return TRUE; +} + +static gboolean +gst_queue_release_locks (GstElement *element) +{ + GstQueue *queue; + + queue = GST_QUEUE (element); + + g_mutex_lock (queue->qlock); + queue->interrupt = TRUE; + g_cond_signal (queue->not_full); + g_cond_signal (queue->not_empty); + g_mutex_unlock (queue->qlock); + + return TRUE; +} + static GstElementStateReturn gst_queue_change_state (GstElement *element) { @@ -543,6 +599,7 @@ gst_queue_change_state (GstElement *element) return GST_STATE_FAILURE; } + queue->interrupt = FALSE; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); diff --git a/gst/gstqueue.h b/gst/gstqueue.h index 6122d2af59..e3ab5bdd30 100644 --- a/gst/gstqueue.h +++ b/gst/gstqueue.h @@ -75,6 +75,7 @@ struct _GstQueue { gint leaky; /* whether the queue is leaky, and if so at which end */ gboolean may_deadlock; /* it the queue should fail on possible deadlocks */ + gboolean interrupt; GMutex *qlock; /* lock for queue (vs object lock) */ /* we are single reader and single writer queue */ diff --git a/gst/gstscheduler.c b/gst/gstscheduler.c index 46de9a5c6a..0291bbcbcf 100644 --- a/gst/gstscheduler.c +++ b/gst/gstscheduler.c @@ -548,12 +548,13 @@ gst_scheduler_auto_clock (GstScheduler *sched) * Returns: the status of the operation */ GstClockReturn -gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, GstClock *clock, GstClockTime time) +gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, GstClock *clock, GstClockTime time, + GstClockTimeDiff *jitter) { g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR); if (CLASS (sched)->clock_wait) - return CLASS (sched)->clock_wait (sched, element, clock, time); + return CLASS (sched)->clock_wait (sched, element, clock, time, jitter); return GST_CLOCK_TIMEOUT; } diff --git a/gst/gstscheduler.h b/gst/gstscheduler.h index ba61ffe2f5..7006d020f4 100644 --- a/gst/gstscheduler.h +++ b/gst/gstscheduler.h @@ -100,7 +100,7 @@ struct _GstSchedulerClass { void (*pad_disconnect) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); void (*pad_select) (GstScheduler *sched, GList *padlist); GstClockReturn (*clock_wait) (GstScheduler *sched, GstElement *element, - GstClock *clock, GstClockTime time); + GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter); GstSchedulerState (*iterate) (GstScheduler *sched); /* for debugging */ void (*show) (GstScheduler *sched); @@ -129,7 +129,7 @@ void gst_scheduler_pad_connect (GstScheduler *sched, GstPad *srcpad, GstPad *s void gst_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); GstPad* gst_scheduler_pad_select (GstScheduler *sched, GList *padlist); GstClockReturn gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element, - GstClock *clock, GstClockTime time); + GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter); gboolean gst_scheduler_iterate (GstScheduler *sched); void gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock); diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c index 978648316d..8ea28b0cad 100644 --- a/gst/gstsystemclock.c +++ b/gst/gstsystemclock.c @@ -108,14 +108,16 @@ static GstClockTime gst_system_clock_get_internal_time (GstClock *clock) { GTimeVal timeval; + g_get_current_time (&timeval); + return GST_TIMEVAL_TO_TIME (timeval); } static guint64 gst_system_clock_get_resolution (GstClock *clock) { - return 1; + return 1 * GST_USECOND; } diff --git a/gst/gstthread.c b/gst/gstthread.c index 58fe4ec60f..072d97d01a 100644 --- a/gst/gstthread.c +++ b/gst/gstthread.c @@ -318,7 +318,7 @@ gst_thread_change_state (GstElement * element) * to perform each elements' change_state() (by calling gstbin.c:: * change_state()). * + the pending state was already set by gstelement.c::set_state() - * + find every queue we manage, and signal its empty and full conditions + * + unlock all elements so the bottom half can start the state change. */ g_mutex_lock (thread->lock); @@ -326,65 +326,45 @@ gst_thread_change_state (GstElement * element) while (elements) { GstElement *element = GST_ELEMENT (elements->data); + GList *pads; + g_assert (element); - THR_DEBUG (" element \"%s\"", GST_ELEMENT_NAME (element)); + THR_DEBUG (" waking element \"%s\"", GST_ELEMENT_NAME (element)); elements = g_list_next (elements); - if (GST_IS_QUEUE (element)) { - GstQueue *queue = GST_QUEUE (element); - /* FIXME make this more efficient by only waking queues that are asleep - * FIXME and only waking the appropriate condition (depending on if it's - * FIXME on up- or down-stream side) - * FIXME also make this more efficient by keeping list of managed queues - */ - THR_DEBUG ("waking queue \"%s\"", GST_ELEMENT_NAME (element)); - g_mutex_lock (queue->qlock); - GST_STATE_PENDING (element) = GST_STATE_PAUSED; - g_cond_signal (queue->not_full); - g_cond_signal (queue->not_empty); - g_mutex_unlock (queue->qlock); + + if (!gst_element_release_locks (element)) { + g_warning ("element %s could not release locks", GST_ELEMENT_NAME (element)); } - else { - GList *pads = GST_ELEMENT_PADS (element); - while (pads) { - GstRealPad *peer = GST_REAL_PAD (GST_PAD_PEER (pads->data)); - GstElement *peerelement; + pads = GST_ELEMENT_PADS (element); - pads = g_list_next (pads); + while (pads) { + GstRealPad *peer = GST_REAL_PAD (GST_PAD_PEER (pads->data)); + GstElement *peerelement; - if (!peer) - continue; + pads = g_list_next (pads); - peerelement = GST_PAD_PARENT (peer); - if (!peerelement) - continue; /* deal with case where there's no peer */ + if (!peer) + continue; - if (!GST_FLAG_IS_SET (peerelement, GST_ELEMENT_DECOUPLED)) { - GST_DEBUG (GST_CAT_THREAD, "peer element isn't DECOUPLED"); - continue; - } + peerelement = GST_PAD_PARENT (peer); + if (!peerelement) + continue; /* deal with case where there's no peer */ - /* FIXME this needs to go away eventually */ - if (!GST_IS_QUEUE (peerelement)) { - GST_DEBUG (GST_CAT_THREAD, "peer element isn't a Queue"); - continue; - } + if (!GST_FLAG_IS_SET (peerelement, GST_ELEMENT_DECOUPLED)) { + GST_DEBUG (GST_CAT_THREAD, "peer element isn't DECOUPLED"); + continue; + } - if (GST_ELEMENT_SCHED (peerelement) != GST_ELEMENT_SCHED (thread)) { - GstQueue *queue = GST_QUEUE (peerelement); - - THR_DEBUG (" element \"%s\" has pad cross sched boundary", GST_ELEMENT_NAME (element)); - /* FIXME!! */ - g_mutex_lock (queue->qlock); - g_cond_signal (queue->not_full); - g_cond_signal (queue->not_empty); - g_mutex_unlock (queue->qlock); + if (GST_ELEMENT_SCHED (peerelement) != GST_ELEMENT_SCHED (thread)) { + THR_DEBUG (" element \"%s\" has pad cross sched boundary", GST_ELEMENT_NAME (element)); + if (!gst_element_release_locks (element)) { + g_warning ("element %s could not release locks", GST_ELEMENT_NAME (element)); } } } - gst_element_disable_threadsafe_properties (element); } THR_DEBUG ("telling thread to pause, signaling"); g_cond_signal (thread->cond); @@ -392,6 +372,12 @@ gst_thread_change_state (GstElement * element) g_cond_wait (thread->cond, thread->lock); THR_DEBUG ("got ack"); g_mutex_unlock (thread->lock); + + elements = gst_bin_get_list (GST_BIN (thread)); + while (elements) { + gst_element_disable_threadsafe_properties ((GstElement*)elements->data); + elements = g_list_next (elements); + } break; } case GST_STATE_READY_TO_NULL: diff --git a/gst/gsttimecache.h b/gst/gsttimecache.h index 826d018673..ff150e69ec 100644 --- a/gst/gsttimecache.h +++ b/gst/gsttimecache.h @@ -88,14 +88,14 @@ struct _GstTimeCache { GType gst_time_cache_get_type (void); GstTimeCache* gst_time_cache_new (void); -gint gst_time_cache_get_group (GstTimeCache *tc); -gint gst_time_cache_new_group (GstTimeCache *tc); -gboolean gst_time_cache_set_group (GstTimeCache *tc, gint groupnum); +gint gst_time_cache_get_group (GstTimeCache *tc); +gint gst_time_cache_new_group (GstTimeCache *tc); +gboolean gst_time_cache_set_group (GstTimeCache *tc, gint groupnum); void gst_time_cache_set_certainty (GstTimeCache *tc, GstTimeCacheCertainty certainty); GstTimeCacheCertainty gst_time_cache_get_certainty (GstTimeCache *tc); -void gst_time_cache_add_entry (GstTimeCache *tc, guint64 location, gint64 timestamp); +void gst_time_cache_add_entry (GstTimeCache *tc, guint64 location, gint64 timestamp); gboolean gst_time_cache_find_location (GstTimeCache *tc, guint64 location, gint64 *timestamp); gboolean gst_time_cache_find_timestamp (GstTimeCache *tc, gint64 timestamp, guint64 *location); diff --git a/gst/gsttypes.h b/gst/gsttypes.h index 54acaf1427..5595ab574d 100644 --- a/gst/gsttypes.h +++ b/gst/gsttypes.h @@ -29,5 +29,10 @@ typedef enum { GST_STATE_ASYNC = 2, } GstElementStateReturn; +typedef enum { + GST_RESULT_OK, + GST_RESULT_NOK, + GST_RESULT_NOT_IMPL, +} GstResult; #endif diff --git a/gst/schedulers/gstbasicscheduler.c b/gst/schedulers/gstbasicscheduler.c index c2bb84646c..94c2a8df69 100644 --- a/gst/schedulers/gstbasicscheduler.c +++ b/gst/schedulers/gstbasicscheduler.c @@ -117,7 +117,7 @@ static void gst_basic_scheduler_pad_connect (GstScheduler *sched, GstPad * static void gst_basic_scheduler_pad_disconnect (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad); static GstPad* gst_basic_scheduler_pad_select (GstScheduler *sched, GList *padlist); static GstClockReturn gst_basic_scheduler_clock_wait (GstScheduler *sched, GstElement *element, - GstClock *clock, GstClockTime time); + GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter); static GstSchedulerState gst_basic_scheduler_iterate (GstScheduler *sched); @@ -289,7 +289,6 @@ gst_basic_scheduler_chain_wrapper (int argc, char *argv[]) buf = gst_pad_pull (pad); if (buf) { if (GST_IS_EVENT (buf) && !GST_ELEMENT_IS_EVENT_AWARE (element)) { - /*gst_pad_event_default (pad, GST_EVENT (buf)); */ gst_pad_send_event (pad, GST_EVENT (buf)); } else { @@ -299,12 +298,6 @@ gst_basic_scheduler_chain_wrapper (int argc, char *argv[]) GST_DEBUG (GST_CAT_DATAFLOW, "calling chain function of element %s done", name); } } - /* - else { - gst_element_error (element, "NULL buffer detected. Is \"%s:%s\" connected?", - name, GST_PAD_NAME (pad), NULL); - } - */ } } } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); @@ -341,27 +334,13 @@ gst_basic_scheduler_src_wrapper (int argc, char *argv[]) pads = g_list_next (pads); if (GST_RPAD_DIRECTION (realpad) == GST_PAD_SRC) { GST_DEBUG (GST_CAT_DATAFLOW, "calling _getfunc for %s:%s", GST_DEBUG_PAD_NAME (realpad)); - if (realpad->regiontype != GST_REGION_VOID) { - g_return_val_if_fail (GST_RPAD_GETREGIONFUNC (realpad) != NULL, 0); -/* if (GST_RPAD_GETREGIONFUNC(realpad) == NULL) */ -/* fprintf(stderr,"error, no getregionfunc in \"%s\"\n", name); */ -/* else */ - buf = - (GST_RPAD_GETREGIONFUNC (realpad)) (GST_PAD_CAST (realpad), realpad->regiontype, - realpad->offset, realpad->len); - realpad->regiontype = GST_REGION_VOID; + g_return_val_if_fail (GST_RPAD_GETFUNC (realpad) != NULL, 0); + buf = GST_RPAD_GETFUNC (realpad) (GST_PAD_CAST (realpad)); + if (buf) { + GST_DEBUG (GST_CAT_DATAFLOW, "calling gst_pad_push on pad %s:%s", + GST_DEBUG_PAD_NAME (realpad)); + gst_pad_push (GST_PAD_CAST (realpad), buf); } - else { - g_return_val_if_fail (GST_RPAD_GETFUNC (realpad) != NULL, 0); -/* if (GST_RPAD_GETFUNC(realpad) == NULL) */ -/* fprintf(stderr,"error, no getfunc in \"%s\"\n", name); */ -/* else */ - buf = GST_RPAD_GETFUNC (realpad) (GST_PAD_CAST (realpad)); - } - - GST_DEBUG (GST_CAT_DATAFLOW, "calling gst_pad_push on pad %s:%s", - GST_DEBUG_PAD_NAME (realpad)); - gst_pad_push (GST_PAD_CAST (realpad), buf); } } } while (!GST_ELEMENT_IS_COTHREAD_STOPPING (element)); @@ -483,46 +462,6 @@ gst_basic_scheduler_gethandler_proxy (GstPad * pad) return buf; } -static GstBuffer * -gst_basic_scheduler_pullregionfunc_proxy (GstPad * pad, GstRegionType type, guint64 offset, guint64 len) -{ - GstBuffer *buf; - GstElement *parent; - GstRealPad *peer; - - parent = GST_PAD_PARENT (pad); - peer = GST_RPAD_PEER (pad); - - GST_DEBUG_ENTER ("%s:%s,%d,%lld,%lld", GST_DEBUG_PAD_NAME (pad), type, offset, len); - - /* put the region info into the pad */ - GST_RPAD_REGIONTYPE (pad) = type; - GST_RPAD_OFFSET (pad) = offset; - GST_RPAD_LEN (pad) = len; - - /* FIXME this should be bounded */ - /* we will loop switching to the peer until it's filled up the bufferpen */ - while (GST_RPAD_BUFPEN (pad) == NULL) { - GST_DEBUG (GST_CAT_DATAFLOW, "switching to %p to fill bufpen", - GST_ELEMENT_THREADSTATE (parent)); - - do_element_switch (parent); - - /* we may no longer be the same pad, check. */ - if (GST_RPAD_PEER (peer) != (GstRealPad *) pad) { - GST_DEBUG (GST_CAT_DATAFLOW, "new pad in mid-switch!"); - pad = (GstPad *) GST_RPAD_PEER (peer); - } - } - GST_DEBUG (GST_CAT_DATAFLOW, "done switching"); - - /* now grab the buffer from the pen, clear the pen, and return the buffer */ - buf = GST_RPAD_BUFPEN (pad); - GST_RPAD_BUFPEN (pad) = NULL; - return buf; -} - - static gboolean gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) { @@ -607,7 +546,6 @@ gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) GST_DEBUG (GST_CAT_SCHEDULING, "copying get function into pull proxy for %s:%s", GST_DEBUG_PAD_NAME (pad)); GST_RPAD_GETHANDLER (pad) = GST_RPAD_GETFUNC (pad); - GST_RPAD_PULLREGIONFUNC (pad) = GST_RPAD_GETREGIONFUNC (pad); } } @@ -622,7 +560,6 @@ gst_basic_scheduler_cothreaded_chain (GstBin * bin, GstSchedulerChain * chain) GST_DEBUG (GST_CAT_SCHEDULING, "setting cothreaded pull proxy for srcpad %s:%s", GST_DEBUG_PAD_NAME (pad)); GST_RPAD_GETHANDLER (pad) = GST_DEBUG_FUNCPTR (gst_basic_scheduler_gethandler_proxy); - GST_RPAD_PULLREGIONFUNC (pad) = GST_DEBUG_FUNCPTR (gst_basic_scheduler_pullregionfunc_proxy); } } } @@ -1116,10 +1053,12 @@ gst_basic_scheduler_yield (GstScheduler *sched, GstElement *element) static gboolean gst_basic_scheduler_interrupt (GstScheduler *sched, GstElement *element) { + GstElement *current = SCHED (element)->current; + GST_FLAG_SET (element, GST_ELEMENT_COTHREAD_STOPPING); - if (element->post_run_func) - element->post_run_func (element); + if (current->post_run_func) + current->post_run_func (current); SCHED (element)->current = NULL; do_cothread_switch (do_cothread_get_main (((GstBasicScheduler *) sched)->context)); @@ -1257,9 +1196,9 @@ gst_basic_scheduler_pad_select (GstScheduler * sched, GList * padlist) static GstClockReturn gst_basic_scheduler_clock_wait (GstScheduler *sched, GstElement *element, - GstClock *clock, GstClockTime time) + GstClock *clock, GstClockTime time, GstClockTimeDiff *jitter) { - return gst_clock_wait (clock, time); + return gst_clock_wait (clock, time, jitter); } static GstSchedulerState diff --git a/libs/gst/bytestream/bytestream.c b/libs/gst/bytestream/bytestream.c index 021810005a..6a20cb8ae5 100644 --- a/libs/gst/bytestream/bytestream.c +++ b/libs/gst/bytestream/bytestream.c @@ -58,6 +58,7 @@ gst_bytestream_new (GstPad * pad) bs->listavail = 0; bs->assembled = NULL; bs->offset = 0LL; + bs->in_seek = FALSE; return bs; } @@ -122,7 +123,9 @@ gst_bytestream_get_next_buf (GstByteStream * bs) GstBuffer *nextbuf, *lastbuf, *headbuf; GSList *end; - g_assert (!bs->event); + /* if there is an event pending, return FALSE */ + if (bs->event) + return FALSE; bs_print ("get_next_buf: pulling buffer"); nextbuf = gst_pad_pull (bs->pad); @@ -429,33 +432,30 @@ gst_bytestream_flush_fast (GstByteStream * bs, guint32 len) } gboolean -gst_bytestream_seek (GstByteStream *bs, GstSeekType type, gint64 offset) +gst_bytestream_seek (GstByteStream *bs, gint64 offset, GstSeekType method) { - GstRealPad *peer = GST_RPAD_PEER (bs->pad); - guint32 waiting; - GstEvent *event = NULL; - GstBuffer *headbuf; + GstRealPad *peer; + + g_return_val_if_fail (bs != NULL, FALSE); + + peer = GST_RPAD_PEER (bs->pad); - if (gst_pad_send_event (GST_PAD (peer), gst_event_new_seek (type, offset, TRUE))) { - + bs_print ("bs: send event\n"); + if (gst_pad_send_event (GST_PAD (peer), gst_event_new_seek ( + GST_FORMAT_BYTES | + (method & GST_SEEK_METHOD_MASK) | + GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, + offset))) + { gst_bytestream_flush_fast (bs, bs->listavail); - while (!gst_bytestream_get_next_buf(bs)) { - gst_bytestream_get_status(bs, &waiting, &event); - - /* it is valid for a seek to cause eos, so lets say it succeeded */ - if (GST_EVENT_TYPE(event) == GST_EVENT_EOS){ - bs->offset = 0LL; - return TRUE; - } - } - - headbuf = GST_BUFFER (bs->buflist->data); - /* we have a new offset */ - bs->offset = GST_BUFFER_OFFSET(headbuf); + /* we set the seek flag here. We cannot pull the pad here + * bacause a seek might occur outisde of the pads cothread context */ + bs->in_seek = TRUE; return TRUE; } + bs_print ("bs: send event failed\n"); return FALSE; } diff --git a/libs/gst/bytestream/bytestream.h b/libs/gst/bytestream/bytestream.h index 051482be08..3f12866232 100644 --- a/libs/gst/bytestream/bytestream.h +++ b/libs/gst/bytestream/bytestream.h @@ -43,6 +43,9 @@ struct _GstByteStream { /* this is needed for gst_bytestream_tell */ guint64 offset; + + /* if we are in the seek state (waiting for DISCONT) */ + gboolean in_seek; }; GstByteStream* gst_bytestream_new (GstPad *pad); @@ -50,7 +53,7 @@ void gst_bytestream_destroy (GstByteStream *bs); guint32 gst_bytestream_read (GstByteStream *bs, GstBuffer** buf, guint32 len); guint64 gst_bytestream_tell (GstByteStream *bs); -gboolean gst_bytestream_seek (GstByteStream *bs, GstSeekType type, gint64 offset); +gboolean gst_bytestream_seek (GstByteStream *bs, gint64 offset, GstSeekType type); guint32 gst_bytestream_peek (GstByteStream *bs, GstBuffer** buf, guint32 len); guint32 gst_bytestream_peek_bytes (GstByteStream *bs, guint8** data, guint32 len); gboolean gst_bytestream_flush (GstByteStream *bs, guint32 len); diff --git a/plugins/elements/gstfakesink.c b/plugins/elements/gstfakesink.c index a9b1276b56..83a24a60cc 100644 --- a/plugins/elements/gstfakesink.c +++ b/plugins/elements/gstfakesink.c @@ -149,6 +149,8 @@ gst_fakesink_init (GstFakeSink *fakesink) fakesink->last_message = NULL; GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock; + + GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE); } static void @@ -251,8 +253,26 @@ gst_fakesink_chain (GstPad *pad, GstBuffer *buf) fakesink = GST_FAKESINK (gst_pad_get_parent (pad)); - if (fakesink->sync) { - gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf)); + if (GST_IS_EVENT (buf)) { + GstEvent *event = GST_EVENT (buf); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_DISCONTINUOUS: + if (fakesink->sync && fakesink->clock) { + gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value; + gst_clock_handle_discont (fakesink->clock, value); + } + default: + gst_pad_event_default (pad, event); + break; + } + + gst_event_free (event); + return; + } + + if (fakesink->sync && fakesink->clock) { + gst_element_clock_wait (GST_ELEMENT (fakesink), fakesink->clock, GST_BUFFER_TIMESTAMP (buf), NULL); } if (!fakesink->silent) { diff --git a/plugins/elements/gstfakesrc.c b/plugins/elements/gstfakesrc.c index 83474cfeb5..bace80d8ff 100644 --- a/plugins/elements/gstfakesrc.c +++ b/plugins/elements/gstfakesrc.c @@ -322,7 +322,7 @@ gst_fakesrc_event_handler (GstPad *pad, GstEvent *event) case GST_EVENT_SEEK: src->buffer_count = GST_EVENT_SEEK_OFFSET (event); - if (!GST_EVENT_SEEK_FLUSH (event)) { + if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { gst_event_free (event); break; } diff --git a/plugins/elements/gstfilesink.c b/plugins/elements/gstfilesink.c index 9b3cd23385..a87e00c159 100644 --- a/plugins/elements/gstfilesink.c +++ b/plugins/elements/gstfilesink.c @@ -271,24 +271,29 @@ gst_filesink_handle_event (GstPad *pad, GstEvent *event) switch (type) { case GST_EVENT_SEEK: /* we need to seek */ - if (GST_EVENT_SEEK_FLUSH(event)) + if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) if (fflush(filesink->file)) gst_element_error(GST_ELEMENT(filesink), "Error flushing the buffer cache of file \'%s\' to disk: %s", gst_filesink_getcurrentfilename(filesink), sys_errlist[errno]); - switch (GST_EVENT_SEEK_TYPE(event)) + + if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { + g_warning("Any other then byte-offset seeking is not supported!\n"); + } + + switch (GST_EVENT_SEEK_METHOD(event)) { - case GST_SEEK_BYTEOFFSET_SET: + case GST_SEEK_METHOD_SET: fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_SET); break; - case GST_SEEK_BYTEOFFSET_CUR: + case GST_SEEK_METHOD_CUR: fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_CUR); break; - case GST_SEEK_BYTEOFFSET_END: + case GST_SEEK_METHOD_END: fseek(filesink->file, GST_EVENT_SEEK_OFFSET(event), SEEK_END); break; default: - g_warning("Any other then byte-offset seeking is not supported!\n"); + g_warning("unkown seek method!\n"); break; } break; diff --git a/plugins/elements/gstfilesrc.c b/plugins/elements/gstfilesrc.c index 4671033ec6..6b885fb5e9 100644 --- a/plugins/elements/gstfilesrc.c +++ b/plugins/elements/gstfilesrc.c @@ -110,6 +110,8 @@ static void gst_filesrc_get_property (GObject *object, guint prop_id, static GstBuffer * gst_filesrc_get (GstPad *pad); static gboolean gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event); +static gboolean gst_filesrc_srcpad_query (GstPad *pad, GstPadQueryType type, + GstSeekType *format, gint64 *value); static GstElementStateReturn gst_filesrc_change_state (GstElement *element); @@ -184,8 +186,9 @@ static void gst_filesrc_init (GstFileSrc *src) { src->srcpad = gst_pad_new ("src", GST_PAD_SRC); - gst_pad_set_get_function (src->srcpad,gst_filesrc_get); - gst_pad_set_event_function (src->srcpad,gst_filesrc_srcpad_event); + gst_pad_set_get_function (src->srcpad, gst_filesrc_get); + gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event); + gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query); gst_element_add_pad (GST_ELEMENT (src), src->srcpad); src->pagesize = getpagesize(); @@ -201,7 +204,7 @@ gst_filesrc_init (GstFileSrc *src) src->mapbuf = NULL; src->mapsize = 4 * 1024 * 1024; /* default is 4MB */ - src->map_regions = g_tree_new(gst_filesrc_bufcmp); + src->map_regions = g_tree_new (gst_filesrc_bufcmp); src->map_regions_lock = g_mutex_new(); src->seek_happened = FALSE; @@ -445,12 +448,19 @@ gst_filesrc_get (GstPad *pad) /* check for seek */ if (src->seek_happened) { + GstEvent *event; + src->seek_happened = FALSE; - return GST_BUFFER (gst_event_new (GST_EVENT_DISCONTINUOUS)); + GST_DEBUG (GST_CAT_EVENT, "filesrc sending discont\n"); + event = gst_event_new_discontinuous (FALSE, GST_FORMAT_BYTES, src->curoffset, NULL); + GST_EVENT_DISCONT_FLUSH (event) = src->need_flush; + src->need_flush = FALSE; + return GST_BUFFER (event); } /* check for flush */ if (src->need_flush) { src->need_flush = FALSE; + GST_DEBUG (GST_CAT_EVENT, "filesrc sending flush\n"); return GST_BUFFER (gst_event_new_flush ()); } @@ -645,6 +655,7 @@ gst_filesrc_change_state (GstElement *element) case GST_STATE_READY_TO_PAUSED: case GST_STATE_PAUSED_TO_READY: src->curoffset = 0; + src->seek_happened = TRUE; default: break; } @@ -655,21 +666,50 @@ gst_filesrc_change_state (GstElement *element) return GST_STATE_SUCCESS; } +static gboolean +gst_filesrc_srcpad_query (GstPad *pad, GstPadQueryType type, + GstFormat *format, gint64 *value) +{ + GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad)); + + switch (type) { + case GST_PAD_QUERY_TOTAL: + if (*format != GST_FORMAT_BYTES) { + return FALSE; + } + *value = src->filelen; + break; + case GST_PAD_QUERY_POSITION: + if (*format != GST_FORMAT_BYTES) { + return FALSE; + } + *value = src->curoffset; + break; + default: + return FALSE; + break; + } + return TRUE; +} + static gboolean gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event) { - GstFileSrc *src = GST_FILESRC(GST_PAD_PARENT(pad)); + GstFileSrc *src = GST_FILESRC (GST_PAD_PARENT (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_SEEK: - switch (GST_EVENT_SEEK_TYPE (event)) { - case GST_SEEK_BYTEOFFSET_SET: + if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { + return FALSE; + } + switch (GST_EVENT_SEEK_METHOD (event)) { + case GST_SEEK_METHOD_SET: src->curoffset = (guint64) GST_EVENT_SEEK_OFFSET (event); break; - case GST_SEEK_BYTEOFFSET_CUR: + case GST_SEEK_METHOD_CUR: src->curoffset += GST_EVENT_SEEK_OFFSET (event); break; - case GST_SEEK_BYTEOFFSET_END: + case GST_SEEK_METHOD_END: src->curoffset = src->filelen - ABS (GST_EVENT_SEEK_OFFSET (event)); break; default: @@ -678,9 +718,7 @@ gst_filesrc_srcpad_event (GstPad *pad, GstEvent *event) } g_object_notify (G_OBJECT (src), "offset"); src->seek_happened = TRUE; - src->need_flush = GST_EVENT_SEEK_FLUSH(event); - gst_event_free (event); - /* push a discontinuous event? */ + src->need_flush = GST_EVENT_SEEK_FLAGS(event) & GST_SEEK_FLAG_FLUSH; break; case GST_EVENT_FLUSH: src->need_flush = TRUE; diff --git a/plugins/elements/gstqueue.c b/plugins/elements/gstqueue.c index 11b3e9cdb8..32b6cb402d 100644 --- a/plugins/elements/gstqueue.c +++ b/plugins/elements/gstqueue.c @@ -82,9 +82,13 @@ static void gst_queue_chain (GstPad *pad, GstBuffer *buf); static GstBuffer * gst_queue_get (GstPad *pad); static GstBufferPool* gst_queue_get_bufferpool (GstPad *pad); -static void gst_queue_locked_flush (GstQueue *queue); +static gboolean gst_queue_handle_src_event (GstPad *pad, GstEvent *event); + + +static void gst_queue_locked_flush (GstQueue *queue); static GstElementStateReturn gst_queue_change_state (GstElement *element); +static gboolean gst_queue_release_locks (GstElement *element); #define GST_TYPE_QUEUE_LEAKY (queue_leaky_get_type()) @@ -157,7 +161,8 @@ gst_queue_class_init (GstQueueClass *klass) gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_queue_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_queue_get_property); - gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_queue_change_state); + gstelement_class->change_state = GST_DEBUG_FUNCPTR(gst_queue_change_state); + gstelement_class->release_locks = GST_DEBUG_FUNCPTR(gst_queue_release_locks); } static GstPadConnectReturn @@ -207,6 +212,7 @@ gst_queue_init (GstQueue *queue) gst_element_add_pad (GST_ELEMENT (queue), queue->srcpad); gst_pad_set_connect_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_connect)); gst_pad_set_getcaps_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_getcaps)); + gst_pad_set_event_function (queue->srcpad, GST_DEBUG_FUNCPTR (gst_queue_handle_src_event)); queue->leaky = GST_QUEUE_NO_LEAK; queue->queue = NULL; @@ -301,6 +307,9 @@ restart: GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "eos in on %s %d\n", GST_ELEMENT_NAME (queue), queue->level_buffers); break; + case GST_EVENT_DISCONTINUOUS: + //gst_queue_locked_flush (queue); + break; default: /*gst_pad_event_default (pad, GST_EVENT (buf)); */ break; @@ -350,7 +359,8 @@ restart: while (queue->level_buffers == queue->size_buffers) { /* if there's a pending state change for this queue or its manager, switch */ /* back to iterator so bottom half of state change executes */ - while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + if (queue->interrupt) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!"); g_mutex_unlock (queue->qlock); if (gst_element_interrupt (GST_ELEMENT (queue))) @@ -435,7 +445,8 @@ restart: /* if there's a pending state change for this queue or its manager, switch * back to iterator so bottom half of state change executes */ - while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + //while (GST_STATE_PENDING (queue) != GST_STATE_VOID_PENDING) { + if (queue->interrupt) { GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "interrupted!!"); g_mutex_unlock (queue->qlock); if (gst_element_interrupt (GST_ELEMENT (queue))) @@ -507,6 +518,51 @@ restart: return buf; } + +static gboolean +gst_queue_handle_src_event (GstPad *pad, GstEvent *event) +{ + GstQueue *queue; + + queue = GST_QUEUE (GST_OBJECT_PARENT (pad)); + + g_mutex_lock (queue->qlock); + + if (gst_element_get_state (GST_ELEMENT (queue)) == GST_STATE_PLAYING) { + g_warning ("queue event in playing state"); + } + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH: + GST_DEBUG_ELEMENT (GST_CAT_DATAFLOW, queue, "FLUSH event, flushing queue\n"); + gst_queue_locked_flush (queue); + break; + case GST_EVENT_SEEK: + gst_queue_locked_flush (queue); + default: + gst_pad_event_default (pad, event); + break; + } + g_mutex_unlock (queue->qlock); + return TRUE; +} + +static gboolean +gst_queue_release_locks (GstElement *element) +{ + GstQueue *queue; + + queue = GST_QUEUE (element); + + g_mutex_lock (queue->qlock); + queue->interrupt = TRUE; + g_cond_signal (queue->not_full); + g_cond_signal (queue->not_empty); + g_mutex_unlock (queue->qlock); + + return TRUE; +} + static GstElementStateReturn gst_queue_change_state (GstElement *element) { @@ -543,6 +599,7 @@ gst_queue_change_state (GstElement *element) return GST_STATE_FAILURE; } + queue->interrupt = FALSE; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element); diff --git a/plugins/elements/gstqueue.h b/plugins/elements/gstqueue.h index 6122d2af59..e3ab5bdd30 100644 --- a/plugins/elements/gstqueue.h +++ b/plugins/elements/gstqueue.h @@ -75,6 +75,7 @@ struct _GstQueue { gint leaky; /* whether the queue is leaky, and if so at which end */ gboolean may_deadlock; /* it the queue should fail on possible deadlocks */ + gboolean interrupt; GMutex *qlock; /* lock for queue (vs object lock) */ /* we are single reader and single writer queue */ diff --git a/tools/gst-inspect.c b/tools/gst-inspect.c index ee8622b5b2..0b8357026c 100644 --- a/tools/gst-inspect.c +++ b/tools/gst-inspect.c @@ -435,8 +435,6 @@ print_element_info (GstElementFactory *factory) printf(" Has chainfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->chainfunc)); if (realpad->getfunc) printf(" Has getfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->getfunc)); - if (realpad->getregionfunc) - printf(" Has getregionfunc(): %s\n",GST_DEBUG_FUNCPTR_NAME(realpad->getregionfunc)); if (pad->padtemplate) printf(" Pad Template: '%s'\n",pad->padtemplate->name_template);