Commit 1e82f617 authored by Benjamin Otte's avatar Benjamin Otte

gst/gstclock.*: deprecate old interface and disable functions that aren't in use anymore.

Original commit message from CVS:
2004-01-13  Benjamin Otte  <in7y118@public.uni-hamburg.de>

* gst/gstclock.c: (gst_clock_class_init), (gst_clock_init),
(gst_clock_set_speed), (gst_clock_set_active),
(gst_clock_is_active), (gst_clock_reset),
(gst_clock_handle_discont):
* gst/gstclock.h:
deprecate old interface and disable functions that aren't in use
anymore.
* gst/gstelement.h:
* gst/gstelement.c: (gst_element_get_time), (gst_element_wait),
(gst_element_set_time), (gst_element_adjust_time):
add concept of "element time" and functions to get/set this time.
* gst/gstelement.c: (gst_element_change_state):
update element time correctly.
* gst/gstelement.c: (gst_element_get_compatible_pad_filtered):
This is a debug message, not a g_critical.
* gst/gstpad.c: (gst_pad_event_default):
handle discontinuous events right with element time.
* gst/gstscheduler.c: (gst_scheduler_state_transition):
update to clocking fixes.
set clocks on elements in READY=>PAUSED. The old behaviour caused
a wrong element time on the first element that started playing.
* gst/schedulers/gstbasicscheduler.c:
(gst_basic_scheduler_class_init):
* gst/schedulers/gstoptimalscheduler.c:
(gst_opt_scheduler_class_init):
remove code that just implements the default behaviour.
* gst/elements/gstfakesink.c: (gst_fakesink_chain):
update to use new clocking functions
* testsuite/clock/clock1.c: (gst_clock_debug), (main):
* testsuite/clock/clock2.c: (gst_clock_debug), (main):
update to test new element time.
* gst/autoplug/gstspideridentity.c: (gst_spider_identity_getcaps):
use _get_allowed_caps instead of _get_caps. This catches filtered
caps correctly.
* testsuite/debug/commandline.c:
update for new GST_DEBUG syntax.
* testsuite/threads/Makefile.am:
disable a test that only works sometimes.
parent e8d8cb81
2004-01-13 Benjamin Otte <in7y118@public.uni-hamburg.de>
* gst/gstclock.c: (gst_clock_class_init), (gst_clock_init),
(gst_clock_set_speed), (gst_clock_set_active),
(gst_clock_is_active), (gst_clock_reset),
(gst_clock_handle_discont):
* gst/gstclock.h:
deprecate old interface and disable functions that aren't in use
anymore.
* gst/gstelement.h:
* gst/gstelement.c: (gst_element_get_time), (gst_element_wait),
(gst_element_set_time), (gst_element_adjust_time):
add concept of "element time" and functions to get/set this time.
* gst/gstelement.c: (gst_element_change_state):
update element time correctly.
* gst/gstelement.c: (gst_element_get_compatible_pad_filtered):
This is a debug message, not a g_critical.
* gst/gstpad.c: (gst_pad_event_default):
handle discontinuous events right with element time.
* gst/gstscheduler.c: (gst_scheduler_state_transition):
update to clocking fixes.
set clocks on elements in READY=>PAUSED. The old behaviour caused
a wrong element time on the first element that started playing.
* gst/schedulers/gstbasicscheduler.c:
(gst_basic_scheduler_class_init):
* gst/schedulers/gstoptimalscheduler.c:
(gst_opt_scheduler_class_init):
remove code that just implements the default behaviour.
* gst/elements/gstfakesink.c: (gst_fakesink_chain):
update to use new clocking functions
* testsuite/clock/clock1.c: (gst_clock_debug), (main):
* testsuite/clock/clock2.c: (gst_clock_debug), (main):
update to test new element time.
* gst/autoplug/gstspideridentity.c: (gst_spider_identity_getcaps):
use _get_allowed_caps instead of _get_caps. This catches filtered
caps correctly.
* testsuite/debug/commandline.c:
update for new GST_DEBUG syntax.
* testsuite/threads/Makefile.am:
disable a test that only works sometimes.
2004-01-13 Julien MOUTTE <julien@moutte.net>
* po/LINGUAS: Adding fr.
......
......@@ -251,10 +251,8 @@ gst_spider_identity_getcaps (GstPad *pad)
otherpad = ident->src;
if (otherpad != NULL) {
GstPad *peer = GST_PAD_PEER (otherpad);
if (peer) {
GstCaps *ret = gst_pad_get_caps (peer);
if (GST_PAD_PEER (otherpad)) {
GstCaps *ret = gst_pad_get_allowed_caps (otherpad);
if (ident->caps) {
GstCaps *ret2 = gst_caps_intersect (ident->caps, ret);
gst_caps_free (ret);
......
......@@ -312,7 +312,7 @@ gst_fakesink_chain (GstPad *pad, GstData *_data)
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);
gst_element_set_time (GST_ELEMENT (fakesink), value);
}
default:
gst_pad_event_default (pad, event);
......@@ -322,10 +322,7 @@ gst_fakesink_chain (GstPad *pad, GstData *_data)
}
if (fakesink->sync && fakesink->clock) {
GstClockID id = gst_clock_new_single_shot_id (fakesink->clock, GST_BUFFER_TIMESTAMP (buf));
gst_element_clock_wait (GST_ELEMENT (fakesink), id, NULL);
gst_clock_id_free (id);
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
}
if (!fakesink->silent) {
......
......@@ -34,16 +34,21 @@
static GstAllocTrace *_gst_clock_entry_trace;
#endif
#define DEFAULT_EVENT_DIFF (GST_SECOND / 10)
#define DEFAULT_MAX_DIFF (2 * GST_SECOND)
enum {
ARG_0,
ARG_STATS,
ARG_MAX_DIFF
ARG_MAX_DIFF,
ARG_EVENT_DIFF
};
static GstMemChunk *_gst_clock_entries_chunk;
void gst_clock_id_unlock (GstClockID id);
static void gst_clock_class_init (GstClockClass *klass);
static void gst_clock_init (GstClock *clock);
static void gst_clock_dispose (GObject *object);
......@@ -381,6 +386,10 @@ gst_clock_class_init (GstClockClass *klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_DIFF,
g_param_spec_int64 ("max-diff", "Max diff", "The maximum amount of time to wait in nanoseconds",
0, G_MAXINT64, DEFAULT_MAX_DIFF, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MAX_DIFF,
g_param_spec_uint64 ("event-diff", "event diff",
"The amount of time that may elapse until 2 events are treated as happening at different times",
0, G_MAXUINT64, DEFAULT_EVENT_DIFF, G_PARAM_READWRITE));
}
static void
......@@ -389,7 +398,7 @@ gst_clock_init (GstClock *clock)
clock->max_diff = DEFAULT_MAX_DIFF;
clock->speed = 1.0;
clock->active = FALSE;
clock->active = TRUE;
clock->start_time = 0;
clock->last_time = 0;
clock->entries = NULL;
......@@ -424,15 +433,9 @@ gst_clock_dispose (GObject *object)
gdouble
gst_clock_set_speed (GstClock *clock, gdouble speed)
{
GstClockClass *cclass;
g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);
cclass = GST_CLOCK_GET_CLASS (clock);
if (cclass->change_speed)
clock->speed = cclass->change_speed (clock, clock->speed, speed);
GST_WARNING_OBJECT (clock, "called deprecated function");
return clock->speed;
}
......@@ -449,6 +452,7 @@ gst_clock_get_speed (GstClock *clock)
{
g_return_val_if_fail (GST_IS_CLOCK (clock), 0.0);
GST_WARNING_OBJECT (clock, "called deprecated function");
return clock->speed;
}
......@@ -511,34 +515,11 @@ gst_clock_get_resolution (GstClock *clock)
void
gst_clock_set_active (GstClock *clock, gboolean active)
{
GstClockTime time = G_GINT64_CONSTANT (0);
GstClockClass *cclass;
g_return_if_fail (GST_IS_CLOCK (clock));
GST_ERROR_OBJECT (clock, "called deprecated function that does nothing now.");
clock->active = active;
cclass = GST_CLOCK_GET_CLASS (clock);
if (cclass->get_internal_time) {
time = cclass->get_internal_time (clock);
}
GST_LOCK (clock);
if (active) {
clock->start_time = time - clock->last_time;
clock->accept_discont = TRUE;
}
else {
clock->last_time = time - clock->start_time;
clock->accept_discont = FALSE;
}
g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
GST_UNLOCK (clock);
g_mutex_lock (clock->active_mutex);
g_cond_broadcast (clock->active_cond);
g_mutex_unlock (clock->active_mutex);
return;
}
/**
......@@ -554,7 +535,9 @@ gst_clock_is_active (GstClock *clock)
{
g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
return clock->active;
GST_WARNING_OBJECT (clock, "called deprecated function.");
return TRUE;
}
/**
......@@ -571,6 +554,8 @@ gst_clock_reset (GstClock *clock)
g_return_if_fail (GST_IS_CLOCK (clock));
GST_ERROR_OBJECT (clock, "called deprecated function.");
cclass = GST_CLOCK_GET_CLASS (clock);
if (cclass->get_internal_time) {
......@@ -578,7 +563,7 @@ gst_clock_reset (GstClock *clock)
}
GST_LOCK (clock);
clock->active = FALSE;
//clock->active = FALSE;
clock->start_time = time;
clock->last_time = G_GINT64_CONSTANT (0);
g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
......@@ -599,35 +584,9 @@ gst_clock_reset (GstClock *clock)
gboolean
gst_clock_handle_discont (GstClock *clock, guint64 time)
{
GstClockTime itime = G_GINT64_CONSTANT (0);
GstClockClass *cclass = GST_CLOCK_GET_CLASS (clock);;
GST_ERROR_OBJECT (clock, "called deprecated function.");
GST_CAT_DEBUG (GST_CAT_CLOCK, "clock discont %" G_GUINT64_FORMAT
" %" G_GUINT64_FORMAT " %d",
time, clock->start_time, clock->accept_discont);
if (! GST_CLOCK_TIME_IS_VALID (time))
return TRUE;
GST_LOCK (clock);
if (cclass->get_internal_time) {
itime = cclass->get_internal_time (clock);
}
clock->start_time = itime - time;
clock->last_time = time;
clock->accept_discont = FALSE;
g_list_foreach (clock->entries, (GFunc) gst_clock_reschedule_func, NULL);
GST_UNLOCK (clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "new time %" G_GUINT64_FORMAT,
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;
return FALSE;
}
/**
......@@ -646,11 +605,6 @@ gst_clock_get_time (GstClock *clock)
g_return_val_if_fail (GST_IS_CLOCK (clock), G_GINT64_CONSTANT (0));
if (!clock->active) {
/* clock is not active return previous time */
ret = clock->last_time;
}
else {
GstClockClass *cclass;
cclass = GST_CLOCK_GET_CLASS (clock);
......@@ -665,11 +619,42 @@ gst_clock_get_time (GstClock *clock)
else {
clock->last_time = ret;
}
}
return ret;
}
/**
* gst_clock_get_event_time:
* @clock: clock to query
*
* Gets the "event time" of a given clock. An event on the clock happens
* whenever this function is called. This ensures that multiple events that
* happen shortly after each other are treated as if they happened at the same
* time. GStreamer uses to keep state changes of multiple elements in sync.
*
* Returns: the time of the event
*/
GstClockTime
gst_clock_get_event_time (GstClock *clock)
{
GstClockTime time;
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_TIME_NONE);
time = gst_clock_get_time (clock);
if (clock->last_event + clock->max_event_diff >= time) {
GST_LOG_OBJECT (clock, "reporting last event time %"G_GUINT64_FORMAT,
clock->last_event);
} else {
GST_LOG_OBJECT (clock, "reporting new event time %"G_GUINT64_FORMAT,
clock->last_event);
clock->last_event = time;
}
return clock->last_event;
}
/**
* gst_clock_get_next_id
* @clock: The clock to query
......@@ -709,9 +694,15 @@ gst_clock_set_property (GObject *object, guint prop_id,
switch (prop_id) {
case ARG_STATS:
clock->stats = g_value_get_boolean (value);
g_object_notify (object, "stats");
break;
case ARG_MAX_DIFF:
clock->max_diff = g_value_get_int64 (value);
g_object_notify (object, "max-diff");
break;
case ARG_EVENT_DIFF:
clock->max_event_diff = g_value_get_uint64 (value);
g_object_notify (object, "max-event-diff");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
......@@ -734,6 +725,9 @@ gst_clock_get_property (GObject *object, guint prop_id,
case ARG_MAX_DIFF:
g_value_set_int64 (value, clock->max_diff);
break;
case ARG_EVENT_DIFF:
g_value_set_uint64 (value, clock->max_event_diff);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......
......@@ -128,16 +128,21 @@ struct _GstClock {
gint64 max_diff;
/* --- private --- */
gboolean accept_discont;
gdouble speed;
gboolean accept_discont; /* FIXME: REMOVE! */
gdouble speed; /* FIXME: REMOVE! */
guint64 resolution;
gboolean active;
gboolean active; /* FIXME: REMOVE! */
GList *entries;
GMutex *active_mutex;
GCond *active_cond;
gboolean stats;
gpointer _gst_reserved[GST_PADDING];
GstClockTime last_event;
GstClockTime max_event_diff;
/* weird padding here */
guint8 padding[sizeof(gpointer) * GST_PADDING - sizeof (GstClockTime) * 2];
/*gpointer _gst_reserved[GST_PADDING];*/
};
struct _GstClockClass {
......@@ -158,25 +163,32 @@ struct _GstClockClass {
GstClockEntryStatus (*wait_async) (GstClock *clock, GstClockEntry *entry);
void (*unschedule) (GstClock *clock, GstClockEntry *entry);
void (*unlock) (GstClock *clock, GstClockEntry *entry);
gpointer _gst_reserved[GST_PADDING];
};
GType gst_clock_get_type (void);
#ifndef GST_DISABLE_DEPRECATED
gdouble gst_clock_set_speed (GstClock *clock, gdouble speed);
gdouble gst_clock_get_speed (GstClock *clock);
#endif
guint64 gst_clock_set_resolution (GstClock *clock, guint64 resolution);
guint64 gst_clock_get_resolution (GstClock *clock);
#ifndef GST_DISABLE_DEPRECATED
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);
#endif
GstClockTime gst_clock_get_time (GstClock *clock);
GstClockTime gst_clock_get_event_time (GstClock *clock);
/* FIXME: deprecate? */
#ifndef GST_DISABLE_DEPRECATED
GstClockID gst_clock_get_next_id (GstClock *clock);
/* creating IDs that can be used to get notifications */
......@@ -196,6 +208,8 @@ GstClockReturn gst_clock_id_wait_async (GstClockID id,
void gst_clock_id_unschedule (GstClockID id);
void gst_clock_id_unlock (GstClockID id);
void gst_clock_id_free (GstClockID id);
#endif
G_END_DECLS
......
......@@ -792,13 +792,162 @@ gst_element_clock_wait (GstElement *element, GstClockID id, GstClockTimeDiff *ji
return res;
}
#undef GST_CAT_DEFAULT
#define GST_CAT_DEFAULT GST_CAT_CLOCK
/**
* gst_element_get_time:
* @element: element to query
*
* Query the element's time. The element must use
*
* Returns: the current time of the element or #GST_CLOCK_TIME_NONE when there
* is no time available.
*/
GstClockTime
gst_element_get_time (GstElement *element)
{
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_TIME_NONE);
if (element->clock == NULL) {
GST_WARNING_OBJECT (element, "element queries time but has no clock");
return GST_CLOCK_TIME_NONE;
}
switch (element->current_state) {
case GST_STATE_NULL:
case GST_STATE_READY:
return GST_CLOCK_TIME_NONE;
case GST_STATE_PAUSED:
return element->base_time;
case GST_STATE_PLAYING:
return gst_clock_get_time (element->clock) - element->base_time;
default:
g_assert_not_reached ();
return GST_CLOCK_TIME_NONE;
}
}
GstClockID gst_clock_new_single_shot_id (GstClock *clock,
GstClockTime time);
void gst_clock_id_free (GstClockID id);
/**
* gst_element_wait:
* @element: element that should wait
* @timestamp: wait until this time has arrived
*
* Waits until the given time has arrived. When this function returns successfully,
* the time specified in the timestamp has passed.
* <note>This function can only be called on elements in #GST_STATE_PLAYING</note>
*
* Returns: TRUE on success
*/
gboolean
gst_element_wait (GstElement *element, GstClockTime timestamp)
{
GstClockID id;
GstClockReturn ret;
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
g_return_val_if_fail (GST_IS_CLOCK (element->clock), FALSE);
g_return_val_if_fail (element->current_state == GST_STATE_PLAYING, FALSE);
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (timestamp), FALSE);
/* shortcut when we're already late... */
if (gst_element_get_time (element) >= timestamp) {
GST_INFO_OBJECT (element, "called gst_element_wait and was late");
return TRUE;
}
id = gst_clock_new_single_shot_id (element->clock, element->base_time + timestamp);
ret = gst_element_clock_wait (element, id, NULL);
gst_clock_id_free (id);
return ret == GST_CLOCK_STOPPED;
}
/**
* gst_element_set_time:
* @element: element to set time on
* @time: time to set
*
* Sets the current time of the element. This function can be used when handling
* discont events. You can only call this function on an element with a clock in
* #GST_STATE_PAUSED or #GST_STATE_PLAYING. You might want to have a look at
* gst_element_adjust_time(), if you want to adjust by a difference as that is
* more accurate.
*/
void
gst_element_set_time (GstElement *element, GstClockTime time)
{
g_return_if_fail (GST_IS_ELEMENT (element));
g_return_if_fail (GST_IS_CLOCK (element->clock));
g_return_if_fail (element->current_state >= GST_STATE_PAUSED);
switch (element->current_state) {
case GST_STATE_PAUSED:
element->base_time = time;
break;
case GST_STATE_PLAYING:
element->base_time = gst_clock_get_time (element->clock) - time;
break;
default:
g_assert_not_reached ();
break;
}
}
/**
* gst_element_adjust_time:
* @element: element to adjust time on
* @difference: difference to adjust
*
* Adjusts the current time of the element by the specified difference. This
* function can be used when handling discont events. You can only call this
* function on an element with a clock in #GST_STATE_PAUSED or
* #GST_STATE_PLAYING. It is more accurate than gst_element_set_time().
*/
void
gst_element_adjust_time (GstElement *element, GstClockTimeDiff diff)
{
GstClockTime time;
g_return_if_fail (GST_IS_ELEMENT (element));
g_return_if_fail (GST_IS_CLOCK (element->clock));
g_return_if_fail (element->current_state >= GST_STATE_PAUSED);
switch (element->current_state) {
case GST_STATE_PAUSED:
if (diff < 0 && element->base_time < abs (diff)) {
g_warning ("attempted to set the current time of element %s below 0",
GST_OBJECT_NAME (element));
element->base_time = 0;
} else {
element->base_time += diff;
}
break;
case GST_STATE_PLAYING:
time = gst_clock_get_time (element->clock);
if (time < element->base_time - diff) {
g_warning ("attempted to set the current time of element %s below 0",
GST_OBJECT_NAME (element));
element->base_time = time;
} else {
element->base_time -= diff;
}
break;
default:
g_assert_not_reached ();
break;
}
}
#undef GST_CAT_DEFAULT
#ifndef GST_DISABLE_INDEX
/**
* gst_element_is_indexable:
* @element: a #GstElement.
*
* Queries if the element can be indexed/
* Queries if the element can be indexed.
*
* Returns: TRUE if the element can be indexed.
*/
......@@ -1496,8 +1645,8 @@ gst_element_get_compatible_pad_filtered (GstElement *element, GstPad *pad,
if (foundpad) return foundpad;
//}
g_critical("Could not find a compatible pad on element %s to link to %s:%s",
GST_ELEMENT_NAME (element), GST_DEBUG_PAD_NAME (pad));
GST_DEBUG_OBJECT (element, "Could not find a compatible pad to link to %s:%s",
GST_DEBUG_PAD_NAME (pad));
return NULL;
}
......@@ -2581,19 +2730,34 @@ gst_element_change_state (GstElement *element)
switch (old_transition) {
case GST_STATE_PLAYING_TO_PAUSED:
if (element->clock) {
GstClockTime time = gst_clock_get_event_time (element->clock);
g_assert (time >= element->base_time);
element->base_time = time - element->base_time;
GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %"
G_GINT64_FORMAT, element->base_time);
}
gst_element_pads_activate (element, FALSE);
break;
case GST_STATE_PAUSED_TO_PLAYING:
gst_element_pads_activate (element, TRUE);
if (element->clock) {
GstClockTime time = gst_clock_get_event_time (element->clock);
element->base_time = time - element->base_time;
GST_CAT_LOG_OBJECT (GST_CAT_CLOCK, element, "setting base time to %"
G_GINT64_FORMAT, element->base_time);
}
break;
/* if we are going to paused, we try to negotiate the pads */
case GST_STATE_READY_TO_PAUSED:
g_assert (element->base_time == 0);
if (!gst_element_negotiate_pads (element))
goto failure;
break;
/* going to the READY state clears all pad caps */
/* FIXME: Why doesn't this happen on READY => NULL? -- Company */
case GST_STATE_PAUSED_TO_READY:
element->base_time = 0;
gst_element_clear_pad_caps (element);
break;
default:
......
......@@ -159,7 +159,7 @@ struct _GstElement {
/* allocated clock */
GstClock *clock;
GstClockTime base_time;
GstClockTimeDiff base_time; /* NULL/READY: 0 - PAUSED: current time - PLAYING: difference to clock */
/* element pads */
guint16 numpads;
......@@ -275,8 +275,14 @@ gboolean gst_element_requires_clock (GstElement *element);
gboolean gst_element_provides_clock (GstElement *element);
GstClock* gst_element_get_clock (GstElement *element);
void gst_element_set_clock (GstElement *element, GstClock *clock);
#ifndef GST_DEISABLE_DEPRECATED
GstClockReturn gst_element_clock_wait (GstElement *element,
GstClockID id, GstClockTimeDiff *jitter);
#endif
GstClockTime gst_element_get_time (GstElement *element);
gboolean gst_element_wait (GstElement *element, GstClockTime timestamp);
void gst_element_set_time (GstElement *element, GstClockTime time);
void gst_element_adjust_time (GstElement *element, GstClockTimeDiff diff);
/* indexs */
gboolean gst_element_is_indexable (GstElement *element);
......