- The clock_wait now returns the difference between requested time and unlock time.

Original commit message from CVS:
- The clock_wait now returns the difference between requested time and
unlock time.
- Misc defines like GST_SECOND in gstclock.h
- remove pre/post in gstelement.c until fixed.
- added release_locks to gstelement so that the element can unlock itself
- added some more predefined events.
- added folowing functions to gstpad:
- convert function: get the relation between formats on this pad
- query function: get stats about the pad (position/total/latency)
- internal connect function: find out how this pad connects to other
pad internally to the element.
- generic pad_dispatcher.
- removed the last bits of pullregion
- use release_locks on the queue.
- added some events to queue
- make gstthread use the new release_locks function
- make the scheduler use the new clock_wait functions
- added events to fakesink
- added query functions to filesrc
- swap type and offset in the bytestream seek API to match fseek
- added some event handling in bytestream.
This commit is contained in:
Wim Taymans 2002-05-26 21:54:27 +00:00
parent 692b076459
commit 6f96a24d2e
31 changed files with 1092 additions and 392 deletions

View file

@ -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) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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;
}
/**

View file

@ -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);

View file

@ -25,6 +25,8 @@
#include "gst/gstevent.h"
#include <string.h> /* 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;
}

View file

@ -25,23 +25,22 @@
#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;
@ -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__ */

49
gst/gstformat.h Normal file
View file

@ -0,0 +1,49 @@
/* 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__ */

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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 */

View file

@ -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;
}

View file

@ -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);

View file

@ -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;
}

View file

@ -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:

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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) {

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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 */

View file

@ -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);