fakesink->last_message = NULL;
GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock;
+
+ GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
}
static void
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) {
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;
}
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;
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);
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();
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;
/* 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 ());
}
case GST_STATE_READY_TO_PAUSED:
case GST_STATE_PAUSED_TO_READY:
src->curoffset = 0;
+ src->seek_happened = TRUE;
default:
break;
}
}
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:
}
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;
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);
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
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 {
* 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;
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;
}
* 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);
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;
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;
GstClockTime start_time;
GstClockTime last_time;
+ gboolean accept_discont;
gdouble speed;
gboolean active;
GList *entries;
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);
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 ();
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),
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);
}
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
if (element->setclockfunc)
element->setclockfunc (element, clock);
+
+ element->clock = clock;
}
/**
* 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;
}
/**
gpointer sched_private;
GstElementSetClockFunction setclockfunc;
GstElementGetClockFunction getclockfunc;
+ GstClock *clock;
/* element pads */
guint16 numpads;
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 */
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);
#include "gst/gstevent.h"
#include <string.h> /* memcpy */
+/* #define MEMPROF */
+
GType _gst_event_type;
static GMemChunk *_gst_event_chunk;
{
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;
{
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));
default:
break;
}
+#ifndef MEMPROF
g_mem_chunk_free (_gst_event_chunk, event);
+#else
+ g_free (event);
+#endif
g_mutex_unlock (_gst_event_chunk_lock);
}
* 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;
+}
+
+
+
#define __GST_EVENT_H__
#include <gst/gsttypes.h>
-#include <gst/gstelement.h>
-#include <gst/gstobject.h>
#include <gst/gstdata.h>
#include <gst/gstcaps.h>
+#include <gst/gstformat.h>
-#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;
#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;
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__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wim.taymans@chello.be>
+ *
+ * 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 <glib.h>
+
+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__ */
#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 *****/
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;
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
/**
- * gst_pad_new:
+ * 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.
+ * Create a new pad with given name from the given type.
*
* Returns: new pad
*/
GstPad*
-gst_pad_new (gchar *name,
- GstPadDirection direction)
+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 (gst_real_pad_get_type (), NULL);
+ pad = g_object_new (type, NULL);
gst_object_set_name (GST_OBJECT (pad), name);
GST_RPAD_DIRECTION (pad) = direction;
}
/**
- * gst_pad_new_from_template:
+ * gst_pad_new:
+ * @name: name of new pad
+ * @direction: either GST_PAD_SRC or GST_PAD_SINK
+ *
+ * Create a new pad with given name.
+ *
+ * Returns: new pad
+ */
+GstPad*
+gst_pad_new (const gchar *name,
+ GstPadDirection direction)
+{
+ 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
*
* Returns: new pad
*/
GstPad*
-gst_pad_new_from_template (GstPadTemplate *templ,
- gchar *name)
+gst_pad_custom_new_from_template (GType type, GstPadTemplate *templ,
+ const gchar *name)
{
GstPad *pad;
gst_object_ref (GST_OBJECT (templ));
GST_PAD_PAD_TEMPLATE (pad) = templ;
+
+ g_signal_emit (G_OBJECT (templ), gst_pad_template_signals[TEMPL_PAD_CREATED], 0, pad);
return pad;
}
/**
+ * gst_pad_new_from_template:
+ * @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_new_from_template (GstPadTemplate *templ,
+ const gchar *name)
+{
+ return gst_pad_custom_new_from_template (gst_real_pad_get_type (), templ, name);
+}
+
+/**
* gst_pad_get_direction:
* @pad: the Pad to get the direction from
*
}
/**
- * 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 convert function for the pad.
+ */
+void
+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_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 getregion function for the pad.
+ * Set the given query function for the pad.
*/
void
-gst_pad_set_getregion_function (GstPad *pad,
- GstPadGetRegionFunction getregion)
+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_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_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
}
#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
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)
{
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;
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;
}
/**
* @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);
/* 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;
}
/**
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));
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 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 handled;
+ 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;
+}
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,
GST_PAD_CONNECT_OK = 1,
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,
GstRealPad *peer;
GstBuffer *bufpen;
- /* CR1: FIXME: regiontype should go away */
- GstRegionType regiontype;
- guint64 offset;
- guint64 len;
GstPadChainFunction chainfunc;
GstPadChainFunction chainhandler;
GstPadEventFunction eventfunc;
GstPadEventFunction eventhandler;
-
- GstPadGetRegionFunction getregionfunc;
- GstPadPullRegionFunction pullregionfunc;
+ GstPadConvertFunction convertfunc;
+ GstPadQueryFunction queryfunc;
+ GstPadIntConnFunction intconnfunc;
GstPadGetCapsFunction getcapsfunc;
GstPadConnectFunction connectfunc;
#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)
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);
#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);
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())
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
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;
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;
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)))
/* 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)))
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)
{
return GST_STATE_FAILURE;
}
+ queue->interrupt = FALSE;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
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 */
* 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;
}
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);
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);
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;
}
* 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);
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);
- }
- else {
- GList *pads = GST_ELEMENT_PADS (element);
- while (pads) {
- GstRealPad *peer = GST_REAL_PAD (GST_PAD_PEER (pads->data));
- GstElement *peerelement;
+ if (!gst_element_release_locks (element)) {
+ g_warning ("element %s could not release locks", GST_ELEMENT_NAME (element));
+ }
- pads = g_list_next (pads);
+ pads = GST_ELEMENT_PADS (element);
- if (!peer)
- continue;
+ while (pads) {
+ GstRealPad *peer = GST_REAL_PAD (GST_PAD_PEER (pads->data));
+ GstElement *peerelement;
- peerelement = GST_PAD_PARENT (peer);
- if (!peerelement)
- continue; /* deal with case where there's no peer */
+ pads = g_list_next (pads);
- if (!GST_FLAG_IS_SET (peerelement, GST_ELEMENT_DECOUPLED)) {
- GST_DEBUG (GST_CAT_THREAD, "peer element isn't DECOUPLED");
- continue;
- }
+ if (!peer)
+ continue;
- /* FIXME this needs to go away eventually */
- if (!GST_IS_QUEUE (peerelement)) {
- GST_DEBUG (GST_CAT_THREAD, "peer element isn't a Queue");
- continue;
- }
+ peerelement = GST_PAD_PARENT (peer);
+ if (!peerelement)
+ continue; /* deal with case where there's no peer */
- if (GST_ELEMENT_SCHED (peerelement) != GST_ELEMENT_SCHED (thread)) {
- GstQueue *queue = GST_QUEUE (peerelement);
+ if (!GST_FLAG_IS_SET (peerelement, GST_ELEMENT_DECOUPLED)) {
+ GST_DEBUG (GST_CAT_THREAD, "peer element isn't DECOUPLED");
+ continue;
+ }
- 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);
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:
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);
GST_STATE_ASYNC = 2,
} GstElementStateReturn;
+typedef enum {
+ GST_RESULT_OK,
+ GST_RESULT_NOK,
+ GST_RESULT_NOT_IMPL,
+} GstResult;
#endif
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);
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 {
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));
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;
- }
- 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));
+ 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);
}
-
- 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));
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)
{
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);
}
}
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);
}
}
}
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));
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
bs->listavail = 0;
bs->assembled = NULL;
bs->offset = 0LL;
+ bs->in_seek = FALSE;
return 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);
}
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;
-
- if (gst_pad_send_event (GST_PAD (peer), gst_event_new_seek (type, offset, TRUE))) {
-
+ GstRealPad *peer;
+
+ g_return_val_if_fail (bs != NULL, FALSE);
+
+ peer = GST_RPAD_PEER (bs->pad);
+
+ 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;
}
/* 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);
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);
fakesink->last_message = NULL;
GST_ELEMENT (fakesink)->setclockfunc = gst_fakesink_set_clock;
+
+ GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
}
static void
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) {
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;
}
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;
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);
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();
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;
/* 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 ());
}
case GST_STATE_READY_TO_PAUSED:
case GST_STATE_PAUSED_TO_READY:
src->curoffset = 0;
+ src->seek_happened = TRUE;
default:
break;
}
}
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:
}
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;
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())
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
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;
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;
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)))
/* 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)))
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)
{
return GST_STATE_FAILURE;
}
+ queue->interrupt = FALSE;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
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 */
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);