mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 00:31:13 +00:00
3ffce00efc
Original commit message from CVS: commiting wim's preliminary threaded work to a branch
507 lines
12 KiB
C
507 lines
12 KiB
C
/* GStreamer
|
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
* 2000 Wim Taymans <wim.taymans@chello.be>
|
|
*
|
|
* gstscheduler.c: Default scheduling code for most cases
|
|
*
|
|
* 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 "gst_private.h"
|
|
|
|
#include "gstsystemclock.h"
|
|
#include "gstscheduler.h"
|
|
#include "gstinfo.h"
|
|
#include "gstregistrypool.h"
|
|
|
|
static void gst_scheduler_class_init (GstSchedulerClass * klass);
|
|
static void gst_scheduler_init (GstScheduler * sched);
|
|
static void gst_scheduler_dispose (GObject * object);
|
|
|
|
static GstObjectClass *parent_class = NULL;
|
|
|
|
static gchar *_default_name = NULL;
|
|
|
|
GType
|
|
gst_scheduler_get_type (void)
|
|
{
|
|
static GType _gst_scheduler_type = 0;
|
|
|
|
if (!_gst_scheduler_type) {
|
|
static const GTypeInfo scheduler_info = {
|
|
sizeof (GstSchedulerClass),
|
|
NULL,
|
|
NULL,
|
|
(GClassInitFunc) gst_scheduler_class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof (GstScheduler),
|
|
0,
|
|
(GInstanceInitFunc) gst_scheduler_init,
|
|
NULL
|
|
};
|
|
|
|
_gst_scheduler_type =
|
|
g_type_register_static (GST_TYPE_OBJECT, "GstScheduler",
|
|
&scheduler_info, G_TYPE_FLAG_ABSTRACT);
|
|
}
|
|
return _gst_scheduler_type;
|
|
}
|
|
|
|
static void
|
|
gst_scheduler_class_init (GstSchedulerClass * klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
|
|
gobject_class = (GObjectClass *) klass;
|
|
|
|
parent_class = g_type_class_ref (GST_TYPE_OBJECT);
|
|
|
|
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_scheduler_dispose);
|
|
}
|
|
|
|
static void
|
|
gst_scheduler_init (GstScheduler * sched)
|
|
{
|
|
sched->parent = NULL;
|
|
}
|
|
|
|
static void
|
|
gst_scheduler_dispose (GObject * object)
|
|
{
|
|
GstScheduler *sched = GST_SCHEDULER (object);
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (sched));
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_setup:
|
|
* @sched: the scheduler
|
|
*
|
|
* Prepare the scheduler.
|
|
*/
|
|
void
|
|
gst_scheduler_setup (GstScheduler * sched)
|
|
{
|
|
GstSchedulerClass *sclass;
|
|
|
|
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
|
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
|
|
if (sclass->setup)
|
|
sclass->setup (sched);
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_reset:
|
|
* @sched: a #GstScheduler to reset.
|
|
*
|
|
* Reset the schedulers.
|
|
*/
|
|
void
|
|
gst_scheduler_reset (GstScheduler * sched)
|
|
{
|
|
GstSchedulerClass *sclass;
|
|
|
|
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
|
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
|
|
if (sclass->reset)
|
|
sclass->reset (sched);
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_add_element:
|
|
* @sched: the scheduler
|
|
* @element: the element to add to the scheduler
|
|
*
|
|
* Add an element to the scheduler.
|
|
*/
|
|
void
|
|
gst_scheduler_add_element (GstScheduler * sched, GstElement * element)
|
|
{
|
|
GstSchedulerClass *sclass;
|
|
|
|
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
|
|
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
|
|
if (sclass->add_element)
|
|
sclass->add_element (sched, element);
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_remove_element:
|
|
* @sched: the scheduler
|
|
* @element: the element to remove
|
|
*
|
|
* Remove an element from the scheduler.
|
|
*/
|
|
void
|
|
gst_scheduler_remove_element (GstScheduler * sched, GstElement * element)
|
|
{
|
|
GstSchedulerClass *sclass;
|
|
|
|
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
g_return_if_fail (GST_IS_ELEMENT (element));
|
|
|
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
|
|
if (sclass->remove_element)
|
|
sclass->remove_element (sched, element);
|
|
}
|
|
|
|
GstTask *
|
|
gst_scheduler_create_task (GstScheduler * sched, GstTaskFunction func,
|
|
gpointer data)
|
|
{
|
|
GstSchedulerClass *sclass;
|
|
GstTask *result = NULL;
|
|
|
|
g_return_val_if_fail (GST_IS_SCHEDULER (sched), result);
|
|
|
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
|
|
if (sclass->create_task)
|
|
result = sclass->create_task (sched, func, data);
|
|
|
|
return result;
|
|
}
|
|
|
|
GstClockReturn gst_clock_id_wait (GstClockID id, GstClockTimeDiff * jitter);
|
|
|
|
/**
|
|
* gst_scheduler_clock_wait:
|
|
* @sched: the scheduler
|
|
* @element: the element that wants to wait
|
|
* @id: the clockid to use
|
|
* @jitter: the time difference between requested time and actual time
|
|
*
|
|
* Wait till the clock reaches a specific time. The ClockID can
|
|
* be obtained from #gst_clock_new_single_shot_id.
|
|
*
|
|
* Returns: the status of the operation
|
|
*/
|
|
GstClockReturn
|
|
gst_scheduler_clock_wait (GstScheduler * sched, GstElement * element,
|
|
GstClockID id, GstClockTimeDiff * jitter)
|
|
{
|
|
GstSchedulerClass *sclass;
|
|
|
|
g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_CLOCK_ERROR);
|
|
g_return_val_if_fail (id != NULL, GST_CLOCK_ERROR);
|
|
|
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
|
|
if (sclass->clock_wait)
|
|
return sclass->clock_wait (sched, element, id, jitter);
|
|
else
|
|
return gst_clock_id_wait (id, jitter);
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_show:
|
|
* @sched: the scheduler
|
|
*
|
|
* Dump the state of the scheduler
|
|
*/
|
|
void
|
|
gst_scheduler_show (GstScheduler * sched)
|
|
{
|
|
GstSchedulerClass *sclass;
|
|
|
|
g_return_if_fail (GST_IS_SCHEDULER (sched));
|
|
|
|
sclass = GST_SCHEDULER_GET_CLASS (sched);
|
|
|
|
if (sclass->show)
|
|
sclass->show (sched);
|
|
}
|
|
|
|
/*
|
|
* Factory stuff starts here
|
|
*
|
|
*/
|
|
static void gst_scheduler_factory_class_init (GstSchedulerFactoryClass * klass);
|
|
static void gst_scheduler_factory_init (GstSchedulerFactory * factory);
|
|
|
|
static GstPluginFeatureClass *factory_parent_class = NULL;
|
|
|
|
/* static guint gst_scheduler_factory_signals[LAST_SIGNAL] = { 0 }; */
|
|
|
|
GType
|
|
gst_scheduler_factory_get_type (void)
|
|
{
|
|
static GType schedulerfactory_type = 0;
|
|
|
|
if (!schedulerfactory_type) {
|
|
static const GTypeInfo schedulerfactory_info = {
|
|
sizeof (GstSchedulerFactoryClass),
|
|
NULL,
|
|
NULL,
|
|
(GClassInitFunc) gst_scheduler_factory_class_init,
|
|
NULL,
|
|
NULL,
|
|
sizeof (GstSchedulerFactory),
|
|
0,
|
|
(GInstanceInitFunc) gst_scheduler_factory_init,
|
|
NULL
|
|
};
|
|
|
|
schedulerfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
|
|
"GstSchedulerFactory", &schedulerfactory_info, 0);
|
|
}
|
|
return schedulerfactory_type;
|
|
}
|
|
|
|
static void
|
|
gst_scheduler_factory_class_init (GstSchedulerFactoryClass * klass)
|
|
{
|
|
GObjectClass *gobject_class;
|
|
GstObjectClass *gstobject_class;
|
|
GstPluginFeatureClass *gstpluginfeature_class;
|
|
|
|
gobject_class = (GObjectClass *) klass;
|
|
gstobject_class = (GstObjectClass *) klass;
|
|
gstpluginfeature_class = (GstPluginFeatureClass *) klass;
|
|
|
|
factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
|
|
|
|
if (!_default_name) {
|
|
if (g_getenv ("GST_SCHEDULER")) {
|
|
_default_name = g_strdup (g_getenv ("GST_SCHEDULER"));
|
|
} else {
|
|
_default_name = g_strdup (GST_SCHEDULER_DEFAULT_NAME);
|
|
}
|
|
}
|
|
g_assert (_default_name);
|
|
}
|
|
|
|
static void
|
|
gst_scheduler_factory_init (GstSchedulerFactory * factory)
|
|
{
|
|
}
|
|
|
|
|
|
/**
|
|
* gst_scheduler_register:
|
|
* @plugin: a #GstPlugin
|
|
* @name: name of the scheduler to register
|
|
* @longdesc: description of the scheduler
|
|
* @type: #GType of the scheduler to register
|
|
*
|
|
* Registers a scheduler with GStreamer.
|
|
*
|
|
* Returns: TRUE, if the registering succeeded, FALSE on error.
|
|
*
|
|
* Since: 0.8.5
|
|
**/
|
|
gboolean
|
|
gst_scheduler_register (GstPlugin * plugin, const gchar * name,
|
|
const gchar * longdesc, GType type)
|
|
{
|
|
GstSchedulerFactory *factory;
|
|
|
|
g_return_val_if_fail (plugin != NULL, FALSE);
|
|
g_return_val_if_fail (name != NULL, FALSE);
|
|
g_return_val_if_fail (longdesc != NULL, FALSE);
|
|
g_return_val_if_fail (g_type_is_a (type, GST_TYPE_SCHEDULER), FALSE);
|
|
|
|
factory = gst_scheduler_factory_find (name);
|
|
if (factory) {
|
|
g_return_val_if_fail (factory->type == 0, FALSE);
|
|
g_free (factory->longdesc);
|
|
factory->longdesc = g_strdup (longdesc);
|
|
factory->type = type;
|
|
} else {
|
|
factory = gst_scheduler_factory_new (name, longdesc, type);
|
|
g_return_val_if_fail (factory, FALSE);
|
|
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_factory_new:
|
|
* @name: name of schedulerfactory to create
|
|
* @longdesc: long description of schedulerfactory to create
|
|
* @type: the gtk type of the GstScheduler element of this factory
|
|
*
|
|
* Create a new schedulerfactory with the given parameters
|
|
*
|
|
* Returns: a new #GstSchedulerFactory.
|
|
*/
|
|
GstSchedulerFactory *
|
|
gst_scheduler_factory_new (const gchar * name, const gchar * longdesc,
|
|
GType type)
|
|
{
|
|
GstSchedulerFactory *factory;
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
factory = gst_scheduler_factory_find (name);
|
|
|
|
if (!factory) {
|
|
factory =
|
|
GST_SCHEDULER_FACTORY (g_object_new (GST_TYPE_SCHEDULER_FACTORY, NULL));
|
|
GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
|
|
} else {
|
|
g_free (factory->longdesc);
|
|
}
|
|
|
|
factory->longdesc = g_strdup (longdesc);
|
|
factory->type = type;
|
|
|
|
return factory;
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_factory_destroy:
|
|
* @factory: factory to destroy
|
|
*
|
|
* Removes the scheduler from the global list.
|
|
*/
|
|
void
|
|
gst_scheduler_factory_destroy (GstSchedulerFactory * factory)
|
|
{
|
|
g_return_if_fail (factory != NULL);
|
|
|
|
/* we don't free the struct bacause someone might have a handle to it.. */
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_factory_find:
|
|
* @name: name of schedulerfactory to find
|
|
*
|
|
* Search for an schedulerfactory of the given name.
|
|
*
|
|
* Returns: #GstSchedulerFactory if found, NULL otherwise
|
|
*/
|
|
GstSchedulerFactory *
|
|
gst_scheduler_factory_find (const gchar * name)
|
|
{
|
|
GstPluginFeature *feature;
|
|
|
|
g_return_val_if_fail (name != NULL, NULL);
|
|
|
|
GST_DEBUG ("gstscheduler: find \"%s\"", name);
|
|
|
|
feature = gst_registry_pool_find_feature (name, GST_TYPE_SCHEDULER_FACTORY);
|
|
|
|
if (feature)
|
|
return GST_SCHEDULER_FACTORY (feature);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_factory_create:
|
|
* @factory: the factory used to create the instance
|
|
* @parent: the parent element of this scheduler
|
|
*
|
|
* Create a new #GstScheduler instance from the
|
|
* given schedulerfactory with the given parent. @parent will
|
|
* have its scheduler set to the returned #GstScheduler instance.
|
|
*
|
|
* Returns: A new #GstScheduler instance with a reference count of %1.
|
|
*/
|
|
GstScheduler *
|
|
gst_scheduler_factory_create (GstSchedulerFactory * factory,
|
|
GstElement * parent)
|
|
{
|
|
GstScheduler *sched = NULL;
|
|
|
|
g_return_val_if_fail (factory != NULL, NULL);
|
|
g_return_val_if_fail (GST_IS_ELEMENT (parent), NULL);
|
|
|
|
if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
|
|
g_return_val_if_fail (factory->type != 0, NULL);
|
|
|
|
sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
|
|
sched->parent = parent;
|
|
|
|
/* let's refcount the scheduler */
|
|
gst_object_ref (GST_OBJECT (sched));
|
|
gst_object_sink (GST_OBJECT (sched));
|
|
}
|
|
|
|
return sched;
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_factory_make:
|
|
* @name: the name of the factory used to create the instance
|
|
* @parent: the parent element of this scheduler
|
|
*
|
|
* Create a new #GstScheduler instance from the
|
|
* schedulerfactory with the given name and parent. @parent will
|
|
* have its scheduler set to the returned #GstScheduler instance.
|
|
* If %NULL is passed as @name, the default scheduler name will
|
|
* be used.
|
|
*
|
|
* Returns: A new #GstScheduler instance with a reference count of %1.
|
|
*/
|
|
GstScheduler *
|
|
gst_scheduler_factory_make (const gchar * name, GstElement * parent)
|
|
{
|
|
GstSchedulerFactory *factory;
|
|
const gchar *default_name = gst_scheduler_factory_get_default_name ();
|
|
|
|
if (name)
|
|
factory = gst_scheduler_factory_find (name);
|
|
else {
|
|
/* FIXME: do better error handling */
|
|
if (default_name == NULL)
|
|
g_error ("No default scheduler name - do you have a registry ?");
|
|
factory = gst_scheduler_factory_find (default_name);
|
|
}
|
|
|
|
if (factory == NULL)
|
|
return NULL;
|
|
|
|
return gst_scheduler_factory_create (factory, parent);
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_factory_set_default_name:
|
|
* @name: the name of the factory used as a default
|
|
*
|
|
* Set the default schedulerfactory name.
|
|
*/
|
|
void
|
|
gst_scheduler_factory_set_default_name (const gchar * name)
|
|
{
|
|
g_free (_default_name);
|
|
|
|
_default_name = g_strdup (name);
|
|
}
|
|
|
|
/**
|
|
* gst_scheduler_factory_get_default_name:
|
|
*
|
|
* Get the default schedulerfactory name.
|
|
*
|
|
* Returns: the name of the default scheduler.
|
|
*/
|
|
const gchar *
|
|
gst_scheduler_factory_get_default_name (void)
|
|
{
|
|
return _default_name;
|
|
}
|