mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-06-18 14:00:41 +00:00
405 lines
10 KiB
C
405 lines
10 KiB
C
/* GStreamer
|
|
* Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
|
|
*
|
|
* gstaction.c: base class for main actions/loops
|
|
*
|
|
* 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 "gstaction.h"
|
|
#include "gstelement.h"
|
|
#include "gstpad.h"
|
|
#include "gstinfo.h"
|
|
#include "gstscheduler.h"
|
|
|
|
/*
|
|
GST_DEBUG_CATEGORY_STATIC (debug, "GST_ACTION",
|
|
GST_DEBUG_BOLD | GST_DEBUG_FG_RED, "action handling");
|
|
#define GST_CAT_DEFAULT debug
|
|
*/
|
|
#if 1
|
|
# define RELEASE(action)
|
|
#else
|
|
# define RELEASE(action) G_STMT_START{\
|
|
gchar *_str; \
|
|
\
|
|
g_assert (action->any.active); \
|
|
_str = gst_action_to_string (action); \
|
|
g_print ("releasing %s\n", _str); \
|
|
g_free (_str); \
|
|
}G_STMT_END
|
|
#endif
|
|
GType
|
|
gst_action_get_type (void)
|
|
{
|
|
g_assert_not_reached ();
|
|
return 0;
|
|
}
|
|
|
|
#define GST_ACTION_SCHEDULER_CALL(action, call) G_STMT_START{ \
|
|
GstScheduler *sched = action->any.element->sched; \
|
|
if (sched) { \
|
|
GstSchedulerClass *klass = GST_SCHEDULER_GET_CLASS (sched); \
|
|
g_assert (klass->call); \
|
|
klass->call (sched, action); \
|
|
} \
|
|
}G_STMT_END
|
|
|
|
GstAction *
|
|
gst_action_new (GstActionType type)
|
|
{
|
|
GstAction *action = g_new0 (GstAction, 1);
|
|
|
|
action->type = type;
|
|
action->any.active = FALSE;
|
|
action->any.coupled = TRUE;
|
|
|
|
return action;
|
|
}
|
|
|
|
void
|
|
gst_element_add_action (GstElement * element, GstAction * action)
|
|
{
|
|
g_return_if_fail (action->any.element == NULL);
|
|
|
|
action->any.element = element;
|
|
element->actions = g_slist_prepend (element->actions, action);
|
|
|
|
#ifndef GST_DISABLE_GST_DEBUG
|
|
/* FIXME: make this work with %P */
|
|
G_STMT_START {
|
|
gchar *str = gst_action_to_string (action);
|
|
|
|
GST_DEBUG_OBJECT (element, "adding action: %s", str);
|
|
g_free (str);
|
|
} G_STMT_END;
|
|
#endif
|
|
|
|
GST_ACTION_SCHEDULER_CALL (action, add_action);
|
|
}
|
|
|
|
void
|
|
gst_element_remove_action (GstAction * action)
|
|
{
|
|
GstElement *element;
|
|
|
|
g_return_if_fail (action->any.element != NULL);
|
|
|
|
element = gst_action_get_element (action);
|
|
GST_ACTION_SCHEDULER_CALL (action, remove_action);
|
|
g_assert (g_slist_find (element->actions, action));
|
|
element->actions = g_slist_remove (element->actions, action);
|
|
|
|
#ifndef GST_DISABLE_GST_DEBUG
|
|
/* FIXME: make this work with %P */
|
|
G_STMT_START {
|
|
gchar *str = gst_action_to_string (action);
|
|
|
|
GST_DEBUG ("removing action: %s", str);
|
|
g_free (str);
|
|
} G_STMT_END;
|
|
#endif
|
|
|
|
action->any.element = NULL;
|
|
/* FIXME: pads manage their actions themselves - which kinda sucks */
|
|
if (action->type != GST_ACTION_SRC_PAD && action->type != GST_ACTION_SINK_PAD)
|
|
gst_action_free (action);
|
|
}
|
|
|
|
GstElement *
|
|
gst_action_get_element (const GstAction * action)
|
|
{
|
|
g_return_val_if_fail (GST_IS_ACTION (action), NULL);
|
|
|
|
return action->any.element;
|
|
}
|
|
|
|
void
|
|
gst_action_set_active (GstAction * action, gboolean active)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION (action));
|
|
|
|
if (action->any.active == active)
|
|
return;
|
|
action->any.active = active;
|
|
GST_ACTION_SCHEDULER_CALL (action, toggle_active);
|
|
}
|
|
|
|
gboolean
|
|
gst_action_is_active (GstAction * action)
|
|
{
|
|
g_return_val_if_fail (GST_IS_ACTION (action), FALSE);
|
|
|
|
return action->any.active;
|
|
}
|
|
|
|
/**
|
|
* gst_action_set_initially_active:
|
|
* @action: ithe action to set
|
|
* @active: whether or not the action should be initially active
|
|
*
|
|
* Initially active actions are activated by default when elements reset their
|
|
* actions. This happens during the state change from READY to PAUSED for
|
|
* example. This function allows modifying that behaviour for an action.
|
|
**/
|
|
void
|
|
gst_action_set_initially_active (GstAction * action, gboolean active)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION (action));
|
|
|
|
action->any.initially_active = active;
|
|
}
|
|
|
|
/**
|
|
* gst_action_is_initially_active:
|
|
* @action: #GstAction to check
|
|
*
|
|
* Retruns if the @action is initially active or not.
|
|
*
|
|
* Returns: TRUE if the @action is initially active, FALSE otherwise
|
|
**/
|
|
gboolean
|
|
gst_action_is_initially_active (GstAction * action)
|
|
{
|
|
g_return_val_if_fail (GST_IS_ACTION (action), FALSE);
|
|
|
|
return action->any.initially_active;
|
|
}
|
|
|
|
/**
|
|
* gst_action_set_coupled:
|
|
* @action: action to set
|
|
* @coupled: new value
|
|
*
|
|
* Makes an action coupled or not. A coupled action's activity depends on the
|
|
* state of the element it belongs to. It gets deactivated automatically when
|
|
* the element changes state to READY or below and it gets reset to its initial
|
|
* state by gst_element_reset_actions (). Activity of coupled actions must be
|
|
* set manually by the element at all times.
|
|
**/
|
|
void
|
|
gst_action_set_coupled (GstAction * action, gboolean coupled)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION (action));
|
|
|
|
if (action->any.coupled == coupled)
|
|
return;
|
|
action->any.coupled = coupled;
|
|
}
|
|
|
|
gboolean
|
|
gst_action_is_coupled (GstAction * action)
|
|
{
|
|
g_return_val_if_fail (GST_IS_ACTION (action), FALSE);
|
|
|
|
return action->any.coupled;
|
|
}
|
|
|
|
GstAction *
|
|
gst_element_add_wakeup (GstElement * element, gboolean active,
|
|
GstActionWakeupFunc release, gpointer user_data)
|
|
{
|
|
GstAction *action;
|
|
GstActionWakeup *wakeup;
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
|
g_return_val_if_fail (release != NULL, NULL);
|
|
|
|
action = gst_action_new (GST_ACTION_WAKEUP);
|
|
action->any.initially_active = active;
|
|
wakeup = &action->wakeup;
|
|
wakeup->release = release;
|
|
wakeup->user_data = user_data;
|
|
gst_element_add_action (element, action);
|
|
|
|
return action;
|
|
}
|
|
|
|
void
|
|
gst_action_wakeup_release (GstAction * action)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION_TYPE (action, GST_ACTION_WAKEUP));
|
|
|
|
RELEASE (action);
|
|
action->wakeup.release (action, action->any.element,
|
|
action->wakeup.user_data);
|
|
}
|
|
|
|
GstRealPad *
|
|
gst_action_get_pad (const GstAction * action)
|
|
{
|
|
g_return_val_if_fail (GST_IS_ACTION (action), NULL);
|
|
g_return_val_if_fail (action->type == GST_ACTION_SINK_PAD
|
|
|| action->type == GST_ACTION_SRC_PAD, NULL);
|
|
|
|
if (action->type == GST_ACTION_SINK_PAD) {
|
|
g_assert (action->sinkpad.pad != NULL);
|
|
return action->sinkpad.pad;
|
|
} else if (action->type == GST_ACTION_SRC_PAD) {
|
|
g_assert (action->srcpad.pad != NULL);
|
|
return action->srcpad.pad;
|
|
} else {
|
|
g_assert_not_reached ();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
gst_action_release_sink_pad (GstAction * action, GstData * data)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION_TYPE (action, GST_ACTION_SINK_PAD));
|
|
|
|
RELEASE (action);
|
|
action->sinkpad.release (action, action->sinkpad.pad, data);
|
|
}
|
|
|
|
GstData *
|
|
gst_action_release_src_pad (GstAction * action)
|
|
{
|
|
g_return_val_if_fail (GST_IS_ACTION_TYPE (action, GST_ACTION_SRC_PAD), NULL);
|
|
|
|
RELEASE (action);
|
|
return action->srcpad.release (action, action->srcpad.pad);
|
|
}
|
|
|
|
GstAction *
|
|
gst_real_pad_get_action (GstRealPad * pad)
|
|
{
|
|
g_return_val_if_fail (GST_IS_REAL_PAD (pad), NULL);
|
|
|
|
g_assert_not_reached ();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
GstAction *
|
|
gst_element_add_wait (GstElement * element, gboolean active,
|
|
GstClockTime start_time, GstClockTime interval, GstActionWaitFunc release)
|
|
{
|
|
GstAction *action;
|
|
GstActionWait *wait;
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
|
g_return_val_if_fail (release != NULL, NULL);
|
|
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (start_time), NULL);
|
|
g_return_val_if_fail (GST_CLOCK_TIME_IS_VALID (interval), NULL);
|
|
|
|
action = gst_action_new (GST_ACTION_WAIT);
|
|
action->any.initially_active = active;
|
|
wait = &action->wait;
|
|
wait->time = start_time;
|
|
wait->interval = interval;
|
|
wait->release = release;
|
|
gst_element_add_action (element, action);
|
|
|
|
return action;
|
|
}
|
|
|
|
void
|
|
gst_action_wait_change (GstAction * action, GstClockTime start_time,
|
|
GstClockTime interval)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION_TYPE (action, GST_ACTION_WAIT));
|
|
|
|
action->wait.time = start_time;
|
|
action->wait.interval = interval;
|
|
GST_ACTION_SCHEDULER_CALL (action, update_values);
|
|
}
|
|
|
|
void
|
|
gst_action_wait_release (GstAction * action)
|
|
{
|
|
GstClockTime time;
|
|
|
|
g_return_if_fail (GST_IS_ACTION_TYPE (action, GST_ACTION_WAIT));
|
|
|
|
RELEASE (action);
|
|
time = action->wait.time;
|
|
action->wait.time += action->wait.interval;
|
|
action->wait.release (action, action->any.element, time);
|
|
}
|
|
|
|
GstAction *
|
|
gst_element_add_fd (GstElement * element, gboolean active,
|
|
gint fd, gushort condition, GstActionFdFunc release)
|
|
{
|
|
GstAction *action;
|
|
GstActionFd *afd;
|
|
|
|
g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
|
|
g_return_val_if_fail (release != NULL, NULL);
|
|
g_return_val_if_fail (condition != 0, NULL);
|
|
|
|
action = gst_action_new (GST_ACTION_FD);
|
|
action->any.initially_active = active;
|
|
afd = &action->fd;
|
|
afd->fd = fd;
|
|
afd->condition = condition;
|
|
gst_element_add_action (element, action);
|
|
|
|
return action;
|
|
}
|
|
|
|
void
|
|
gst_action_fd_release (GstAction * action, GIOCondition condition)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION_TYPE (action, GST_ACTION_FD));
|
|
|
|
RELEASE (action);
|
|
action->fd.release (action, action->any.element, action->fd.fd, condition);
|
|
}
|
|
|
|
void
|
|
gst_action_fd_change (GstAction * action, gint fd, gushort condition)
|
|
{
|
|
g_return_if_fail (GST_IS_ACTION_TYPE (action, GST_ACTION_FD));
|
|
|
|
action->fd.fd = fd;
|
|
action->fd.condition = condition;
|
|
GST_ACTION_SCHEDULER_CALL (action, update_values);
|
|
}
|
|
|
|
static const gchar *
|
|
gst_action_type_to_string (GstActionType type)
|
|
{
|
|
switch (type) {
|
|
case GST_ACTION_WAKEUP:
|
|
return "WAKEUP";
|
|
case GST_ACTION_SINK_PAD:
|
|
return "SINKPAD";
|
|
case GST_ACTION_SRC_PAD:
|
|
return "SRCPAD";
|
|
case GST_ACTION_FD:
|
|
return "FD";
|
|
case GST_ACTION_WAIT:
|
|
return "TIME";
|
|
default:
|
|
g_return_val_if_reached (NULL);
|
|
}
|
|
}
|
|
|
|
gchar *
|
|
gst_action_to_string (const GstAction * action)
|
|
{
|
|
g_return_val_if_fail (GST_IS_ACTION (action), NULL);
|
|
|
|
return g_strdup_printf ("%s for %s",
|
|
gst_action_type_to_string (action->type),
|
|
GST_ELEMENT_NAME (gst_action_get_element (action)));
|
|
}
|