mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-16 19:25:18 +00:00
Added a first stab at a better clocking system.
Original commit message from CVS: Added a first stab at a better clocking system. It still needs more infrastructure for async notification and custom clock implementors. This thing can still deadlock the pipeline.
This commit is contained in:
parent
6b2df345f7
commit
53b6bb6242
15 changed files with 695 additions and 191 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "common"]
|
||||||
|
path = common
|
||||||
|
url = git://anongit.freedesktop.org/gstreamer/common
|
1
common
Submodule
1
common
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit d81417a103945ab1c393e74557983b1163e9e353
|
|
@ -79,6 +79,7 @@ libgst_la_SOURCES = \
|
||||||
gstprops.c \
|
gstprops.c \
|
||||||
gstqueue.c \
|
gstqueue.c \
|
||||||
gstscheduler.c \
|
gstscheduler.c \
|
||||||
|
gstsystemclock.c \
|
||||||
gstthread.c \
|
gstthread.c \
|
||||||
$(GST_TRACE_SRC) \
|
$(GST_TRACE_SRC) \
|
||||||
gsttype.c \
|
gsttype.c \
|
||||||
|
@ -187,6 +188,7 @@ libgstinclude_HEADERS = \
|
||||||
gstprops.h \
|
gstprops.h \
|
||||||
gstqueue.h \
|
gstqueue.h \
|
||||||
gstscheduler.h \
|
gstscheduler.h \
|
||||||
|
gstsystemclock.h \
|
||||||
gstthread.h \
|
gstthread.h \
|
||||||
gsttrace.h \
|
gsttrace.h \
|
||||||
gsttype.h \
|
gsttype.h \
|
||||||
|
|
|
@ -137,6 +137,8 @@ int main(int argc,char *argv[])
|
||||||
exit (-4);
|
exit (-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gst_bin_use_clock (GST_BIN (bin), gst_system_clock_obtain ());
|
||||||
|
|
||||||
/* start playing */
|
/* start playing */
|
||||||
gst_element_set_state(bin, GST_STATE_PLAYING);
|
gst_element_set_state(bin, GST_STATE_PLAYING);
|
||||||
|
|
||||||
|
|
|
@ -304,7 +304,7 @@ gst_disksink_handle_event (GstPad *pad, GstEvent *event)
|
||||||
gst_disksink_getcurrentfilename(disksink), sys_errlist[errno]);
|
gst_disksink_getcurrentfilename(disksink), sys_errlist[errno]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_warning("Unhandled event %d\n", type);
|
gst_pad_event_default (pad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
#include <gst/gstpad.h>
|
#include <gst/gstpad.h>
|
||||||
#include <gst/gstbuffer.h>
|
#include <gst/gstbuffer.h>
|
||||||
#include <gst/gstcpu.h>
|
#include <gst/gstcpu.h>
|
||||||
#include <gst/gstclock.h>
|
#include <gst/gstsystemclock.h>
|
||||||
#include <gst/gstelement.h>
|
#include <gst/gstelement.h>
|
||||||
#include <gst/gstbin.h>
|
#include <gst/gstbin.h>
|
||||||
#include <gst/gstpipeline.h>
|
#include <gst/gstpipeline.h>
|
||||||
|
|
128
gst/gstbin.c
128
gst/gstbin.c
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "gstevent.h"
|
#include "gstevent.h"
|
||||||
#include "gstbin.h"
|
#include "gstbin.h"
|
||||||
|
#include "gstxml.h"
|
||||||
|
#include "gstsystemclock.h"
|
||||||
|
|
||||||
#include "gstscheduler.h"
|
#include "gstscheduler.h"
|
||||||
|
|
||||||
|
@ -160,6 +162,93 @@ gst_bin_reset_element_sched (GstElement * element, GstScheduler * sched)
|
||||||
gst_element_set_sched (element, sched);
|
gst_element_set_sched (element, sched);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_bin_get_clock_elements (GstBin *bin, GList **needing, GList **providing)
|
||||||
|
{
|
||||||
|
GList *children = gst_bin_get_list (bin);
|
||||||
|
|
||||||
|
while (children) {
|
||||||
|
GstElement *child = GST_ELEMENT (children->data);
|
||||||
|
|
||||||
|
if (GST_IS_BIN (child)) {
|
||||||
|
gst_bin_get_clock_elements (GST_BIN (child), needing, providing);
|
||||||
|
}
|
||||||
|
if (child->getclockfunc) {
|
||||||
|
*providing = g_list_prepend (*providing, child);
|
||||||
|
}
|
||||||
|
if (child->setclockfunc) {
|
||||||
|
*needing = g_list_prepend (*needing, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
children = g_list_next (children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_bin_distribute_clock (GstBin *bin, GList *needing, GstClock *clock)
|
||||||
|
{
|
||||||
|
while (needing) {
|
||||||
|
GST_DEBUG (GST_CAT_CLOCK, "setting clock on %s\n", GST_ELEMENT_NAME (needing->data));
|
||||||
|
gst_element_set_clock (GST_ELEMENT (needing->data), clock);
|
||||||
|
|
||||||
|
needing = g_list_next (needing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_bin_distribute_clocks (GstBin *bin)
|
||||||
|
{
|
||||||
|
GList *needing = NULL, *providing = NULL;
|
||||||
|
GstElement *provider;
|
||||||
|
GstClock *clock;
|
||||||
|
|
||||||
|
gst_bin_get_clock_elements (bin, &needing, &providing);
|
||||||
|
|
||||||
|
if (GST_FLAG_IS_SET (bin, GST_BIN_FLAG_FIXED_CLOCK)) {
|
||||||
|
clock = bin->clock;
|
||||||
|
}
|
||||||
|
else if (providing) {
|
||||||
|
clock = gst_element_get_clock (GST_ELEMENT (providing->data));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GST_DEBUG (GST_CAT_CLOCK, "no clock provided, using default clock\n");
|
||||||
|
clock = gst_system_clock_obtain ();
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_BIN_CLOCK (bin) = clock;
|
||||||
|
gst_bin_distribute_clock (bin, needing, clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
GstClock*
|
||||||
|
gst_bin_get_clock (GstBin *bin)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (bin != NULL, NULL);
|
||||||
|
g_return_val_if_fail (GST_IS_BIN (bin), NULL);
|
||||||
|
|
||||||
|
return GST_BIN_CLOCK (bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_bin_use_clock (GstBin *bin, GstClock *clock)
|
||||||
|
{
|
||||||
|
g_return_if_fail (bin != NULL);
|
||||||
|
g_return_if_fail (GST_IS_BIN (bin));
|
||||||
|
|
||||||
|
GST_FLAG_SET (bin, GST_BIN_FLAG_FIXED_CLOCK);
|
||||||
|
GST_BIN_CLOCK (bin) = clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_bin_auto_clock (GstBin *bin)
|
||||||
|
{
|
||||||
|
g_return_if_fail (bin != NULL);
|
||||||
|
g_return_if_fail (GST_IS_BIN (bin));
|
||||||
|
|
||||||
|
GST_FLAG_UNSET (bin, GST_BIN_FLAG_FIXED_CLOCK);
|
||||||
|
GST_BIN_CLOCK (bin) = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
|
gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
|
||||||
{
|
{
|
||||||
|
@ -412,14 +501,9 @@ gst_bin_child_state_change (GstBin *bin, GstElementState oldstate, GstElementSta
|
||||||
void
|
void
|
||||||
gst_bin_child_error (GstBin *bin, GstElement *child)
|
gst_bin_child_error (GstBin *bin, GstElement *child)
|
||||||
{
|
{
|
||||||
|
g_return_if_fail (GST_IS_BIN (bin));
|
||||||
|
|
||||||
if (GST_STATE (bin) != GST_STATE_NULL) {
|
if (GST_STATE (bin) != GST_STATE_NULL) {
|
||||||
/*
|
|
||||||
GST_STATE_PENDING (bin) = ((GST_STATE (bin) >> 1));
|
|
||||||
if (gst_element_set_state (bin, GST_STATE (bin)>>1) != GST_STATE_SUCCESS) {
|
|
||||||
gst_element_error (GST_ELEMENT (bin), "bin \"%s\" couldn't change state on error from child \"%s\"",
|
|
||||||
GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (child));
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
gst_element_info (GST_ELEMENT (bin), "bin \"%s\" stopped because child \"%s\" signalled an error",
|
gst_element_info (GST_ELEMENT (bin), "bin \"%s\" stopped because child \"%s\" signalled an error",
|
||||||
GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (child));
|
GST_ELEMENT_NAME (bin), GST_ELEMENT_NAME (child));
|
||||||
}
|
}
|
||||||
|
@ -443,6 +527,7 @@ gst_bin_change_state (GstElement * element)
|
||||||
GstElement *child;
|
GstElement *child;
|
||||||
GstElementStateReturn ret;
|
GstElementStateReturn ret;
|
||||||
GstElementState old_state, pending;
|
GstElementState old_state, pending;
|
||||||
|
gint transition;
|
||||||
gboolean have_async = FALSE;
|
gboolean have_async = FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
|
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
|
||||||
|
@ -451,6 +536,7 @@ gst_bin_change_state (GstElement * element)
|
||||||
|
|
||||||
old_state = GST_STATE (element);
|
old_state = GST_STATE (element);
|
||||||
pending = GST_STATE_PENDING (element);
|
pending = GST_STATE_PENDING (element);
|
||||||
|
transition = GST_STATE_TRANSITION (element);
|
||||||
|
|
||||||
GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
|
GST_INFO_ELEMENT (GST_CAT_STATES, element, "changing childrens' state from %s to %s",
|
||||||
gst_element_statename (old_state), gst_element_statename (pending));
|
gst_element_statename (old_state), gst_element_statename (pending));
|
||||||
|
@ -482,6 +568,28 @@ gst_bin_change_state (GstElement * element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (GST_ELEMENT_SCHED (bin) != NULL && GST_ELEMENT_PARENT (bin) == NULL) {
|
||||||
|
switch (transition) {
|
||||||
|
case GST_STATE_NULL_TO_READY:
|
||||||
|
gst_bin_distribute_clocks (bin);
|
||||||
|
break;
|
||||||
|
case GST_STATE_READY_TO_PAUSED:
|
||||||
|
if (GST_BIN_CLOCK (bin))
|
||||||
|
gst_clock_reset (GST_BIN_CLOCK (bin));
|
||||||
|
break;
|
||||||
|
case GST_STATE_PAUSED_TO_PLAYING:
|
||||||
|
gst_bin_distribute_clocks (bin);
|
||||||
|
if (GST_BIN_CLOCK (bin))
|
||||||
|
gst_clock_activate (GST_BIN_CLOCK (bin), TRUE);
|
||||||
|
break;
|
||||||
|
case GST_STATE_PLAYING_TO_PAUSED:
|
||||||
|
if (GST_BIN_CLOCK (bin))
|
||||||
|
gst_clock_activate (GST_BIN_CLOCK (bin), FALSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s, now in %s",
|
GST_INFO_ELEMENT (GST_CAT_STATES, element, "done changing bin's state from %s to %s, now in %s",
|
||||||
gst_element_statename (old_state),
|
gst_element_statename (old_state),
|
||||||
gst_element_statename (pending),
|
gst_element_statename (pending),
|
||||||
|
@ -499,9 +607,13 @@ gst_bin_change_state (GstElement * element)
|
||||||
static GstElementStateReturn
|
static GstElementStateReturn
|
||||||
gst_bin_change_state_norecurse (GstBin * bin)
|
gst_bin_change_state_norecurse (GstBin * bin)
|
||||||
{
|
{
|
||||||
|
GstElementStateReturn ret;
|
||||||
|
|
||||||
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
|
if (GST_ELEMENT_CLASS (parent_class)->change_state) {
|
||||||
GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
|
GST_DEBUG_ELEMENT (GST_CAT_STATES, bin, "setting bin's own state\n");
|
||||||
return GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
|
ret = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (bin));
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return GST_STATE_FAILURE;
|
return GST_STATE_FAILURE;
|
||||||
|
|
15
gst/gstbin.h
15
gst/gstbin.h
|
@ -48,6 +48,10 @@ extern GType _gst_bin_type;
|
||||||
# define GST_BIN_CLASS GST_BIN_CLASS_CAST
|
# define GST_BIN_CLASS GST_BIN_CLASS_CAST
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define GST_BIN_CLOCK_PROVIDERS(bin) (GST_BIN(bin)->clock_providers)
|
||||||
|
#define GST_BIN_CLOCK_RECEIVERS(bin) (GST_BIN(bin)->clock_receivers)
|
||||||
|
#define GST_BIN_CLOCK(bin) (GST_BIN(bin)->clock)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* this bin is a manager of child elements, i.e. a pipeline or thread */
|
/* this bin is a manager of child elements, i.e. a pipeline or thread */
|
||||||
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
|
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
|
||||||
|
@ -57,6 +61,8 @@ typedef enum {
|
||||||
/* we prefer to have cothreads when its an option, over chain-based */
|
/* we prefer to have cothreads when its an option, over chain-based */
|
||||||
GST_BIN_FLAG_PREFER_COTHREADS,
|
GST_BIN_FLAG_PREFER_COTHREADS,
|
||||||
|
|
||||||
|
GST_BIN_FLAG_FIXED_CLOCK,
|
||||||
|
|
||||||
/* padding */
|
/* padding */
|
||||||
GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4,
|
GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 4,
|
||||||
} GstBinFlags;
|
} GstBinFlags;
|
||||||
|
@ -73,6 +79,8 @@ struct _GstBin {
|
||||||
|
|
||||||
GstElementState child_states[GST_NUM_STATES];
|
GstElementState child_states[GST_NUM_STATES];
|
||||||
|
|
||||||
|
GstClock *clock;
|
||||||
|
|
||||||
gpointer sched_private;
|
gpointer sched_private;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,11 +116,18 @@ gboolean gst_bin_set_state_type (GstBin *bin, GstElementState state, GType type
|
||||||
|
|
||||||
gboolean gst_bin_iterate (GstBin *bin);
|
gboolean gst_bin_iterate (GstBin *bin);
|
||||||
|
|
||||||
|
void gst_bin_use_clock (GstBin *bin, GstClock *clock);
|
||||||
|
GstClock* gst_bin_get_clock (GstBin *bin);
|
||||||
|
void gst_bin_auto_clock (GstBin *bin);
|
||||||
|
|
||||||
/* internal */
|
/* internal */
|
||||||
|
/* one of our childs signaled a state change */
|
||||||
void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate,
|
void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate,
|
||||||
GstElementState newstate, GstElement *child);
|
GstElementState newstate, GstElement *child);
|
||||||
|
/* one of our childs signaled an error */
|
||||||
void gst_bin_child_error (GstBin *bin, GstElement *child);
|
void gst_bin_child_error (GstBin *bin, GstElement *child);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
265
gst/gstclock.c
265
gst/gstclock.c
|
@ -25,176 +25,153 @@
|
||||||
/* #define GST_DEBUG_ENABLED */
|
/* #define GST_DEBUG_ENABLED */
|
||||||
#include "gst_private.h"
|
#include "gst_private.h"
|
||||||
|
|
||||||
#include "gstelement.h"
|
|
||||||
#include "gstclock.h"
|
#include "gstclock.h"
|
||||||
|
|
||||||
|
#define CLASS(clock) GST_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock))
|
||||||
|
|
||||||
static GstClock *the_system_clock = NULL;
|
|
||||||
|
|
||||||
/**
|
static void gst_clock_class_init (GstClockClass *klass);
|
||||||
* gst_clock_new:
|
static void gst_clock_init (GstClock *clock);
|
||||||
* @name: the name of the new clock
|
|
||||||
*
|
static GstObjectClass *parent_class = NULL;
|
||||||
* create a new clock element
|
/* static guint gst_clock_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
*
|
|
||||||
* Returns: the new clock element
|
GType
|
||||||
*/
|
gst_clock_get_type (void)
|
||||||
GstClock*
|
|
||||||
gst_clock_new (gchar *name)
|
|
||||||
{
|
{
|
||||||
GstClock *clock = (GstClock *) g_malloc(sizeof(GstClock));
|
static GType clock_type = 0;
|
||||||
|
|
||||||
clock->name = g_strdup (name);
|
if (!clock_type) {
|
||||||
clock->sinkobjects = NULL;
|
static const GTypeInfo clock_info = {
|
||||||
clock->sinkmutex = g_mutex_new ();
|
sizeof (GstObjectClass),
|
||||||
clock->lock = g_mutex_new ();
|
NULL,
|
||||||
g_mutex_lock (clock->sinkmutex);
|
NULL,
|
||||||
|
(GClassInitFunc) gst_clock_class_init,
|
||||||
clock->num = 0;
|
NULL,
|
||||||
clock->num_locked = 0;
|
NULL,
|
||||||
clock->locking = FALSE;
|
sizeof (GstObject),
|
||||||
|
4,
|
||||||
return clock;
|
(GInstanceInitFunc) gst_clock_init,
|
||||||
}
|
NULL
|
||||||
|
};
|
||||||
/**
|
clock_type = g_type_register_static (GST_TYPE_OBJECT, "GstClock",
|
||||||
* gst_clock_get_system:
|
&clock_info, G_TYPE_FLAG_ABSTRACT);
|
||||||
*
|
|
||||||
* Get the global system clock
|
|
||||||
*
|
|
||||||
* Returns: the global clock
|
|
||||||
*/
|
|
||||||
GstClock*
|
|
||||||
gst_clock_get_system(void)
|
|
||||||
{
|
|
||||||
if (the_system_clock == NULL) {
|
|
||||||
the_system_clock = gst_clock_new ("system_clock");
|
|
||||||
gst_clock_reset (the_system_clock);
|
|
||||||
}
|
}
|
||||||
return the_system_clock;
|
return clock_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* gst_clock_register:
|
gst_clock_class_init (GstClockClass *klass)
|
||||||
* @clock: the name of the clock to register to
|
|
||||||
* @obj: the object registering to the clock
|
|
||||||
*
|
|
||||||
* State that an object is interested in listening to the
|
|
||||||
* given clock
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_clock_register (GstClock *clock, GstObject *obj)
|
|
||||||
{
|
{
|
||||||
if ((GST_ELEMENT(obj))->numsrcpads == 0) {
|
GObjectClass *gobject_class;
|
||||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting registered sink object 0x%p\n", obj);
|
GstObjectClass *gstobject_class;
|
||||||
clock->sinkobjects = g_list_append (clock->sinkobjects, obj);
|
|
||||||
clock->num++;
|
gobject_class = (GObjectClass*) klass;
|
||||||
}
|
gstobject_class = (GstObjectClass*) klass;
|
||||||
|
|
||||||
|
parent_class = g_type_class_ref (GST_TYPE_OBJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void
|
||||||
* gst_clock_set:
|
gst_clock_init (GstClock *clock)
|
||||||
* @clock: The clock to set
|
|
||||||
* @time: the time to set
|
|
||||||
*
|
|
||||||
* Set the time of the given clock to time.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
gst_clock_set (GstClock *clock, GstClockTime time)
|
|
||||||
{
|
{
|
||||||
struct timeval tfnow;
|
clock->speed = 1.0;
|
||||||
GstClockTime now;
|
clock->active = FALSE;
|
||||||
|
clock->start_time = 0;
|
||||||
|
|
||||||
gettimeofday (&tfnow, (struct timezone *)NULL);
|
clock->active_mutex = g_mutex_new ();
|
||||||
now = tfnow.tv_sec*1000000LL+tfnow.tv_usec;
|
clock->active_cond = g_cond_new ();
|
||||||
g_mutex_lock (clock->lock);
|
|
||||||
clock->start_time = now - time;
|
|
||||||
g_mutex_unlock (clock->lock);
|
|
||||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting clock to %llu %llu %llu\n",
|
|
||||||
time, now, clock->start_time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_clock_current_diff:
|
|
||||||
* @clock: the clock to calculate the diff against
|
|
||||||
* @time: the time
|
|
||||||
*
|
|
||||||
* Calculate the difference between the given clock and the
|
|
||||||
* given time
|
|
||||||
*
|
|
||||||
* Returns: the clock difference
|
|
||||||
*/
|
|
||||||
GstClockTimeDiff
|
|
||||||
gst_clock_current_diff (GstClock *clock, GstClockTime time)
|
|
||||||
{
|
|
||||||
struct timeval tfnow;
|
|
||||||
GstClockTime now;
|
|
||||||
|
|
||||||
gettimeofday (&tfnow, (struct timezone *)NULL);
|
|
||||||
g_mutex_lock (clock->lock);
|
|
||||||
now = ((guint64)tfnow.tv_sec*1000000LL+tfnow.tv_usec) - (guint64)clock->start_time;
|
|
||||||
g_mutex_unlock (clock->lock);
|
|
||||||
|
|
||||||
return GST_CLOCK_DIFF (time, now);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_clock_reset:
|
|
||||||
* @clock: the clock to reset
|
|
||||||
*
|
|
||||||
* Reset the given clock. The of the clock will be adjusted back
|
|
||||||
* to 0.
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
gst_clock_reset (GstClock *clock)
|
gst_clock_reset (GstClock *clock)
|
||||||
{
|
{
|
||||||
struct timeval tfnow;
|
g_return_if_fail (GST_IS_CLOCK (clock));
|
||||||
|
|
||||||
gettimeofday (&tfnow, (struct timezone *)NULL);
|
clock->start_time = 0;
|
||||||
g_mutex_lock (clock->lock);
|
clock->active = FALSE;
|
||||||
clock->start_time = ((guint64)tfnow.tv_sec)*1000000LL+tfnow.tv_usec;
|
|
||||||
clock->current_time = clock->start_time;
|
if (CLASS (clock)->reset)
|
||||||
clock->adjust = 0LL;
|
CLASS (clock)->reset (clock);
|
||||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: setting start clock %llu\n", clock->start_time);
|
|
||||||
g_mutex_unlock (clock->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gst_clock_wait:
|
|
||||||
* @clock: the clock to wait on
|
|
||||||
* @time: the time to wait for
|
|
||||||
* @obj: the object performing the wait
|
|
||||||
*
|
|
||||||
* Wait for a specific clock tick on the given clock.
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj)
|
gst_clock_activate (GstClock *clock, gboolean active)
|
||||||
{
|
{
|
||||||
struct timeval tfnow;
|
g_return_if_fail (GST_IS_CLOCK (clock));
|
||||||
GstClockTime now;
|
|
||||||
GstClockTimeDiff diff;
|
|
||||||
|
|
||||||
|
clock->active = active;
|
||||||
|
|
||||||
gettimeofday (&tfnow, (struct timezone *)NULL);
|
if (CLASS (clock)->activate)
|
||||||
g_mutex_lock (clock->lock);
|
CLASS (clock)->activate (clock, active);
|
||||||
now = tfnow.tv_sec*1000000LL+tfnow.tv_usec - clock->start_time;
|
|
||||||
|
|
||||||
diff = GST_CLOCK_DIFF (time, now);
|
g_mutex_lock (clock->active_mutex);
|
||||||
/* if we are not behind wait a bit */
|
g_cond_signal (clock->active_cond);
|
||||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld\n",
|
g_mutex_unlock (clock->active_mutex);
|
||||||
GST_OBJECT_NAME (obj), time, now, diff);
|
|
||||||
|
|
||||||
g_mutex_unlock (clock->lock);
|
|
||||||
if (diff > 10000 ) {
|
|
||||||
tfnow.tv_usec = (diff % 1000000);
|
|
||||||
tfnow.tv_sec = diff / 1000000;
|
|
||||||
/* FIXME, this piece of code does not work with egcs optimisations on, had to use the following line */
|
|
||||||
if (!tfnow.tv_sec) {
|
|
||||||
select(0, NULL, NULL, NULL, &tfnow);
|
|
||||||
}
|
|
||||||
else GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting %u %llu %llu %llu seconds\n",
|
|
||||||
GST_OBJECT_NAME (obj), (int)tfnow.tv_sec, now, diff, time);
|
|
||||||
}
|
|
||||||
GST_DEBUG (GST_CAT_CLOCK,"gst_clock: %s waiting for time %08llu %08llu %08lld done \n",
|
|
||||||
GST_OBJECT_NAME (obj), time, now, diff);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
gst_clock_is_active (GstClock *clock)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_CLOCK (clock), FALSE);
|
||||||
|
|
||||||
|
return clock->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_clock_set_time (GstClock *clock, GstClockTime time)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_CLOCK (clock));
|
||||||
|
|
||||||
|
if (CLASS (clock)->set_time)
|
||||||
|
CLASS (clock)->set_time (clock, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
GstClockTime
|
||||||
|
gst_clock_get_time (GstClock *clock)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL);
|
||||||
|
|
||||||
|
if (CLASS (clock)->get_time)
|
||||||
|
return CLASS (clock)->get_time (clock);
|
||||||
|
|
||||||
|
return 0LL;
|
||||||
|
}
|
||||||
|
|
||||||
|
GstClockReturn
|
||||||
|
gst_clock_wait (GstClock *clock, GstClockTime time)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_CLOCK (clock), GST_CLOCK_STOPPED);
|
||||||
|
|
||||||
|
if (!clock->active) {
|
||||||
|
g_mutex_lock (clock->active_mutex);
|
||||||
|
g_cond_wait (clock->active_cond, clock->active_mutex);
|
||||||
|
g_mutex_unlock (clock->active_mutex);
|
||||||
|
}
|
||||||
|
if (CLASS (clock)->wait)
|
||||||
|
return CLASS (clock)->wait (clock, time);
|
||||||
|
|
||||||
|
return GST_CLOCK_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gst_clock_set_resolution (GstClock *clock, guint64 resolution)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_IS_CLOCK (clock));
|
||||||
|
|
||||||
|
if (CLASS (clock)->set_resolution)
|
||||||
|
CLASS (clock)->set_resolution (clock, resolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
guint64
|
||||||
|
gst_clock_get_resolution (GstClock *clock)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GST_IS_CLOCK (clock), 0LL);
|
||||||
|
|
||||||
|
if (CLASS (clock)->get_resolution)
|
||||||
|
return CLASS (clock)->get_resolution (clock);
|
||||||
|
|
||||||
|
return 0LL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,45 +24,103 @@
|
||||||
#ifndef __GST_CLOCK_H__
|
#ifndef __GST_CLOCK_H__
|
||||||
#define __GST_CLOCK_H__
|
#define __GST_CLOCK_H__
|
||||||
|
|
||||||
#include <gst/gstobject.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#include <gst/gstobject.h>
|
||||||
|
|
||||||
|
#define GST_TYPE_CLOCK \
|
||||||
|
(gst_clock_get_type())
|
||||||
|
#define GST_CLOCK(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CLOCK,GstClock))
|
||||||
|
#define GST_CLOCK_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CLOCK,GstClockClass))
|
||||||
|
#define GST_IS_CLOCK(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CLOCK))
|
||||||
|
#define GST_IS_CLOCK_CLASS(obj) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CLOCK))
|
||||||
|
|
||||||
typedef guint64 GstClockTime;
|
typedef guint64 GstClockTime;
|
||||||
typedef gint64 GstClockTimeDiff;
|
typedef gint64 GstClockTimeDiff;
|
||||||
|
typedef gpointer GstClockID;
|
||||||
|
|
||||||
#define GST_CLOCK_DIFF(s, e) (GstClockTimeDiff)((s)-(e))
|
#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)
|
||||||
|
|
||||||
typedef struct _GstClock GstClock;
|
typedef struct _GstClock GstClock;
|
||||||
|
typedef struct _GstClockClass GstClockClass;
|
||||||
|
|
||||||
|
typedef void (*GstClockCallback) (GstClock *clock, GstClockTime time, GstClockID id, gpointer user_data);
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
GST_CLOCK_STOPPED = 0,
|
||||||
|
GST_CLOCK_TIMEOUT = 1,
|
||||||
|
GST_CLOCK_EARLY = 2,
|
||||||
|
GST_CLOCK_ERROR = 3,
|
||||||
|
} GstClockReturn;
|
||||||
|
|
||||||
struct _GstClock {
|
struct _GstClock {
|
||||||
gchar *name;
|
GstObject object;
|
||||||
|
|
||||||
GstClockTime start_time;
|
GstClockTime start_time;
|
||||||
GstClockTime current_time;
|
gdouble speed;
|
||||||
GstClockTimeDiff adjust;
|
gboolean active;
|
||||||
gboolean locking;
|
|
||||||
GList *sinkobjects;
|
GMutex *active_mutex;
|
||||||
gint num, num_locked;
|
GCond *active_cond;
|
||||||
GMutex *sinkmutex;
|
|
||||||
GMutex *lock;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GstClock* gst_clock_new (gchar *name);
|
struct _GstClockClass {
|
||||||
GstClock* gst_clock_get_system (void);
|
GstObjectClass parent_class;
|
||||||
|
|
||||||
void gst_clock_register (GstClock *clock, GstObject *obj);
|
/* vtable */
|
||||||
void gst_clock_set (GstClock *clock, GstClockTime time);
|
void (*activate) (GstClock *clock, gboolean active);
|
||||||
|
void (*reset) (GstClock *clock);
|
||||||
|
|
||||||
|
void (*set_time) (GstClock *clock, GstClockTime time);
|
||||||
|
GstClockTime (*get_time) (GstClock *clock);
|
||||||
|
|
||||||
|
GstClockReturn (*wait) (GstClock *clock, GstClockTime time);
|
||||||
|
GstClockID (*wait_async) (GstClock *clock, GstClockTime time,
|
||||||
|
GstClockCallback func, gpointer user_data);
|
||||||
|
void (*cancel_wait_async) (GstClock *clock, GstClockID id);
|
||||||
|
GstClockID (*notify_async) (GstClock *clock, GstClockTime interval,
|
||||||
|
GstClockCallback func, gpointer user_data);
|
||||||
|
void (*remove_notify_async) (GstClock *clock, GstClockID id);
|
||||||
|
|
||||||
|
void (*set_resolution) (GstClock *clock, guint64 resolution);
|
||||||
|
guint64 (*get_resolution) (GstClock *clock);
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_clock_get_type (void);
|
||||||
|
|
||||||
|
void gst_clock_set_speed (GstClock *clock, gdouble speed);
|
||||||
|
void gst_clock_get_speed (GstClock *clock, gdouble speed);
|
||||||
|
|
||||||
|
void gst_clock_activate (GstClock *clock, gboolean active);
|
||||||
|
gboolean gst_clock_is_active (GstClock *clock);
|
||||||
void gst_clock_reset (GstClock *clock);
|
void gst_clock_reset (GstClock *clock);
|
||||||
void gst_clock_wait (GstClock *clock, GstClockTime time, GstObject *obj);
|
|
||||||
GstClockTimeDiff gst_clock_current_diff (GstClock *clock, GstClockTime time);
|
void gst_clock_set_time (GstClock *clock, GstClockTime time);
|
||||||
|
GstClockTime gst_clock_get_time (GstClock *clock);
|
||||||
|
|
||||||
|
GstClockReturn gst_clock_wait (GstClock *clock, GstClockTime time);
|
||||||
|
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);
|
||||||
|
|
||||||
|
void gst_clock_set_resolution (GstClock *clock, guint64 resolution);
|
||||||
|
guint64 gst_clock_get_resolution (GstClock *clock);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif /* __cplusplus */
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_CLOCK_H__ */
|
#endif /* __GST_CLOCK_H__ */
|
||||||
|
|
|
@ -187,7 +187,7 @@ gst_element_set_property (GObject *object, guint prop_id, const GValue *value, G
|
||||||
GstElementClass *oclass = CLASS (object);
|
GstElementClass *oclass = CLASS (object);
|
||||||
|
|
||||||
if (oclass->set_property)
|
if (oclass->set_property)
|
||||||
(oclass->set_property)(object,prop_id,value,pspec);
|
(oclass->set_property) (object, prop_id, value, pspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ gst_element_get_property (GObject *object, guint prop_id, GValue *value, GParamS
|
||||||
GstElementClass *oclass = CLASS (object);
|
GstElementClass *oclass = CLASS (object);
|
||||||
|
|
||||||
if (oclass->get_property)
|
if (oclass->get_property)
|
||||||
(oclass->get_property)(object,prop_id,value,pspec);
|
(oclass->get_property) (object, prop_id, value, pspec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -273,6 +273,61 @@ gst_element_get_parent (GstElement *element)
|
||||||
return GST_OBJECT_PARENT (element);
|
return GST_OBJECT_PARENT (element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_set_clock:
|
||||||
|
* @element: GstElement to set the clock to
|
||||||
|
* @clock: the clock to set for the element
|
||||||
|
*
|
||||||
|
* Set the clock for the element
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gst_element_set_clock (GstElement *element, GstClock *clock)
|
||||||
|
{
|
||||||
|
GstElementClass *oclass;
|
||||||
|
|
||||||
|
g_return_if_fail (element != NULL);
|
||||||
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
||||||
|
|
||||||
|
if (element->setclockfunc)
|
||||||
|
element->setclockfunc (element, clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_get_clock:
|
||||||
|
* @element: GstElement to get the clock of
|
||||||
|
*
|
||||||
|
* Get the clock of the element
|
||||||
|
*/
|
||||||
|
GstClock*
|
||||||
|
gst_element_get_clock (GstElement *element)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (element != NULL, NULL);
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
||||||
|
|
||||||
|
if (element->getclockfunc)
|
||||||
|
return element->getclockfunc (element);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gst_element_clock_wait:
|
||||||
|
* @element: GstElement to wait for the clock
|
||||||
|
* @clock: the clock to wait for
|
||||||
|
* @time: the time to wait for
|
||||||
|
*
|
||||||
|
* Wait for a specific time on the clock
|
||||||
|
*/
|
||||||
|
GstClockReturn
|
||||||
|
gst_element_clock_wait (GstElement *element, GstClock *clock, GstClockTime time)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (element != NULL, GST_CLOCK_ERROR);
|
||||||
|
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_CLOCK_ERROR);
|
||||||
|
|
||||||
|
/* FIXME inform the scheduler */
|
||||||
|
return gst_clock_wait (clock, time);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_element_add_pad:
|
* gst_element_add_pad:
|
||||||
* @element: element to add pad to
|
* @element: element to add pad to
|
||||||
|
@ -328,11 +383,11 @@ gst_element_remove_pad (GstElement *element, GstPad *pad)
|
||||||
g_return_if_fail (GST_IS_PAD (pad));
|
g_return_if_fail (GST_IS_PAD (pad));
|
||||||
|
|
||||||
g_return_if_fail (GST_PAD_PARENT (pad) == element);
|
g_return_if_fail (GST_PAD_PARENT (pad) == element);
|
||||||
|
|
||||||
/* check to see if the pad is still connected */
|
/* check to see if the pad is still connected */
|
||||||
/* FIXME: what if someone calls _remove_pad instead of
|
/* FIXME: what if someone calls _remove_pad instead of
|
||||||
_remove_ghost_pad? */
|
_remove_ghost_pad? */
|
||||||
if (GST_IS_REAL_PAD (pad))
|
if (GST_IS_REAL_PAD (pad)) {
|
||||||
{
|
|
||||||
g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
|
g_return_if_fail (GST_RPAD_PEER (pad) == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1364,12 +1419,14 @@ gst_element_dispose (GObject *object)
|
||||||
orig = pads = g_list_copy (element->pads);
|
orig = pads = g_list_copy (element->pads);
|
||||||
while (pads) {
|
while (pads) {
|
||||||
pad = GST_PAD (pads->data);
|
pad = GST_PAD (pads->data);
|
||||||
if (GST_PAD_PEER (pad))
|
|
||||||
{
|
if (GST_PAD_PEER (pad)) {
|
||||||
GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'\n",GST_OBJECT_NAME(GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
|
GST_DEBUG (GST_CAT_REFCOUNTING, "disconnecting pad '%s'\n",
|
||||||
|
GST_OBJECT_NAME (GST_OBJECT (GST_PAD (GST_PAD_PEER (pad)))));
|
||||||
gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
|
gst_pad_disconnect (pad, GST_PAD (GST_PAD_PEER (pad)));
|
||||||
}
|
}
|
||||||
gst_element_remove_pad (element, pad);
|
gst_element_remove_pad (element, pad);
|
||||||
|
|
||||||
pads = g_list_next (pads);
|
pads = g_list_next (pads);
|
||||||
}
|
}
|
||||||
g_list_free (orig);
|
g_list_free (orig);
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include <gst/gsttypes.h>
|
#include <gst/gsttypes.h>
|
||||||
#include <gst/gstobject.h>
|
#include <gst/gstobject.h>
|
||||||
#include <gst/gstpad.h>
|
#include <gst/gstpad.h>
|
||||||
|
#include <gst/gstclock.h>
|
||||||
#include <gst/gstpluginfeature.h>
|
#include <gst/gstpluginfeature.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -108,6 +109,7 @@ typedef enum {
|
||||||
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
|
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
|
||||||
#define GST_ELEMENT_MANAGER(obj) (((GstElement*)(obj))->manager)
|
#define GST_ELEMENT_MANAGER(obj) (((GstElement*)(obj))->manager)
|
||||||
#define GST_ELEMENT_SCHED(obj) (((GstElement*)(obj))->sched)
|
#define GST_ELEMENT_SCHED(obj) (((GstElement*)(obj))->sched)
|
||||||
|
#define GST_ELEMENT_CLOCK(obj) (((GstElement*)(obj))->clock)
|
||||||
#define GST_ELEMENT_PADS(obj) ((obj)->pads)
|
#define GST_ELEMENT_PADS(obj) ((obj)->pads)
|
||||||
|
|
||||||
/*typedef struct _GstElement GstElement;*/
|
/*typedef struct _GstElement GstElement;*/
|
||||||
|
@ -116,6 +118,8 @@ typedef struct _GstElementFactory GstElementFactory;
|
||||||
typedef struct _GstElementFactoryClass GstElementFactoryClass;
|
typedef struct _GstElementFactoryClass GstElementFactoryClass;
|
||||||
|
|
||||||
typedef void (*GstElementLoopFunction) (GstElement *element);
|
typedef void (*GstElementLoopFunction) (GstElement *element);
|
||||||
|
typedef void (*GstElementSetClockFunction) (GstElement *element, GstClock *clock);
|
||||||
|
typedef GstClock* (*GstElementGetClockFunction) (GstElement *element);
|
||||||
|
|
||||||
struct _GstElement {
|
struct _GstElement {
|
||||||
GstObject object;
|
GstObject object;
|
||||||
|
@ -128,6 +132,8 @@ struct _GstElement {
|
||||||
|
|
||||||
GstScheduler *sched;
|
GstScheduler *sched;
|
||||||
gpointer sched_private;
|
gpointer sched_private;
|
||||||
|
GstElementSetClockFunction setclockfunc;
|
||||||
|
GstElementGetClockFunction getclockfunc;
|
||||||
|
|
||||||
/* element pads */
|
/* element pads */
|
||||||
guint16 numpads;
|
guint16 numpads;
|
||||||
|
@ -183,6 +189,10 @@ const gchar* gst_element_get_name (GstElement *element);
|
||||||
void gst_element_set_parent (GstElement *element, GstObject *parent);
|
void gst_element_set_parent (GstElement *element, GstObject *parent);
|
||||||
GstObject* gst_element_get_parent (GstElement *element);
|
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);
|
||||||
|
|
||||||
void gst_element_yield (GstElement *element);
|
void gst_element_yield (GstElement *element);
|
||||||
gboolean gst_element_interrupt (GstElement *element);
|
gboolean gst_element_interrupt (GstElement *element);
|
||||||
void gst_element_set_sched (GstElement *element, GstScheduler *sched);
|
void gst_element_set_sched (GstElement *element, GstScheduler *sched);
|
||||||
|
|
199
gst/gstsystemclock.c
Normal file
199
gst/gstsystemclock.c
Normal file
|
@ -0,0 +1,199 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
|
* 2000 Wim Taymans <wim.taymans@chello.be>
|
||||||
|
*
|
||||||
|
* gstclock.c: Clock subsystem for maintaining time sync
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
/* #define GST_DEBUG_ENABLED */
|
||||||
|
#include "gst_private.h"
|
||||||
|
|
||||||
|
#include "gstsystemclock.h"
|
||||||
|
|
||||||
|
#define CLASS(clock) GST_SYSTEM_CLOCK_CLASS (G_OBJECT_GET_CLASS (clock))
|
||||||
|
|
||||||
|
static GstClock *_the_system_clock = NULL;
|
||||||
|
|
||||||
|
static void gst_system_clock_class_init (GstSystemClockClass *klass);
|
||||||
|
static void gst_system_clock_init (GstSystemClock *clock);
|
||||||
|
|
||||||
|
static void gst_system_clock_activate (GstClock *clock, gboolean active);
|
||||||
|
static void gst_system_clock_reset (GstClock *clock);
|
||||||
|
static void gst_system_clock_set_time (GstClock *clock, GstClockTime time);
|
||||||
|
static GstClockTime gst_system_clock_get_time (GstClock *clock);
|
||||||
|
static GstClockReturn gst_system_clock_wait (GstClock *clock, GstClockTime time);
|
||||||
|
static guint64 gst_system_clock_get_resolution (GstClock *clock);
|
||||||
|
|
||||||
|
|
||||||
|
static GstClockClass *parent_class = NULL;
|
||||||
|
/* static guint gst_system_clock_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
|
|
||||||
|
GType
|
||||||
|
gst_system_clock_get_type (void)
|
||||||
|
{
|
||||||
|
static GType clock_type = 0;
|
||||||
|
|
||||||
|
if (!clock_type) {
|
||||||
|
static const GTypeInfo clock_info = {
|
||||||
|
sizeof (GstSystemClockClass),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
(GClassInitFunc) gst_system_clock_class_init,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
sizeof (GstSystemClock),
|
||||||
|
4,
|
||||||
|
(GInstanceInitFunc) gst_system_clock_init,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
clock_type = g_type_register_static (GST_TYPE_CLOCK, "GstSystemClock",
|
||||||
|
&clock_info, 0);
|
||||||
|
}
|
||||||
|
return clock_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_system_clock_class_init (GstSystemClockClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class;
|
||||||
|
GstObjectClass *gstobject_class;
|
||||||
|
GstClockClass *gstclock_class;
|
||||||
|
|
||||||
|
gobject_class = (GObjectClass*) klass;
|
||||||
|
gstobject_class = (GstObjectClass*) klass;
|
||||||
|
gstclock_class = (GstClockClass*) klass;
|
||||||
|
|
||||||
|
parent_class = g_type_class_ref (GST_TYPE_CLOCK);
|
||||||
|
|
||||||
|
gstclock_class->activate = gst_system_clock_activate;
|
||||||
|
gstclock_class->reset = gst_system_clock_reset;
|
||||||
|
gstclock_class->set_time = gst_system_clock_set_time;
|
||||||
|
gstclock_class->get_time = gst_system_clock_get_time;
|
||||||
|
gstclock_class->wait = gst_system_clock_wait;
|
||||||
|
gstclock_class->get_resolution = gst_system_clock_get_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_system_clock_init (GstSystemClock *clock)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GstClock*
|
||||||
|
gst_system_clock_obtain (void)
|
||||||
|
{
|
||||||
|
if (_the_system_clock == NULL) {
|
||||||
|
_the_system_clock = GST_CLOCK (g_object_new (GST_TYPE_SYSTEM_CLOCK, NULL));
|
||||||
|
gst_object_set_name (GST_OBJECT (_the_system_clock), "GstSystemClock");
|
||||||
|
}
|
||||||
|
return _the_system_clock;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_system_clock_activate (GstClock *clock, gboolean active)
|
||||||
|
{
|
||||||
|
GTimeVal timeval;
|
||||||
|
GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
|
||||||
|
|
||||||
|
g_get_current_time (&timeval);
|
||||||
|
GST_LOCK (clock);
|
||||||
|
if (active) {
|
||||||
|
sys_clock->absolute_start = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->current_time;;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sys_clock->current_time = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->absolute_start;
|
||||||
|
}
|
||||||
|
GST_UNLOCK (clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_system_clock_set_time (GstClock *clock, GstClockTime time)
|
||||||
|
{
|
||||||
|
GTimeVal timeval;
|
||||||
|
GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
|
||||||
|
|
||||||
|
g_get_current_time (&timeval);
|
||||||
|
|
||||||
|
GST_LOCK (clock);
|
||||||
|
sys_clock->absolute_start = GST_TIMEVAL_TO_TIME (timeval) - time;
|
||||||
|
sys_clock->current_time = time;
|
||||||
|
GST_UNLOCK (clock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_system_clock_reset (GstClock *clock)
|
||||||
|
{
|
||||||
|
gst_system_clock_set_time (clock, 0LL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstClockTime
|
||||||
|
gst_system_clock_get_time (GstClock *clock)
|
||||||
|
{
|
||||||
|
GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
|
||||||
|
GstClockTime res;
|
||||||
|
|
||||||
|
if (!clock->active) {
|
||||||
|
GST_LOCK (clock);
|
||||||
|
res = sys_clock->current_time;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GTimeVal timeval;
|
||||||
|
|
||||||
|
g_get_current_time (&timeval);
|
||||||
|
|
||||||
|
GST_LOCK (clock);
|
||||||
|
res = GST_TIMEVAL_TO_TIME (timeval) - sys_clock->absolute_start;
|
||||||
|
}
|
||||||
|
GST_UNLOCK (clock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstClockReturn
|
||||||
|
gst_system_clock_wait (GstClock *clock, GstClockTime time)
|
||||||
|
{
|
||||||
|
GstClockTime target;
|
||||||
|
GTimeVal timeval;
|
||||||
|
GCond *cond = g_cond_new ();
|
||||||
|
GstSystemClock *sys_clock = GST_SYSTEM_CLOCK (clock);
|
||||||
|
GstClockReturn ret;
|
||||||
|
|
||||||
|
GST_LOCK (clock);
|
||||||
|
target = time + sys_clock->absolute_start;
|
||||||
|
|
||||||
|
timeval.tv_usec = target % 1000000;
|
||||||
|
timeval.tv_sec = target / 1000000;
|
||||||
|
|
||||||
|
g_cond_timed_wait (cond, GST_GET_LOCK (clock), &timeval);
|
||||||
|
GST_UNLOCK (clock);
|
||||||
|
|
||||||
|
ret = GST_CLOCK_TIMEOUT;
|
||||||
|
|
||||||
|
g_cond_free (cond);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint64
|
||||||
|
gst_system_clock_get_resolution (GstClock *clock)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
68
gst/gstsystemclock.h
Normal file
68
gst/gstsystemclock.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* GStreamer
|
||||||
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
||||||
|
* 2000 Wim Taymans <wtay@chello.be>
|
||||||
|
*
|
||||||
|
* gstclock.h: Header for clock 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_SYSTEM_CLOCK_H__
|
||||||
|
#define __GST_SYSTEM_CLOCK_H__
|
||||||
|
|
||||||
|
#include <gst/gstclock.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#define GST_TYPE_SYSTEM_CLOCK \
|
||||||
|
(gst_system_clock_get_type())
|
||||||
|
#define GST_SYSTEM_CLOCK(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SYSTEM_CLOCK,GstSystemClock))
|
||||||
|
#define GST_SYSTEM_CLOCK_CLASS(klass) \
|
||||||
|
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SYSTEM_CLOCK,GstSystemClockClass))
|
||||||
|
#define GST_IS_SYSTEM_CLOCK(obj) \
|
||||||
|
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SYSTEM_CLOCK))
|
||||||
|
#define GST_IS_SYSTEM_CLOCK_CLASS(obj) \
|
||||||
|
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SYSTEM_CLOCK))
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct _GstSystemClock GstSystemClock;
|
||||||
|
typedef struct _GstSystemClockClass GstSystemClockClass;
|
||||||
|
|
||||||
|
struct _GstSystemClock {
|
||||||
|
GstClock clock;
|
||||||
|
|
||||||
|
GstClockTime absolute_start;
|
||||||
|
GstClockTime current_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GstSystemClockClass {
|
||||||
|
GstClockClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
GType gst_system_clock_get_type (void);
|
||||||
|
|
||||||
|
GstClock* gst_system_clock_obtain (void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __GST_SYSTEM_CLOCK_H__ */
|
|
@ -304,7 +304,7 @@ gst_disksink_handle_event (GstPad *pad, GstEvent *event)
|
||||||
gst_disksink_getcurrentfilename(disksink), sys_errlist[errno]);
|
gst_disksink_getcurrentfilename(disksink), sys_errlist[errno]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
g_warning("Unhandled event %d\n", type);
|
gst_pad_event_default (pad, event);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue