diff --git a/sys/oss/gstossclock.c b/sys/oss/gstossclock.c new file mode 100644 index 0000000000..625cb07a4c --- /dev/null +++ b/sys/oss/gstossclock.c @@ -0,0 +1,329 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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 "gstossclock.h" + +static GMemChunk *_gst_clock_entries_chunk; +static GMutex *_gst_clock_entries_chunk_lock; +static GList *_gst_clock_entries_pool; + +typedef struct _GstClockEntry GstClockEntry; + +typedef enum { + GST_ENTRY_OK, + GST_ENTRY_RESTART, +} GstEntryStatus; + +struct _GstClockEntry { + GstClockTime time; + GstEntryStatus status; + GMutex *lock; + GCond *cond; +}; + +static void gst_oss_clock_class_init (GstOssClockClass *klass); +static void gst_oss_clock_init (GstOssClock *clock); + +static void gst_oss_clock_reset (GstClock *clock); +static void gst_oss_clock_activate (GstClock *clock, gboolean activate); +static void gst_oss_clock_set_time (GstClock *clock, GstClockTime time); +static GstClockReturn gst_oss_clock_wait (GstClock *clock, GstClockTime time); + +static GstSystemClockClass *parent_class = NULL; +/* static guint gst_oss_clock_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_oss_clock_get_type (void) +{ + static GType clock_type = 0; + + if (!clock_type) { + static const GTypeInfo clock_info = { + sizeof (GstOssClockClass), + NULL, + NULL, + (GClassInitFunc) gst_oss_clock_class_init, + NULL, + NULL, + sizeof (GstOssClock), + 4, + (GInstanceInitFunc) gst_oss_clock_init, + NULL + }; + clock_type = g_type_register_static (GST_TYPE_SYSTEM_CLOCK, "GstOssClock", + &clock_info, 0); + } + return clock_type; +} + + +static void +gst_oss_clock_class_init (GstOssClockClass *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_SYSTEM_CLOCK); + + gstclock_class->reset = gst_oss_clock_reset; + gstclock_class->activate = gst_oss_clock_activate; + gstclock_class->set_time = gst_oss_clock_set_time; + gstclock_class->wait = gst_oss_clock_wait; +} + +static void +gst_oss_clock_init (GstOssClock *clock) +{ + gst_object_set_name (GST_OBJECT (clock), "GstOssClock"); + clock->is_updated = FALSE; +} + +#define GST_CLOCK_ENTRY(entry) ((GstClockEntry *)(entry)) +#define GST_CLOCK_ENTRY_TIME(entry) (((GstClockEntry *)(entry))->time) +#define GST_CLOCK_ENTRY_LOCK(entry) (g_mutex_lock ((entry)->lock)) +#define GST_CLOCK_ENTRY_UNLOCK(entry) (g_mutex_unlock ((entry)->lock)) +#define GST_CLOCK_ENTRY_SIGNAL(entry) (g_cond_signal ((entry)->cond)) +#define GST_CLOCK_ENTRY_WAIT(entry) (g_cond_wait (entry->cond, entry->lock)) +#define GST_CLOCK_ENTRY_TIMED_WAIT(entry, time) (g_cond_timed_wait (entry->cond, entry->lock, (time))) + +static GstClockEntry* +gst_clock_entry_new (GstClockTime time) +{ + GstClockEntry *entry; + + g_mutex_lock (_gst_clock_entries_chunk_lock); + if (_gst_clock_entries_pool) { + entry = GST_CLOCK_ENTRY (_gst_clock_entries_pool->data); + + _gst_clock_entries_pool = g_list_remove (_gst_clock_entries_pool, entry); + g_mutex_unlock (_gst_clock_entries_chunk_lock); + } + else { + entry = g_mem_chunk_alloc (_gst_clock_entries_chunk); + g_mutex_unlock (_gst_clock_entries_chunk_lock); + + entry->lock = g_mutex_new (); + entry->cond = g_cond_new (); + } + + entry->time = time; + + return entry; +} + +static void +gst_clock_entry_free (GstClockEntry *entry) +{ + g_mutex_lock (_gst_clock_entries_chunk_lock); + _gst_clock_entries_pool = g_list_prepend (_gst_clock_entries_pool, entry); + g_mutex_unlock (_gst_clock_entries_chunk_lock); +} + +GstOssClock* +gst_oss_clock_new (gchar *name, GstElement *owner) +{ + GstOssClock *oss_clock = GST_OSS_CLOCK (g_object_new (GST_TYPE_OSS_CLOCK, NULL)); + + oss_clock->entries = NULL; + oss_clock->current_time = 0; + oss_clock->next_time = 0; + + _gst_clock_entries_chunk = g_mem_chunk_new ("GstClockEntries", + sizeof (GstClockEntry), sizeof (GstClockEntry) * 32, + G_ALLOC_AND_FREE); + _gst_clock_entries_chunk_lock = g_mutex_new (); + _gst_clock_entries_pool = NULL; + + return oss_clock; +} + +void +gst_oss_clock_set_update (GstOssClock *clock, gboolean update) +{ + GST_LOCK (clock); + + if (!update) { + + GST_UNLOCK (clock); + GST_CLOCK_CLASS (parent_class)->set_time (GST_CLOCK (clock), clock->current_time); + GST_LOCK (clock); + clock->is_updated = FALSE; + + /* FIXME, convert the entries to ones that wait for the system clock */ + if (clock->entries) { + GList *entries = g_list_copy (clock->entries); + while (entries) { + GstClockEntry *entry = (GstClockEntry *)entries->data; + + GST_CLOCK_ENTRY_LOCK (entry); + GST_CLOCK_ENTRY_SIGNAL (entry); + entry->status = GST_ENTRY_RESTART; + GST_CLOCK_ENTRY_UNLOCK (entry); + + clock->entries = g_list_remove (clock->entries, entry); + entries = g_list_next (entries); + } + } + } + else { + clock->is_updated = TRUE; + } + + GST_UNLOCK (clock); +} + +void +gst_oss_clock_set_base (GstOssClock *clock, guint64 base) +{ + GstOssClock *oss_clock = GST_OSS_CLOCK (clock); + + oss_clock->base_time = base; + + GST_CLOCK_CLASS (parent_class)->set_time (clock, base); +} + +static void +gst_oss_clock_reset (GstClock *clock) +{ + GstOssClock *oss_clock = GST_OSS_CLOCK (clock); + + oss_clock->next_time = 0; + oss_clock->current_time = 0; + oss_clock->base_time = 0; + + GST_CLOCK_CLASS (parent_class)->reset (clock); +} + +static void +gst_oss_clock_activate (GstClock *clock, gboolean activate) +{ + GstOssClock *oss_clock = GST_OSS_CLOCK (clock); + + if (!activate) { + oss_clock->base_time = oss_clock->current_time; + } + + GST_CLOCK_CLASS (parent_class)->activate (clock, activate); +} + +static void +gst_oss_clock_set_time (GstClock *clock, GstClockTime time) +{ + GList *entries; + GstOssClock *oss_clock = GST_OSS_CLOCK (clock); + + GST_LOCK (clock); + + time += oss_clock->base_time; + + //g_print ("set time %llu\n", time); + + oss_clock->current_time = time; + + if (oss_clock->next_time > time) { + GST_UNLOCK (clock); + return; + } + + entries = g_list_copy (oss_clock->entries); + + while (entries) { + GstClockEntry *entry = (GstClockEntry *)entries->data; + + if (GST_CLOCK_ENTRY_TIME (entry) <= oss_clock->current_time) { + + GST_CLOCK_ENTRY_LOCK (entry); + GST_CLOCK_ENTRY_SIGNAL (entry); + entry->status = GST_ENTRY_OK; + GST_CLOCK_ENTRY_UNLOCK (entry); + + oss_clock->entries = g_list_remove (oss_clock->entries, entry); + } + else { + break; + } + entries = g_list_next (entries); + } + + if (oss_clock->entries) { + oss_clock->next_time = GST_CLOCK_ENTRY_TIME (oss_clock->entries->data); + } + else { + oss_clock->next_time = 0; + } + + GST_UNLOCK (oss_clock); +} + +static gint +clock_compare_func (gconstpointer a, + gconstpointer b) +{ + GstClockEntry *entry1 = (GstClockEntry *)a; + GstClockEntry *entry2 = (GstClockEntry *)b; + + return (entry1->time - entry2->time); +} + +static GstClockReturn +gst_oss_clock_wait (GstClock *clock, GstClockTime time) +{ + GstClockReturn ret; + GstOssClock *oss_clock = GST_OSS_CLOCK (clock); + + GST_LOCK (clock); +restart: + if (!oss_clock->is_updated) { + GST_UNLOCK (clock); + ret = GST_CLOCK_CLASS (parent_class)->wait (clock, time); + } + else if (time > oss_clock->current_time) { + GstClockEntry *entry = gst_clock_entry_new (time); + + oss_clock->entries = g_list_insert_sorted (oss_clock->entries, entry, clock_compare_func); + + oss_clock->next_time = GST_CLOCK_ENTRY_TIME (oss_clock->entries->data); + + GST_CLOCK_ENTRY_LOCK (entry); + GST_UNLOCK (clock); + GST_CLOCK_ENTRY_WAIT (entry); + if (entry->status == GST_ENTRY_RESTART) + goto restart; + GST_CLOCK_ENTRY_UNLOCK (entry); + + gst_clock_entry_free (entry); + + ret = GST_CLOCK_TIMEOUT; + } + else { + GST_UNLOCK (clock); + + ret = GST_CLOCK_EARLY; + } + + return ret; +} diff --git a/sys/oss/gstossclock.h b/sys/oss/gstossclock.h new file mode 100644 index 0000000000..30659fea37 --- /dev/null +++ b/sys/oss/gstossclock.h @@ -0,0 +1,77 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * 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_OSS_CLOCK_H__ +#define __GST_OSS_CLOCK_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_OSS_CLOCK \ + (gst_oss_clock_get_type()) +#define GST_OSS_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSS_CLOCK,GstOssClock)) +#define GST_OSS_CLOCK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSS_CLOCK,GstOssClockClass)) +#define GST_IS_OSS_CLOCK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSS_CLOCK)) +#define GST_IS_OSS_CLOCK_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSS_CLOCK)) + +typedef struct _GstOssClock GstOssClock; +typedef struct _GstOssClockClass GstOssClockClass; + +struct _GstOssClock { + GstSystemClock clock; + + GList *entries; + GstClockTime current_time; + GstClockTime next_time; + GstClockTime base_time; + gboolean is_updated; + GstClockTime start_time; + GstClockTime origin; + + GstElement *owner; +}; + +struct _GstOssClockClass { + GstSystemClockClass parent_class; +}; + +GType gst_oss_clock_get_type (void); +GstOssClock* gst_oss_clock_new (gchar *name, GstElement *owner); + +void gst_oss_clock_set_update (GstOssClock *clock, gboolean update); +void gst_oss_clock_set_base (GstOssClock *clock, guint64 base); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_OSS_CLOCK_H__ */