Next big merge.

Original commit message from CVS:
Next big merge.
Added GstBus for mainloop integration.
Added GstMessage for sending notifications on the bus.
Added GstTask as an abstraction for pipeline entry points.
Removed GstThread.
Removed Schedulers.
Simplified GstQueue for multithreaded core.
Made _link threadsafe, removed old capsnego.
Added STREAM_LOCK and PREROLL_LOCK in GstPad.
Added pad blocking functions.
Reworked scheduling functions in GstPad to prepare for
scheduling updates soon.
Moved events out of data stream.
Simplified GstEvent types.
Added return values to push/pull.
Removed clocking from GstElement.
Added prototypes for state change function for next merge.
Removed iterate from bins and state change management.
Fixed some elements, disabled others for now.
Fixed -inspect and -launch.
Added check for GstBus.
This commit is contained in:
Wim Taymans 2005-03-21 17:34:02 +00:00
parent 007cff6d75
commit c2f41a8906
86 changed files with 7431 additions and 15691 deletions

190
ChangeLog
View file

@ -1,3 +1,193 @@
2005-03-21 Wim Taymans <wim@fluendo.com>
* check/Makefile.am:
* gst/Makefile.am:
* gst/elements/Makefile.am:
* gst/elements/gstelements.c:
* gst/elements/gstfakesink.c: (gst_fakesink_init),
(gst_fakesink_event), (gst_fakesink_chain):
* gst/elements/gstfakesrc.c: (gst_fakesrc_class_init),
(gst_fakesrc_init), (gst_fakesrc_get_event_mask),
(gst_fakesrc_event_handler), (gst_fakesrc_set_pad_functions),
(gst_fakesrc_set_all_pad_functions), (gst_fakesrc_request_new_pad),
(gst_fakesrc_set_property), (gst_fakesrc_get_property),
(gst_fakesrc_get_range_unlocked), (gst_fakesrc_get_range),
(gst_fakesrc_loop), (gst_fakesrc_activate),
(gst_fakesrc_change_state):
* gst/elements/gstfakesrc.h:
* gst/elements/gstfilesrc.c: (gst_filesrc_init),
(gst_filesrc_get_read), (gst_filesrc_getrange), (gst_filesrc_get),
(gst_filesrc_open_file), (gst_filesrc_loop),
(gst_filesrc_activate), (gst_filesrc_change_state),
(filesrc_find_peek), (filesrc_find_suggest),
(gst_filesrc_type_find):
* gst/elements/gstidentity.c: (gst_identity_finalize),
(gst_identity_class_init), (gst_identity_init),
(gst_identity_proxy_getcaps), (identity_queue_push),
(identity_queue_pop), (identity_queue_flush), (gst_identity_event),
(gst_identity_getrange), (gst_identity_chain),
(gst_identity_sink_loop), (gst_identity_src_loop),
(gst_identity_handle_buffer), (gst_identity_set_dataflow_funcs),
(gst_identity_set_property), (gst_identity_get_property),
(gst_identity_change_state):
* gst/elements/gstidentity.h:
* gst/elements/gsttee.c: (gst_tee_class_init), (gst_tee_init),
(gst_tee_update_pad_functions), (gst_tee_request_new_pad),
(gst_tee_set_property), (gst_tee_get_property), (gst_tee_do_push),
(gst_tee_handle_buffer), (gst_tee_chain), (gst_tee_loop),
(gst_tee_sink_activate):
* gst/elements/gsttee.h:
* gst/gst.c: (gst_register_core_elements), (init_post):
* gst/gst.h:
* gst/gstbin.c: (gst_bin_class_init), (gst_bin_set_bus),
(gst_bin_set_scheduler), (gst_bin_add_func), (gst_bin_add),
(gst_bin_remove_func), (gst_bin_remove), (gst_bin_get_state),
(gst_bin_change_state):
* gst/gstbin.h:
* gst/gstbus.c: (gst_bus_get_type), (gst_bus_class_init),
(gst_bus_init), (gst_bus_dispose), (gst_bus_set_property),
(gst_bus_get_property), (gst_bus_new), (gst_bus_post),
(gst_bus_have_pending), (gst_bus_pop), (gst_bus_peek),
(gst_bus_set_sync_handler), (gst_bus_create_watch),
(bus_watch_callback), (bus_watch_destroy),
(gst_bus_add_watch_full), (gst_bus_add_watch), (poll_handler),
(poll_timeout), (gst_bus_poll):
* gst/gstbus.h:
* gst/gstcaps.h:
* gst/gstdata.h:
* gst/gstelement.c: (gst_element_class_init), (gst_element_init),
(gst_element_post_message), (gst_element_message_full),
(gst_element_get_state_func), (gst_element_get_state),
(gst_element_abort_state), (gst_element_commit_state),
(gst_element_lost_state), (gst_element_set_state),
(gst_element_pads_activate), (gst_element_change_state),
(gst_element_dispose), (gst_element_set_manager_func),
(gst_element_set_bus_func), (gst_element_set_scheduler_func),
(gst_element_set_manager), (gst_element_get_manager),
(gst_element_set_bus), (gst_element_get_bus),
(gst_element_set_scheduler), (gst_element_get_scheduler):
* gst/gstelement.h:
* gst/gstevent.c: (gst_event_new_segment_seek),
(gst_event_new_flush):
* gst/gstevent.h:
* gst/gstmessage.c: (_gst_message_initialize), (_gst_message_copy),
(_gst_message_free), (gst_message_get_type), (gst_message_new),
(gst_message_new_eos), (gst_message_new_error),
(gst_message_new_warning), (gst_message_new_tag),
(gst_message_new_state_changed), (gst_message_new_application),
(gst_message_get_structure), (gst_message_parse_tag),
(gst_message_parse_state_changed), (gst_message_parse_error),
(gst_message_parse_warning):
* gst/gstmessage.h:
* gst/gstpad.c: (gst_real_pad_class_init), (gst_real_pad_init),
(gst_real_pad_set_property), (gst_pad_set_active),
(gst_pad_is_active), (gst_pad_set_blocked_async),
(gst_pad_set_blocked), (gst_pad_is_blocked),
(gst_pad_set_activate_function), (gst_pad_set_loop_function),
(gst_pad_set_getrange_function), (gst_pad_set_acceptcaps_function),
(gst_pad_set_fixatecaps_function), (gst_pad_set_setcaps_function),
(gst_pad_unlink), (gst_pad_link_prepare_filtered),
(gst_pad_link_filtered), (gst_pad_relink_filtered),
(gst_real_pad_get_caps_unlocked), (gst_pad_get_caps),
(gst_pad_peer_get_caps), (gst_pad_fixate_caps),
(gst_pad_accept_caps), (gst_pad_peer_accept_caps),
(gst_pad_set_caps), (gst_pad_configure_sink),
(gst_pad_configure_src), (gst_pad_get_negotiated_caps),
(gst_pad_get_filter_caps), (gst_pad_alloc_buffer),
(gst_real_pad_dispose), (gst_real_pad_finalize),
(handle_pad_block), (gst_pad_push), (gst_pad_pull_range),
(gst_pad_event_default_dispatch), (gst_pad_event_default),
(gst_pad_push_event), (gst_pad_send_event), (gst_pad_get_formats):
* gst/gstpad.h:
* gst/gstpipeline.c: (gst_pipeline_init), (is_eos),
(pipeline_bus_handler), (gst_pipeline_change_state),
(gst_pipeline_get_scheduler), (gst_pipeline_get_bus):
* gst/gstpipeline.h:
* gst/gstprobe.h:
* gst/gstqueue.c: (gst_queue_class_init), (gst_queue_init),
(gst_queue_finalize), (gst_queue_getcaps), (gst_queue_link_sink),
(gst_queue_link_src), (gst_queue_bufferalloc),
(gst_queue_locked_flush), (gst_queue_handle_sink_event),
(gst_queue_is_empty), (gst_queue_is_filled), (gst_queue_chain),
(gst_queue_loop), (gst_queue_handle_src_event),
(gst_queue_handle_src_query), (gst_queue_src_activate),
(gst_queue_change_state):
* gst/gstqueue.h:
* gst/gstscheduler.c: (gst_scheduler_init),
(gst_scheduler_dispose), (gst_scheduler_create_task),
(gst_scheduler_factory_create):
* gst/gstscheduler.h:
* gst/gststructure.c: (gst_structure_get_type),
(gst_structure_copy_conditional):
* gst/gststructure.h:
* gst/gsttaginterface.h:
* gst/gsttask.c: (gst_task_get_type), (gst_task_class_init),
(gst_task_init), (gst_task_dispose), (gst_task_create),
(gst_task_get_state), (gst_task_start), (gst_task_stop),
(gst_task_pause):
* gst/gsttask.h:
* gst/gstthread.c:
* gst/gstthread.h:
* gst/gsttypes.h:
* gst/schedulers/Makefile.am:
* gst/schedulers/cothreads_compat.h:
* gst/schedulers/entryscheduler.c:
* gst/schedulers/faircothreads.c:
* gst/schedulers/faircothreads.h:
* gst/schedulers/fairscheduler.c:
* gst/schedulers/gstbasicscheduler.c:
* gst/schedulers/gstoptimalscheduler.c:
* gst/schedulers/gthread-cothreads.h:
* gst/schedulers/threadscheduler.c:
(gst_thread_scheduler_task_get_type),
(gst_thread_scheduler_task_class_init),
(gst_thread_scheduler_task_init),
(gst_thread_scheduler_task_start),
(gst_thread_scheduler_task_stop),
(gst_thread_scheduler_task_pause), (gst_thread_scheduler_get_type),
(gst_thread_scheduler_class_init), (gst_thread_scheduler_func),
(gst_thread_scheduler_init), (gst_thread_scheduler_create_task),
(gst_thread_scheduler_setup), (gst_thread_scheduler_reset),
(plugin_init):
* libs/gst/Makefile.am:
* libs/gst/bytestream/bytestream.c: (gst_bytestream_get_next_buf):
* libs/gst/bytestream/filepad.c: (gst_file_pad_init),
(gst_file_pad_parent_set):
* libs/gst/dataprotocol/dataprotocol.c: (gst_dp_packet_from_event),
(gst_dp_event_from_packet):
* tests/complexity.c: (main):
* tests/mass_elements.c: (main):
* testsuite/states/locked.c: (message_received), (main):
* testsuite/states/parent.c: (main):
* tools/gst-inspect.c: (print_element_flag_info),
(print_implementation_info), (print_pad_info):
* tools/gst-launch.c: (check_intr), (play_handler), (event_loop),
(main):
* tools/gst-md5sum.c: (event_loop), (main):
* tools/gst-typefind.c: (main):
* tools/gst-xmlinspect.c: (print_element_info):
Next big merge.
Added GstBus for mainloop integration.
Added GstMessage for sending notifications on the bus.
Added GstTask as an abstraction for pipeline entry points.
Removed GstThread.
Removed Schedulers.
Simplified GstQueue for multithreaded core.
Made _link threadsafe, removed old capsnego.
Added STREAM_LOCK and PREROLL_LOCK in GstPad.
Added pad blocking functions.
Reworked scheduling functions in GstPad to prepare for
scheduling updates soon.
Moved events out of data stream.
Simplified GstEvent types.
Added return values to push/pull.
Removed clocking from GstElement.
Added prototypes for state change function for next merge.
Removed iterate from bins and state change management.
Fixed some elements, disabled others for now.
Fixed -inspect and -launch.
Added check for GstBus.
2005-03-10 Wim Taymans <wim@fluendo.com>
* docs/design/part-MT-refcounting.txt:

View file

@ -20,6 +20,7 @@ CLEANFILES = core.*
TESTS = $(top_builddir)/tools/gst-register-@GST_MAJORMINOR@ \
gst/gstbin \
gst/gstbus \
gst/gstcaps \
gst/gstdata \
gst/gstiterator \

2
common

@ -1 +1 @@
Subproject commit b2638c100721f67b280c3b43b21f1ce1c9b5e316
Subproject commit 131c2632127e6f061b5270d8f80651782a4fdd13

View file

@ -1,10 +1,6 @@
lib_LTLIBRARIES = libgstreamer-@GST_MAJORMINOR@.la
AS_LIBTOOL_LIB = libgstreamer-@GST_MAJORMINOR@
if GST_DISABLE_OMEGA_COTHREADS
noinst_LTLIBRARIES =
else
noinst_LTLIBRARIES = libcothreads.la
endif
#GST_INSTRUMENT_FLAGS = -finstrument-functions -DGST_ENABLE_FUNC_INSTRUMENTATION
@ -67,7 +63,7 @@ GST_URI_SRC = gsturi.c
endif
SUBDIRS = $(GST_PARSE_DIRS) $(GST_REGISTRY_DIRS) . elements schedulers $(GST_INDEX_DIRS)
DIST_SUBDIRS = autoplug elements parse registries schedulers indexers
DIST_SUBDIRS = elements parse registries schedulers indexers
# make variables for all generated source and header files to make the
# distinction clear
@ -85,6 +81,7 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
gstatomic.c \
gstbin.c \
gstbuffer.c \
gstbus.c \
gstcaps.c \
gstclock.c \
gstcpu.c \
@ -100,19 +97,20 @@ libgstreamer_@GST_MAJORMINOR@_la_SOURCES = \
gstinterface.c \
gstiterator.c \
gstmemchunk.c \
gstmessage.c \
gstpad.c \
gstpipeline.c \
gstplugin.c \
gstpluginfeature.c \
gstprobe.c \
gstqueue.c \
gstquery.c \
gstqueue.c \
gstscheduler.c \
gststructure.c \
gstsystemclock.c \
gsttag.c \
gsttaginterface.c \
gstthread.c \
gsttask.c \
$(GST_TRACE_SRC) \
gsttrashstack.c \
gsttypefind.c \
@ -159,6 +157,7 @@ gst_headers = \
gstobject.h \
gstbin.h \
gstbuffer.h \
gstbus.h \
gstcaps.h \
gstclock.h \
gstcompat.h \
@ -175,19 +174,20 @@ gst_headers = \
gstiterator.h \
gstmacros.h \
gstmemchunk.h \
gstmessage.h \
gstpad.h \
gstpipeline.h \
gstplugin.h \
gstpluginfeature.h \
gstprobe.h \
gstqueue.h \
gstquery.h \
gstqueue.h \
gstscheduler.h \
gststructure.h \
gstsystemclock.h \
gsttag.h \
gsttaginterface.h \
gstthread.h \
gsttask.h \
gsttrace.h \
gsttrashstack.h \
gsttypefind.h \
@ -215,15 +215,6 @@ noinst_HEADERS = \
gstarch.h \
cothreads.h
if GST_DISABLE_OMEGA_COTHREADS
#libcothreads_la_SOURCES =
#libcothreads_la_CFLAGS =
else
libcothreads_la_SOURCES = cothreads.c
libcothreads_la_CFLAGS = $(libgstreamer_@GST_MAJORMINOR@_la_CFLAGS)
endif
gstmarshal.h: gstmarshal.list
glib-genmarshal --header --prefix=gst_marshal $(srcdir)/gstmarshal.list > gstmarshal.h.tmp
mv gstmarshal.h.tmp gstmarshal.h

View file

@ -24,23 +24,24 @@ endif
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
libgstelements_la_SOURCES = \
gstaggregator.c \
gstbufferstore.c \
gstelements.c \
gstfakesink.c \
gstfakesrc.c \
gstfilesink.c \
gstfakesink.c \
gstfilesrc.c \
gstfdsink.c \
gstfdsrc.c \
gstidentity.c \
gstmd5sink.c \
$(multifilesrc) \
$(pipefilter) \
gstshaper.c \
gststatistics.c \
gsttee.c \
gsttypefindelement.c
gstelements.c \
gsttee.c
# gstaggregator.c \
# gstbufferstore.c \
# gstfilesink.c \
# gstfdsink.c \
# gstfdsrc.c \
# gstmd5sink.c \
# $(multifilesrc) \
# $(pipefilter) \
# gstshaper.c \
# gststatistics.c \
# gsttypefindelement.c
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
libgstelements_la_LIBADD = $(GST_OBJ_LIBS)

View file

@ -55,24 +55,24 @@ extern GType gst_filesrc_get_type (void);
extern GstElementDetails gst_filesrc_details;
static struct _elements_entry _elements[] = {
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
// {"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
{"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
{"filesrc", GST_RANK_NONE, gst_filesrc_get_type},
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
{"identity", GST_RANK_NONE, gst_identity_get_type},
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
// {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
// {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
// {"filesink", GST_RANK_NONE, gst_filesink_get_type},
// {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
#ifndef HAVE_WIN32
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
// {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
// {"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
#endif
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
// {"shaper", GST_RANK_NONE, gst_shaper_get_type},
// {"statistics", GST_RANK_NONE, gst_statistics_get_type},
{"tee", GST_RANK_NONE, gst_tee_get_type},
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
{NULL, 0},
// {"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
// {NULL, 0},
};
static gboolean

View file

@ -113,7 +113,8 @@ static void gst_fakesink_get_property (GObject * object, guint prop_id,
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
static void gst_fakesink_chain (GstPad * pad, GstData * _data);
static GstFlowReturn gst_fakesink_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_fakesink_event (GstPad * pad, GstEvent * event);
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
@ -188,6 +189,7 @@ gst_fakesink_init (GstFakeSink * fakesink)
"sink");
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
fakesink->silent = FALSE;
fakesink->dump = FALSE;
@ -195,8 +197,6 @@ gst_fakesink_init (GstFakeSink * fakesink)
fakesink->last_message = NULL;
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
fakesink->signal_handoffs = FALSE;
GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
}
static void
@ -307,47 +307,43 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
}
}
static void
gst_fakesink_chain (GstPad * pad, GstData * _data)
static gboolean
gst_fakesink_event (GstPad * pad, GstEvent * event)
{
GstBuffer *buf = GST_BUFFER (_data);
GstFakeSink *fakesink;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
if (!fakesink->silent) {
g_free (fakesink->last_message);
if (!fakesink->silent) {
g_free (fakesink->last_message);
fakesink->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
fakesink->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
g_object_notify (G_OBJECT (fakesink), "last_message");
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
if (fakesink->sync && fakesink->clock) {
gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
gst_element_set_time (GST_ELEMENT (fakesink), value);
}
default:
gst_pad_event_default (pad, event);
break;
}
return;
g_object_notify (G_OBJECT (fakesink), "last_message");
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
default:
gst_pad_event_default (pad, event);
break;
}
return TRUE;
}
static GstFlowReturn
gst_fakesink_chain (GstPad * pad, GstBuffer * buffer)
{
GstBuffer *buf = GST_BUFFER (buffer);
GstFakeSink *fakesink;
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
if (fakesink->sync && fakesink->clock) {
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
//gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
}
if (!fakesink->silent) {
@ -374,6 +370,8 @@ gst_fakesink_chain (GstPad * pad, GstData * _data)
}
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
static GstElementStateReturn

View file

@ -64,7 +64,8 @@ enum
{
ARG_0,
ARG_NUM_SOURCES,
ARG_LOOP_BASED,
ARG_HAS_LOOP,
ARG_HAS_GETRANGE,
ARG_OUTPUT,
ARG_DATA,
ARG_SIZETYPE,
@ -179,7 +180,7 @@ GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstElement, GST_TYPE_ELEMENT,
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused);
static void gst_fakesrc_update_functions (GstFakeSrc * src);
static gboolean gst_fakesrc_activate (GstPad * pad, GstActivateMode mode);
static void gst_fakesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_fakesrc_get_property (GObject * object, guint prop_id,
@ -188,8 +189,9 @@ static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
static GstData *gst_fakesrc_get (GstPad * pad);
static void gst_fakesrc_loop (GstElement * element);
static void gst_fakesrc_loop (GstPad * pad);
static GstFlowReturn gst_fakesrc_get_range (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buf);
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
@ -220,9 +222,14 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
g_param_spec_int ("num-sources", "num-sources", "Number of sources",
1, G_MAXINT, 1, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
g_param_spec_boolean ("loop-based", "loop-based",
"Enable loop-based operation", FALSE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
g_param_spec_boolean ("has-loop", "has-loop",
"Enable loop-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_GETRANGE,
g_param_spec_boolean ("has-getrange", "has-getrange",
"Enable getrange-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OUTPUT,
g_param_spec_enum ("output", "output", "Output method (currently unused)",
GST_TYPE_FAKESRC_OUTPUT, FAKESRC_FIRST_LAST_LOOP, G_PARAM_READWRITE));
@ -300,9 +307,6 @@ gst_fakesrc_init (GstFakeSrc * fakesrc)
"src");
gst_element_add_pad (GST_ELEMENT (fakesrc), pad);
fakesrc->loop_based = FALSE;
gst_fakesrc_update_functions (fakesrc);
fakesrc->output = FAKESRC_FIRST_LAST_LOOP;
fakesrc->segment_start = -1;
fakesrc->segment_end = -1;
@ -324,6 +328,7 @@ gst_fakesrc_init (GstFakeSrc * fakesrc)
fakesrc->last_message = NULL;
fakesrc->datarate = DEFAULT_DATARATE;
fakesrc->sync = DEFAULT_SYNC;
fakesrc->pad_mode = GST_ACTIVATE_NONE;
}
static void
@ -336,35 +341,6 @@ gst_fakesrc_set_clock (GstElement * element, GstClock * clock)
src->clock = clock;
}
static GstPad *
gst_fakesrc_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
gchar *name;
GstPad *srcpad;
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
return NULL;
}
fakesrc = GST_FAKESRC (element);
name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
srcpad = gst_pad_new_from_template (templ, name);
gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
gst_fakesrc_update_functions (fakesrc);
g_free (name);
return srcpad;
}
static const GstFormat *
gst_fakesrc_get_formats (GstPad * pad)
{
@ -419,8 +395,7 @@ static const GstEventMask *
gst_fakesrc_get_event_mask (GstPad * pad)
{
static const GstEventMask masks[] = {
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH},
{GST_EVENT_SEEK_SEGMENT, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_FLUSH, 0},
{0, 0},
};
@ -433,22 +408,16 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
{
GstFakeSrc *src;
src = GST_FAKESRC (gst_pad_get_parent (pad));
src = GST_FAKESRC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
break;
}
/* else we do a flush too */
case GST_EVENT_SEEK_SEGMENT:
src->segment_start = GST_EVENT_SEEK_OFFSET (event);
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
src->buffer_count = src->segment_start;
src->segment_loop =
GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
src->need_flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
break;
case GST_EVENT_FLUSH:
src->need_flush = TRUE;
@ -462,34 +431,61 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
}
static void
gst_fakesrc_update_functions (GstFakeSrc * src)
gst_fakesrc_set_pad_functions (GstFakeSrc * src, GstPad * pad)
{
GList *pads;
gst_pad_set_activate_function (pad, gst_fakesrc_activate);
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_fakesrc_query);
gst_pad_set_query_type_function (pad, gst_fakesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_fakesrc_get_formats);
if (src->loop_based) {
gst_element_set_loop_function (GST_ELEMENT (src),
GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
} else {
gst_element_set_loop_function (GST_ELEMENT (src), NULL);
if (src->has_loop)
gst_pad_set_loop_function (pad, gst_fakesrc_loop);
else
gst_pad_set_loop_function (pad, NULL);
if (src->has_getrange)
gst_pad_set_getrange_function (pad, gst_fakesrc_get_range);
else
gst_pad_set_getrange_function (pad, NULL);
}
static void
gst_fakesrc_set_all_pad_functions (GstFakeSrc * src)
{
GList *l;
for (l = GST_ELEMENT_PADS (src); l; l = l->next)
gst_fakesrc_set_pad_functions (src, (GstPad *) l->data);
}
static GstPad *
gst_fakesrc_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
gchar *name;
GstPad *srcpad;
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
return NULL;
}
pads = GST_ELEMENT (src)->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);
fakesrc = GST_FAKESRC (element);
if (src->loop_based) {
gst_pad_set_get_function (pad, NULL);
} else {
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
}
name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_fakesrc_query);
gst_pad_set_query_type_function (pad, gst_fakesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_fakesrc_get_formats);
pads = g_list_next (pads);
}
srcpad = gst_pad_new_from_template (templ, name);
gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
gst_fakesrc_set_pad_functions (fakesrc, srcpad);
g_free (name);
return srcpad;
}
static void
@ -511,13 +507,16 @@ gst_fakesrc_set_property (GObject * object, guint prop_id, const GValue * value,
{
GstFakeSrc *src;
/* it's not null if we got it, but it might not be ours */
src = GST_FAKESRC (object);
switch (prop_id) {
case ARG_LOOP_BASED:
src->loop_based = g_value_get_boolean (value);
gst_fakesrc_update_functions (src);
case ARG_HAS_LOOP:
src->has_loop = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_HAS_GETRANGE:
src->has_getrange = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_OUTPUT:
g_warning ("not yet implemented");
@ -595,8 +594,11 @@ gst_fakesrc_get_property (GObject * object, guint prop_id, GValue * value,
case ARG_NUM_SOURCES:
g_value_set_int (value, GST_ELEMENT (src)->numsrcpads);
break;
case ARG_LOOP_BASED:
g_value_set_boolean (value, src->loop_based);
case ARG_HAS_LOOP:
g_value_set_boolean (value, src->has_loop);
break;
case ARG_HAS_GETRANGE:
g_value_set_boolean (value, src->has_getrange);
break;
case ARG_OUTPUT:
g_value_set_enum (value, src->output);
@ -789,36 +791,28 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
return buf;
}
static GstData *
gst_fakesrc_get (GstPad * pad)
static GstFlowReturn
gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFakeSrc *src;
GstBuffer *buf;
GstClockTime time;
g_return_val_if_fail (pad != NULL, NULL);
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
if (src->need_flush) {
src->need_flush = FALSE;
return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
}
if (src->buffer_count == src->segment_end) {
if (src->segment_loop) {
return GST_DATA (gst_event_new (GST_EVENT_SEGMENT_DONE));
//gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
} else {
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED;
}
}
if (src->rt_num_buffers == 0) {
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED;
} else {
if (src->rt_num_buffers > 0)
src->rt_num_buffers--;
@ -826,8 +820,8 @@ gst_fakesrc_get (GstPad * pad)
if (src->eos) {
GST_INFO ("fakesrc is setting eos on pad");
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED;
}
buf = gst_fakesrc_create_buffer (src);
@ -838,7 +832,7 @@ gst_fakesrc_get (GstPad * pad)
if (src->datarate > 0) {
time = (src->bytes_sent * GST_SECOND) / src->datarate;
if (src->sync) {
gst_element_wait (GST_ELEMENT (src), time);
/* gst_element_wait (GST_ELEMENT (src), time); */
}
GST_BUFFER_DURATION (buf) =
@ -866,49 +860,121 @@ gst_fakesrc_get (GstPad * pad)
src->bytes_sent += GST_BUFFER_SIZE (buf);
return GST_DATA (buf);
*ret = buf;
return GST_FLOW_OK;
}
static GstFlowReturn
gst_fakesrc_get_range (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFlowReturn fret;
g_assert (GST_FAKESRC (GST_OBJECT_PARENT (pad))->pad_mode ==
GST_ACTIVATE_PULL);
GST_STREAM_LOCK (pad);
fret = gst_fakesrc_get_range_unlocked (pad, offset, length, ret);
GST_STREAM_UNLOCK (pad);
return fret;
}
/**
* gst_fakesrc_loop:
* @element: the faksesrc to loop
*
* generate an empty buffer and push it to the next element.
*/
static void
gst_fakesrc_loop (GstElement * element)
gst_fakesrc_loop (GstPad * pad)
{
GstFakeSrc *src;
const GList *pads;
GstBuffer *buf = NULL;
GstFlowReturn ret;
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_FAKESRC (element));
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
src = GST_FAKESRC (element);
g_assert (src->pad_mode == GST_ACTIVATE_PUSH);
pads = element->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);
GstData *data;
data = gst_fakesrc_get (pad);
gst_pad_push (pad, data);
if (src->eos) {
return;
}
pads = g_list_next (pads);
GST_STREAM_LOCK (pad);
if (src->need_flush) {
src->need_flush = FALSE;
gst_pad_push_event (pad, gst_event_new (GST_EVENT_FLUSH));
}
ret = gst_fakesrc_get_range_unlocked (pad, src->buffer_count,
DEFAULT_SIZEMAX, &buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
ret = gst_pad_push (pad, buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
GST_STREAM_UNLOCK (pad);
return;
pause:
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
static gboolean
gst_fakesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstFakeSrc *fakesrc;
fakesrc = GST_FAKESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
g_return_val_if_fail (fakesrc->has_loop, FALSE);
if (GST_ELEMENT_SCHEDULER (fakesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (fakesrc),
(GstTaskFunction) gst_fakesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_PULL:
g_return_val_if_fail (fakesrc->has_getrange, FALSE);
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
if (GST_RPAD_TASK (pad)) {
gst_task_stop (GST_RPAD_TASK (pad));
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
fakesrc->pad_mode = mode;
return result;
}
static GstElementStateReturn
gst_fakesrc_change_state (GstElement * element)
{
GstFakeSrc *fakesrc;
GstElementStateReturn result = GST_STATE_FAILURE;
g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_FAKESRC (element), result);
fakesrc = GST_FAKESRC (element);
@ -916,6 +982,7 @@ gst_fakesrc_change_state (GstElement * element)
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
{
fakesrc->buffer_count = 0;
fakesrc->pattern_byte = 0x00;
fakesrc->need_flush = FALSE;
@ -923,7 +990,14 @@ gst_fakesrc_change_state (GstElement * element)
fakesrc->bytes_sent = 0;
fakesrc->rt_num_buffers = fakesrc->num_buffers;
break;
}
case GST_STATE_PAUSED_TO_PLAYING:
break;
}
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
@ -940,8 +1014,5 @@ gst_fakesrc_change_state (GstElement * element)
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
return result;
}

View file

@ -76,13 +76,15 @@ typedef struct _GstFakeSrcClass GstFakeSrcClass;
struct _GstFakeSrc {
GstElement element;
gboolean loop_based;
gboolean has_loop;
gboolean has_getrange;
gboolean eos;
GstFakeSrcOutputType output;
GstFakeSrcDataType data;
GstFakeSrcSizeType sizetype;
GstFakeSrcFillType filltype;
GstActivateMode pad_mode;
guint sizemin;
guint sizemax;

View file

@ -170,13 +170,17 @@ static void gst_filesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
static GstData *gst_filesrc_get (GstPad * pad);
static GstFlowReturn gst_filesrc_get (GstPad * pad, GstBuffer ** buffer);
static GstFlowReturn gst_filesrc_getrange (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buffer);
static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value);
static gboolean gst_filesrc_activate (GstPad * pad, GstActivateMode mode);
static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
static GstCaps *gst_filesrc_type_find (GstFileSrc * src);
static void gst_filesrc_uri_handler_init (gpointer g_iface,
gpointer iface_data);
@ -247,7 +251,8 @@ gst_filesrc_init (GstFileSrc * src)
src->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_pad_set_get_function (src->srcpad, gst_filesrc_get);
gst_pad_set_getrange_function (src->srcpad, gst_filesrc_getrange);
gst_pad_set_activate_function (src->srcpad, gst_filesrc_activate);
gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
@ -672,7 +677,7 @@ gst_filesrc_get_read (GstFileSrc * src)
if (ret == 0) {
GST_DEBUG ("non-regular file hits EOS");
gst_buffer_unref (buf);
gst_element_set_eos (GST_ELEMENT (src));
//gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
}
readsize = ret;
@ -686,20 +691,36 @@ gst_filesrc_get_read (GstFileSrc * src)
return GST_DATA (buf);
}
static GstData *
gst_filesrc_get (GstPad * pad)
static GstFlowReturn
gst_filesrc_getrange (GstPad * pad, guint64 offset, guint length,
GstBuffer ** buffer)
{
GstFileSrc *src;
g_return_val_if_fail (pad != NULL, NULL);
src = GST_FILESRC (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), NULL);
src = GST_FILESRC (GST_PAD_PARENT (pad));
src->curoffset = offset;
src->block_size = length;
return gst_filesrc_get (pad, buffer);
}
static GstFlowReturn
gst_filesrc_get (GstPad * pad, GstBuffer ** buffer)
{
GstFileSrc *src;
GstData *data;
src = GST_FILESRC (GST_PAD_PARENT (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN),
GST_FLOW_WRONG_STATE);
/* check for flush */
if (src->need_flush) {
src->need_flush = FALSE;
GST_DEBUG_OBJECT (src, "sending flush");
return GST_DATA (gst_event_new_flush ());
gst_pad_push_event (pad, gst_event_new_flush (TRUE));
}
/* check for seek */
if (src->need_discont) {
@ -710,7 +731,7 @@ gst_filesrc_get (GstPad * pad)
gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
(guint64) src->curoffset, GST_FORMAT_UNDEFINED);
src->need_discont = 0;
return GST_DATA (event);
gst_pad_push_event (pad, event);
}
/* check for EOF if it's a regular file */
@ -721,20 +742,33 @@ gst_filesrc_get (GstPad * pad)
GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
src->curoffset, src->filelen);
}
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
//gst_element_set_eos (GST_ELEMENT (src));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_WRONG_STATE;
}
}
#ifdef HAVE_MMAP
if (src->using_mmap) {
return gst_filesrc_get_mmap (src);
data = gst_filesrc_get_mmap (src);
} else {
return gst_filesrc_get_read (src);
data = gst_filesrc_get_read (src);
}
#else
return gst_filesrc_get_read (src);
data = gst_filesrc_get_read (src);
#endif
if (data == NULL) {
GST_DEBUG_OBJECT (src, "could not get data");
return GST_FLOW_ERROR;
}
if (GST_IS_EVENT (data)) {
gst_pad_push_event (pad, GST_EVENT (data));
} else {
*buffer = GST_BUFFER (data);
}
return GST_FLOW_OK;
}
/* TRUE if the filesize of the file was updated */
@ -821,6 +855,22 @@ gst_filesrc_open_file (GstFileSrc * src)
src->curoffset = 0;
GST_FLAG_SET (src, GST_FILESRC_OPEN);
{
GstCaps *caps;
guint64 offset;
guint length;
offset = src->curoffset;
length = src->block_size;
caps = gst_filesrc_type_find (src);
gst_pad_set_caps (src->srcpad, caps);
src->curoffset = offset;
src->block_size = length;
}
}
return TRUE;
}
@ -848,10 +898,77 @@ gst_filesrc_close_file (GstFileSrc * src)
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
}
static void
gst_filesrc_loop (GstPad * pad)
{
GstFileSrc *filesrc;
gboolean result;
GstBuffer *buffer;
filesrc = GST_FILESRC (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
result = gst_filesrc_get (pad, &buffer);
if (result != GST_FLOW_OK) {
gst_task_pause (GST_RPAD_TASK (pad));
goto done;
}
result = gst_pad_push (pad, buffer);
if (result != GST_FLOW_OK) {
gst_task_pause (GST_RPAD_TASK (pad));
}
done:
GST_STREAM_UNLOCK (pad);
}
static gboolean
gst_filesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstFileSrc *filesrc;
filesrc = GST_FILESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
if (GST_ELEMENT_SCHEDULER (filesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (filesrc),
(GstTaskFunction) gst_filesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
result = TRUE;
GST_STREAM_UNLOCK (pad);
}
break;
case GST_ACTIVATE_PULL:
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
gst_task_stop (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
return result;
}
static GstElementStateReturn
gst_filesrc_change_state (GstElement * element)
{
GstElementStateReturn result = GST_STATE_SUCCESS;
GstFileSrc *src = GST_FILESRC (element);
switch (GST_STATE_TRANSITION (element)) {
@ -866,6 +983,17 @@ gst_filesrc_change_state (GstElement * element)
}
src->need_discont = 2;
break;
case GST_STATE_PAUSED_TO_PLAYING:
gst_task_start (GST_RPAD_TASK (src->srcpad));
break;
}
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_PLAYING_TO_PAUSED:
gst_task_start (GST_RPAD_TASK (src->srcpad));
break;
case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
gst_filesrc_close_file (GST_FILESRC (element));
@ -874,10 +1002,7 @@ gst_filesrc_change_state (GstElement * element)
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
return result;
}
static gboolean
@ -1013,6 +1138,90 @@ error:
return FALSE;
}
typedef struct
{
GstFileSrc *src;
guint best_probability;
GstCaps *caps;
GstBuffer *buffer;
}
FileSrcTypeFind;
static guint8 *
filesrc_find_peek (gpointer data, gint64 offset, guint size)
{
FileSrcTypeFind *find;
GstBuffer *buffer;
GstFileSrc *src;
if (size == 0)
return NULL;
find = (FileSrcTypeFind *) data;
src = find->src;
if (offset < 0) {
offset += src->filelen;
}
buffer = NULL;
gst_filesrc_getrange (src->srcpad, offset, size, &buffer);
if (find->buffer) {
gst_buffer_unref (find->buffer);
}
find->buffer = buffer;
return GST_BUFFER_DATA (buffer);
}
static void
filesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
{
FileSrcTypeFind *find = (FileSrcTypeFind *) data;
if (probability > find->best_probability) {
gst_caps_replace (&find->caps, gst_caps_copy (caps));
find->best_probability = probability;
}
}
static GstCaps *
gst_filesrc_type_find (GstFileSrc * src)
{
GstTypeFind gst_find;
FileSrcTypeFind find;
GList *walk, *type_list = NULL;
GstCaps *result = NULL;
walk = type_list = gst_type_find_factory_get_list ();
find.src = src;
find.best_probability = 0;
find.caps = NULL;
find.buffer = NULL;
gst_find.data = &find;
gst_find.peek = filesrc_find_peek;
gst_find.suggest = filesrc_find_suggest;
gst_find.get_length = NULL;
while (walk) {
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
gst_type_find_factory_call_function (factory, &gst_find);
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
break;
walk = g_list_next (walk);
}
if (find.best_probability > 0)
result = find.caps;
return result;
}
/*** GSTURIHANDLER INTERFACE *************************************************/
static guint

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstidentity.c:
*
@ -71,21 +72,28 @@ enum
enum
{
ARG_0,
ARG_LOOP_BASED,
ARG_SLEEP_TIME,
ARG_DUPLICATE,
ARG_ERROR_AFTER,
ARG_DROP_PROBABILITY,
ARG_DATARATE,
ARG_SILENT,
ARG_LAST_MESSAGE,
ARG_DUMP,
ARG_SYNC,
ARG_CHECK_PERFECT
PROP_0,
PROP_HAS_GETRANGE,
PROP_HAS_CHAIN,
PROP_HAS_SINK_LOOP,
PROP_HAS_SRC_LOOP,
PROP_LOOP_BASED,
PROP_SLEEP_TIME,
PROP_DUPLICATE,
PROP_ERROR_AFTER,
PROP_DROP_PROBABILITY,
PROP_DATARATE,
PROP_SILENT,
PROP_LAST_MESSAGE,
PROP_DUMP,
PROP_SYNC,
PROP_CHECK_PERFECT
};
typedef GstFlowReturn (*IdentityPushFunc) (GstIdentity *, GstBuffer *);
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
@ -99,8 +107,16 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstElementStateReturn gst_identity_change_state (GstElement * element);
static void gst_identity_chain (GstPad * pad, GstData * _data);
static gboolean gst_identity_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_identity_getrange (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buffer);
static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer);
static void gst_identity_src_loop (GstPad * pad);
static void gst_identity_sink_loop (GstPad * pad);
static GstFlowReturn gst_identity_handle_buffer (GstIdentity * identity,
GstBuffer * buf);
static void gst_identity_set_clock (GstElement * element, GstClock * clock);
static GstCaps *gst_identity_proxy_getcaps (GstPad * pad);
static guint gst_identity_signals[LAST_SIGNAL] = { 0 };
@ -124,6 +140,9 @@ gst_identity_finalize (GObject * object)
identity = GST_IDENTITY (object);
g_mutex_free (identity->pen_lock);
g_cond_free (identity->pen_cond);
g_free (identity->last_message);
G_OBJECT_CLASS (parent_class)->finalize (object);
@ -141,42 +160,54 @@ gst_identity_class_init (GstIdentityClass * klass)
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
g_param_spec_boolean ("loop-based", "Loop-based",
"Set to TRUE to use loop-based rather than chain-based scheduling",
DEFAULT_LOOP_BASED, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLEEP_TIME,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
g_param_spec_boolean ("has-getrange", "Has getrange",
"If the src pad will implement a getrange function",
TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
g_param_spec_boolean ("has-chain", "Has chain",
"If the sink pad will implement a chain function",
TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SRC_LOOP,
g_param_spec_boolean ("has-src-loop", "Has src loop",
"If the src pad will implement a loop function",
FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
g_param_spec_boolean ("has-sink-loop", "Has sink loop",
"If the sink pad will implement a loop function",
FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLEEP_TIME,
g_param_spec_uint ("sleep-time", "Sleep time",
"Microseconds to sleep between processing", 0, G_MAXUINT,
DEFAULT_SLEEP_TIME, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUPLICATE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE,
g_param_spec_uint ("duplicate", "Duplicate Buffers",
"Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ERROR_AFTER,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER,
g_param_spec_int ("error_after", "Error After", "Error after N buffers",
G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DROP_PROBABILITY,
g_param_spec_float ("drop_probability", "Drop Probability",
"The Probability a buffer is dropped", 0.0, 1.0,
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_DROP_PROBABILITY, g_param_spec_float ("drop_probability",
"Drop Probability", "The Probability a buffer is dropped", 0.0, 1.0,
DEFAULT_DROP_PROBABILITY, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATARATE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DATARATE,
g_param_spec_int ("datarate", "Datarate",
"(Re)timestamps buffers with number of bytes per second (0 = inactive)",
0, G_MAXINT, DEFAULT_DATARATE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
g_param_spec_boolean ("silent", "silent", "silent", DEFAULT_SILENT,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
g_param_spec_string ("last-message", "last-message", "last-message", NULL,
G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump buffer contents",
DEFAULT_DUMP, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SYNC,
g_param_spec_boolean ("sync", "Synchronize",
"Synchronize to pipeline clock", DEFAULT_SYNC, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CHECK_PERFECT,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CHECK_PERFECT,
g_param_spec_boolean ("check-perfect", "Check For Perfect Stream",
"Verify that the stream is time- and data-contiguous",
DEFAULT_CHECK_PERFECT, G_PARAM_READWRITE));
@ -202,19 +233,20 @@ gst_identity_init (GstIdentity * identity)
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
gst_pad_set_chain_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_chain));
//gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
gst_pad_set_getcaps_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
gst_pad_set_event_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_event));
identity->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_pad_set_getcaps_function (identity->srcpad,
GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
gst_pad_set_getrange_function (identity->srcpad,
GST_DEBUG_FUNCPTR (gst_identity_getrange));
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
//gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
identity->loop_based = DEFAULT_LOOP_BASED;
identity->sleep_time = DEFAULT_SLEEP_TIME;
identity->duplicate = DEFAULT_DUPLICATE;
identity->error_after = DEFAULT_ERROR_AFTER;
@ -227,7 +259,10 @@ gst_identity_init (GstIdentity * identity)
identity->last_message = NULL;
identity->srccaps = NULL;
GST_FLAG_SET (identity, GST_ELEMENT_EVENT_AWARE);
identity->pen_data = NULL;
identity->pen_lock = g_mutex_new ();
identity->pen_cond = g_cond_new ();
identity->pen_flushing = FALSE;
}
static void
@ -238,36 +273,230 @@ gst_identity_set_clock (GstElement * element, GstClock * clock)
gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
}
static GstCaps *
gst_identity_proxy_getcaps (GstPad * pad)
{
GstPad *otherpad;
GstIdentity *identity = GST_IDENTITY (GST_OBJECT_PARENT (pad));
otherpad = pad == identity->srcpad ? identity->sinkpad : identity->srcpad;
return gst_pad_peer_get_caps (otherpad);
}
static gboolean
identity_queue_push (GstIdentity * identity, GstData * data)
{
gboolean ret;
g_mutex_lock (identity->pen_lock);
while (identity->pen_data && !identity->pen_flushing)
g_cond_wait (identity->pen_cond, identity->pen_lock);
if (identity->pen_flushing) {
gst_data_unref (identity->pen_data);
identity->pen_data = NULL;
gst_data_unref (data);
ret = FALSE;
} else {
identity->pen_data = data;
ret = TRUE;
}
g_cond_signal (identity->pen_cond);
g_mutex_unlock (identity->pen_lock);
return ret;
}
static GstData *
identity_queue_pop (GstIdentity * identity)
{
GstData *ret;
g_mutex_lock (identity->pen_lock);
while (!(ret = identity->pen_data) && !identity->pen_flushing)
g_cond_wait (identity->pen_cond, identity->pen_lock);
g_cond_signal (identity->pen_cond);
g_mutex_unlock (identity->pen_lock);
return ret;
}
static void
gst_identity_chain (GstPad * pad, GstData * _data)
identity_queue_flush (GstIdentity * identity)
{
g_mutex_lock (identity->pen_lock);
identity->pen_flushing = TRUE;
g_cond_signal (identity->pen_cond);
g_mutex_unlock (identity->pen_lock);
}
static gboolean
gst_identity_event (GstPad * pad, GstEvent * event)
{
GstBuffer *buf = GST_BUFFER (_data);
GstIdentity *identity;
guint i;
gboolean ret;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
identity = GST_IDENTITY (gst_pad_get_parent (pad));
GST_STREAM_LOCK (pad);
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
if (!identity->silent) {
g_free (identity->last_message);
if (!identity->silent) {
g_free (identity->last_message);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
g_object_notify (G_OBJECT (identity), "last_message");
}
gst_pad_event_default (pad, event);
return;
g_object_notify (G_OBJECT (identity), "last_message");
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH:
/* forward event */
gst_pad_event_default (pad, event);
if (GST_EVENT_FLUSH_DONE (event)) {
if (identity->sink_mode == GST_ACTIVATE_PULL) {
/* already have the sink stream lock */
gst_task_start (GST_RPAD_TASK (identity->sinkpad));
}
if (identity->src_mode == GST_ACTIVATE_PUSH) {
GST_STREAM_LOCK (identity->srcpad);
gst_task_start (GST_RPAD_TASK (identity->srcpad));
GST_STREAM_UNLOCK (identity->srcpad);
}
} else {
/* unblock both functions */
identity_queue_flush (identity);
}
ret = TRUE;
goto done;
case GST_EVENT_EOS:
if (identity->sink_mode == GST_ACTIVATE_PULL) {
/* already have the sink stream lock */
gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
}
break;
default:
break;
}
if (identity->decoupled) {
ret = identity_queue_push (identity, (GstData *) event);
} else {
ret = gst_pad_push_event (identity->srcpad, event);
}
done:
GST_STREAM_UNLOCK (pad);
return ret;
}
static GstFlowReturn
gst_identity_getrange (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buffer)
{
GstIdentity *identity;
GstFlowReturn ret;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
ret = gst_pad_pull_range (identity->sinkpad, offset, length, buffer);
GST_STREAM_UNLOCK (pad);
return ret;
}
static GstFlowReturn
gst_identity_chain (GstPad * pad, GstBuffer * buffer)
{
GstIdentity *identity;
GstFlowReturn ret = GST_FLOW_OK;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
ret = gst_identity_handle_buffer (identity, buffer);
GST_STREAM_UNLOCK (pad);
return ret;
}
#define DEFAULT_PULL_SIZE 1024
static void
gst_identity_sink_loop (GstPad * pad)
{
GstIdentity *identity;
GstBuffer *buffer;
GstFlowReturn ret;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
ret = gst_pad_pull_range (pad, identity->offset, DEFAULT_PULL_SIZE, &buffer);
if (ret != GST_FLOW_OK)
goto sink_loop_pause;
ret = gst_identity_handle_buffer (identity, buffer);
if (ret != GST_FLOW_OK)
goto sink_loop_pause;
GST_STREAM_UNLOCK (pad);
return;
sink_loop_pause:
gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
GST_STREAM_UNLOCK (pad);
return;
}
static void
gst_identity_src_loop (GstPad * pad)
{
GstIdentity *identity;
GstData *data;
GstFlowReturn ret;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
data = identity_queue_pop (identity);
if (!data) /* we're getting flushed */
goto src_loop_pause;
if (GST_IS_EVENT (data)) {
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS)
gst_task_pause (GST_RPAD_TASK (identity->srcpad));
gst_pad_push_event (identity->srcpad, GST_EVENT (data));
} else {
ret = gst_pad_push (identity->srcpad, (GstBuffer *) data);
if (ret != GST_FLOW_OK)
goto src_loop_pause;
}
GST_STREAM_UNLOCK (pad);
return;
src_loop_pause:
gst_task_pause (GST_RPAD_TASK (identity->srcpad));
GST_STREAM_UNLOCK (pad);
return;
}
static GstFlowReturn
gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
{
GstFlowReturn ret = GST_FLOW_OK;
guint i;
/* see if we need to do perfect stream checking */
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
if (identity->check_perfect &&
@ -303,7 +532,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
gst_buffer_unref (buf);
GST_ELEMENT_ERROR (identity, CORE, FAILED,
(_("Failed after iterations as requested.")), (NULL));
return;
return GST_FLOW_ERROR;
}
}
@ -320,9 +549,10 @@ gst_identity_chain (GstPad * pad, GstData * _data)
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
g_object_notify (G_OBJECT (identity), "last-message");
gst_buffer_unref (buf);
return;
return GST_FLOW_OK;
}
}
if (identity->dump) {
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
@ -346,7 +576,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
time = GST_BUFFER_TIMESTAMP (buf);
if (identity->datarate > 0) {
time = identity->bytes_handled * GST_SECOND / identity->datarate;
time = identity->offset * GST_SECOND / identity->datarate;
GST_BUFFER_TIMESTAMP (buf) = time;
GST_BUFFER_DURATION (buf) =
@ -361,41 +591,49 @@ gst_identity_chain (GstPad * pad, GstData * _data)
if (identity->sync) {
if (identity->clock) {
gst_element_wait (GST_ELEMENT (identity), time);
/* gst_element_wait (GST_ELEMENT (identity), time); */
}
}
identity->bytes_handled += GST_BUFFER_SIZE (buf);
gst_pad_push (identity->srcpad, GST_DATA (buf));
identity->offset += GST_BUFFER_SIZE (buf);
if (identity->decoupled) {
if (!identity_queue_push (identity, (GstData *) buf))
return GST_FLOW_UNEXPECTED;
} else {
ret = gst_pad_push (identity->srcpad, buf);
if (ret != GST_FLOW_OK)
return ret;
}
if (identity->sleep_time)
g_usleep (identity->sleep_time);
}
return ret;
}
static void
gst_identity_loop (GstElement * element)
gst_identity_set_dataflow_funcs (GstIdentity * identity)
{
GstIdentity *identity;
GstBuffer *buf;
if (identity->has_getrange)
gst_pad_set_getrange_function (identity->srcpad, gst_identity_getrange);
else
gst_pad_set_getrange_function (identity->srcpad, NULL);
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_IDENTITY (element));
if (identity->has_chain)
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
else
gst_pad_set_chain_function (identity->sinkpad, NULL);
identity = GST_IDENTITY (element);
if (identity->has_src_loop)
gst_pad_set_loop_function (identity->srcpad, gst_identity_src_loop);
else
gst_pad_set_loop_function (identity->srcpad, NULL);
buf = GST_BUFFER (gst_pad_pull (identity->sinkpad));
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
if (GST_EVENT_IS_INTERRUPT (event)) {
gst_event_unref (event);
} else {
gst_pad_event_default (identity->sinkpad, event);
}
} else {
gst_identity_chain (identity->sinkpad, GST_DATA (buf));
}
if (identity->has_sink_loop)
gst_pad_set_loop_function (identity->sinkpad, gst_identity_sink_loop);
else
gst_pad_set_loop_function (identity->sinkpad, NULL);
}
static void
@ -404,48 +642,50 @@ gst_identity_set_property (GObject * object, guint prop_id,
{
GstIdentity *identity;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_IDENTITY (object));
identity = GST_IDENTITY (object);
switch (prop_id) {
case ARG_LOOP_BASED:
identity->loop_based = g_value_get_boolean (value);
if (identity->loop_based) {
gst_element_set_loop_function (GST_ELEMENT (identity),
gst_identity_loop);
gst_pad_set_chain_function (identity->sinkpad, NULL);
} else {
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
gst_element_set_loop_function (GST_ELEMENT (identity), NULL);
}
case PROP_HAS_GETRANGE:
identity->has_getrange = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case ARG_SLEEP_TIME:
case PROP_HAS_CHAIN:
identity->has_chain = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case PROP_HAS_SRC_LOOP:
identity->has_src_loop = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case PROP_HAS_SINK_LOOP:
identity->has_sink_loop = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case PROP_SLEEP_TIME:
identity->sleep_time = g_value_get_uint (value);
break;
case ARG_SILENT:
case PROP_SILENT:
identity->silent = g_value_get_boolean (value);
break;
case ARG_DUPLICATE:
case PROP_DUPLICATE:
identity->duplicate = g_value_get_uint (value);
break;
case ARG_DUMP:
case PROP_DUMP:
identity->dump = g_value_get_boolean (value);
break;
case ARG_ERROR_AFTER:
case PROP_ERROR_AFTER:
identity->error_after = g_value_get_int (value);
break;
case ARG_DROP_PROBABILITY:
case PROP_DROP_PROBABILITY:
identity->drop_probability = g_value_get_float (value);
break;
case ARG_DATARATE:
case PROP_DATARATE:
identity->datarate = g_value_get_int (value);
break;
case ARG_SYNC:
case PROP_SYNC:
identity->sync = g_value_get_boolean (value);
break;
case ARG_CHECK_PERFECT:
case PROP_CHECK_PERFECT:
identity->check_perfect = g_value_get_boolean (value);
break;
default:
@ -460,43 +700,49 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
{
GstIdentity *identity;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_IDENTITY (object));
identity = GST_IDENTITY (object);
switch (prop_id) {
case ARG_LOOP_BASED:
g_value_set_boolean (value, identity->loop_based);
case PROP_HAS_GETRANGE:
g_value_set_boolean (value, identity->has_getrange);
break;
case ARG_SLEEP_TIME:
case PROP_HAS_CHAIN:
g_value_set_boolean (value, identity->has_chain);
break;
case PROP_HAS_SRC_LOOP:
g_value_set_boolean (value, identity->has_src_loop);
break;
case PROP_HAS_SINK_LOOP:
g_value_set_boolean (value, identity->has_sink_loop);
break;
case PROP_SLEEP_TIME:
g_value_set_uint (value, identity->sleep_time);
break;
case ARG_DUPLICATE:
case PROP_DUPLICATE:
g_value_set_uint (value, identity->duplicate);
break;
case ARG_ERROR_AFTER:
case PROP_ERROR_AFTER:
g_value_set_int (value, identity->error_after);
break;
case ARG_DROP_PROBABILITY:
case PROP_DROP_PROBABILITY:
g_value_set_float (value, identity->drop_probability);
break;
case ARG_DATARATE:
case PROP_DATARATE:
g_value_set_int (value, identity->datarate);
break;
case ARG_SILENT:
case PROP_SILENT:
g_value_set_boolean (value, identity->silent);
break;
case ARG_DUMP:
case PROP_DUMP:
g_value_set_boolean (value, identity->dump);
break;
case ARG_LAST_MESSAGE:
case PROP_LAST_MESSAGE:
g_value_set_string (value, identity->last_message);
break;
case ARG_SYNC:
case PROP_SYNC:
g_value_set_boolean (value, identity->sync);
break;
case ARG_CHECK_PERFECT:
case PROP_CHECK_PERFECT:
g_value_set_boolean (value, identity->check_perfect);
break;
default:
@ -518,7 +764,7 @@ gst_identity_change_state (GstElement * element)
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
identity->bytes_handled = 0;
identity->offset = 0;
identity->prev_timestamp = GST_CLOCK_TIME_NONE;
identity->prev_duration = GST_CLOCK_TIME_NONE;
identity->prev_offset_end = -1;

View file

@ -50,7 +50,19 @@ struct _GstIdentity {
GstPad *sinkpad;
GstPad *srcpad;
gboolean loop_based;
GstData *pen_data;
GMutex *pen_lock;
GCond *pen_cond;
gboolean pen_flushing;
gboolean has_chain;
gboolean has_getrange;
gboolean has_src_loop;
gboolean has_sink_loop;
GstActivateMode sink_mode;
GstActivateMode src_mode;
gboolean decoupled;
guint duplicate;
gint error_after;
gfloat drop_probability;
@ -67,7 +79,7 @@ struct _GstIdentity {
gchar *last_message;
GstCaps *srccaps;
guint64 bytes_handled;
guint64 offset;
};
struct _GstIdentityClass {

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
* 2000,2001,2002,2003,2004,2005 Wim Taymans <wim@fluendo.com>
*
*
* gsttee.c: Tee element, one in N out
*
@ -40,21 +41,16 @@ GstElementDetails gst_tee_details = GST_ELEMENT_DETAILS ("Tee pipe fitting",
"Generic",
"1-to-N pipe fitting",
"Erik Walthinsen <omega@cse.ogi.edu>, "
"Wim Taymans <wim.taymans@chello.be>");
/* Tee signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
"Wim \"Tim\" Taymans <wim@fluendo.com>");
enum
{
ARG_0,
ARG_SILENT,
ARG_NUM_PADS,
ARG_LAST_MESSAGE
PROP_0,
PROP_NUM_SRC_PADS,
PROP_HAS_SINK_LOOP,
PROP_HAS_CHAIN,
PROP_SILENT,
PROP_LAST_MESSAGE
/* FILL ME */
};
@ -77,7 +73,9 @@ static void gst_tee_set_property (GObject * object, guint prop_id,
static void gst_tee_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_tee_chain (GstPad * pad, GstData * _data);
static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer);
static void gst_tee_loop (GstPad * pad);
static gboolean gst_tee_sink_activate (GstPad * pad, GstActivateMode mode);
static void
@ -113,22 +111,26 @@ gst_tee_class_init (GstTeeClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tee_finalize);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_tee_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_tee_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
g_param_spec_int ("num_pads", "num_pads", "num_pads",
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_SRC_PADS,
g_param_spec_int ("num-src-pads", "num-src-pads", "num-src-pads",
0, G_MAXINT, 0, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
g_param_spec_boolean ("has-sink-loop", "has-sink-loop", "has-sink-loop",
FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
g_param_spec_boolean ("has-chain", "has-chain", "has-chain",
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
g_param_spec_boolean ("silent", "silent", "silent",
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
g_param_spec_string ("last_message", "last_message", "last_message",
NULL, G_PARAM_READABLE));
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tee_finalize);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_tee_request_new_pad);
}
@ -140,72 +142,30 @@ gst_tee_init (GstTee * tee)
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
//gst_pad_set_link_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
gst_pad_set_setcaps_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
gst_pad_set_getcaps_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
tee->last_message = NULL;
}
/* helper compare function */
gint
name_pad_compare (gconstpointer a, gconstpointer b)
static void
gst_tee_update_pad_functions (GstTee * tee)
{
GstPad *pad = (GstPad *) a;
gchar *name = (gchar *) b;
gst_pad_set_activate_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_tee_sink_activate));
g_assert (GST_IS_PAD (pad));
if (tee->has_chain)
gst_pad_set_chain_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_tee_chain));
else
gst_pad_set_chain_function (tee->sinkpad, NULL);
return strcmp (name, gst_pad_get_name (pad)); /* returns 0 if match */
}
static GstCaps *
gst_tee_getcaps (GstPad * _pad)
{
GstTee *tee = GST_TEE (gst_pad_get_parent (_pad));
GstCaps *caps = gst_caps_new_any (), *tmp, *res;
GstPad *pad;
const GList *pads;
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
tmp = gst_pad_get_allowed_caps (pad);
res = gst_caps_intersect (caps, tmp);
gst_caps_unref (tmp);
gst_caps_unref (caps);
caps = res;
}
return caps;
}
static GstPadLinkReturn
gst_tee_link (GstPad * _pad, const GstCaps * caps)
{
GstTee *tee = GST_TEE (gst_pad_get_parent (_pad));
GstPadLinkReturn res;
GstPad *pad;
const GList *pads;
GST_DEBUG_OBJECT (tee, "Forwarding link to all other pads");
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
res = gst_pad_try_set_caps (pad, caps);
GST_DEBUG_OBJECT (tee, "Pad %s:%s gave response %d",
GST_DEBUG_PAD_NAME (pad), res);
if (GST_PAD_LINK_FAILED (res))
return res;
}
return GST_PAD_LINK_OK;
if (tee->has_sink_loop)
gst_pad_set_loop_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_loop));
else
gst_pad_set_loop_function (tee->sinkpad, NULL);
}
static GstPad *
@ -215,48 +175,21 @@ gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
gchar *name;
GstPad *srcpad;
GstTee *tee;
gint i = 0;
const GList *pads;
g_return_val_if_fail (GST_IS_TEE (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gsttee: request new pad that is not a SRC pad\n");
return NULL;
}
tee = GST_TEE (element);
/* try names in order and find one that's not in use atm */
pads = element->pads;
name = NULL;
while (!name) {
name = g_strdup_printf ("src%d", i);
if (g_list_find_custom ((GList *) pads, (gconstpointer) name,
name_pad_compare) != NULL) {
/* this name is taken, use the next one */
++i;
g_free (name);
name = NULL;
}
}
if (!tee->silent) {
g_free (tee->last_message);
tee->last_message = g_strdup_printf ("new pad %s", name);
g_object_notify (G_OBJECT (tee), "last_message");
}
GST_LOCK (tee);
name = g_strdup_printf ("src%d", tee->pad_counter++);
GST_UNLOCK (tee);
srcpad = gst_pad_new_from_template (templ, name);
g_free (name);
gst_pad_set_link_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_link));
gst_pad_set_getcaps_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_getcaps));
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
if (GST_PAD_CAPS (tee->sinkpad)) {
gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
}
gst_pad_set_setcaps_function (srcpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
gst_pad_set_getcaps_function (srcpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
return srcpad;
}
@ -265,95 +198,202 @@ static void
gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstTee *tee;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_TEE (object));
tee = GST_TEE (object);
GstTee *tee = GST_TEE (object);
GST_LOCK (tee);
switch (prop_id) {
case ARG_SILENT:
case PROP_HAS_SINK_LOOP:
tee->has_sink_loop = g_value_get_boolean (value);
gst_tee_update_pad_functions (tee);
break;
case PROP_HAS_CHAIN:
tee->has_chain = g_value_get_boolean (value);
gst_tee_update_pad_functions (tee);
break;
case PROP_SILENT:
tee->silent = g_value_get_boolean (value);
g_object_notify (G_OBJECT (tee), "silent");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_UNLOCK (tee);
}
static void
gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstTee *tee;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_TEE (object));
tee = GST_TEE (object);
GstTee *tee = GST_TEE (object);
GST_LOCK (tee);
switch (prop_id) {
case ARG_NUM_PADS:
case PROP_NUM_SRC_PADS:
g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
break;
case ARG_SILENT:
case PROP_HAS_SINK_LOOP:
g_value_set_boolean (value, tee->has_sink_loop);
break;
case PROP_HAS_CHAIN:
g_value_set_boolean (value, tee->has_chain);
break;
case PROP_SILENT:
g_value_set_boolean (value, tee->silent);
break;
case ARG_LAST_MESSAGE:
case PROP_LAST_MESSAGE:
g_value_set_string (value, tee->last_message);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_UNLOCK (tee);
}
/**
* gst_tee_chain:
* @pad: the pad to follow
* @buf: the buffer to pass
*
* Chain a buffer on a pad.
*/
static void
gst_tee_chain (GstPad * pad, GstData * _data)
typedef struct
{
GstBuffer *buf = GST_BUFFER (_data);
GstTee *tee;
const GList *pads;
GstBuffer *buffer;
} PushData;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
static gboolean
gst_tee_do_push (GstPad * pad, GValue * ret, PushData * data)
{
GstFlowReturn res;
if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC || !GST_PAD_IS_USABLE (pad))
return TRUE;
if (G_UNLIKELY (!data->tee->silent)) {
GstTee *tee = data->tee;
GstBuffer *buf = data->buffer;
g_free (tee->last_message);
tee->last_message =
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (pad),
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (tee), "last_message");
}
res = gst_pad_push (pad, gst_buffer_ref (data->buffer));
g_value_set_enum (ret, res);
return (res == GST_FLOW_OK);
}
static GstFlowReturn
gst_tee_handle_buffer (GstTee * tee, GstBuffer * buffer)
{
GstIterator *iter;
PushData data;
GValue ret = { 0, };
GstIteratorResult res;
tee->offset += GST_BUFFER_SIZE (buffer);
g_value_init (&ret, GST_TYPE_FLOW_RETURN);
iter = gst_element_iterate_pads (GST_ELEMENT (tee));
data.tee = tee;
data.buffer = buffer;
res = gst_iterator_fold (iter, (GstIteratorFoldFunction) gst_tee_do_push,
&ret, &data);
gst_iterator_free (iter);
gst_buffer_unref (buffer);
/* no need to unset gvalue */
return g_value_get_enum (&ret);
}
#define WITH_STREAM_LOCK(pad, expr) G_STMT_START {\
GST_STREAM_LOCK (pad); \
expr; \
GST_STREAM_UNLOCK (pad); \
}G_STMT_END
static GstFlowReturn
gst_tee_chain (GstPad * pad, GstBuffer * buffer)
{
GstFlowReturn res;
GstTee *tee;
tee = GST_TEE (gst_pad_get_parent (pad));
gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
WITH_STREAM_LOCK (pad, res = gst_tee_handle_buffer (tee, buffer));
pads = GST_ELEMENT (tee)->pads;
while (pads) {
GstPad *outpad = GST_PAD (pads->data);
pads = g_list_next (pads);
if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC)
continue;
if (!tee->silent) {
g_free (tee->last_message);
tee->last_message =
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (outpad),
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (tee), "last_message");
}
if (GST_PAD_IS_USABLE (outpad))
gst_pad_push (outpad, GST_DATA (buf));
else
gst_buffer_unref (buf);
}
return res;
}
#define DEFAULT_SIZE 1024
static void
gst_tee_loop (GstPad * pad)
{
GstBuffer *buffer;
GstFlowReturn res;
GstTee *tee;
GST_STREAM_LOCK (pad);
tee = GST_TEE (gst_pad_get_parent (pad));
res = gst_pad_pull_range (pad, tee->offset, DEFAULT_SIZE, &buffer);
if (res != GST_FLOW_OK)
goto pause_task;
res = gst_tee_handle_buffer (tee, buffer);
if (res != GST_FLOW_OK)
goto pause_task;
GST_STREAM_UNLOCK (pad);
return;
pause_task:
gst_pad_pause_task (pad);
GST_STREAM_UNLOCK (pad);
return;
}
static gboolean
gst_tee_sink_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstTee *tee;
tee = GST_TEE (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
g_return_val_if_fail (tee->has_chain, FALSE);
result = TRUE;
break;
case GST_ACTIVATE_PULL:
g_return_val_if_fail (tee->has_sink_loop, FALSE);
if (GST_ELEMENT_SCHEDULER (tee)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (tee),
(GstTaskFunction) gst_tee_loop, pad);
gst_pad_start_task (pad);
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_NONE:
GST_STREAM_LOCK (pad);
if (GST_RPAD_TASK (pad)) {
gst_pad_stop_task (pad);
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
tee->sink_mode = mode;
return result;
}

View file

@ -49,6 +49,12 @@ struct _GstTee {
GstPad *sinkpad;
gboolean silent;
gboolean has_chain;
gboolean has_sink_loop;
gint pad_counter;
guint64 offset;
GstActivateMode sink_mode;
gchar *last_message;
};

View file

@ -535,9 +535,8 @@ gst_register_core_elements (GstPlugin * plugin)
GST_TYPE_BIN) ||
!gst_element_register (plugin, "pipeline", GST_RANK_PRIMARY,
GST_TYPE_PIPELINE) ||
!gst_element_register (plugin, "thread", GST_RANK_PRIMARY,
GST_TYPE_THREAD) ||
!gst_element_register (plugin, "queue", GST_RANK_NONE, GST_TYPE_QUEUE))
!gst_element_register (plugin, "queue", GST_RANK_NONE, GST_TYPE_QUEUE)
)
g_assert_not_reached ();
return TRUE;
@ -617,6 +616,7 @@ init_post (void)
_gst_plugin_initialize ();
_gst_event_initialize ();
_gst_buffer_initialize ();
_gst_message_initialize ();
_gst_tag_initialize ();
#ifndef GST_DISABLE_REGISTRY

View file

@ -44,6 +44,7 @@
#include <gst/gstinterface.h>
#include <gst/gstiterator.h>
#include <gst/gstmarshal.h>
#include <gst/gstmessage.h>
#include <gst/gstobject.h>
#include <gst/gstpad.h>
#include <gst/gstpipeline.h>
@ -53,7 +54,7 @@
#include <gst/gstsystemclock.h>
#include <gst/gsttag.h>
#include <gst/gsttaginterface.h>
#include <gst/gstthread.h>
#include <gst/gsttask.h>
#include <gst/gsttrace.h>
#include <gst/gsttypefind.h>
#include <gst/gsturi.h>

View file

@ -52,13 +52,11 @@ static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
GType _gst_bin_type = 0;
static gboolean _gst_boolean_did_something_accumulator (GSignalInvocationHint *
ihint, GValue * return_accu, const GValue * handler_return, gpointer dummy);
static void gst_bin_dispose (GObject * object);
static GstElementStateReturn gst_bin_change_state (GstElement * element);
static GstElementStateReturn gst_bin_change_state_norecurse (GstBin * bin);
static GstElementStateReturn gst_bin_get_state (GstElement * element,
GstElementState * state, GstElementState * pending, GTimeVal * timeout);
static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
@ -69,12 +67,9 @@ static void gst_bin_set_index_func (GstElement * element, GstIndex * index);
static GstClock *gst_bin_get_clock_func (GstElement * element);
static void gst_bin_set_clock_func (GstElement * element, GstClock * clock);
static void gst_bin_child_state_change_func (GstBin * bin,
GstElementState oldstate, GstElementState newstate, GstElement * child);
GstElementStateReturn gst_bin_set_state (GstElement * element,
GstElementState state);
static void gst_bin_set_bus (GstElement * element, GstBus * bus);
static void gst_bin_set_scheduler (GstElement * element, GstScheduler * sched);
static gboolean gst_bin_iterate_func (GstBin * bin);
#ifndef GST_DISABLE_LOADSAVE
static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
@ -86,7 +81,6 @@ enum
{
ELEMENT_ADDED,
ELEMENT_REMOVED,
ITERATE,
LAST_SIGNAL
};
@ -163,11 +157,6 @@ gst_bin_class_init (GstBinClass * klass)
g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
gst_bin_signals[ITERATE] =
g_signal_new ("iterate", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstBinClass, iterate),
_gst_boolean_did_something_accumulator, NULL, gst_marshal_BOOLEAN__VOID,
G_TYPE_BOOLEAN, 0);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
@ -178,34 +167,17 @@ gst_bin_class_init (GstBinClass * klass)
#endif
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
gstelement_class->set_state = GST_DEBUG_FUNCPTR (gst_bin_set_state);
gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state);
#ifndef GST_DISABLE_INDEX
gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func);
#endif
gstelement_class->get_clock = GST_DEBUG_FUNCPTR (gst_bin_get_clock_func);
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_bin_set_clock_func);
gstelement_class->set_bus = GST_DEBUG_FUNCPTR (gst_bin_set_bus);
gstelement_class->set_scheduler = GST_DEBUG_FUNCPTR (gst_bin_set_scheduler);
klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
klass->child_state_change =
GST_DEBUG_FUNCPTR (gst_bin_child_state_change_func);
klass->iterate = GST_DEBUG_FUNCPTR (gst_bin_iterate_func);
}
static gboolean
_gst_boolean_did_something_accumulator (GSignalInvocationHint * ihint,
GValue * return_accu, const GValue * handler_return, gpointer dummy)
{
gboolean did_something;
did_something = g_value_get_boolean (handler_return);
if (did_something) {
g_value_set_boolean (return_accu, TRUE);
}
/* always continue emission */
return TRUE;
}
static void
@ -300,130 +272,50 @@ gst_bin_get_clock_func (GstElement * element)
return result;
}
/* will be removed */
/* set the bus on all of the children in this bin
*
* MT safe
*/
static void
gst_bin_set_element_sched (GstElement * element, GstScheduler * sched)
gst_bin_set_bus (GstElement * element, GstBus * bus)
{
GST_CAT_LOG (GST_CAT_SCHEDULING, "setting element \"%s\" sched to %p",
GST_ELEMENT_NAME (element), sched);
GList *children;
GstBin *bin;
/* if it's actually a Bin */
if (GST_IS_BIN (element)) {
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
"child is already a manager, not resetting sched");
if (GST_ELEMENT_SCHEDULER (element))
gst_scheduler_add_scheduler (sched, GST_ELEMENT_SCHEDULER (element));
return;
}
bin = GST_BIN (element);
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
"setting child bin's scheduler to be the same as the parent's");
gst_scheduler_add_element (sched, element);
parent_class->set_bus (element, bus);
/* set the children's schedule */
g_list_foreach (GST_BIN (element)->children,
(GFunc) gst_bin_set_element_sched, sched);
} else {
/* otherwise, if it's just a regular old element */
GList *pads;
GST_LOCK (bin);
for (children = bin->children; children; children = g_list_next (children)) {
GstElement *child = GST_ELEMENT (children->data);
gst_scheduler_add_element (sched, element);
if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
/* set the sched pointer in all the pads */
pads = element->pads;
while (pads) {
GstPad *pad;
pad = GST_PAD (pads->data);
pads = g_list_next (pads);
/* we only operate on real pads */
if (!GST_IS_REAL_PAD (pad))
continue;
/* if the peer element exists and is a candidate */
if (GST_PAD_PEER (pad)) {
if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
GST_CAT_LOG (GST_CAT_SCHEDULING,
"peer is in same scheduler, telling scheduler");
if (GST_PAD_IS_SRC (pad))
gst_scheduler_pad_link (sched, pad, GST_PAD_PEER (pad));
else
gst_scheduler_pad_link (sched, GST_PAD_PEER (pad), pad);
}
}
}
}
gst_element_set_bus (child, bus);
}
GST_UNLOCK (bin);
}
/* will be removed */
/* set the scheduler on all of the children in this bin
*
* MT safe
*/
static void
gst_bin_unset_element_sched (GstElement * element, GstScheduler * sched)
gst_bin_set_scheduler (GstElement * element, GstScheduler * sched)
{
if (GST_ELEMENT_SCHEDULER (element) == NULL) {
GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element \"%s\" has no scheduler",
GST_ELEMENT_NAME (element));
return;
}
GST_CAT_DEBUG (GST_CAT_SCHEDULING,
"removing element \"%s\" from its sched %p", GST_ELEMENT_NAME (element),
GST_ELEMENT_SCHEDULER (element));
/* if it's actually a Bin */
if (GST_IS_BIN (element)) {
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, element,
"child is already a manager, not unsetting sched");
if (sched) {
gst_scheduler_remove_scheduler (sched, GST_ELEMENT_SCHEDULER (element));
}
return;
}
/* for each child, remove them from their schedule */
g_list_foreach (GST_BIN (element)->children,
(GFunc) gst_bin_unset_element_sched, sched);
gst_scheduler_remove_element (GST_ELEMENT_SCHEDULER (element), element);
} else {
/* otherwise, if it's just a regular old element */
GList *pads;
if (!GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
/* unset the sched pointer in all the pads */
pads = element->pads;
while (pads) {
GstPad *pad;
pad = GST_PAD (pads->data);
pads = g_list_next (pads);
/* we only operate on real pads */
if (!GST_IS_REAL_PAD (pad))
continue;
/* if the peer element exists and is a candidate */
if (GST_PAD_PEER (pad)) {
if (gst_pad_get_scheduler (GST_PAD_PEER (pad)) == sched) {
GST_CAT_LOG (GST_CAT_SCHEDULING,
"peer is in same scheduler, telling scheduler");
if (GST_PAD_IS_SRC (pad))
gst_scheduler_pad_unlink (sched, pad, GST_PAD_PEER (pad));
else
gst_scheduler_pad_unlink (sched, GST_PAD_PEER (pad), pad);
}
}
}
}
gst_scheduler_remove_element (GST_ELEMENT_SCHEDULER (element), element);
GList *children;
GstBin *bin;
bin = GST_BIN (element);
parent_class->set_scheduler (element, sched);
GST_LOCK (bin);
for (children = bin->children; children; children = g_list_next (children)) {
GstElement *child = GST_ELEMENT (children->data);
gst_element_set_scheduler (child, sched);
}
GST_UNLOCK (bin);
}
/* add an element to this bin
@ -462,6 +354,8 @@ gst_bin_add_func (GstBin * bin, GstElement * element)
bin->numchildren++;
bin->children_cookie++;
gst_element_set_manager (element, GST_ELEMENT (bin)->manager);
gst_element_set_bus (element, GST_ELEMENT (bin)->bus);
gst_element_set_scheduler (element, GST_ELEMENT_SCHEDULER (bin));
GST_UNLOCK (bin);
@ -571,6 +465,8 @@ gst_bin_remove_func (GstBin * bin, GstElement * element)
elem_name);
g_free (elem_name);
gst_element_set_manager (element, NULL);
gst_element_set_bus (element, NULL);
gst_element_set_scheduler (element, NULL);
/* we ref here because after the _unparent() the element can be disposed
@ -837,290 +733,38 @@ gst_bin_iterate_sinks (GstBin * bin)
return result;
}
/**
* gst_bin_child_state_change:
* @bin: #GstBin with the child
* @oldstate: The old child state
* @newstate: The new child state
* @child: #GstElement that signaled an changed state
/* this functions loops over all children, as soon as one does
* not return SUCCESS, we return that value.
*
* An internal function to inform the parent bin about a state change
* of a child.
*
* Marked for removal.
* MT safe
*/
void
gst_bin_child_state_change (GstBin * bin, GstElementState oldstate,
GstElementState newstate, GstElement * child)
static GstElementStateReturn
gst_bin_get_state (GstElement * element, GstElementState * state,
GstElementState * pending, GTimeVal * timeout)
{
GstBinClass *bclass;
g_return_if_fail (GST_IS_BIN (bin));
g_return_if_fail (GST_IS_ELEMENT (child));
GST_CAT_LOG (GST_CAT_STATES, "child %s changed state in bin %s from %s to %s",
GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin),
gst_element_state_get_name (oldstate),
gst_element_state_get_name (newstate));
bclass = GST_BIN_GET_CLASS (bin);
if (bclass->child_state_change) {
bclass->child_state_change (bin, oldstate, newstate, child);
} else {
g_warning ("cannot signal state change of child %s to bin %s\n",
GST_ELEMENT_NAME (child), GST_ELEMENT_NAME (bin));
}
/* implement me */
return GST_STATE_FAILURE;
}
/* will be removed */
static void
gst_bin_child_state_change_func (GstBin * bin, GstElementState oldstate,
GstElementState newstate, GstElement * child)
{
GstElementState old = 0, new = 0;
gint old_idx = 0, new_idx = 0, i;
old = oldstate;
new = newstate;
while ((old >>= 1) != 0)
old_idx++;
while ((new >>= 1) != 0)
new_idx++;
GST_LOCK (bin);
GST_LOG_BIN_CONTENTS (bin, "before child state change");
bin->child_states[old_idx]--;
bin->child_states[new_idx]++;
for (i = GST_NUM_STATES - 1; i >= 0; i--) {
if (bin->child_states[i] != 0) {
gint state = (1 << i);
/* We only change state on the parent if the state is not locked.
* State locking can occur if the bin itself set state on children,
* which should not recurse since it leads to infinite loops. */
if (GST_STATE (bin) != state &&
!GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED)) {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
"highest child state is %s, changing bin state accordingly",
gst_element_state_get_name (state));
GST_STATE_PENDING (bin) = state;
GST_UNLOCK (bin);
gst_bin_change_state_norecurse (bin);
if (state != GST_STATE (bin)) {
g_warning ("%s: state change in callback %d %d",
GST_ELEMENT_NAME (bin), state, GST_STATE (bin));
}
GST_LOG_BIN_CONTENTS (bin, "after child state change");
return;
}
break;
}
}
GST_LOG_BIN_CONTENTS (bin, "after child state change");
GST_UNLOCK (bin);
}
typedef gboolean (*GstBinForeachFunc) (GstBin * bin, GstElement * element,
gpointer data);
/*
* gst_bin_foreach:
* @bin: bin to traverse
* @func: function to call on each child
* @data: user data handed to each function call
/* this function is called with the STATE_LOCK held. It works
* as follows:
*
* Calls @func on each child of the bin. If @func returns FALSE,
* gst_bin_foreach() immediately returns.
* It is assumed that calling @func may alter the set of @bin's children. @func
* will only be called on children that were in @bin when gst_bin_foreach() was
* called, and that are still in @bin when the child is reached.
* 1) put all sink elements on the queue.
* 2) change state of elements in queue, put linked elements to queue.
* 3) while queue not empty goto 2)
*
* Returns: TRUE if @func always returned TRUE, FALSE otherwise
* This will effectively change the state of all elements in the bin
* from the sinks to the sources. We have to change the states this
* way so that when a source element pushes data, the downstream element
* is in the right state to receive the data.
*
* Marked for removal.
**/
static gboolean
gst_bin_foreach (GstBin * bin, GstBinForeachFunc func, gpointer data)
{
GList *kids, *walk;
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
g_return_val_if_fail (func != NULL, FALSE);
kids = g_list_copy (bin->children);
for (walk = kids; walk; walk = g_list_next (walk)) {
GstElement *element = (GstElement *) walk->data;
if (g_list_find (bin->children, element)) {
gboolean res = func (bin, element, data);
if (!res) {
g_list_free (kids);
return FALSE;
}
}
}
g_list_free (kids);
return TRUE;
}
typedef struct
{
GstElementState pending;
GstElementStateReturn result;
}
SetKidStateData;
static int
set_kid_state_func (GstBin * bin, GstElement * child, gpointer user_data)
{
GstElementState old_child_state;
SetKidStateData *data = user_data;
if (GST_FLAG_IS_SET (child, GST_ELEMENT_LOCKED_STATE)) {
return TRUE;
}
old_child_state = GST_STATE (child);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
"changing state of child %s from current %s to pending %s",
GST_ELEMENT_NAME (child), gst_element_state_get_name (old_child_state),
gst_element_state_get_name (data->pending));
switch (gst_element_set_state (child, data->pending)) {
case GST_STATE_FAILURE:
GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
"child '%s' failed to go to state %d(%s)",
GST_ELEMENT_NAME (child),
data->pending, gst_element_state_get_name (data->pending));
gst_element_set_state (child, old_child_state);
return FALSE; /* error out to the caller */
case GST_STATE_ASYNC:
GST_CAT_INFO_OBJECT (GST_CAT_STATES, bin,
"child '%s' is changing state asynchronously",
GST_ELEMENT_NAME (child));
data->result = GST_STATE_ASYNC;
return TRUE;
case GST_STATE_SUCCESS:
GST_CAT_DEBUG (GST_CAT_STATES,
"child '%s' changed state to %d(%s) successfully",
GST_ELEMENT_NAME (child), data->pending,
gst_element_state_get_name (data->pending));
return TRUE;
default:
g_assert_not_reached ();
return FALSE; /* satisfy gcc */
}
}
* MT safe.
*/
static GstElementStateReturn
gst_bin_change_state (GstElement * element)
{
GstBin *bin;
GstElementStateReturn ret;
GstElementState old_state, pending;
g_return_val_if_fail (GST_IS_BIN (element), GST_STATE_FAILURE);
bin = GST_BIN (element);
old_state = GST_STATE (element);
pending = GST_STATE_PENDING (element);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"changing state of children from %s to %s",
gst_element_state_get_name (old_state),
gst_element_state_get_name (pending));
if (pending == GST_STATE_VOID_PENDING)
return GST_STATE_SUCCESS;
/* If we're changing state non-recursively (see _norecurse()),
* this flag is already set and we should not set children states. */
if (!GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED)) {
SetKidStateData data;
/* So now we use this flag to make sure that kids don't re-set our
* state, which would lead to infinite loops. */
GST_FLAG_SET (bin, GST_BIN_STATE_LOCKED);
data.pending = pending;
data.result = GST_STATE_SUCCESS;
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
GST_STATE_PENDING (element) = old_state;
return GST_STATE_FAILURE;
}
GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"done changing bin's state from %s to %s, now in %s",
gst_element_state_get_name (old_state),
gst_element_state_get_name (pending),
gst_element_state_get_name (GST_STATE (element)));
/* if we're async, the kids will change state later (when the
* lock-state flag is no longer held) and all will be fine. */
if (data.result == GST_STATE_ASYNC)
return GST_STATE_ASYNC;
} else {
GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
"Not recursing state change onto children");
}
/* FIXME: this should have been done by the children already, no? */
if (parent_class->change_state) {
ret = parent_class->change_state (element);
} else {
ret = GST_STATE_SUCCESS;
}
return ret;
}
GstElementStateReturn
gst_bin_set_state (GstElement * element, GstElementState state)
{
GstBin *bin = GST_BIN (element);
if (GST_STATE (bin) == state) {
SetKidStateData data;
data.pending = state;
data.result = GST_STATE_SUCCESS;
if (!gst_bin_foreach (bin, set_kid_state_func, &data)) {
return GST_STATE_FAILURE;
} else {
return data.result;
}
} else {
return GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, set_state, (element,
state), GST_STATE_FAILURE);
}
}
static GstElementStateReturn
gst_bin_change_state_norecurse (GstBin * bin)
{
GstElementStateReturn ret;
if (GST_ELEMENT_GET_CLASS (bin)->change_state) {
GST_CAT_LOG_OBJECT (GST_CAT_STATES, bin, "setting bin's own state");
/* Non-recursive state change flag */
GST_FLAG_SET (bin, GST_BIN_STATE_LOCKED);
ret = GST_ELEMENT_GET_CLASS (bin)->change_state (GST_ELEMENT (bin));
GST_FLAG_UNSET (bin, GST_BIN_STATE_LOCKED);
return ret;
} else
return GST_STATE_FAILURE;
/* implement me */
return GST_STATE_FAILURE;
}
static void
@ -1303,58 +947,6 @@ gst_bin_iterate_all_by_interface (GstBin * bin, GType interface)
return result;
}
/**
* gst_bin_sync_children_state:
* @bin: #Gstbin to sync state
*
* Tries to set the state of the children of this bin to the same state of the
* bin by calling gst_element_set_state for each child not already having a
* synchronized state.
*
* Returns: The worst return value of any gst_element_set_state. So if one child
* returns #GST_STATE_FAILURE while all others return #GST_STATE_SUCCESS
* this function returns #GST_STATE_FAILURE.
*/
GstElementStateReturn
gst_bin_sync_children_state (GstBin * bin)
{
GList *children;
GstElement *element;
GstElementState state;
GstElementStateReturn ret = GST_STATE_SUCCESS;
g_return_val_if_fail (GST_IS_BIN (bin), GST_STATE_FAILURE);
state = GST_STATE (bin);
children = bin->children;
GST_CAT_INFO (GST_CAT_STATES,
"syncing state of children with bin \"%s\"'s state %s",
GST_ELEMENT_NAME (bin), gst_element_state_get_name (state));
while (children) {
element = GST_ELEMENT (children->data);
children = children->next;
if (GST_STATE (element) != state) {
switch (gst_element_set_state (element, state)) {
case GST_STATE_SUCCESS:
break;
case GST_STATE_ASYNC:
if (ret == GST_STATE_SUCCESS)
ret = GST_STATE_ASYNC;
break;
case GST_STATE_FAILURE:
ret = GST_STATE_FAILURE;
break;
default:
/* make sure gst_element_set_state never returns this */
g_assert_not_reached ();
}
}
}
return ret;
}
#ifndef GST_DISABLE_LOADSAVE
static xmlNodePtr
gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
@ -1416,85 +1008,3 @@ gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
(GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
}
#endif /* GST_DISABLE_LOADSAVE */
static GStaticRecMutex iterate_lock = G_STATIC_REC_MUTEX_INIT;
static gboolean
gst_bin_iterate_func (GstBin * bin)
{
GstScheduler *sched = GST_ELEMENT_SCHEDULER (bin);
g_static_rec_mutex_unlock (&iterate_lock);
/* only iterate if this is the manager bin */
if (sched && sched->parent == GST_ELEMENT (bin)) {
GstSchedulerState state;
state = gst_scheduler_iterate (sched);
if (state == GST_SCHEDULER_STATE_RUNNING) {
goto done;
} else if (state == GST_SCHEDULER_STATE_ERROR) {
gst_element_set_state (GST_ELEMENT (bin), GST_STATE_PAUSED);
} else if (state == GST_SCHEDULER_STATE_STOPPED) {
/* check if we have children scheds that are still running */
/* FIXME: remove in 0.9? autouseless because iterations gone? */
GList *walk;
for (walk = sched->schedulers; walk; walk = g_list_next (walk)) {
GstScheduler *test = walk->data;
g_return_val_if_fail (test->parent, FALSE);
if (GST_STATE (test->parent) == GST_STATE_PLAYING) {
GST_CAT_DEBUG_OBJECT (GST_CAT_SCHEDULING, bin,
"current bin is not iterating, but children are, "
"so returning TRUE anyway...");
g_usleep (1);
goto done;
}
}
}
} else {
g_warning ("bin \"%s\" is not the managing bin, can't be iterated on!\n",
GST_ELEMENT_NAME (bin));
}
g_static_rec_mutex_lock (&iterate_lock);
return FALSE;
done:
g_static_rec_mutex_lock (&iterate_lock);
return TRUE;
}
/**
* gst_bin_iterate:
* @bin: a#GstBin to iterate.
*
* Iterates over the elements in this bin.
*
* Returns: TRUE if the bin did something useful. This value
* can be used to determine it the bin is in EOS.
*/
gboolean
gst_bin_iterate (GstBin * bin)
{
gboolean running;
g_return_val_if_fail (bin != NULL, FALSE);
g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "starting iteration");
gst_object_ref (GST_OBJECT (bin));
g_static_rec_mutex_lock (&iterate_lock);
running = FALSE;
g_signal_emit (G_OBJECT (bin), gst_bin_signals[ITERATE], 0, &running);
g_static_rec_mutex_unlock (&iterate_lock);
gst_object_unref (GST_OBJECT (bin));
GST_CAT_LOG_OBJECT (GST_CAT_SCHEDULING, bin, "finished iteration");
return running;
}

View file

@ -60,9 +60,6 @@ GST_EXPORT GType _gst_bin_type;
* and (un)set using GST_FLAG_SET () and GST_FLAG_UNSET ().
*/
typedef enum {
GST_BIN_FLAG_MANAGER = GST_ELEMENT_FLAG_LAST,
GST_BIN_SELF_SCHEDULABLE,
GST_BIN_STATE_LOCKED,
/* padding */
GST_BIN_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 5
} GstBinFlags;
@ -84,8 +81,6 @@ struct _GstBin {
GList *children;
guint32 children_cookie;
GstElementState child_states[GST_NUM_STATES];
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
@ -94,13 +89,6 @@ struct _GstBinClass {
GstElementClass parent_class;
/*< public >*/
/* run a full iteration of operation */
gboolean (*iterate) (GstBin *bin);
void (*child_state_change) (GstBin *bin, GstElementState oldstate,
GstElementState newstate, GstElement *element);
/* signals */
void (*element_added) (GstBin *bin, GstElement *child);
void (*element_removed) (GstBin *bin, GstElement *child);
@ -133,15 +121,6 @@ GstIterator* gst_bin_iterate_recurse (GstBin *bin);
GstIterator* gst_bin_iterate_sinks (GstBin *bin);
GstIterator* gst_bin_iterate_all_by_interface (GstBin *bin, GType interface);
gboolean gst_bin_iterate (GstBin *bin);
GstElementStateReturn gst_bin_sync_children_state (GstBin *bin);
/* internal */
/* one of our childs signaled a state change */
void gst_bin_child_state_change (GstBin *bin, GstElementState oldstate,
GstElementState newstate, GstElement *child);
G_END_DECLS

621
gst/gstbus.c Normal file
View file

@ -0,0 +1,621 @@
/* GStreamer
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
*
* gstbus.c: GstBus 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.
*/
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "gst_private.h"
#include "gstinfo.h"
#include "gstbus.h"
enum
{
ARG_0,
};
static void gst_bus_class_init (GstBusClass * klass);
static void gst_bus_init (GstBus * bus);
static void gst_bus_dispose (GObject * object);
static void gst_bus_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_bus_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstObjectClass *parent_class = NULL;
/* static guint gst_bus_signals[LAST_SIGNAL] = { 0 }; */
GType
gst_bus_get_type (void)
{
static GType bus_type = 0;
if (!bus_type) {
static const GTypeInfo bus_info = {
sizeof (GstBusClass),
NULL,
NULL,
(GClassInitFunc) gst_bus_class_init,
NULL,
NULL,
sizeof (GstBus),
0,
(GInstanceInitFunc) gst_bus_init,
NULL
};
bus_type = g_type_register_static (GST_TYPE_OBJECT, "GstBus", &bus_info, 0);
}
return bus_type;
}
static void
gst_bus_class_init (GstBusClass * klass)
{
GObjectClass *gobject_class;
GstObjectClass *gstobject_class;
gobject_class = (GObjectClass *) klass;
gstobject_class = (GstObjectClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_OBJECT);
if (!g_thread_supported ())
g_thread_init (NULL);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bus_dispose);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_bus_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_bus_get_property);
}
static void
gst_bus_init (GstBus * bus)
{
bus->queue = g_queue_new ();
bus->queue_lock = g_mutex_new ();
if (socketpair (PF_UNIX, SOCK_STREAM, 0, bus->control_socket) < 0)
goto no_socketpair;
bus->io_channel = g_io_channel_unix_new (bus->control_socket[0]);
return;
/* errors */
no_socketpair:
{
g_warning ("cannot create io channel");
bus->io_channel = NULL;
}
}
static void
gst_bus_dispose (GObject * object)
{
GstBus *bus;
bus = GST_BUS (object);
if (bus->io_channel) {
g_io_channel_shutdown (bus->io_channel, TRUE, NULL);
g_io_channel_unref (bus->io_channel);
bus->io_channel = NULL;
}
close (bus->control_socket[0]);
close (bus->control_socket[1]);
if (bus->queue) {
g_mutex_lock (bus->queue_lock);
g_queue_free (bus->queue);
bus->queue = NULL;
g_mutex_unlock (bus->queue_lock);
g_mutex_free (bus->queue_lock);
bus->queue_lock = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_bus_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstBus *bus;
bus = GST_BUS (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_bus_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstBus *bus;
bus = GST_BUS (object);
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
GstBus *
gst_bus_new (void)
{
GstBus *result;
result = g_object_new (gst_bus_get_type (), NULL);
return result;
}
/**
* gst_bus_post:
* @bus: a #GstBus to post on
* @message: The #GstMessage to post
*
* Post a message on the given bus.
*
* Returns: TRUE if the message could be posted.
*
* MT safe.
*/
gboolean
gst_bus_post (GstBus * bus, GstMessage * message)
{
gchar c;
GstBusSyncReply reply = GST_BUS_PASS;
GstBusSyncHandler handler;
gpointer handler_data;
gboolean need_write = FALSE;
ssize_t write_ret = -1;
g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
g_return_val_if_fail (GST_IS_MESSAGE (message), FALSE);
//g_print ("posting message on bus, type %d\n", GST_MESSAGE_TYPE (message));
GST_DEBUG_OBJECT (bus, "posting message on bus");
GST_LOCK (bus);
handler = bus->sync_handler;
handler_data = bus->sync_handler_data;
GST_UNLOCK (bus);
/* first call the sync handler if it is installed */
if (handler) {
reply = handler (bus, message, handler_data);
}
/* now see what we should do with the message */
switch (reply) {
case GST_BUS_DROP:
/* drop the message */
break;
case GST_BUS_PASS:
/* pass the message to the async queue */
g_mutex_lock (bus->queue_lock);
if (g_queue_get_length (bus->queue) == 0)
need_write = TRUE;
g_queue_push_tail (bus->queue, message);
g_mutex_unlock (bus->queue_lock);
if (g_queue_get_length (bus->queue) == 0)
need_write = TRUE;
if (need_write) {
c = 'p';
errno = EAGAIN;
while (write_ret == -1) {
switch (errno) {
case EAGAIN:
case EINTR:
break;
default:
perror ("gst_bus_post: could not write to fd");
return FALSE;
}
write_ret = write (bus->control_socket[1], &c, 1);
}
}
break;
case GST_BUS_ASYNC:
{
/* async delivery, we need a mutex and a cond to block
* on */
GMutex *lock = g_mutex_new ();
GCond *cond = g_cond_new ();
GST_MESSAGE_COND (message) = cond;
GST_MESSAGE_GET_LOCK (message) = lock;
GST_DEBUG ("waiting for async delivery of message %p", message);
/* now we lock the message mutex, send the message to the async
* queue. When the message is handled by the app and destroyed,
* the cond will be signalled and we can continue */
g_mutex_lock (lock);
g_mutex_lock (bus->queue_lock);
if (g_queue_get_length (bus->queue) == 0)
need_write = TRUE;
g_queue_push_tail (bus->queue, message);
g_mutex_unlock (bus->queue_lock);
if (need_write) {
c = 'p';
errno = EAGAIN;
while (write_ret == -1) {
switch (errno) {
case EAGAIN:
case EINTR:
break;
default:
perror ("gst_bus_post: could not write to fd");
return FALSE;
}
write_ret = write (bus->control_socket[1], &c, 1);
}
}
/* now block till the message is freed */
g_cond_wait (cond, lock);
g_mutex_unlock (lock);
GST_DEBUG ("message %p delivered asynchronously", message);
g_mutex_free (lock);
g_cond_free (cond);
break;
}
}
return TRUE;
}
/**
* gst_bus_have_pending:
* @bus: a #GstBus to check
*
* Check if there are pending messages on the bus that should be
* handled.
*
* Returns: TRUE if there are messages on the bus to be handled.
*
* MT safe.
*/
gboolean
gst_bus_have_pending (GstBus * bus)
{
gint length;
g_return_val_if_fail (GST_IS_BUS (bus), FALSE);
g_mutex_lock (bus->queue_lock);
length = g_queue_get_length (bus->queue);
g_mutex_unlock (bus->queue_lock);
return (length > 0);
}
/**
* gst_bus_pop:
* @bus: a #GstBus to pop
*
* Get a message from the bus.
*
* Returns: The #GstMessage that is on the bus, or NULL if the bus is empty.
*
* MT safe.
*/
GstMessage *
gst_bus_pop (GstBus * bus)
{
GstMessage *message;
gboolean needs_read = FALSE;
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
g_mutex_lock (bus->queue_lock);
message = g_queue_pop_head (bus->queue);
if (message && g_queue_get_length (bus->queue) == 0)
needs_read = TRUE;
g_mutex_unlock (bus->queue_lock);
if (needs_read) {
gchar c;
ssize_t read_ret = -1;
/* the char in the fd is essentially just a way to wake us up. read it off so
we're not woken up again. */
errno = EAGAIN;
while (read_ret == -1) {
switch (errno) {
case EAGAIN:
case EINTR:
break;
default:
perror ("gst_bus_pop: could not read from fd");
return NULL;
}
read_ret = read (bus->control_socket[0], &c, 1);
}
}
return message;
}
/**
* gst_bus_peek:
* @bus: a #GstBus
*
* Peek the message on the top of the bus' queue. The bus maintains ownership of
* the message, and the message will remain on the bus' message queue.
*
* Returns: The #GstMessage that is on the bus, or NULL if the bus is empty.
*
* MT safe.
*/
GstMessage *
gst_bus_peek (GstBus * bus)
{
GstMessage *message;
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
g_mutex_lock (bus->queue_lock);
message = g_queue_peek_head (bus->queue);
g_mutex_unlock (bus->queue_lock);
return message;
}
/**
* gst_bus_set_sync_handler:
* @bus: a #GstBus to install the handler on
* @func: The handler function to install
* @data: User data that will be sent to the handler function.
*
* Install a synchronous handler on the bus. The function will be called
* every time a new message is posted on the bus. Note that the function
* will be called in the same thread context as the posting object.
*/
void
gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func, gpointer data)
{
g_return_if_fail (GST_IS_BUS (bus));
GST_LOCK (bus);
bus->sync_handler = func;
bus->sync_handler_data = data;
GST_UNLOCK (bus);
}
/**
* gst_bus_create_watch:
* @bus: a #GstBus to create the watch for
*
* Create watch for this bus.
*
* Returns: A #GSource that can be added to a mainloop.
*/
GSource *
gst_bus_create_watch (GstBus * bus)
{
GSource *source;
g_return_val_if_fail (GST_IS_BUS (bus), NULL);
/* FIXME, we need to ref the bus and unref it when the source
* is destroyed */
source = g_io_create_watch (bus->io_channel, G_IO_IN);
return source;
}
typedef struct
{
GSource *source;
GstBus *bus;
gint priority;
GstBusHandler handler;
gpointer user_data;
GDestroyNotify notify;
} GstBusWatch;
static gboolean
bus_watch_callback (GIOChannel * channel, GIOCondition cond,
GstBusWatch * watch)
{
GstMessage *message;
gboolean needs_pop = TRUE;
g_return_val_if_fail (GST_IS_BUS (watch->bus), FALSE);
message = gst_bus_peek (watch->bus);
g_return_val_if_fail (message != NULL, TRUE);
if (watch->handler)
needs_pop = watch->handler (watch->bus, message, watch->user_data);
if (needs_pop)
gst_message_unref (gst_bus_pop (watch->bus));
return TRUE;
}
static void
bus_watch_destroy (GstBusWatch * watch)
{
if (watch->notify) {
watch->notify (watch->user_data);
}
gst_object_unref (GST_OBJECT_CAST (watch->bus));
g_free (watch);
}
/**
* gst_bus_add_watch_full:
* @bus: a #GstBus to create the watch for
* @handler: A function to call when a message is received.
*
* Adds the bus to the mainloop with the given priority. If the handler returns
* TRUE, the message will then be popped off the queue. When the handler is
* called, the message belongs to the caller; if you want to keep a copy of it,
* call gst_message_ref before leaving the handler.
*
* Returns: The event source id.
*
* MT safe.
*/
guint
gst_bus_add_watch_full (GstBus * bus, gint priority,
GstBusHandler handler, gpointer user_data, GDestroyNotify notify)
{
guint id;
GstBusWatch *watch;
g_return_val_if_fail (GST_IS_BUS (bus), 0);
watch = g_new (GstBusWatch, 1);
gst_object_ref (GST_OBJECT_CAST (bus));
watch->source = gst_bus_create_watch (bus);
watch->bus = bus;
watch->priority = priority;
watch->handler = handler;
watch->user_data = user_data;
watch->notify = notify;
if (priority != G_PRIORITY_DEFAULT)
g_source_set_priority (watch->source, priority);
g_source_set_callback (watch->source, (GSourceFunc) bus_watch_callback,
watch, (GDestroyNotify) bus_watch_destroy);
id = g_source_attach (watch->source, NULL);
g_source_unref (watch->source);
return id;
}
/**
* gst_bus_add_watch:
* @bus: a #GstBus to create the watch for
*
* Adds the bus to the mainloop with the default priority.
*
* Returns: The event source id.
*
* MT safe.
*/
guint
gst_bus_add_watch (GstBus * bus, GstBusHandler handler, gpointer user_data)
{
return gst_bus_add_watch_full (bus, G_PRIORITY_DEFAULT, handler, user_data,
NULL);
}
typedef struct
{
GMainLoop *loop;
guint timeout_id;
GstMessageType events;
GstMessageType revent;
} GstBusPollData;
static gboolean
poll_handler (GstBus * bus, GstMessage * message, GstBusPollData * poll_data)
{
if (GST_MESSAGE_TYPE (message) & poll_data->events) {
poll_data->revent = GST_MESSAGE_TYPE (message);
if (g_main_loop_is_running (poll_data->loop))
g_main_loop_quit (poll_data->loop);
/* keep the message on the queue */
return FALSE;
} else {
/* pop and unref the message */
return TRUE;
}
}
static gboolean
poll_timeout (GstBusPollData * poll_data)
{
poll_data->timeout_id = 0;
g_main_loop_quit (poll_data->loop);
/* returning FALSE will remove the source id */
return FALSE;
}
/**
* gst_bus_poll:
* @bus: a #GstBus
* @events: a mask of #GstMessageType, representing the set of message types to
* poll for.
* @timeout: the poll timeout, as a #GstClockTimeDiff, or -1 to poll indefinitely.
*
* Poll the bus for events. Will block while waiting for events to come. You can
* specify a maximum time to poll with the @timeout parameter. If @timeout is
* negative, this function will block indefinitely.
*
* Returns: The type of the message that was received, or GST_MESSAGE_UNKNOWN if
* the poll timed out. The message will remain in the bus queue; you will need
* to gst_bus_pop() it off before entering gst_bus_poll() again.
*/
GstMessageType
gst_bus_poll (GstBus * bus, GstMessageType events, GstClockTimeDiff timeout)
{
GstBusPollData *poll_data;
GstMessageType ret;
guint id;
poll_data = g_new0 (GstBusPollData, 1);
if (timeout >= 0)
poll_data->timeout_id = g_timeout_add (timeout / GST_MSECOND,
(GSourceFunc) poll_timeout, poll_data);
poll_data->loop = g_main_loop_new (NULL, FALSE);
poll_data->events = events;
poll_data->revent = GST_MESSAGE_UNKNOWN;
id = gst_bus_add_watch (bus, (GstBusHandler) poll_handler, poll_data);
g_main_loop_run (poll_data->loop);
g_source_remove (id);
ret = poll_data->revent;
if (poll_data->timeout_id)
g_source_remove (poll_data->timeout_id);
g_main_loop_unref (poll_data->loop);
g_free (poll_data);
return ret;
}

103
gst/gstbus.h Normal file
View file

@ -0,0 +1,103 @@
/* GStreamer
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
*
* gstbus.h: Header for GstBus 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_BUS_H__
#define __GST_BUS_H__
#include <gst/gsttypes.h>
#include <gst/gstmessage.h>
#include <gst/gstclock.h>
G_BEGIN_DECLS
/* --- standard type macros --- */
#define GST_TYPE_BUS (gst_bus_get_type ())
#define GST_BUS(bus) (G_TYPE_CHECK_INSTANCE_CAST ((bus), GST_TYPE_BUS, GstBus))
#define GST_IS_BUS(bus) (G_TYPE_CHECK_INSTANCE_TYPE ((bus), GST_TYPE_BUS))
#define GST_BUS_CLASS(bclass) (G_TYPE_CHECK_CLASS_CAST ((bclass), GST_TYPE_BUS, GstBusClass))
#define GST_IS_BUS_CLASS(bclass) (G_TYPE_CHECK_CLASS_TYPE ((bclass), GST_TYPE_BUS))
#define GST_BUS_GET_CLASS(bus) (G_TYPE_INSTANCE_GET_CLASS ((bus), GST_TYPE_BUS, GstBusClass))
#define GST_BUS_CAST(bus) ((GstBus*)(bus))
typedef enum
{
GST_BUS_DROP = 0, /* drop message */
GST_BUS_PASS = 1, /* pass message to async queue */
GST_BUS_ASYNC = 2, /* pass message to async queue, continue if message is handled */
} GstBusSyncReply;
typedef GstBusSyncReply (*GstBusSyncHandler) (GstBus * bus, GstMessage * message, gpointer data);
typedef gboolean (*GstBusHandler) (GstBus * bus, GstMessage * message, gpointer data);
struct _GstBus
{
GstObject object;
/*< private > */
GQueue *queue;
GMutex *queue_lock;
GstBusSyncHandler sync_handler;
gpointer sync_handler_data;
gint control_socket[2];
GIOChannel *io_channel;
/*< private > */
gpointer _gst_reserved[GST_PADDING];
};
struct _GstBusClass
{
GstObjectClass parent_class;
/*< private > */
gpointer _gst_reserved[GST_PADDING];
};
GType gst_bus_get_type (void);
GstBus* gst_bus_new (void);
gboolean gst_bus_post (GstBus * bus, GstMessage * message);
gboolean gst_bus_have_pending (GstBus * bus);
GstMessage * gst_bus_peek (GstBus * bus);
GstMessage * gst_bus_pop (GstBus * bus);
void gst_bus_set_sync_handler (GstBus * bus, GstBusSyncHandler func,
gpointer data);
GSource * gst_bus_create_watch (GstBus * bus);
guint gst_bus_add_watch_full (GstBus * bus,
gint priority,
GstBusHandler handler,
gpointer user_data,
GDestroyNotify notify);
guint gst_bus_add_watch (GstBus * bus,
GstBusHandler handler,
gpointer user_data);
GstMessageType gst_bus_poll (GstBus *bus, GstMessageType events,
GstClockTimeDiff timeout);
G_END_DECLS
#endif /* __GST_BUS_H__ */

View file

@ -81,7 +81,7 @@ struct _GstStaticCaps {
gpointer _gst_reserved[GST_PADDING];
};
GType gst_caps_get_type (void) G_GNUC_CONST;
GType gst_caps_get_type (void);
GstCaps * gst_caps_new_empty (void);
GstCaps * gst_caps_new_any (void);
GstCaps * gst_caps_new_simple (const char *media_type,

View file

@ -102,7 +102,7 @@ GstData* gst_data_ref_by_count (GstData* data, gint count);
void gst_data_unref (GstData* data);
/* GType for GstData */
GType gst_data_get_type (void) G_GNUC_CONST;
GType gst_data_get_type (void);
G_END_DECLS

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,7 @@
#include <gst/gstpluginfeature.h>
#include <gst/gstindex.h>
#include <gst/gstiterator.h>
#include <gst/gstmessage.h>
#include <gst/gsttag.h>
G_BEGIN_DECLS
@ -105,17 +106,6 @@ GST_EXPORT GType _gst_element_type;
typedef enum
{
/* input and output pads aren't directly coupled to each other
examples: queues, multi-output async readers, etc. */
GST_ELEMENT_DECOUPLED,
/* this element, for some reason, has a loop function that performs
* an infinite loop without calls to gst_element_yield () */
GST_ELEMENT_INFINITE_LOOP,
/* there is a new loopfunction ready for placement */
GST_ELEMENT_NEW_LOOPFUNC,
/* if this element can handle events */
GST_ELEMENT_EVENT_AWARE,
/* private flags that can be used by the scheduler */
GST_ELEMENT_SCHEDULER_PRIVATE1,
GST_ELEMENT_SCHEDULER_PRIVATE2,
@ -123,20 +113,16 @@ typedef enum
/* ignore state changes from parent */
GST_ELEMENT_LOCKED_STATE,
/* element is in error */
GST_ELEMENT_IN_ERROR,
/* use some padding for future expansion */
GST_ELEMENT_FLAG_LAST = GST_OBJECT_FLAG_LAST + 16
} GstElementFlags;
#define GST_ELEMENT_IS_THREAD_SUGGESTED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_THREAD_SUGGESTED))
#define GST_ELEMENT_IS_EVENT_AWARE(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_EVENT_AWARE))
#define GST_ELEMENT_IS_DECOUPLED(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_DECOUPLED))
#define GST_ELEMENT_IS_LOCKED_STATE(obj) (GST_FLAG_IS_SET(obj,GST_ELEMENT_LOCKED_STATE))
#define GST_ELEMENT_NAME(obj) (GST_OBJECT_NAME(obj))
#define GST_ELEMENT_PARENT(obj) (GST_OBJECT_PARENT(obj))
#define GST_ELEMENT_PARENT(obj) (GST_ELEMENT_CAST(GST_OBJECT_PARENT(obj)))
#define GST_ELEMENT_MANAGER(obj) (GST_ELEMENT_CAST(obj)->manager)
#define GST_ELEMENT_BUS(obj) (GST_ELEMENT_CAST(obj)->bus)
#define GST_ELEMENT_SCHEDULER(obj) (GST_ELEMENT_CAST(obj)->scheduler)
#define GST_ELEMENT_CLOCK(obj) (GST_ELEMENT_CAST(obj)->clock)
#define GST_ELEMENT_PADS(obj) (GST_ELEMENT_CAST(obj)->pads)
@ -153,23 +139,32 @@ typedef enum
* data processing error. The pipeline will throw an error signal and the
* application will be requested to stop further media processing.
*/
#define GST_ELEMENT_ERROR(el, domain, code, message, debug) \
G_STMT_START { \
gchar *__msg = _gst_element_error_printf message; \
gchar *__dbg = _gst_element_error_printf debug; \
if (__msg) \
GST_ERROR_OBJECT (el, "%s", __msg); \
if (__dbg) \
GST_ERROR_OBJECT (el, "%s", __dbg); \
gst_element_error_full (GST_ELEMENT(el), \
GST_ ## domain ## _ERROR, GST_ ## domain ## _ERROR_ ## code, \
__msg, __dbg, __FILE__, GST_FUNCTION, __LINE__); \
#define GST_ELEMENT_ERROR(el, domain, code, text, debug) \
G_STMT_START { \
gchar *__txt = _gst_element_error_printf text; \
gchar *__dbg = _gst_element_error_printf debug; \
if (__txt) \
GST_ERROR_OBJECT (el, "%s", __txt); \
if (__dbg) \
GST_ERROR_OBJECT (el, "%s", __dbg); \
gst_element_message_full (GST_ELEMENT(el), GST_MESSAGE_ERROR, \
GST_ ## domain ## _ERROR, GST_ ## domain ## _ERROR_ ## code, \
__txt, __dbg, __FILE__, GST_FUNCTION, __LINE__); \
} G_STMT_END
typedef struct _GstElementFactory GstElementFactory;
typedef struct _GstElementFactoryClass GstElementFactoryClass;
typedef void (*GstElementLoopFunction) (GstElement *element);
/* log a (non-fatal) warning message and post it on the bus */
#define GST_ELEMENT_WARNING(el, domain, code, text, debug) \
G_STMT_START { \
gchar *__txt = _gst_element_error_printf text; \
gchar *__dbg = _gst_element_error_printf debug; \
if (__txt) \
GST_WARNING_OBJECT (el, "%s", __txt); \
if (__dbg) \
GST_WARNING_OBJECT (el, "%s", __dbg); \
gst_element_message_full (GST_ELEMENT(el), GST_MESSAGE_WARNING, \
GST_ ## domain ## _ERROR, GST_ ## domain ## _ERROR_ ## code, \
__txt, __dbg, __FILE__, GST_FUNCTION, __LINE__); \
} G_STMT_END
/* the state change mutexes and conds */
#define GST_STATE_GET_LOCK(elem) (GST_ELEMENT_CAST(elem)->state_lock)
@ -183,6 +178,9 @@ typedef void (*GstElementLoopFunction) (GstElement *element);
#define GST_STATE_SIGNAL(elem) g_cond_signal (GST_STATE_GET_COND (elem));
#define GST_STATE_BROADCAST(elem) g_cond_broadcast (GST_STATE_GET_COND (elem));
typedef struct _GstElementFactory GstElementFactory;
typedef struct _GstElementFactoryClass GstElementFactoryClass;
struct _GstElement
{
GstObject object;
@ -196,8 +194,9 @@ struct _GstElement
gboolean state_error; /* flag is set when the element has an error in the last state
change. it is cleared when doing another state change. */
/*< public >*/ /* with LOCK */
/* scheduling */
GstElementLoopFunction loopfunc;
/* element manager */
GstPipeline *manager;
GstBus *bus;
GstScheduler *scheduler;
/* private pointer for the scheduler */
gpointer sched_private;
@ -241,9 +240,6 @@ struct _GstElementClass
void (*new_pad) (GstElement *element, GstPad *pad);
void (*pad_removed) (GstElement *element, GstPad *pad);
void (*no_more_pads) (GstElement *element);
void (*error) (GstElement *element, GstElement *source, GError *error, gchar *debug);
void (*eos) (GstElement *element);
void (*found_tag) (GstElement *element, GstElement *source, const GstTagList *tag_list);
/*< protected >*/
/* vtable */
@ -253,11 +249,13 @@ struct _GstElementClass
void (*release_pad) (GstElement *element, GstPad *pad);
/* state changes */
GstElementStateReturn (*get_state) (GstElement * element, GstElementState * state,
GstElementState * pending, GTimeVal * timeout);
GstElementStateReturn (*change_state) (GstElement *element);
GstElementStateReturn (*set_state) (GstElement *element, GstElementState state);
/* scheduling */
gboolean (*release_locks) (GstElement *element);
/* manager */
void (*set_manager) (GstElement * element, GstPipeline * pipeline);
void (*set_bus) (GstElement * element, GstBus * bus);
void (*set_scheduler) (GstElement *element, GstScheduler *scheduler);
/* set/get clocks */
@ -304,29 +302,19 @@ 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);
GstClockReturn gst_element_clock_wait (GstElement *element,
GstClockID id, GstClockTimeDiff *jitter);
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_set_time_delay (GstElement *element, GstClockTime time, GstClockTime delay);
void gst_element_adjust_time (GstElement *element, GstClockTimeDiff diff);
/* indexes */
gboolean gst_element_is_indexable (GstElement *element);
void gst_element_set_index (GstElement *element, GstIndex *index);
GstIndex* gst_element_get_index (GstElement *element);
/* scheduling */
void gst_element_set_loop_function (GstElement *element,
GstElementLoopFunction loop);
gboolean gst_element_release_locks (GstElement *element);
void gst_element_yield (GstElement *element);
gboolean gst_element_interrupt (GstElement *element);
/* manager and tasks */
void gst_element_set_manager (GstElement * element, GstPipeline * pipeline);
GstPipeline *gst_element_get_manager (GstElement * element);
void gst_element_set_bus (GstElement * element, GstBus * bus);
GstBus *gst_element_get_bus (GstElement * element);
void gst_element_set_scheduler (GstElement *element, GstScheduler *sched);
GstScheduler* gst_element_get_scheduler (GstElement *element);
GstBin* gst_element_get_managing_bin (GstElement *element);
/* pad management */
gboolean gst_element_add_pad (GstElement *element, GstPad *pad);
@ -357,34 +345,33 @@ gboolean gst_element_convert (GstElement *element,
GstFormat src_format, gint64 src_value,
GstFormat *dest_format, gint64 *dest_value);
/* messages */
gboolean gst_element_post_message (GstElement * element, GstMessage * message);
/* error handling */
gchar * _gst_element_error_printf (const gchar *format, ...);
void gst_element_error_full (GstElement *element, GQuark domain, gint code,
gchar *message, gchar *debug,
const gchar *file, const gchar *function, gint line);
void gst_element_default_error (GObject *object, GstObject *orig, GError *error, gchar *debug);
#define gst_element_default_deep_notify gst_object_default_deep_notify
void gst_element_message_full (GstElement * element, GstMessageType type,
GQuark domain, gint code, gchar * text, gchar * debug, const gchar * file,
const gchar * function, gint line);
/* state management */
gboolean gst_element_is_locked_state (GstElement *element);
gboolean gst_element_set_locked_state (GstElement *element, gboolean locked_state);
gboolean gst_element_sync_state_with_parent (GstElement *element);
GstElementState gst_element_get_state (GstElement *element);
GstElementStateReturn gst_element_get_state (GstElement * element,
GstElementState * state,
GstElementState * pending,
GTimeVal * timeout);
GstElementStateReturn gst_element_set_state (GstElement *element, GstElementState state);
void gst_element_wait_state_change (GstElement *element);
void gst_element_set_eos (GstElement *element);
void gst_element_abort_state (GstElement * element);
void gst_element_commit_state (GstElement * element);
void gst_element_lost_state (GstElement * element);
/* factory management */
GstElementFactory* gst_element_get_factory (GstElement *element);
/* misc */
void gst_element_found_tags (GstElement *element, const GstTagList *tag_list);
void gst_element_found_tags_for_pad (GstElement *element, GstPad *pad, GstClockTime timestamp,
GstTagList *list);
/*
*
* factories stuff
@ -446,15 +433,10 @@ GstElement* gst_element_factory_create (GstElementFactory *factory,
const gchar *name);
GstElement* gst_element_factory_make (const gchar *factoryname, const gchar *name);
gboolean gst_element_factory_can_src_caps (GstElementFactory *factory,
const GstCaps *caps);
gboolean gst_element_factory_can_sink_caps (GstElementFactory *factory,
const GstCaps *caps);
void __gst_element_factory_add_pad_template (GstElementFactory *elementfactory,
GstPadTemplate *templ);
void __gst_element_factory_add_interface (GstElementFactory *elementfactory,
const gchar *interfacename);
void __gst_element_factory_add_pad_template (GstElementFactory *elementfactory,
GstPadTemplate *templ);
void __gst_element_factory_add_interface (GstElementFactory *elementfactory,
const gchar *interfacename);
G_END_DECLS

View file

@ -25,7 +25,6 @@
#include "gst_private.h"
#include "gstdata_private.h"
#include "gstclock.h"
#include "gstinfo.h"
#include "gstmemchunk.h"
#include "gstevent.h"
@ -347,9 +346,9 @@ gst_event_new_segment_seek (GstSeekType type, gint64 start, gint64 stop)
{
GstEvent *event;
g_return_val_if_fail (start < stop, NULL);
g_return_val_if_fail (start < stop || stop == -1, NULL);
event = gst_event_new (GST_EVENT_SEEK_SEGMENT);
event = gst_event_new (GST_EVENT_SEEK);
GST_EVENT_SEEK_TYPE (event) = type;
GST_EVENT_SEEK_OFFSET (event) = start;
@ -359,70 +358,20 @@ gst_event_new_segment_seek (GstSeekType type, gint64 start, gint64 stop)
}
/**
* gst_event_new_filler_stamped:
* @time: timestamp of the filler, in nanoseconds.
* @duration: duration of the filler, in nanoseconds.
* gst_event_new_flush:
* @done: Indicates the end of the flush
*
* Creates "filler" data, which is basically empty data that is used to
* synchronize streams if one stream has no data for a while. This is
* used to prevent deadlocks.
* Allocate a new flush event.
*
* Returns: the newly created event.
* Returns: A new flush event.
*/
GstEvent *
gst_event_new_filler_stamped (guint64 time, guint64 duration)
gst_event_new_flush (gboolean done)
{
GstEvent *event = gst_event_new_filler ();
GstEvent *event;
GST_EVENT_TIMESTAMP (event) = time;
if (GST_CLOCK_TIME_IS_VALID (duration)) {
GValue value = { 0 };
event->event_data.structure.structure =
gst_structure_new ("application/x-gst-filler", NULL);
g_value_init (&value, G_TYPE_UINT64);
g_value_set_uint64 (&value, duration);
gst_structure_set_value (event->event_data.structure.structure,
"duration", &value);
g_value_unset (&value);
}
event = gst_event_new (GST_EVENT_FLUSH);
GST_EVENT_FLUSH_DONE (event) = done;
return event;
}
/**
* gst_event_filler_get_duration:
* @event: the event to get the duration from.
*
* Filler events are used to synchronize streams (and thereby prevent
* application deadlocks) if one stream receives no data for a while.
* This function gets the duration of a filler event, which is the
* amount of time from the start of this event (see GST_EVENT_TIMESTAMP())
* that no data is available.
*
* Returns: duration of the lack of data, or GST_CLOCK_TIME_NONE.
*/
guint64
gst_event_filler_get_duration (GstEvent * event)
{
const GValue *value;
g_return_val_if_fail (event != NULL, GST_CLOCK_TIME_NONE);
g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_FILLER,
GST_CLOCK_TIME_NONE);
/* check the event */
if (!event->event_data.structure.structure)
return GST_CLOCK_TIME_NONE;
value = gst_structure_get_value (event->event_data.structure.structure,
"duration");
if (!value)
return GST_CLOCK_TIME_NONE;
g_return_val_if_fail (G_VALUE_TYPE (value) == G_TYPE_UINT64,
GST_CLOCK_TIME_NONE);
/* return */
return g_value_get_uint64 (value);
}

View file

@ -34,24 +34,30 @@ G_BEGIN_DECLS
GST_EXPORT GType _gst_event_type;
/**
* GstEventType:
* @GST_EVENT_UNKNOWN:
* @GST_EVENT_EOS:
* @GST_EVENT_FLUSH:
* @GST_EVENT_DISCONTINUOUS:
* @GST_EVENT_QOS:
* @GST_EVENT_SEEK:
* @GST_EVENT_SIZE:
* @GST_EVENT_RATE:
* @GST_EVENT_NAVIGATION:
* @GST_EVENT_TAG:
*/
typedef enum {
GST_EVENT_UNKNOWN = 0,
GST_EVENT_EOS = 1,
GST_EVENT_FLUSH = 2,
GST_EVENT_EMPTY = 3,
GST_EVENT_DISCONTINUOUS = 4,
/*GST_EVENT_NEW_MEDIA = 5, <- removed */
GST_EVENT_QOS = 6,
GST_EVENT_SEEK = 7,
GST_EVENT_SEEK_SEGMENT = 8,
GST_EVENT_SEGMENT_DONE = 9,
GST_EVENT_SIZE = 10,
GST_EVENT_RATE = 11,
GST_EVENT_FILLER = 12,
GST_EVENT_TS_OFFSET = 13,
GST_EVENT_INTERRUPT = 14,
GST_EVENT_NAVIGATION = 15,
GST_EVENT_TAG = 16
GST_EVENT_DISCONTINUOUS = 3,
GST_EVENT_QOS = 4,
GST_EVENT_SEEK = 5,
GST_EVENT_SIZE = 8,
GST_EVENT_RATE = 9,
GST_EVENT_NAVIGATION = 10,
GST_EVENT_TAG = 11
} GstEventType;
#define GST_EVENT_ANY GST_EVENT_NAVIGATION
@ -87,7 +93,6 @@ typedef struct
GstEventFlag flags;
} GstEventMask;
#ifndef GST_DISABLE_DEPRECATED
#ifdef G_HAVE_ISO_VARARGS
#define GST_EVENT_MASK_FUNCTION(type,functionname, ...) \
static const GstEventMask* \
@ -111,7 +116,6 @@ functionname (type pad) \
return masks; \
}
#endif
#endif
/* seek events, extends GstEventFlag */
typedef enum {
@ -153,6 +157,8 @@ typedef struct
#define GST_EVENT_DISCONT_OFFSET(event,i) (GST_EVENT(event)->event_data.discont.offsets[i])
#define GST_EVENT_DISCONT_OFFSET_LEN(event) (GST_EVENT(event)->event_data.discont.noffsets)
#define GST_EVENT_FLUSH_DONE(event) (GST_EVENT(event)->event_data.flush.done)
#define GST_EVENT_SIZE_FORMAT(event) (GST_EVENT(event)->event_data.size.format)
#define GST_EVENT_SIZE_VALUE(event) (GST_EVENT(event)->event_data.size.value)
@ -178,6 +184,9 @@ struct _GstEvent {
gint noffsets;
gboolean new_media;
} discont;
struct {
gboolean done;
} flush;
struct {
GstFormat format;
gint64 value;
@ -226,12 +235,9 @@ GstEvent* gst_event_new_discontinuous_valist (gboolean new_media,
gboolean gst_event_discont_get_value (GstEvent *event, GstFormat format, gint64 *value);
#define gst_event_new_filler() gst_event_new(GST_EVENT_FILLER)
GstEvent* gst_event_new_filler_stamped (guint64 time,
guint64 duration);
guint64 gst_event_filler_get_duration (GstEvent *event);
/* flush events */
#define gst_event_new_flush() gst_event_new(GST_EVENT_FLUSH)
GstEvent* gst_event_new_flush (gboolean done);
G_END_DECLS

404
gst/gstmessage.c Normal file
View file

@ -0,0 +1,404 @@
/* GStreamer
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
*
* gstmessage.c: GstMessage 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.
*/
#include <string.h> /* memcpy */
#include "gst_private.h"
#include "gstdata_private.h"
#include "gstinfo.h"
#include "gstmemchunk.h"
#include "gstmessage.h"
#include "gsttag.h"
#ifndef GST_DISABLE_TRACE
/* #define GST_WITH_ALLOC_TRACE */
#include "gsttrace.h"
static GstAllocTrace *_message_trace;
#endif
static GstMemChunk *chunk;
/* #define MEMPROF */
GType _gst_message_type;
void
_gst_message_initialize (void)
{
GST_CAT_INFO (GST_CAT_GST_INIT, "init messages");
/* register the type */
_gst_message_type = g_boxed_type_register_static ("GstMessage",
(GBoxedCopyFunc) gst_data_copy, (GBoxedFreeFunc) gst_data_unref);
#ifndef GST_DISABLE_TRACE
_message_trace = gst_alloc_trace_register (GST_MESSAGE_TRACE_NAME);
#endif
chunk = gst_mem_chunk_new ("GstMessageChunk", sizeof (GstMessage),
sizeof (GstMessage) * 50, 0);
}
static GstMessage *
_gst_message_copy (GstMessage * message)
{
GstMessage *copy;
GST_CAT_INFO (GST_CAT_MESSAGE, "copy message %p", message);
copy = gst_mem_chunk_alloc (chunk);
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_new (_message_trace, copy);
#endif
memcpy (copy, message, sizeof (GstMessage));
if (GST_MESSAGE_SRC (copy)) {
gst_object_ref (GST_MESSAGE_SRC (copy));
}
if (copy->structure)
copy->structure = gst_structure_copy (copy->structure);
return copy;
}
static void
_gst_message_free (GstMessage * message)
{
GST_CAT_INFO (GST_CAT_MESSAGE, "freeing message %p", message);
if (GST_MESSAGE_SRC (message)) {
gst_object_unref (GST_MESSAGE_SRC (message));
}
if (message->lock) {
GST_MESSAGE_LOCK (message);
GST_MESSAGE_SIGNAL (message);
GST_MESSAGE_UNLOCK (message);
}
if (message->structure)
gst_structure_free (message->structure);
_GST_DATA_DISPOSE (GST_DATA (message));
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_free (_message_trace, message);
#endif
gst_mem_chunk_free (chunk, message);
}
GType
gst_message_get_type (void)
{
return _gst_message_type;
}
/**
* gst_message_new:
* @type: The type of the new message
*
* Allocate a new message of the given type.
*
* Returns: A new message.
*
* MT safe.
*/
GstMessage *
gst_message_new (GstMessageType type, GstObject * src)
{
GstMessage *message;
message = gst_mem_chunk_alloc0 (chunk);
#ifndef GST_DISABLE_TRACE
gst_alloc_trace_new (_message_trace, message);
#endif
GST_CAT_INFO (GST_CAT_MESSAGE, "creating new message %p %d", message, type);
_GST_DATA_INIT (GST_DATA (message),
_gst_message_type,
0,
(GstDataFreeFunction) _gst_message_free,
(GstDataCopyFunction) _gst_message_copy);
GST_MESSAGE_TYPE (message) = type;
GST_MESSAGE_TIMESTAMP (message) = G_GINT64_CONSTANT (0);
if (src) {
gst_object_ref (src);
GST_MESSAGE_SRC (message) = src;
}
return message;
}
/**
* gst_message_new_eos:
*
* Create a new eos message.
*
* Returns: The new eos message.
*
* MT safe.
*/
GstMessage *
gst_message_new_eos (GstObject * src)
{
GstMessage *message;
message = gst_message_new (GST_MESSAGE_EOS, src);
return message;
}
/**
* gst_message_new_error:
* @src: The object originating the message.
* @error: The GError for this message.
* @debug: A debugging string for something or other.
*
* Create a new error message. The message will take ownership of @error and
* @debug.
*
* Returns: The new error message.
*
* MT safe.
*/
GstMessage *
gst_message_new_error (GstObject * src, GError * error, gchar * debug)
{
GstMessage *message;
GstStructure *s;
message = gst_message_new (GST_MESSAGE_ERROR, src);
s = gst_structure_new ("GstMessageError", "gerror", G_TYPE_POINTER, error,
"debug", G_TYPE_STRING, debug, NULL);
message->structure = s;
return message;
}
/**
* gst_message_new_warning:
* @src: The object originating the message.
* @error: The GError for this message.
* @debug: A debugging string for something or other.
*
* Create a new warning message. The message will take ownership of @error and
* @debug.
*
* Returns: The new warning message.
*
* MT safe.
*/
GstMessage *
gst_message_new_warning (GstObject * src, GError * error, gchar * debug)
{
GstMessage *message;
GstStructure *s;
message = gst_message_new (GST_MESSAGE_WARNING, src);
s = gst_structure_new ("GstMessageWarning", "gerror", G_TYPE_POINTER, error,
"debug", G_TYPE_STRING, debug, NULL);
message->structure = s;
return message;
}
/**
* gst_message_new_tag:
* @src: The object originating the message.
* @tag_list: The tag list for the message.
*
* Create a new tag message. The message will take ownership of the tag list.
*
* Returns: The new tag message.
*
* MT safe.
*/
GstMessage *
gst_message_new_tag (GstObject * src, GstTagList * tag_list)
{
GstMessage *message;
message = gst_message_new (GST_MESSAGE_TAG, src);
message->structure = tag_list;
return message;
}
/**
* gst_message_new_state_change:
* @src: The object originating the message.
* @old: The previous state.
* @new: The new (current) state.
*
* Create a state change message.
*
* Returns: The new state change message.
*
* MT safe.
*/
GstMessage *
gst_message_new_state_changed (GstObject * src, GstElementState old,
GstElementState new)
{
GstMessage *message;
GstStructure *s;
message = gst_message_new (GST_MESSAGE_STATE_CHANGED, src);
s = gst_structure_new ("GstMessageError", "old-state", G_TYPE_INT, old,
"new-state", G_TYPE_INT, new, NULL);
message->structure = s;
return message;
}
/**
* gst_message_new_application:
* @structure: The structure for the message. The message will take ownership of
* the structure.
*
* Create a new application-specific message. These messages can be used by
* application-specific plugins to pass data to the app.
*
* Returns: The new message.
*
* MT safe.
*/
GstMessage *
gst_message_new_application (GstStructure * structure)
{
GstMessage *message;
message = gst_message_new (GST_MESSAGE_APPLICATION, NULL);
message->structure = structure;
return message;
}
/**
* gst_message_get_structure:
* @message: The #GstMessage.
*
* Access the structure of the message.
*
* Returns: The structure of the message, owned by the message.
*
* MT safe.
*/
const GstStructure *
gst_message_get_structure (GstMessage * message)
{
g_return_val_if_fail (GST_IS_MESSAGE (message), NULL);
return message->structure;
}
/**
* gst_message_parse_tag:
* @message: A valid #GstMessage of type GST_MESSAGE_TAG.
*
* Extracts the tag list from the GstMessage. The tag list returned in the
* output argument is a copy; the caller must free it when done.
*
* MT safe.
*/
void
gst_message_parse_tag (GstMessage * message, GstTagList ** tag_list)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_TAG);
*tag_list = (GstTagList *) gst_structure_copy (message->structure);
}
/**
* gst_message_parse_tag:
* @message: A valid #GstMessage of type GST_MESSAGE_STATE_CHANGED.
*
* Extracts the old and new states from the GstMessage.
*
* MT safe.
*/
void
gst_message_parse_state_changed (GstMessage * message, GstElementState * old,
GstElementState * new)
{
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_STATE_CHANGED);
if (!gst_structure_get_int (message->structure, "old-state", (gint *) old))
g_assert_not_reached ();
if (!gst_structure_get_int (message->structure, "new-state", (gint *) new))
g_assert_not_reached ();
}
/**
* gst_message_parse_error:
* @message: A valid #GstMessage of type GST_MESSAGE_ERROR.
*
* Extracts the GError and debug strung from the GstMessage. The values returned
* in the output arguments are copies; the caller must free them when done.
*
* MT safe.
*/
void
gst_message_parse_error (GstMessage * message, GError ** gerror, gchar ** debug)
{
const GValue *error_gvalue;
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR);
error_gvalue = gst_structure_get_value (message->structure, "gerror");
g_return_if_fail (error_gvalue != NULL);
g_return_if_fail (G_VALUE_TYPE (error_gvalue) == G_TYPE_POINTER);
*gerror = g_error_copy (g_value_get_pointer (error_gvalue));
*debug = g_strdup (gst_structure_get_string (message->structure, "debug"));
}
/**
* gst_message_parse_warning:
* @message: A valid #GstMessage of type GST_MESSAGE_WARNING.
*
* Extracts the GError and debug strung from the GstMessage. The values returned
* in the output arguments are copies; the caller must free them when done.
*
* MT safe.
*/
void
gst_message_parse_warning (GstMessage * message, GError ** gerror,
gchar ** debug)
{
const GValue *error_gvalue;
g_return_if_fail (GST_IS_MESSAGE (message));
g_return_if_fail (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING);
error_gvalue = gst_structure_get_value (message->structure, "gerror");
g_return_if_fail (error_gvalue != NULL);
g_return_if_fail (G_VALUE_TYPE (error_gvalue) == G_TYPE_POINTER);
*gerror = g_error_copy (g_value_get_pointer (error_gvalue));
*debug = g_strdup (gst_structure_get_string (message->structure, "debug"));
}

141
gst/gstmessage.h Normal file
View file

@ -0,0 +1,141 @@
/* GStreamer
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
*
* gstmessage.h: Header for GstMessage 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_MESSAGE_H__
#define __GST_MESSAGE_H__
#include <gst/gsttypes.h>
#include <gst/gstdata.h>
#include <gst/gstobject.h>
#include <gst/gsttag.h>
#include <gst/gststructure.h>
G_BEGIN_DECLS
GST_EXPORT GType _gst_message_type;
/**
* GstMessageType:
* @GST_MESSAGE_UNKNOWN: an undefined message
* @GST_MESSAGE_EOS: end-of-stream reached in a pipeline
* @GST_MESSAGE_ERROR: an error occured
* @GST_MESSAGE_WARNING: a warning occured.
* @GST_MESSAGE_INFO: an info message occured
* @GST_MESSAGE_TAG: a tag was found.
* @GST_MESSAGE_BUFFERING: the pipeline is buffering
* @GST_MESSAGE_STATE_CHANGED: a state change happened
* @GST_MESSAGE_STEP_DONE: a framestep finished.
* @GST_MESSAGE_NEW_CLOCK: a new clock was selected in the pipeline
* @GST_MESSAGE_STRUCTURE_CHANGE: the structure of the pipeline changed.
* @GST_MESSAGE_STREAM_STATUS: status about a stream, emited when it starts,
* stops, errors, etc..
* @GST_MESSAGE_APPLICATION: message posted by the application, possibly
* via an application-specific element.
* @GST_MESSAGE_ANY: mask for all of the above messages.
*/
typedef enum
{
GST_MESSAGE_UNKNOWN = 0,
GST_MESSAGE_EOS = (1 << 0),
GST_MESSAGE_ERROR = (1 << 1),
GST_MESSAGE_WARNING = (1 << 2),
GST_MESSAGE_INFO = (1 << 3),
GST_MESSAGE_TAG = (1 << 4),
GST_MESSAGE_BUFFERING = (1 << 5),
GST_MESSAGE_STATE_CHANGED = (1 << 6),
GST_MESSAGE_STEP_DONE = (1 << 7),
GST_MESSAGE_NEW_CLOCK = (1 << 8),
GST_MESSAGE_STRUCTURE_CHANGE = (1 << 9),
GST_MESSAGE_STREAM_STATUS = (1 << 10),
GST_MESSAGE_APPLICATION = (1 << 11),
GST_MESSAGE_ANY = 0xffffffff
} GstMessageType;
#define GST_MESSAGE_TRACE_NAME "GstMessage"
#define GST_TYPE_MESSAGE (_gst_message_type)
#define GST_MESSAGE(message) ((GstMessage*)(message))
#define GST_IS_MESSAGE(message) (GST_DATA_TYPE(message) == GST_TYPE_MESSAGE)
/* the lock is used to handle the synchronous handling of messages,
* the emiting thread is block until the handling thread processed
* the message using this mutex/cond pair */
#define GST_MESSAGE_GET_LOCK(message) (GST_MESSAGE(message)->lock)
#define GST_MESSAGE_LOCK(message) g_mutex_lock(GST_MESSAGE_GET_LOCK(message))
#define GST_MESSAGE_UNLOCK(message) g_mutex_unlock(GST_MESSAGE_GET_LOCK(message))
#define GST_MESSAGE_COND(message) (GST_MESSAGE(message)->cond)
#define GST_MESSAGE_WAIT(message) g_cond_wait(GST_MESSAGE_COND(message),GST_MESSAGE_GET_LOCK(message))
#define GST_MESSAGE_SIGNAL(message) g_cond_signal(GST_MESSAGE_COND(message))
#define GST_MESSAGE_TYPE(message) (GST_MESSAGE(message)->type)
#define GST_MESSAGE_TIMESTAMP(message) (GST_MESSAGE(message)->timestamp)
#define GST_MESSAGE_SRC(message) (GST_MESSAGE(message)->src)
struct _GstMessage
{
GstData data;
/*< public > *//* with MESSAGE_LOCK */
GMutex *lock; /* lock and cond for async delivery */
GCond *cond;
/*< public > *//* with COW */
GstMessageType type;
guint64 timestamp;
GstObject *src;
GstStructure *structure;
/*< private > */
gpointer _gst_reserved[GST_PADDING];
};
void _gst_message_initialize (void);
GType gst_message_get_type (void);
GstMessage * gst_message_new (GstMessageType type, GstObject * src);
/* refcounting */
#define gst_message_ref(ev) GST_MESSAGE (gst_data_ref (GST_DATA (ev)))
#define gst_message_ref_by_count(ev,c) GST_MESSAGE (gst_data_ref_by_count (GST_DATA (ev), c))
#define gst_message_unref(ev) gst_data_unref (GST_DATA (ev))
/* copy message */
#define gst_message_copy(ev) GST_MESSAGE (gst_data_copy (GST_DATA (ev)))
GstMessage * gst_message_new_eos (GstObject * src);
GstMessage * gst_message_new_error (GstObject * src, GError * error, gchar * debug);
GstMessage * gst_message_new_warning (GstObject * src, GError * error, gchar * debug);
GstMessage * gst_message_new_tag (GstObject * src, GstTagList * tag_list);
GstMessage * gst_message_new_state_changed (GstObject * src, GstElementState old_state,
GstElementState new_state);
GstMessage * gst_message_new_application (GstStructure *structure);
const GstStructure * gst_message_get_structure (GstMessage *message);
void gst_message_parse_tag (GstMessage *message, GstTagList **tag_list);
void gst_message_parse_state_changed (GstMessage *message, GstElementState *old_state,
GstElementState *new_state);
void gst_message_parse_error (GstMessage *message, GError **gerror, gchar **debug);
void gst_message_parse_warning (GstMessage *message, GError **gerror, gchar **debug);
G_END_DECLS
#endif /* __GST_MESSAGE_H__ */

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,7 @@
#include <gst/gstevent.h>
#include <gst/gstprobe.h>
#include <gst/gstquery.h>
#include <gst/gsttask.h>
G_BEGIN_DECLS
@ -87,10 +88,12 @@ typedef struct _GstStaticPadTemplate GstStaticPadTemplate;
typedef struct _GstPadLink GstPadLink;
typedef enum {
GST_PAD_LINK_REFUSED = -1,
GST_PAD_LINK_DELAYED = 0,
GST_PAD_LINK_OK = 1,
GST_PAD_LINK_DONE = 2
GST_PAD_LINK_NOSCHED = -5, /* pads cannot cooperate in scheduling */
GST_PAD_LINK_NOFORMAT = -4, /* pads do not have common format */
GST_PAD_LINK_REFUSED = -3, /* refused for some reason */
GST_PAD_LINK_WRONG_DIRECTION = -2, /* pads have wrong direction */
GST_PAD_LINK_WAS_LINKED = -1, /* pad was already linked */
GST_PAD_LINK_OK = 0, /* link ok */
} GstPadLinkReturn;
#define GST_PAD_LINK_FAILED(ret) (ret < GST_PAD_LINK_OK)
@ -128,11 +131,11 @@ typedef enum {
/* pad states */
typedef gboolean (*GstPadActivateFunction) (GstPad *pad, GstActivateMode mode);
/* this defines the functions used to chain buffers
* pad is the sink pad (so the same chain function can be used for N pads)
* buf is the buffer being passed */
typedef void (*GstPadChainFunction) (GstPad *pad,GstData *data);
typedef GstData* (*GstPadGetFunction) (GstPad *pad);
/* data passing */
typedef void (*GstPadLoopFunction) (GstPad *pad);
typedef GstFlowReturn (*GstPadChainFunction) (GstPad *pad, GstBuffer *buffer);
typedef GstFlowReturn (*GstPadGetRangeFunction) (GstPad *pad, guint64 offset,
guint length, GstBuffer **buffer);
typedef gboolean (*GstPadEventFunction) (GstPad *pad, GstEvent *event);
/* convert/query/format functions */
@ -147,16 +150,20 @@ typedef const GstEventMask* (*GstPadEventMaskFunction) (GstPad *pad);
typedef const GstQueryType* (*GstPadQueryTypeFunction) (GstPad *pad);
/* linking */
typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, const GstCaps *caps);
typedef void (*GstPadUnlinkFunction) (GstPad *pad);
typedef GstPadLinkReturn (*GstPadLinkFunction) (GstPad *pad, GstPad *peer);
typedef void (*GstPadUnlinkFunction) (GstPad *pad);
/* caps nego */
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad);
typedef GstCaps* (*GstPadFixateFunction) (GstPad *pad, const GstCaps *caps);
typedef GstBuffer* (*GstPadBufferAllocFunction) (GstPad *pad, guint64 offset, guint size);
typedef GstCaps* (*GstPadGetCapsFunction) (GstPad *pad);
typedef gboolean (*GstPadSetCapsFunction) (GstPad *pad, GstCaps *caps);
typedef gboolean (*GstPadAcceptCapsFunction) (GstPad *pad, GstCaps *caps);
typedef GstCaps* (*GstPadFixateCapsFunction) (GstPad *pad, GstCaps *caps);
typedef GstBuffer* (*GstPadBufferAllocFunction) (GstPad *pad, guint64 offset, guint size,
GstCaps *caps);
/* misc */
typedef gboolean (*GstPadDispatcherFunction) (GstPad *pad, gpointer data);
typedef gboolean (*GstPadDispatcherFunction) (GstPad *pad, gpointer data);
typedef void (*GstPadBlockCallback) (GstPad *pad, gboolean blocked, gpointer user_data);
typedef enum {
GST_PAD_UNKNOWN,
@ -166,8 +173,10 @@ typedef enum {
typedef enum {
GST_PAD_ACTIVE = GST_OBJECT_FLAG_LAST,
GST_PAD_NEGOTIATING,
GST_PAD_DISPATCHING,
GST_PAD_BLOCKED,
GST_PAD_FLUSHING,
GST_PAD_IN_GETCAPS,
GST_PAD_IN_SETCAPS,
GST_PAD_FLAG_LAST = GST_OBJECT_FLAG_LAST + 8
} GstPadFlags;
@ -188,39 +197,48 @@ struct _GstPadClass {
gpointer _gst_reserved[GST_PADDING];
};
typedef enum {
GST_RPAD_IN_GETFUNC = GST_PAD_FLAG_LAST,
GST_RPAD_IN_CHAINFUNC,
GST_RPAD_FLAG_LAST = GST_PAD_FLAG_LAST + 4
} GstRealPadFlags;
struct _GstRealPad {
GstPad pad;
/* direction cannot change after creating the pad */
GstPadDirection direction;
/*< public >*/ /* with STREAM_LOCK */
/* streaming rec_lock */
GStaticRecMutex *stream_rec_lock;
GstTask *task;
/*< public >*/ /* with PREROLL_LOCK */
GMutex *preroll_lock;
GCond *preroll_cond;
/*< public >*/ /* with LOCK */
/* block cond, mutex is from the object */
GCond *block_cond;
GstPadBlockCallback block_callback;
gpointer block_data;
/* the pad capabilities */
GstCaps *caps;
GstCaps *appfilter;
GstPadGetCapsFunction getcapsfunc;
GstPadFixateFunction appfixatefunc;
GstPadFixateFunction fixatefunc;
GstCaps *caps;
GstCaps *appfilter;
GstPadGetCapsFunction getcapsfunc;
GstPadSetCapsFunction setcapsfunc;
GstPadAcceptCapsFunction acceptcapsfunc;
GstPadFixateCapsFunction fixatecapsfunc;
GstPadActivateFunction activatefunc;
/* pad link */
GstPadLinkFunction linkfunc;
GstPadUnlinkFunction unlinkfunc;
GstRealPad *peer;
GstPadLinkFunction linkfunc;
GstPadUnlinkFunction unlinkfunc;
GstRealPad *peer;
gpointer sched_private;
gpointer sched_private;
/* data transport functions */
GstPadChainFunction chainfunc;
GstPadChainFunction chainhandler;
GstPadGetFunction getfunc;
GstPadGetFunction gethandler;
GstPadLoopFunction loopfunc;
GstPadChainFunction chainfunc;
GstPadGetRangeFunction getrangefunc;
GstPadEventFunction eventfunc;
GstPadEventFunction eventhandler;
GstPadEventMaskFunction eventmaskfunc;
@ -239,9 +257,6 @@ struct _GstRealPad {
GstProbeDispatcher probedisp;
GstPadLink *link;
GstCaps *explicit_caps;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
@ -252,9 +267,7 @@ struct _GstRealPadClass {
/* signal callbacks */
void (*linked) (GstPad *pad, GstPad *peer);
void (*unlinked) (GstPad *pad, GstPad *peer);
GstPadFixateFunction appfixatefunc;
void (*caps_nego_failed) (GstPad *pad, GstCaps *caps);
void (*request_link) (GstPad *pad);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
@ -284,12 +297,12 @@ struct _GstGhostPadClass {
/* GstRealPad */
#define GST_RPAD_DIRECTION(pad) (GST_REAL_PAD_CAST(pad)->direction)
#define GST_RPAD_TASK(pad) (GST_REAL_PAD_CAST(pad)->task)
#define GST_RPAD_ACTIVATEFUNC(pad) (GST_REAL_PAD_CAST(pad)->activatefunc)
#define GST_RPAD_LOOPFUNC(pad) (GST_REAL_PAD_CAST(pad)->loopfunc)
#define GST_RPAD_CHAINFUNC(pad) (GST_REAL_PAD_CAST(pad)->chainfunc)
#define GST_RPAD_CHAINHANDLER(pad) (GST_REAL_PAD_CAST(pad)->chainhandler)
#define GST_RPAD_GETFUNC(pad) (GST_REAL_PAD_CAST(pad)->getfunc)
#define GST_RPAD_GETHANDLER(pad) (GST_REAL_PAD_CAST(pad)->gethandler)
#define GST_RPAD_GETRANGEFUNC(pad) (GST_REAL_PAD_CAST(pad)->getrangefunc)
#define GST_RPAD_EVENTFUNC(pad) (GST_REAL_PAD_CAST(pad)->eventfunc)
#define GST_RPAD_EVENTHANDLER(pad) (GST_REAL_PAD_CAST(pad)->eventhandler)
#define GST_RPAD_CONVERTFUNC(pad) (GST_REAL_PAD_CAST(pad)->convertfunc)
#define GST_RPAD_QUERYFUNC(pad) (GST_REAL_PAD_CAST(pad)->queryfunc)
#define GST_RPAD_INTLINKFUNC(pad) (GST_REAL_PAD_CAST(pad)->intlinkfunc)
@ -304,35 +317,62 @@ struct _GstGhostPadClass {
#define GST_RPAD_CAPS(pad) (GST_REAL_PAD_CAST(pad)->caps)
#define GST_RPAD_APPFILTER(pad) (GST_REAL_PAD_CAST(pad)->appfilter)
#define GST_RPAD_GETCAPSFUNC(pad) (GST_REAL_PAD_CAST(pad)->getcapsfunc)
#define GST_RPAD_FIXATEFUNC(pad) (GST_REAL_PAD_CAST(pad)->fixatefunc)
#define GST_RPAD_LINK(pad) (GST_REAL_PAD_CAST(pad)->link)
#define GST_RPAD_EXPLICIT_CAPS(pad) (GST_REAL_PAD_CAST(pad)->explicit_caps)
#define GST_RPAD_SETCAPSFUNC(pad) (GST_REAL_PAD_CAST(pad)->setcapsfunc)
#define GST_RPAD_ACCEPTCAPSFUNC(pad) (GST_REAL_PAD_CAST(pad)->acceptcapsfunc)
#define GST_RPAD_FIXATECAPSFUNC(pad) (GST_REAL_PAD_CAST(pad)->fixatecapsfunc)
#define GST_RPAD_BUFFERALLOCFUNC(pad) (GST_REAL_PAD_CAST(pad)->bufferallocfunc)
#define GST_RPAD_IS_LINKED(pad) (GST_RPAD_PEER(pad) != NULL)
#define GST_RPAD_IS_ACTIVE(pad) (GST_FLAG_IS_SET (pad, GST_PAD_ACTIVE))
#define GST_RPAD_IS_BLOCKED(pad) (GST_FLAG_IS_SET (pad, GST_PAD_BLOCKED))
#define GST_RPAD_IS_FLUSHING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_FLUSHING))
#define GST_RPAD_IS_IN_GETCAPS(pad) (GST_FLAG_IS_SET (pad, GST_PAD_IN_GETCAPS))
#define GST_RPAD_IS_IN_SETCAPS(pad) (GST_FLAG_IS_SET (pad, GST_PAD_IN_SETCAPS))
#define GST_RPAD_IS_USABLE(pad) (GST_RPAD_IS_LINKED (pad) && \
GST_RPAD_IS_ACTIVE(pad) && GST_RPAD_IS_ACTIVE(GST_RPAD_PEER (pad)))
#define GST_RPAD_IS_SRC(pad) (GST_RPAD_DIRECTION(pad) == GST_PAD_SRC)
#define GST_RPAD_IS_SINK(pad) (GST_RPAD_DIRECTION(pad) == GST_PAD_SINK)
#define GST_STREAM_GET_LOCK(pad) (GST_PAD_REALIZE(pad)->stream_rec_lock)
#define GST_STREAM_LOCK(pad) (g_static_rec_mutex_lock(GST_STREAM_GET_LOCK(pad)))
#define GST_STREAM_TRYLOCK(pad) (g_static_rec_mutex_trylock(GST_STREAM_GET_LOCK(pad)))
#define GST_STREAM_UNLOCK(pad) (g_static_rec_mutex_unlock(GST_STREAM_GET_LOCK(pad)))
#define GST_PREROLL_GET_LOCK(pad) (GST_PAD_REALIZE(pad)->preroll_lock)
#define GST_PREROLL_LOCK(pad) (g_mutex_lock(GST_PREROLL_GET_LOCK(pad)))
#define GST_PREROLL_TRYLOCK(pad) (g_mutex_trylock(GST_PREROLL_GET_LOCK(pad)))
#define GST_PREROLL_UNLOCK(pad) (g_mutex_unlock(GST_PREROLL_GET_LOCK(pad)))
#define GST_PREROLL_GET_COND(pad) (GST_PAD_REALIZE(pad)->preroll_cond)
#define GST_PREROLL_WAIT(pad) g_cond_wait (GST_PREROLL_GET_COND (pad), GST_PREROLL_GET_LOCK (pad))
#define GST_PREROLL_TIMED_WAIT(pad, timeval) g_cond_timed_wait (GST_PREROLL_GET_COND (pad), GST_PREROLL_GET_LOCK (pad),\
timeval)
#define GST_PREROLL_SIGNAL(pad) g_cond_signal (GST_PREROLL_GET_COND (pad));
#define GST_PREROLL_BROADCAST(pad) g_cond_broadcast (GST_PREROLL_GET_COND (pad));
#define GST_PAD_BLOCK_GET_COND(pad) (GST_PAD_REALIZE(pad)->block_cond)
#define GST_PAD_BLOCK_WAIT(pad) (g_cond_wait(GST_PAD_BLOCK_GET_COND (pad), GST_GET_LOCK (pad)))
#define GST_PAD_BLOCK_SIGNAL(pad) (g_cond_signal(GST_PAD_BLOCK_GET_COND (pad)))
/* GstGhostPad */
#define GST_GPAD_REALPAD(pad) (((GstGhostPad *)(pad))->realpad)
/* Generic */
/* Generic, be VERY carefull with these macros as the ghostpad could be lost */
#define GST_PAD_REALIZE(pad) (GST_IS_REAL_PAD(pad) ? ((GstRealPad *)(pad)) : GST_GPAD_REALPAD(pad))
#define GST_PAD_DIRECTION(pad) GST_RPAD_DIRECTION(GST_PAD_REALIZE(pad))
#define GST_PAD_CAPS(pad) (gst_pad_get_negotiated_caps(GST_PAD (pad)))
#define GST_PAD_CAPS(pad) GST_RPAD_CAPS(GST_PAD_REALIZE (pad))
#define GST_PAD_APPFILTER(pad) GST_RPAD_APPFILTER(GST_PAD_REALIZE (pad))
#define GST_PAD_PEER(pad) GST_PAD_CAST(GST_RPAD_PEER(GST_PAD_REALIZE(pad)))
/* Some check functions (unused?) */
#define GST_PAD_IS_LINKED(pad) (GST_RPAD_IS_LINKED(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_ACTIVE(pad) (GST_RPAD_IS_ACTIVE(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_NEGOTIATING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_NEGOTIATING))
#define GST_PAD_IS_DISPATCHING(pad) (GST_FLAG_IS_SET (pad, GST_PAD_DISPATCHING))
#define GST_PAD_IS_BLOCKED(pad) (GST_RPAD_IS_BLOCKED(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_NEGOTIATING(pad) (GST_RPAD_IS_NEGOTIATING(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_IN_GETCAPS(pad) (GST_RPAD_IS_IN_GETCAPS(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_IN_SETCAPS(pad) (GST_RPAD_IS_IN_SETCAPS(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_USABLE(pad) (GST_RPAD_IS_USABLE(GST_PAD_REALIZE(pad)))
#define GST_PAD_CAN_PULL(pad) (GST_IS_REAL_PAD(pad) && GST_REAL_PAD(pad)->gethandler != NULL)
#define GST_PAD_CAN_PULL(pad) (GST_RPAD_CAN_PULL(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_SRC(pad) (GST_RPAD_IS_SRC(GST_PAD_REALIZE(pad)))
#define GST_PAD_IS_SINK(pad) (GST_RPAD_IS_SINK(GST_PAD_REALIZE(pad)))
@ -417,22 +457,27 @@ GstElement* gst_pad_get_real_parent (GstPad *pad);
GstPadDirection gst_pad_get_direction (GstPad *pad);
gboolean gst_pad_set_active (GstPad *pad, gboolean active);
gboolean gst_pad_set_active (GstPad *pad, GstActivateMode mode);
gboolean gst_pad_is_active (GstPad *pad);
gboolean gst_pad_set_blocked (GstPad *pad, gboolean blocked);
gboolean gst_pad_set_blocked_async (GstPad *pad, gboolean blocked,
GstPadBlockCallback callback, gpointer user_data);
gboolean gst_pad_is_blocked (GstPad *pad);
void gst_pad_set_element_private (GstPad *pad, gpointer priv);
gpointer gst_pad_get_element_private (GstPad *pad);
GstScheduler* gst_pad_get_scheduler (GstPad *pad);
GstPadTemplate* gst_pad_get_pad_template (GstPad *pad);
void gst_pad_set_bufferalloc_function (GstPad *pad, GstPadBufferAllocFunction bufalloc);
GstBuffer* gst_pad_alloc_buffer (GstPad *pad, guint64 offset, gint size);
void gst_pad_set_bufferalloc_function (GstPad *pad, GstPadBufferAllocFunction bufalloc);
GstBuffer* gst_pad_alloc_buffer (GstPad *pad, guint64 offset, gint size,
GstCaps *caps);
/* data passing setup functions */
void gst_pad_set_activate_function (GstPad *pad, GstPadActivateFunction activate);
void gst_pad_set_loop_function (GstPad *pad, GstPadLoopFunction loop);
void gst_pad_set_chain_function (GstPad *pad, GstPadChainFunction chain);
void gst_pad_set_get_function (GstPad *pad, GstPadGetFunction get);
void gst_pad_set_getrange_function (GstPad *pad, GstPadGetRangeFunction get);
void gst_pad_set_event_function (GstPad *pad, GstPadEventFunction event);
void gst_pad_set_event_mask_function (GstPad *pad, GstPadEventMaskFunction mask_func);
G_CONST_RETURN GstEventMask*
@ -442,13 +487,14 @@ G_CONST_RETURN GstEventMask*
/* pad links */
void gst_pad_set_link_function (GstPad *pad, GstPadLinkFunction link);
gboolean gst_pad_can_link (GstPad *srcpad, GstPad *sinkpad);
gboolean gst_pad_can_link_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
void gst_pad_set_unlink_function (GstPad *pad, GstPadUnlinkFunction unlink);
gboolean gst_pad_link (GstPad *srcpad, GstPad *sinkpad);
gboolean gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
void gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
GstPadLinkReturn gst_pad_link (GstPad *srcpad, GstPad *sinkpad);
GstPadLinkReturn gst_pad_link_filtered (GstPad *srcpad, GstPad *sinkpad,
const GstCaps *filtercaps);
GstPadLinkReturn gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad,
const GstCaps *filtercaps);
gboolean gst_pad_unlink (GstPad *srcpad, GstPad *sinkpad);
gboolean gst_pad_is_linked (GstPad *pad);
GstPad* gst_pad_get_peer (GstPad *pad);
@ -456,45 +502,38 @@ GstPad* gst_pad_realize (GstPad *pad);
/* capsnego functions */
void gst_pad_set_getcaps_function (GstPad *pad, GstPadGetCapsFunction getcaps);
void gst_pad_set_fixate_function (GstPad *pad, GstPadFixateFunction fixate);
GstCaps * gst_pad_proxy_getcaps (GstPad *pad);
GstCaps * gst_pad_proxy_fixate (GstPad *pad, const GstCaps *caps);
gboolean gst_pad_set_explicit_caps (GstPad *pad, const GstCaps *caps);
void gst_pad_use_explicit_caps (GstPad *pad);
gboolean gst_pad_relink_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
GstPadLinkReturn gst_pad_renegotiate (GstPad *pad);
void gst_pad_unnegotiate (GstPad *pad);
gboolean gst_pad_try_relink_filtered (GstPad *srcpad, GstPad *sinkpad, const GstCaps *filtercaps);
void gst_pad_caps_change_notify (GstPad *pad);
gboolean gst_pad_recover_caps_error (GstPad *pad, const GstCaps *allowed);
void gst_pad_set_acceptcaps_function (GstPad *pad, GstPadAcceptCapsFunction acceptcaps);
void gst_pad_set_fixatecaps_function (GstPad *pad, GstPadFixateCapsFunction fixatecaps);
void gst_pad_set_setcaps_function (GstPad *pad, GstPadSetCapsFunction setcaps);
G_CONST_RETURN GstCaps* gst_pad_get_pad_template_caps (GstPad *pad);
/* capsnego function for connected/unconnected pads */
GstCaps* gst_pad_get_caps (GstPad *pad);
gboolean gst_pad_set_caps (GstPad *pad, GstCaps *caps);
GstPadLinkReturn gst_pad_try_set_caps (GstPad *pad, const GstCaps *caps);
GstPadLinkReturn gst_pad_try_set_caps_nonfixed (GstPad *pad, const GstCaps *caps);
gboolean gst_pad_check_compatibility (GstPad *srcpad, GstPad *sinkpad);
GstCaps * gst_pad_get_caps (GstPad * pad);
GstCaps* gst_pad_fixate_caps (GstPad * pad, GstCaps *caps);
gboolean gst_pad_accept_caps (GstPad * pad, GstCaps *caps);
gboolean gst_pad_set_caps (GstPad * pad, GstCaps *caps);
GstCaps * gst_pad_peer_get_caps (GstPad * pad);
gboolean gst_pad_peer_accept_caps (GstPad * pad, GstCaps *caps);
/* capsnego for connected pads */
GstCaps* gst_pad_get_allowed_caps (GstPad *pad);
G_CONST_RETURN GstCaps* gst_pad_get_negotiated_caps (GstPad *pad);
gboolean gst_pad_is_negotiated (GstPad *pad);
GstCaps * gst_pad_get_allowed_caps (GstPad * srcpad);
GstCaps * gst_pad_get_negotiated_caps (GstPad * pad);
GstCaps * gst_pad_get_filter_caps (GstPad * pad);
/* data passing functions */
void gst_pad_push (GstPad *pad, GstData *data);
GstData* gst_pad_pull (GstPad *pad);
GstFlowReturn gst_pad_push (GstPad *pad, GstBuffer *buffer);
GstFlowReturn gst_pad_pull_range (GstPad *pad, guint64 offset, guint size,
GstBuffer **buffer);
gboolean gst_pad_push_event (GstPad *pad, GstEvent *event);
gboolean gst_pad_send_event (GstPad *pad, GstEvent *event);
gboolean gst_pad_event_default (GstPad *pad, GstEvent *event);
/* FIXME 0.9: rename to _select? Otherwise rename SchedulerClass pointer */
GstData * gst_pad_collectv (GstPad **selected, const GList *padlist);
GstData * gst_pad_collect (GstPad **selected, GstPad *pad, ...);
GstData * gst_pad_collect_valist (GstPad **selected, GstPad *pad, va_list varargs);
/* pad tasks */
gboolean gst_pad_start_task (GstPad *pad);
gboolean gst_pad_pause_task (GstPad *pad);
gboolean gst_pad_stop_task (GstPad *pad);
/* convert/query/format functions */
void gst_pad_set_formats_function (GstPad *pad,
@ -561,9 +600,6 @@ xmlNodePtr gst_ghost_pad_save_thyself (GstPad *pad,
xmlNodePtr parent);
#endif
/* for schedulers only */
void gst_pad_call_chain_function (GstPad *pad, GstData *data);
GstData * gst_pad_call_get_function (GstPad *pad);
G_END_DECLS

View file

@ -61,6 +61,9 @@ static void gst_pipeline_set_property (GObject * object, guint prop_id,
static void gst_pipeline_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstBusSyncReply pipeline_bus_handler (GstBus * bus, GstMessage * message,
GstPipeline * pipeline);
static GstClock *gst_pipeline_get_clock_func (GstElement * element);
static GstElementStateReturn gst_pipeline_change_state (GstElement * element);
@ -135,9 +138,7 @@ gst_pipeline_init (GTypeInstance * instance, gpointer g_class)
{
GstScheduler *scheduler;
GstPipeline *pipeline = GST_PIPELINE (instance);
/* pipelines are managing bins */
GST_FLAG_SET (pipeline, GST_BIN_FLAG_MANAGER);
GstBus *bus;
/* get an instance of the default scheduler */
scheduler = gst_scheduler_factory_make (NULL, GST_ELEMENT (pipeline));
@ -150,6 +151,16 @@ gst_pipeline_init (GTypeInstance * instance, gpointer g_class)
"Are you sure you have a registry ?\n"
"Run gst-register as root if you haven't done so yet.", name);
}
bus = g_object_new (gst_bus_get_type (), NULL);
gst_bus_set_sync_handler (bus,
(GstBusSyncHandler) pipeline_bus_handler, pipeline);
pipeline->eosed = NULL;
pipeline->delay = DEFAULT_DELAY;
pipeline->play_timeout = DEFAULT_PLAY_TIMEOUT;
/* we are our own manager */
GST_ELEMENT_MANAGER (pipeline) = pipeline;
gst_element_set_bus (GST_ELEMENT (pipeline), bus);
gst_element_set_scheduler (GST_ELEMENT (pipeline), scheduler);
}
static void
@ -205,6 +216,103 @@ gst_pipeline_get_property (GObject * object, guint prop_id,
GST_UNLOCK (pipeline);
}
static gboolean
is_eos (GstPipeline * pipeline)
{
GstIterator *sinks;
gboolean result = TRUE;
gboolean done = FALSE;
sinks = gst_bin_iterate_sinks (GST_BIN (pipeline));
while (!done) {
gpointer data;
switch (gst_iterator_next (sinks, &data)) {
case GST_ITERATOR_OK:
{
GstElement *element = GST_ELEMENT (data);
GList *eosed;
GstElementState state, pending;
GstElementStateReturn complete;
gchar *name;
complete = gst_element_get_state (element, &state, &pending, NULL);
name = gst_element_get_name (element);
if (complete == GST_STATE_ASYNC) {
GST_DEBUG ("element %s still performing state change", name);
result = FALSE;
done = TRUE;
goto done;
} else if (state != GST_STATE_PLAYING) {
GST_DEBUG ("element %s not playing %d %d", name, state, pending);
goto done;
}
eosed = g_list_find (pipeline->eosed, element);
if (!eosed) {
result = FALSE;
done = TRUE;
}
done:
g_free (name);
gst_object_unref (GST_OBJECT (element));
break;
}
case GST_ITERATOR_RESYNC:
result = TRUE;
gst_iterator_resync (sinks);
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
default:
g_assert_not_reached ();
break;
}
}
gst_iterator_free (sinks);
return result;
}
/* FIXME, make me threadsafe */
static GstBusSyncReply
pipeline_bus_handler (GstBus * bus, GstMessage * message,
GstPipeline * pipeline)
{
GstBusSyncReply result = GST_BUS_PASS;
gboolean posteos = FALSE;
/* we don't want messages from the streaming thread while we're doing the
* state change. We do want them from the state change functions. */
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
if (GST_MESSAGE_SRC (message) != GST_OBJECT (pipeline)) {
GST_LOCK (bus);
pipeline->eosed =
g_list_prepend (pipeline->eosed, GST_MESSAGE_SRC (message));
GST_UNLOCK (bus);
if (is_eos (pipeline)) {
posteos = TRUE;
}
/* we drop all EOS messages */
result = GST_BUS_DROP;
gst_message_unref (message);
}
break;
case GST_MESSAGE_ERROR:
break;
default:
break;
}
if (posteos) {
gst_bus_post (bus, gst_message_new_eos (GST_OBJECT (pipeline)));
}
return result;
}
/**
* gst_pipeline_new:
* @name: name of new pipeline
@ -221,25 +329,44 @@ gst_pipeline_new (const gchar * name)
return gst_element_factory_make ("pipeline", name);
}
/* MT safe */
static GstElementStateReturn
gst_pipeline_change_state (GstElement * element)
{
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
gst_scheduler_setup (GST_ELEMENT_SCHEDULER (element));
break;
case GST_STATE_READY_TO_PAUSED:
case GST_STATE_PAUSED_TO_PLAYING:
case GST_STATE_PLAYING_TO_PAUSED:
case GST_STATE_PAUSED_TO_READY:
case GST_STATE_READY_TO_NULL:
break;
}
/* implement me */
return GST_STATE_FAILURE;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
/**
* gst_pipeline_get_scheduler:
* @pipeline: the pipeline
*
* Gets the #GstScheduler of this pipeline.
*
* Returns: a GstScheduler.
*
* MT safe.
*/
GstScheduler *
gst_pipeline_get_scheduler (GstPipeline * pipeline)
{
return gst_element_get_scheduler (GST_ELEMENT (pipeline));
}
return GST_STATE_SUCCESS;
/**
* gst_pipeline_get_bus:
* @pipeline: the pipeline
*
* Gets the #GstBus of this pipeline.
*
* Returns: a GstBus
*
* MT safe.
*/
GstBus *
gst_pipeline_get_bus (GstPipeline * pipeline)
{
return gst_element_get_bus (GST_ELEMENT (pipeline));
}
static GstClock *

View file

@ -26,6 +26,7 @@
#include <gst/gsttypes.h>
#include <gst/gstbin.h>
#include <gst/gstbus.h>
G_BEGIN_DECLS
@ -69,6 +70,8 @@ struct _GstPipelineClass {
GType gst_pipeline_get_type (void);
GstElement* gst_pipeline_new (const gchar *name);
GstScheduler* gst_pipeline_get_scheduler (GstPipeline *pipeline);
GstBus* gst_pipeline_get_bus (GstPipeline *pipeline);
void gst_pipeline_use_clock (GstPipeline *pipeline, GstClock *clock);
void gst_pipeline_set_clock (GstPipeline *pipeline, GstClock *clock);

View file

@ -34,7 +34,7 @@ G_BEGIN_DECLS
typedef struct _GstProbe GstProbe;
GType gst_probe_get_type (void) G_GNUC_CONST;
GType gst_probe_get_type (void);
/* the callback should return FALSE if the data should be discarded */
typedef gboolean (*GstProbeCallback) (GstProbe *probe,

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,6 @@
#include <gst/gstelement.h>
G_BEGIN_DECLS
#define GST_TYPE_QUEUE \
@ -80,23 +79,14 @@ struct _GstQueue {
/* it the queue should fail on possible deadlocks */
gboolean may_deadlock;
gboolean interrupt;
gboolean flush;
GMutex *qlock; /* lock for queue (vs object lock) */
GCond *item_add; /* signals buffers now available for reading */
GCond *item_del; /* signals space now available for writing */
GCond *event_done; /* upstream event signaller */
GTimeVal *timeval; /* the timeout for the queue locking */
GQueue *events; /* upstream events get decoupled here */
GstCaps *negotiated_caps;
GMutex *event_lock; /* lock when handling the events queue */
gpointer _gst_reserved[GST_PADDING - 1];
gpointer _gst_reserved[GST_PADDING];
};
struct _GstQueueClass {

View file

@ -76,13 +76,7 @@ gst_scheduler_class_init (GstSchedulerClass * klass)
static void
gst_scheduler_init (GstScheduler * sched)
{
sched->clock_providers = NULL;
sched->clock_receivers = NULL;
sched->schedulers = NULL;
sched->state = GST_SCHEDULER_STATE_NONE;
sched->parent = NULL;
sched->parent_sched = NULL;
sched->clock = NULL;
}
static void
@ -90,21 +84,7 @@ gst_scheduler_dispose (GObject * object)
{
GstScheduler *sched = GST_SCHEDULER (object);
/* thse lists should all be NULL */
GST_DEBUG ("scheduler %p dispose %p %p %p",
object,
sched->clock_providers, sched->clock_receivers, sched->schedulers);
gst_object_replace ((GstObject **) & sched->current_clock, NULL);
gst_object_replace ((GstObject **) & sched->clock, NULL);
/* kids are held reference to, so dereference here. */
while (sched->schedulers != NULL) {
gst_scheduler_remove_scheduler (sched,
GST_SCHEDULER (sched->schedulers->data));
}
G_OBJECT_CLASS (parent_class)->dispose (object);
G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (sched));
}
/**
@ -145,626 +125,21 @@ gst_scheduler_reset (GstScheduler * sched)
sclass->reset (sched);
}
/**
* gst_scheduler_pad_link:
* @sched: the scheduler
* @srcpad: the srcpad to link
* @sinkpad: the sinkpad to link to
*
* Links the srcpad to the given sinkpad.
*/
void
gst_scheduler_pad_link (GstScheduler * sched, GstPad * srcpad, GstPad * sinkpad)
GstTask *
gst_scheduler_create_task (GstScheduler * sched, GstTaskFunction func,
gpointer data)
{
GstSchedulerClass *sclass;
GstTask *result = NULL;
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_PAD (srcpad));
g_return_if_fail (GST_IS_PAD (sinkpad));
g_return_val_if_fail (GST_IS_SCHEDULER (sched), result);
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->pad_link)
sclass->pad_link (sched, srcpad, sinkpad);
}
if (sclass->create_task)
result = sclass->create_task (sched, func, data);
/**
* gst_scheduler_pad_unlink:
* @sched: the scheduler
* @srcpad: the srcpad to unlink
* @sinkpad: the sinkpad to unlink from
*
* Unlinks the srcpad from the given sinkpad.
*/
void
gst_scheduler_pad_unlink (GstScheduler * sched, GstPad * srcpad,
GstPad * sinkpad)
{
GstSchedulerClass *sclass;
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_PAD (srcpad));
g_return_if_fail (GST_IS_PAD (sinkpad));
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->pad_unlink)
sclass->pad_unlink (sched, srcpad, sinkpad);
}
/**
* gst_scheduler_pad_select:
* @sched: the scheduler
* @padlist: the padlist to select on
*
* register the given padlist for a select operation.
*
* Returns: the pad which received a buffer.
*/
GstPad *
gst_scheduler_pad_select (GstScheduler * sched, GList * padlist)
{
g_return_val_if_fail (GST_IS_SCHEDULER (sched), NULL);
g_return_val_if_fail (padlist != NULL, NULL);
return NULL;
}
/**
* 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;
gboolean redistribute_clock = FALSE;
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_ELEMENT (element));
/* if it's already in this scheduler, don't bother doing anything */
if (GST_ELEMENT_SCHEDULER (element) == sched) {
GST_CAT_DEBUG (GST_CAT_SCHEDULING, "element %s already in scheduler %p",
GST_ELEMENT_NAME (element), sched);
return;
}
/* if it's not inside this scheduler, it has to be NULL */
g_assert (GST_ELEMENT_SCHEDULER (element) == NULL);
if (gst_element_provides_clock (element)) {
sched->clock_providers = g_list_prepend (sched->clock_providers, element);
GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock provider %s",
GST_ELEMENT_NAME (element));
redistribute_clock = TRUE;
}
if (gst_element_requires_clock (element)) {
sched->clock_receivers = g_list_prepend (sched->clock_receivers, element);
GST_CAT_DEBUG (GST_CAT_CLOCK, "added clock receiver %s",
GST_ELEMENT_NAME (element));
redistribute_clock = TRUE;
}
gst_element_set_scheduler (element, sched);
if (redistribute_clock) {
GstClock *clock;
clock = gst_scheduler_get_clock (sched);
gst_scheduler_set_clock (sched, clock);
}
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;
GList *link;
gboolean redistribute_clock = FALSE;
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_ELEMENT (element));
link = g_list_find (sched->clock_providers, element);
if (link) {
sched->clock_providers = g_list_delete_link (sched->clock_providers, link);
GST_CAT_DEBUG (GST_CAT_CLOCK, "removed clock provider %s",
GST_ELEMENT_NAME (element));
redistribute_clock = TRUE;
}
link = g_list_find (sched->clock_receivers, element);
if (link) {
sched->clock_receivers = g_list_delete_link (sched->clock_receivers, link);
GST_CAT_DEBUG (GST_CAT_CLOCK, "removed clock receiver %s",
GST_ELEMENT_NAME (element));
redistribute_clock = TRUE;
}
if (redistribute_clock) {
GstClock *clock;
clock = gst_scheduler_get_clock (sched);
gst_scheduler_set_clock (sched, clock);
}
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->remove_element)
sclass->remove_element (sched, element);
gst_element_set_scheduler (element, NULL);
}
/**
* gst_scheduler_state_transition:
* @sched: the scheduler
* @element: the element with the state transition
* @transition: the state transition
*
* Tell the scheduler that an element changed its state.
*
* Returns: a GstElementStateReturn indicating success or failure
* of the state transition.
*/
GstElementStateReturn
gst_scheduler_state_transition (GstScheduler * sched, GstElement * element,
gint transition)
{
GstSchedulerClass *sclass;
g_return_val_if_fail (GST_IS_SCHEDULER (sched), GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_FAILURE);
if (element == sched->parent && sched->parent_sched == NULL) {
/* FIXME is distributing the clock in the state change still needed
* when we distribute as soon as we add/remove elements? I think not.*/
switch (transition) {
case GST_STATE_READY_TO_PAUSED:
{
GstClock *clock = gst_scheduler_get_clock (sched);
GST_CAT_DEBUG (GST_CAT_CLOCK,
"scheduler READY to PAUSED clock is %p (%s)", clock,
(clock ? GST_OBJECT_NAME (clock) : "nil"));
gst_scheduler_set_clock (sched, clock);
break;
}
}
}
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->state_transition)
return sclass->state_transition (sched, element, transition);
return GST_STATE_SUCCESS;
}
/**
* gst_scheduler_scheduling_change:
* @sched: the scheduler
* @element: the element that changed its scheduling strategy
*
* Tell the scheduler that an element changed its scheduling strategy.
* An element could, for example, change its loop function or changes
* from a loop based element to a chain based element.
*/
void
gst_scheduler_scheduling_change (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->scheduling_change)
sclass->scheduling_change (sched, element);
}
/**
* gst_scheduler_add_scheduler:
* @sched: a #GstScheduler to add to
* @sched2: the #GstScheduler to add
*
* Notifies the scheduler that it has to monitor this scheduler.
*/
void
gst_scheduler_add_scheduler (GstScheduler * sched, GstScheduler * sched2)
{
GstSchedulerClass *sclass;
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_SCHEDULER (sched2));
g_return_if_fail (sched2->parent_sched == NULL);
GST_DEBUG ("gstscheduler: %p add scheduler %p", sched, sched2);
gst_object_ref (GST_OBJECT (sched2));
gst_object_ref (GST_OBJECT (sched));
sched->schedulers = g_list_prepend (sched->schedulers, sched2);
sched2->parent_sched = sched;
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->add_scheduler)
sclass->add_scheduler (sched, sched2);
}
/**
* gst_scheduler_remove_scheduler:
* @sched: the scheduler
* @sched2: the scheduler to remove
*
a Notifies the scheduler that it can stop monitoring this scheduler.
*/
void
gst_scheduler_remove_scheduler (GstScheduler * sched, GstScheduler * sched2)
{
GstSchedulerClass *sclass;
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_SCHEDULER (sched2));
g_return_if_fail (sched2->parent_sched == sched);
GST_DEBUG ("gstscheduler: %p remove scheduler %p", sched, sched2);
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->remove_scheduler)
sclass->remove_scheduler (sched, sched2);
sched->schedulers = g_list_remove (sched->schedulers, sched2);
sched2->parent_sched = NULL;
gst_object_unref (GST_OBJECT (sched2));
gst_object_unref (GST_OBJECT (sched));
}
/**
* gst_scheduler_lock_element:
* @sched: the scheduler
* @element: the element to lock
*
* Acquire a lock on the given element in the given scheduler.
*/
void
gst_scheduler_lock_element (GstScheduler * sched, GstElement * element)
{
g_return_if_fail (GST_IS_SCHEDULER (sched));
g_return_if_fail (GST_IS_ELEMENT (element));
}
/**
* gst_scheduler_unlock_element:
* @sched: the scheduler
* @element: the element to unlock
*
* Release the lock on the given element in the given scheduler.
*/
void
gst_scheduler_unlock_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);
}
/**
* gst_scheduler_error:
* @sched: the scheduler
* @element: the element with the error
*
* Tell the scheduler an element was in error
*/
void
gst_scheduler_error (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->error)
sclass->error (sched, element);
}
/**
* gst_scheduler_yield:
* @sched: the scheduler
* @element: the element requesting a yield
*
* Tell the scheduler to schedule another element.
*
* Returns: TRUE if the element should save its state, FALSE
* if the scheduler can perform this action itself.
*/
gboolean
gst_scheduler_yield (GstScheduler * sched, GstElement * element)
{
GstSchedulerClass *sclass;
g_return_val_if_fail (GST_IS_SCHEDULER (sched), TRUE);
g_return_val_if_fail (GST_IS_ELEMENT (element), TRUE);
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->yield)
return sclass->yield (sched, element);
return TRUE;
}
/**
* gst_scheduler_interrupt:
* @sched: the scheduler
* @element: the element requesting an interrupt
*
* Tell the scheduler to interrupt execution of this element.
*
* Returns: TRUE if the element should return NULL from the chain/get
* function.
*/
gboolean
gst_scheduler_interrupt (GstScheduler * sched, GstElement * element)
{
GstSchedulerClass *sclass;
g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->interrupt)
return sclass->interrupt (sched, element);
return FALSE;
}
/**
* gst_scheduler_get_clock:
* @sched: the scheduler
*
* Gets the current clock used by the scheduler.
*
* Returns: a GstClock
*/
GstClock *
gst_scheduler_get_clock (GstScheduler * sched)
{
GstClock *clock = NULL;
/* if we have a fixed clock, use that one */
if (GST_FLAG_IS_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK)) {
clock = sched->clock;
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)",
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
} else {
GList *schedulers = sched->schedulers;
GList *providers = sched->clock_providers;
/* try to get a clock from one of the schedulers we manage first */
while (schedulers) {
GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
clock = gst_scheduler_get_clock (scheduler);
if (clock) {
GST_CAT_DEBUG (GST_CAT_CLOCK,
"scheduler found managed sched clock %p (%s)",
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
break;
}
schedulers = g_list_next (schedulers);
}
/* still no clock, try to find one in the providers */
while (!clock && providers) {
clock = gst_element_get_clock (GST_ELEMENT (providers->data));
if (clock)
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler found provider clock: %p (%s)",
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
providers = g_list_next (providers);
}
/* still no clock, use a system clock */
if (!clock && sched->parent_sched == NULL) {
clock = gst_system_clock_obtain ();
/* we unref since this function is not supposed to increase refcount
* of clock object returned; this is ok since the systemclock always
* has a refcount of at least one in the current code. */
gst_object_unref (GST_OBJECT (clock));
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler obtained system clock: %p (%s)",
clock, clock ? GST_STR_NULL (GST_OBJECT_NAME (clock)) : "-");
}
}
return clock;
}
/**
* gst_scheduler_use_clock:
* @sched: the scheduler
* @clock: the clock to use
*
* Force the scheduler to use the given clock. The scheduler will
* always use the given clock even if new clock providers are added
* to this scheduler.
*/
void
gst_scheduler_use_clock (GstScheduler * sched, GstClock * clock)
{
g_return_if_fail (sched != NULL);
g_return_if_fail (GST_IS_SCHEDULER (sched));
GST_FLAG_SET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
gst_object_replace ((GstObject **) & sched->clock, (GstObject *) clock);
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using fixed clock %p (%s)", clock,
(clock ? GST_OBJECT_NAME (clock) : "nil"));
}
/**
* gst_scheduler_set_clock:
* @sched: the scheduler
* @clock: the clock to set
*
* Set the clock for the scheduler. The clock will be distributed
* to all the elements managed by the scheduler.
*/
void
gst_scheduler_set_clock (GstScheduler * sched, GstClock * clock)
{
GList *receivers;
GList *schedulers;
g_return_if_fail (sched != NULL);
g_return_if_fail (GST_IS_SCHEDULER (sched));
receivers = sched->clock_receivers;
schedulers = sched->schedulers;
gst_object_replace ((GstObject **) & sched->current_clock,
(GstObject *) clock);
while (receivers) {
GstElement *element = GST_ELEMENT (receivers->data);
GST_CAT_DEBUG (GST_CAT_CLOCK,
"scheduler setting clock %p (%s) on element %s", clock,
(clock ? GST_OBJECT_NAME (clock) : "nil"), GST_ELEMENT_NAME (element));
gst_element_set_clock (element, clock);
receivers = g_list_next (receivers);
}
while (schedulers) {
GstScheduler *scheduler = GST_SCHEDULER (schedulers->data);
GST_CAT_DEBUG (GST_CAT_CLOCK,
"scheduler setting clock %p (%s) on scheduler %p", clock,
(clock ? GST_OBJECT_NAME (clock) : "nil"), scheduler);
gst_scheduler_set_clock (scheduler, clock);
schedulers = g_list_next (schedulers);
}
}
/**
* gst_scheduler_auto_clock:
* @sched: the scheduler
*
* Let the scheduler select a clock automatically.
*/
void
gst_scheduler_auto_clock (GstScheduler * sched)
{
g_return_if_fail (sched != NULL);
g_return_if_fail (GST_IS_SCHEDULER (sched));
GST_FLAG_UNSET (sched, GST_SCHEDULER_FLAG_FIXED_CLOCK);
gst_object_replace ((GstObject **) & sched->clock, NULL);
GST_CAT_DEBUG (GST_CAT_CLOCK, "scheduler using automatic clock");
}
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_iterate:
* @sched: the scheduler
*
* Perform one iteration on the scheduler.
*
* Returns: a boolean indicating something usefull has happened.
*/
gboolean
gst_scheduler_iterate (GstScheduler * sched)
{
GstSchedulerClass *sclass;
gboolean res = FALSE;
g_return_val_if_fail (GST_IS_SCHEDULER (sched), FALSE);
sclass = GST_SCHEDULER_GET_CLASS (sched);
if (sclass->iterate) {
res = sclass->iterate (sched);
}
return res;
}
/**
* 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);
return result;
}
/*
@ -970,8 +345,6 @@ gst_scheduler_factory_create (GstSchedulerFactory * factory,
sched = GST_SCHEDULER (g_object_new (factory->type, NULL));
sched->parent = parent;
GST_ELEMENT_SCHEDULER (parent) = sched;
/* let's refcount the scheduler */
gst_object_ref (GST_OBJECT (sched));
gst_object_sink (GST_OBJECT (sched));

View file

@ -27,6 +27,7 @@
#include <glib.h>
#include <gst/gstelement.h>
#include <gst/gstbin.h>
#include <gst/gsttask.h>
G_BEGIN_DECLS
@ -38,11 +39,6 @@ G_BEGIN_DECLS
#define GST_SCHEDULER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SCHEDULER, GstSchedulerClass))
typedef enum {
/* this scheduler works with a fixed clock */
GST_SCHEDULER_FLAG_FIXED_CLOCK = GST_OBJECT_FLAG_LAST,
/* this scheduler supports select and lock calls */
GST_SCHEDULER_FLAG_NEW_API,
/* padding */
GST_SCHEDULER_FLAG_LAST = GST_OBJECT_FLAG_LAST + 4
} GstSchedulerFlags;
@ -52,27 +48,11 @@ typedef enum {
/*typedef struct _GstScheduler GstScheduler; */
/*typedef struct _GstSchedulerClass GstSchedulerClass; */
typedef enum {
GST_SCHEDULER_STATE_NONE,
GST_SCHEDULER_STATE_RUNNING,
GST_SCHEDULER_STATE_STOPPED,
GST_SCHEDULER_STATE_ERROR
} GstSchedulerState;
struct _GstScheduler {
GstObject object;
GstElement *parent;
GstScheduler *parent_sched;
GstSchedulerState state;
GstClock *clock;
GstClock *current_clock;
GList *clock_providers;
GList *clock_receivers;
GList *schedulers;
gpointer _gst_reserved[GST_PADDING];
};
@ -83,32 +63,8 @@ struct _GstSchedulerClass {
/* virtual methods */
void (*setup) (GstScheduler *sched);
void (*reset) (GstScheduler *sched);
void (*add_element) (GstScheduler *sched, GstElement *element);
void (*remove_element) (GstScheduler *sched, GstElement *element);
void (*add_scheduler) (GstScheduler *sched, GstScheduler *sched2);
void (*remove_scheduler) (GstScheduler *sched, GstScheduler *sched2);
GstElementStateReturn (*state_transition) (GstScheduler *sched, GstElement *element, gint transition);
void (*scheduling_change) (GstScheduler *sched, GstElement *element);
/* next two are optional, require NEW_API flag */
/* FIXME 0.9: rename to (un)lock_object */
void (*lock_element) (GstScheduler *sched, GstObject *object);
void (*unlock_element) (GstScheduler *sched, GstObject *object);
gboolean (*yield) (GstScheduler *sched, GstElement *element);
gboolean (*interrupt) (GstScheduler *sched, GstElement *element);
void (*error) (GstScheduler *sched, GstElement *element);
void (*pad_link) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
void (*pad_unlink) (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
/* optional, requires NEW_API flag */
GstData * (*pad_select) (GstScheduler *sched, GstPad **selected, GstPad **pads);
GstClockReturn (*clock_wait) (GstScheduler *sched, GstElement *element,
GstClockID id, GstClockTimeDiff *jitter);
GstSchedulerState (*iterate) (GstScheduler *sched);
/* for debugging */
void (*show) (GstScheduler *sched);
/* signals */
void (*object_sync) (GstScheduler *sched, GstClock *clock, GstObject *object,
GstClockID id);
GstTask* (*create_task) (GstScheduler *sched, GstTaskFunction func, gpointer data);
gpointer _gst_reserved[GST_PADDING];
};
@ -118,34 +74,8 @@ GType gst_scheduler_get_type (void);
void gst_scheduler_setup (GstScheduler *sched);
void gst_scheduler_reset (GstScheduler *sched);
void gst_scheduler_add_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_remove_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_add_scheduler (GstScheduler *sched, GstScheduler *sched2);
void gst_scheduler_remove_scheduler (GstScheduler *sched, GstScheduler *sched2);
GstElementStateReturn gst_scheduler_state_transition (GstScheduler *sched, GstElement *element, gint transition);
void gst_scheduler_scheduling_change (GstScheduler *sched, GstElement *element);
#ifndef GST_DISABLE_DEPRECATED
void gst_scheduler_lock_element (GstScheduler *sched, GstElement *element);
void gst_scheduler_unlock_element (GstScheduler *sched, GstElement *element);
#endif
gboolean gst_scheduler_yield (GstScheduler *sched, GstElement *element);
gboolean gst_scheduler_interrupt (GstScheduler *sched, GstElement *element);
void gst_scheduler_error (GstScheduler *sched, GstElement *element);
void gst_scheduler_pad_link (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
void gst_scheduler_pad_unlink (GstScheduler *sched, GstPad *srcpad, GstPad *sinkpad);
#ifndef GST_DISABLE_DEPRECATED
GstPad* gst_scheduler_pad_select (GstScheduler *sched, GList *padlist);
#endif
GstClockReturn gst_scheduler_clock_wait (GstScheduler *sched, GstElement *element,
GstClockID id, GstClockTimeDiff *jitter);
gboolean gst_scheduler_iterate (GstScheduler *sched);
GstTask* gst_scheduler_create_task (GstScheduler *sched, GstTaskFunction func, gpointer data);
void gst_scheduler_use_clock (GstScheduler *sched, GstClock *clock);
void gst_scheduler_set_clock (GstScheduler *sched, GstClock *clock);
GstClock* gst_scheduler_get_clock (GstScheduler *sched);
void gst_scheduler_auto_clock (GstScheduler *sched);
void gst_scheduler_show (GstScheduler *sched);
/*
* creating schedulers
@ -159,7 +89,7 @@ void gst_scheduler_show (GstScheduler *sched);
#define GST_SCHEDULER_FACTORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_SCHEDULER_FACTORY, GstSchedulerFactoryClass))
/* change this to change the default scheduler */
#define GST_SCHEDULER_DEFAULT_NAME "opt"
#define GST_SCHEDULER_DEFAULT_NAME "thread"
typedef struct _GstSchedulerFactory GstSchedulerFactory;
typedef struct _GstSchedulerFactoryClass GstSchedulerFactoryClass;

View file

@ -61,7 +61,7 @@ static gboolean gst_structure_parse_simple_string (gchar * s, gchar ** end);
GType
gst_structure_get_type (void)
{
static GType gst_structure_type;
static GType gst_structure_type = 0;
if (!gst_structure_type) {
gst_structure_type = g_boxed_type_register_static ("GstStructure",

View file

@ -54,7 +54,7 @@ struct _GstStructure {
gpointer _gst_reserved[GST_PADDING];
};
GType gst_structure_get_type (void) G_GNUC_CONST;
GType gst_structure_get_type (void);
GstStructure * gst_structure_empty_new (const gchar * name);
GstStructure * gst_structure_id_empty_new (GQuark quark);

View file

@ -46,7 +46,7 @@ struct _GstTagSetterIFace
/* virtual table */
};
GType gst_tag_setter_get_type (void) G_GNUC_CONST;
GType gst_tag_setter_get_type (void);
void gst_tag_setter_merge (GstTagSetter * setter,
const GstTagList * list,

View file

@ -46,7 +46,7 @@ struct _GstTagSetterIFace
/* virtual table */
};
GType gst_tag_setter_get_type (void) G_GNUC_CONST;
GType gst_tag_setter_get_type (void);
void gst_tag_setter_merge (GstTagSetter * setter,
const GstTagList * list,

210
gst/gsttask.c Normal file
View file

@ -0,0 +1,210 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gsttask.c: Streaming tasks
*
* 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 "gstinfo.h"
#include "gsttask.h"
static void gst_task_class_init (GstTaskClass * klass);
static void gst_task_init (GstTask * task);
static void gst_task_dispose (GObject * object);
static GstObjectClass *parent_class = NULL;
GType
gst_task_get_type (void)
{
static GType _gst_task_type = 0;
if (!_gst_task_type) {
static const GTypeInfo task_info = {
sizeof (GstTaskClass),
NULL,
NULL,
(GClassInitFunc) gst_task_class_init,
NULL,
NULL,
sizeof (GstTask),
0,
(GInstanceInitFunc) gst_task_init,
NULL
};
_gst_task_type =
g_type_register_static (GST_TYPE_OBJECT, "GstTask",
&task_info, G_TYPE_FLAG_ABSTRACT);
}
return _gst_task_type;
}
static void
gst_task_class_init (GstTaskClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_OBJECT);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_task_dispose);
}
static void
gst_task_init (GstTask * task)
{
task->cond = g_cond_new ();
task->state = GST_TASK_STOPPED;
}
static void
gst_task_dispose (GObject * object)
{
GstTask *task = GST_TASK (object);
GST_DEBUG ("task %p dispose", task);
g_cond_free (task->cond);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
/**
* gst_task_create:
* @func: The #GstTaskFunction to use
* @data: User data to pass to @func
*
* Create a new Task that will repeadedly call the provided @func
* with @data as a parameter. Typically the task will run in
* a new thread.
*
* Returns: A new #GstTask.
*
* MT safe.
*/
GstTask *
gst_task_create (GstTaskFunction func, gpointer data)
{
return NULL;
}
/**
* gst_task_get_state:
* @task: The #GstTask to query
*
* Get the current state of the task.
*
* Returns: The #GstTaskState of the task
*
* MT safe.
*/
GstTaskState
gst_task_get_state (GstTask * task)
{
GstTaskState result;
g_return_val_if_fail (GST_IS_TASK (task), GST_TASK_STOPPED);
GST_LOCK (task);
result = task->state;
GST_UNLOCK (task);
return result;
}
/**
* gst_task_start:
* @task: The #GstTask to start
*
* Starts @task.
*
* Returns: TRUE if the task could be started.
*
* MT safe.
*/
gboolean
gst_task_start (GstTask * task)
{
GstTaskClass *tclass;
gboolean result = FALSE;
g_return_val_if_fail (GST_IS_TASK (task), FALSE);
tclass = GST_TASK_GET_CLASS (task);
if (tclass->start)
result = tclass->start (task);
return result;
}
/**
* gst_task_stop:
* @task: The #GstTask to stop
*
* Stops @task.
*
* Returns: TRUE if the task could be stopped.
*
* MT safe.
*/
gboolean
gst_task_stop (GstTask * task)
{
GstTaskClass *tclass;
gboolean result = FALSE;
g_return_val_if_fail (GST_IS_TASK (task), FALSE);
tclass = GST_TASK_GET_CLASS (task);
if (tclass->stop)
result = tclass->stop (task);
return result;
}
/**
* gst_task_pause:
* @task: The #GstTask to pause
*
* Pauses @task.
*
* Returns: TRUE if the task could be paused.
*
* MT safe.
*/
gboolean
gst_task_pause (GstTask * task)
{
GstTaskClass *tclass;
gboolean result = FALSE;
g_return_val_if_fail (GST_IS_TASK (task), FALSE);
tclass = GST_TASK_GET_CLASS (task);
if (tclass->pause)
result = tclass->pause (task);
return result;
}

96
gst/gsttask.h Normal file
View file

@ -0,0 +1,96 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2005> Wim Taymans <wim@fluendo.com>
*
* gsttask.h: Streaming tasks
*
* 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_TASK_H__
#define __GST_TASK_H__
#include <gst/gstobject.h>
G_BEGIN_DECLS
typedef void (*GstTaskFunction) (void *data);
/* --- standard type macros --- */
#define GST_TYPE_TASK (gst_task_get_type ())
#define GST_TASK(task) (G_TYPE_CHECK_INSTANCE_CAST ((task), GST_TYPE_TASK, GstTask))
#define GST_IS_TASK(task) (G_TYPE_CHECK_INSTANCE_TYPE ((task), GST_TYPE_TASK))
#define GST_TASK_CLASS(tclass) (G_TYPE_CHECK_CLASS_CAST ((tclass), GST_TYPE_TASK, GstTaskClass))
#define GST_IS_TASK_CLASS(tclass) (G_TYPE_CHECK_CLASS_TYPE ((tclass), GST_TYPE_TASK))
#define GST_TASK_GET_CLASS(task) (G_TYPE_INSTANCE_GET_CLASS ((task), GST_TYPE_TASK, GstTaskClass))
#define GST_TASK_CAST(task) ((GstTask*)(task))
typedef struct _GstTask GstTask;
typedef struct _GstTaskClass GstTaskClass;
typedef enum {
GST_TASK_STARTED,
GST_TASK_STOPPED,
GST_TASK_PAUSED,
} GstTaskState;
#define GST_TASK_STATE(task) (GST_TASK_CAST(task)->state)
#define GST_TASK_GET_COND(task) (GST_TASK_CAST(task)->cond)
#define GST_TASK_WAIT(task) g_cond_wait(GST_TASK_GET_COND (task), GST_GET_LOCK (task))
#define GST_TASK_SIGNAL(task) g_cond_signal(GST_TASK_GET_COND (task))
#define GST_TASK_BROADCAST(task) g_cond_breadcast(GST_TASK_GET_COND (task))
struct _GstTask {
GstObject object;
/*< public >*/ /* with TASK_LOCK */
GstTaskState state;
GCond *cond;
GstTaskFunction func;
gpointer data;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
struct _GstTaskClass {
GstObjectClass parent_class;
/*< protected >*/
gboolean (*start) (GstTask *task);
gboolean (*stop) (GstTask *task);
gboolean (*pause) (GstTask *task);
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
};
GType gst_task_get_type (void);
GstTask* gst_task_create (GstTaskFunction func, gpointer data);
GstTaskState gst_task_get_state (GstTask *task);
gboolean gst_task_start (GstTask *task);
gboolean gst_task_stop (GstTask *task);
gboolean gst_task_pause (GstTask *task);
G_END_DECLS
#endif /* __GST_TASK_H__ */

View file

@ -1,746 +0,0 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gstthread.c: Threaded container object
*
* 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 "gstthread.h"
#include "gstmarshal.h"
#include "gstscheduler.h"
#include "gstutils.h"
#include "gstinfo.h"
#define GST_CAT_DEFAULT GST_CAT_THREAD
#define STACK_SIZE 0x200000
static GstElementDetails gst_thread_details =
GST_ELEMENT_DETAILS ("Threaded container",
"Generic/Bin",
"Container that creates/manages a thread",
"Erik Walthinsen <omega@cse.ogi.edu>, "
"Benjamin Otte <in7y118@informatik.uni-hamburg.de"
"Wim Taymans <wim@fluendo.com");
/* Thread signals and args */
enum
{
SHUTDOWN,
/* FILL ME */
LAST_SIGNAL
};
enum
{
SPINUP = 0,
STATECHANGE,
STARTUP
};
enum
{
ARG_0,
ARG_PRIORITY
};
static void gst_thread_base_init (gpointer g_class);
static void gst_thread_class_init (gpointer g_class, gpointer class_data);
static void gst_thread_init (GTypeInstance * instance, gpointer g_class);
static void gst_thread_dispose (GObject * object);
static void gst_thread_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_thread_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstElementStateReturn gst_thread_change_state (GstElement * element);
static void gst_thread_child_state_change (GstBin * bin,
GstElementState oldstate, GstElementState newstate, GstElement * element);
static void gst_thread_sync (GstThread * thread, gboolean is_self);
#ifndef GST_DISABLE_LOADSAVE
static xmlNodePtr gst_thread_save_thyself (GstObject * object,
xmlNodePtr parent);
static void gst_thread_restore_thyself (GstObject * object, xmlNodePtr self);
#endif
static void *gst_thread_main_loop (void *arg);
#define GST_TYPE_THREAD_PRIORITY (gst_thread_priority_get_type())
static GType
gst_thread_priority_get_type (void)
{
static GType thread_priority_type = 0;
static GEnumValue thread_priority[] = {
{G_THREAD_PRIORITY_LOW, "LOW", "Low Priority Scheduling"},
{G_THREAD_PRIORITY_NORMAL, "NORMAL", "Normal Scheduling"},
{G_THREAD_PRIORITY_HIGH, "HIGH", "High Priority Scheduling"},
{G_THREAD_PRIORITY_URGENT, "URGENT", "Urgent Scheduling"},
{0, NULL, NULL},
};
if (!thread_priority_type) {
thread_priority_type =
g_enum_register_static ("GstThreadPriority", thread_priority);
}
return thread_priority_type;
}
static GstBinClass *parent_class = NULL;
static guint gst_thread_signals[LAST_SIGNAL] = { 0 };
GPrivate *gst_thread_current;
GType
gst_thread_get_type (void)
{
static GType thread_type = 0;
if (!thread_type) {
static const GTypeInfo thread_info = {
sizeof (GstThreadClass),
gst_thread_base_init,
NULL,
gst_thread_class_init,
NULL,
NULL,
sizeof (GstThread),
0,
gst_thread_init,
NULL
};
thread_type = g_type_register_static (GST_TYPE_BIN, "GstThread",
&thread_info, 0);
}
return thread_type;
}
static void
gst_thread_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (gstelement_class, &gst_thread_details);
}
static void
do_nothing (gpointer hi)
{
}
static void
gst_thread_class_init (gpointer g_class, gpointer class_data)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
#ifndef GST_DISABLE_LOADSAVE
GstObjectClass *gstobject_class = GST_OBJECT_CLASS (g_class);
#endif
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
GstBinClass *gstbin_class = GST_BIN_CLASS (g_class);
GstThreadClass *klass = GST_THREAD_CLASS (g_class);
/* setup gst_thread_current */
gst_thread_current = g_private_new (do_nothing);
parent_class = g_type_class_peek_parent (g_class);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_thread_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_thread_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_PRIORITY,
g_param_spec_enum ("priority", "Scheduling Policy",
"The scheduling priority of the thread", GST_TYPE_THREAD_PRIORITY,
G_THREAD_PRIORITY_NORMAL, G_PARAM_READWRITE));
gst_thread_signals[SHUTDOWN] =
g_signal_new ("shutdown", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstThreadClass, shutdown), NULL, NULL,
gst_marshal_VOID__VOID, G_TYPE_NONE, 0);
gobject_class->dispose = gst_thread_dispose;
#ifndef GST_DISABLE_LOADSAVE
gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_thread_save_thyself);
gstobject_class->restore_thyself =
GST_DEBUG_FUNCPTR (gst_thread_restore_thyself);
#endif
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_thread_change_state);
gstbin_class->child_state_change =
GST_DEBUG_FUNCPTR (gst_thread_child_state_change);
}
static void
gst_thread_init (GTypeInstance * instance, gpointer g_class)
{
GstScheduler *scheduler;
GstThread *thread = GST_THREAD (instance);
GST_DEBUG ("initializing thread");
/* threads are managing bins and iterate themselves */
/* CR1: the GstBin code checks these flags */
GST_FLAG_SET (thread, GST_BIN_FLAG_MANAGER);
GST_FLAG_SET (thread, GST_BIN_SELF_SCHEDULABLE);
scheduler = gst_scheduler_factory_make (NULL, GST_ELEMENT (thread));
g_assert (scheduler);
thread->lock = g_mutex_new ();
thread->cond = g_cond_new ();
thread->iterate_lock = g_mutex_new ();
thread->thread_id = (GThread *) NULL; /* set in NULL -> READY */
thread->priority = G_THREAD_PRIORITY_NORMAL;
}
static void
gst_thread_dispose (GObject * object)
{
GstThread *thread = GST_THREAD (object);
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose");
/* if we get here, the thread is really stopped as it has released
* the last refcount to the thread object, so we can safely free the
* mutex and cond vars */
G_OBJECT_CLASS (parent_class)->dispose (object);
g_assert (GST_STATE (thread) == GST_STATE_NULL);
GST_CAT_DEBUG (GST_CAT_REFCOUNTING, "GstThread: dispose, freeing locks");
g_mutex_free (thread->lock);
g_cond_free (thread->cond);
g_mutex_free (thread->iterate_lock);
gst_object_replace ((GstObject **) & GST_ELEMENT_SCHEDULER (thread), NULL);
}
/**
* gst_thread_set_priority:
* @thread: the thread to change
* @priority: the new priority for the thread
*
* change the thread's priority
*/
void
gst_thread_set_priority (GstThread * thread, GThreadPriority priority)
{
g_return_if_fail (GST_IS_THREAD (thread));
thread->priority = priority;
}
static void
gst_thread_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstThread *thread;
thread = GST_THREAD (object);
switch (prop_id) {
case ARG_PRIORITY:
thread->priority = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_thread_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstThread *thread;
thread = GST_THREAD (object);
switch (prop_id) {
case ARG_PRIORITY:
g_value_set_enum (value, thread->priority);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* gst_thread_new:
* @name: the name of the thread
*
* Create a new thread with the given name.
*
* Returns: The new thread
*/
GstElement *
gst_thread_new (const gchar * name)
{
return gst_element_factory_make ("thread", name);
}
/**
* gst_thread_get_current:
*
* Gets the current GstThread.
*
* Returns: The current GstThread or NULL if you are not running inside a
* #GstThread.
*/
GstThread *
gst_thread_get_current (void)
{
return (GstThread *) g_private_get (gst_thread_current);
}
static inline void
gst_thread_release_children_locks (GstThread * thread)
{
GstRealPad *peer = NULL;
GstElement *peerelement;
/* not MT safe but gstthread is going away soon */
GList *elements = (GList *) GST_BIN (thread)->children;
while (elements) {
GstElement *element = GST_ELEMENT (elements->data);
GList *pads;
g_assert (element);
GST_DEBUG_OBJECT (thread, "waking element \"%s\"",
GST_ELEMENT_NAME (element));
elements = g_list_next (elements);
if (!gst_element_release_locks (element))
g_warning ("element %s could not release locks",
GST_ELEMENT_NAME (element));
pads = GST_ELEMENT_PADS (element);
while (pads) {
if (GST_PAD_PEER (pads->data)) {
peer = GST_REAL_PAD (GST_PAD_PEER (pads->data));
pads = g_list_next (pads);
} else {
pads = g_list_next (pads);
continue;
}
if (!peer)
continue;
peerelement = GST_PAD_PARENT (peer);
if (!peerelement)
continue; /* FIXME: deal with case where there's no peer */
if (GST_ELEMENT_SCHEDULER (peerelement) != GST_ELEMENT_SCHEDULER (thread)) {
GST_LOG_OBJECT (thread, "element \"%s\" has pad cross sched boundary",
GST_ELEMENT_NAME (element));
GST_LOG_OBJECT (thread, "waking element \"%s\"",
GST_ELEMENT_NAME (peerelement));
if (!gst_element_release_locks (peerelement))
g_warning ("element %s could not release locks",
GST_ELEMENT_NAME (peerelement));
}
}
}
}
/* sync the main thread, if there is one and makes sure that the thread
* is not spinning and in the waiting state. We can only do this if
* this function is not called from the thread itself.
*
* This function should be called with the thread lock held.
*/
static void
gst_thread_sync (GstThread * thread, gboolean is_self)
{
if (thread->thread_id == NULL)
return;
/* need to stop spinning in any case */
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
if (is_self) {
/* we're trying to sync ourself. Not much we can do here but hope
* that the thread will stop spinning and end up in the waiting
* state */
GST_DEBUG_OBJECT (thread, "syncing itself");
} else {
GST_DEBUG_OBJECT (thread, "syncing thread, grabbing lock");
/* another thread is trying to sync us. The strategy is to
* repeadetly unlock the element locks until the thread is
* blocking in the waiting state. We use a timeout because
* unlocking all of the children at the same time is not
* atomic and might fail. */
while (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING)) {
GTimeVal tv;
GST_LOG_OBJECT (thread, "syncing thread...");
/* release child locks */
gst_thread_release_children_locks (thread);
g_get_current_time (&tv);
g_time_val_add (&tv, 1000); /* wait a millisecond to sync the thread */
GST_DEBUG_OBJECT (thread, "wait");
g_cond_timed_wait (thread->cond, thread->lock, &tv);
}
GST_LOG_OBJECT (thread, "caught thread");
/* at this point we should be waiting */
g_assert (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING));
}
g_assert (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING));
}
static GstElementStateReturn
gst_thread_change_state (GstElement * element)
{
GstThread *thread;
GstElementStateReturn ret;
gint transition;
gboolean is_self, reverting = FALSE;
g_return_val_if_fail (GST_IS_THREAD (element), GST_STATE_FAILURE);
GST_DEBUG_OBJECT (element, "changing state from %s to %s",
gst_element_state_get_name (GST_STATE (element)),
gst_element_state_get_name (GST_STATE_PENDING (element)));
thread = GST_THREAD (element);
/* boolean to check if we called the state change in the same thread as
* the iterate thread */
is_self = (thread == gst_thread_get_current ());
transition = GST_STATE_TRANSITION (element);
revert:
GST_LOG_OBJECT (thread, "grabbing lock");
g_mutex_lock (thread->lock);
gst_thread_sync (thread, is_self);
/* no iteration is allowed during this state change because an iteration
* can cause another state change conflicting with this one */
/* do not try to grab the lock if this method is called from the
* same thread as the iterate thread, the lock might be held and we
* might deadlock */
if (!is_self && !reverting)
g_mutex_lock (thread->iterate_lock);
switch (transition) {
case GST_STATE_NULL_TO_READY:{
GError *err = NULL;
/* create the thread */
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
GST_LOG_OBJECT (element, "grabbing lock");
thread->thread_id = g_thread_create_full (gst_thread_main_loop,
thread, STACK_SIZE, FALSE, TRUE, thread->priority, &err);
if (!thread->thread_id) {
GST_ERROR_OBJECT (element, "g_thread_create_full failed: %s",
err->message);
g_error_free (err);
goto error_out;
}
GST_LOG_OBJECT (element, "GThread created");
/* wait for it to 'spin up' */
g_cond_wait (thread->cond, thread->lock);
break;
}
case GST_STATE_READY_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_PLAYING:
{
/* reset self to spinning */
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
break;
}
case GST_STATE_PLAYING_TO_PAUSED:
{
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
break;
}
case GST_STATE_PAUSED_TO_READY:
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
break;
case GST_STATE_READY_TO_NULL:
/* we can't join the threads here, because this could have been triggered
by ourself (ouch) */
GST_LOG_OBJECT (thread, "destroying GThread %p", thread->thread_id);
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
/* thread was already gone */
if (thread->thread_id != NULL) {
thread->thread_id = NULL;
if (is_self) {
GST_LOG_OBJECT (thread,
"Thread %s is destroying itself. Returning to mainloop ASAP!",
GST_ELEMENT_NAME (thread));
break;
} else {
/* now wait for the thread to destroy itself */
GST_DEBUG_OBJECT (thread, "signal");
g_cond_signal (thread->cond);
GST_DEBUG_OBJECT (thread, "wait");
g_cond_wait (thread->cond, thread->lock);
GST_DEBUG_OBJECT (thread, "done");
/* it should be dead now */
}
}
break;
default:
break;
}
GST_LOG_OBJECT (thread, "unlocking lock");
g_mutex_unlock (thread->lock);
if (reverting) {
goto error_out_unlocked;
} else if (GST_ELEMENT_CLASS (parent_class)->change_state) {
ret = GST_ELEMENT_CLASS (parent_class)->change_state (GST_ELEMENT (thread));
if (ret == GST_STATE_FAILURE) {
reverting = TRUE;
transition = ((transition & 0xff) << 8) | (transition >> 8);
goto revert;
}
} else {
ret = GST_STATE_SUCCESS;
}
g_mutex_lock (thread->lock);
if (GST_STATE (thread) == GST_STATE_PLAYING &&
GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING)) {
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
if (!is_self) {
g_cond_signal (thread->cond);
}
}
g_mutex_unlock (thread->lock);
if (!is_self)
g_mutex_unlock (thread->iterate_lock);
return ret;
error_out:
GST_CAT_DEBUG (GST_CAT_STATES, "changing state from %s to %s failed for %s",
gst_element_state_get_name (GST_STATE (element)),
gst_element_state_get_name (GST_STATE_PENDING (element)),
GST_ELEMENT_NAME (element));
g_mutex_unlock (thread->lock);
error_out_unlocked:
if (!is_self)
g_mutex_unlock (thread->iterate_lock);
return GST_STATE_FAILURE;
}
/* When a child changes its state the thread might have to start.
*
* When we are in the thread context we set the spinning flag.
* When we are not in the thread context, we grab the lock. The
* thread can then only be in the waiting or spinning state. If it's
* waiting we signal it to start. If it was spinning, we let it spin.
*/
static void
gst_thread_child_state_change (GstBin * bin, GstElementState oldstate,
GstElementState newstate, GstElement * element)
{
GstThread *thread = GST_THREAD (bin);
gboolean is_self;
GstThread *current;
current = gst_thread_get_current ();
is_self = (current == thread);
GST_LOG_OBJECT (bin, "(from thread %s) child %s changed state from %s to %s",
current ? GST_ELEMENT_NAME (current) :
"(none)", GST_ELEMENT_NAME (element),
gst_element_state_get_name (oldstate),
gst_element_state_get_name (newstate));
if (parent_class->child_state_change)
parent_class->child_state_change (bin, oldstate, newstate, element);
/* if we're changing from playing to paused, kids will one-by-one go
* to paused while we're playing, which is bad if we execute the code
* below. We should only do that when a child explicitely changed
* state outside our own context. */
if (GST_FLAG_IS_SET (bin, GST_BIN_STATE_LOCKED))
return;
/* see if we have to wake up the thread now. */
if (is_self) {
GST_LOG_OBJECT (element, "we are in the thread context");
/* we are the thread, set the spinning flag so that we start spinning
* next time */
if (newstate == GST_STATE_PLAYING) {
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
}
} else {
g_mutex_lock (thread->lock);
/* thread is now spinning or waiting after grabbing the lock */
if (newstate == GST_STATE_PLAYING) {
if (!GST_FLAG_IS_SET (thread, GST_THREAD_STATE_WAITING)) {
/* its spinning, that's not really a problem, it will
* continue to do so */
GST_LOG_OBJECT (element, "thread is playing");
} else {
/* waiting, set spinning flag and trigger restart. */
GST_LOG_OBJECT (element, "signal playing");
GST_FLAG_SET (thread, GST_THREAD_STATE_SPINNING);
g_cond_signal (GST_THREAD (bin)->cond);
}
}
g_mutex_unlock (thread->lock);
}
GST_LOG_OBJECT (element, "done child state change");
}
/**
* gst_thread_main_loop:
* @arg: the thread to start
*
* The main loop of the thread. The thread will iterate
* while the state is GST_THREAD_STATE_SPINNING.
*/
static void *
gst_thread_main_loop (void *arg)
{
GstThread *thread = NULL;
GstElement *element = NULL;
GstScheduler *sched;
thread = GST_THREAD (arg);
GST_LOG_OBJECT (element, "grabbing lock");
g_mutex_lock (thread->lock);
element = GST_ELEMENT (arg);
GST_LOG_OBJECT (thread, "Started main loop");
/* initialize gst_thread_current */
g_private_set (gst_thread_current, thread);
/* set up the element's scheduler */
gst_scheduler_setup (GST_ELEMENT_SCHEDULER (thread));
GST_FLAG_UNSET (thread, GST_THREAD_STATE_REAPING);
GST_FLAG_UNSET (thread, GST_THREAD_STATE_WAITING);
/* signals the startup of the thread */
GST_LOG_OBJECT (element, "signal");
g_cond_signal (thread->cond);
GST_LOG_OBJECT (element, "unlocking lock");
gst_object_ref (GST_OBJECT (thread));
/* as long as we're not dying we can continue */
while (!(GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING))) {
/* in the playing state we need to do something special */
if (GST_STATE (thread) == GST_STATE_PLAYING) {
GST_LOG_OBJECT (thread, "starting to iterate");
/* continue iteration while spinning */
while (GST_FLAG_IS_SET (thread, GST_THREAD_STATE_SPINNING)) {
gboolean status;
g_mutex_unlock (thread->lock);
g_mutex_lock (thread->iterate_lock);
status = gst_bin_iterate (GST_BIN (thread));
g_mutex_unlock (thread->iterate_lock);
g_mutex_lock (thread->lock);
if (!status) {
GST_DEBUG_OBJECT (thread, "iterate returned false");
if (GST_STATE (thread) != GST_STATE_PLAYING) {
GST_DEBUG_OBJECT (thread,
"stopping spinning as state is not playing");
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
}
}
/* if we hold the last refcount, the app unreffed the
* thread and we should stop ASAP */
if (G_OBJECT (thread)->ref_count == 1) {
GST_DEBUG_OBJECT (thread, "reaping as refcount is only 1");
GST_FLAG_SET (thread, GST_THREAD_STATE_REAPING);
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
}
}
}
/* do not try to sync when we are REAPING */
if (!(GST_FLAG_IS_SET (thread, GST_THREAD_STATE_REAPING))) {
/* sync section */
GST_LOG_OBJECT (thread, "entering sync");
GST_DEBUG_OBJECT (thread, "signal");
g_cond_signal (thread->cond);
GST_DEBUG_OBJECT (thread, "wait");
GST_FLAG_UNSET (thread, GST_THREAD_STATE_SPINNING);
GST_FLAG_SET (thread, GST_THREAD_STATE_WAITING);
g_cond_wait (thread->cond, thread->lock);
GST_FLAG_UNSET (thread, GST_THREAD_STATE_WAITING);
GST_LOG_OBJECT (thread, "wait done");
}
}
GST_LOG_OBJECT (thread, "unlocking lock");
thread->thread_id = NULL;
g_mutex_unlock (thread->lock);
/* we need to destroy the scheduler here because it might have
* mapped it's stack into the threads stack space */
sched = GST_ELEMENT_SCHEDULER (thread);
if (sched)
gst_scheduler_reset (sched);
g_signal_emit (G_OBJECT (thread), gst_thread_signals[SHUTDOWN], 0);
/* signal - we are out */
GST_LOG_OBJECT (thread, "Thread %p exits main loop", g_thread_self ());
g_cond_signal (thread->cond);
gst_object_unref (GST_OBJECT (thread));
/* don't assume the GstThread object exists anymore now */
return NULL;
}
#ifndef GST_DISABLE_LOADSAVE
static xmlNodePtr
gst_thread_save_thyself (GstObject * object, xmlNodePtr self)
{
if (GST_OBJECT_CLASS (parent_class)->save_thyself)
GST_OBJECT_CLASS (parent_class)->save_thyself (object, self);
return NULL;
}
static void
gst_thread_restore_thyself (GstObject * object, xmlNodePtr self)
{
GST_LOG_OBJECT (object, "restoring");
if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
GST_OBJECT_CLASS (parent_class)->restore_thyself (object, self);
}
#endif /* GST_DISABLE_LOADSAVE */

View file

@ -1,88 +0,0 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* gstthread.h: Header for GstThread object
*
* 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_THREAD_H__
#define __GST_THREAD_H__
#include <glib.h>
#include <gst/gstbin.h>
G_BEGIN_DECLS
extern GPrivate *gst_thread_current;
typedef enum {
GST_THREAD_STATE_SPINNING = GST_BIN_FLAG_LAST,
GST_THREAD_STATE_REAPING,
GST_THREAD_STATE_WAITING,
/* padding */
GST_THREAD_FLAG_LAST = GST_BIN_FLAG_LAST + 4
} GstThreadState;
#define GST_TYPE_THREAD (gst_thread_get_type())
#define GST_THREAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_THREAD,GstThread))
#define GST_IS_THREAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_THREAD))
#define GST_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_THREAD,GstThreadClass))
#define GST_IS_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_THREAD))
#define GST_THREAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_THREAD, GstThreadClass))
typedef struct _GstThread GstThread;
typedef struct _GstThreadClass GstThreadClass;
struct _GstThread {
GstBin bin;
GThread *thread_id; /* id of the thread, if any */
GThreadPriority priority;
GMutex *lock; /* thread lock/condititon pairs */
GCond *cond; /* used to control the thread */
GMutex *iterate_lock; /* lock iteration in state change */
gpointer _gst_reserved[GST_PADDING-1];
};
struct _GstThreadClass {
GstBinClass parent_class;
/* signals */
void (*shutdown) (GstThread *thread);
gpointer _gst_reserved[GST_PADDING];
};
GType gst_thread_get_type (void);
GstElement* gst_thread_new (const gchar *name);
void gst_thread_set_priority (GstThread *thread, GThreadPriority priority);
GstThread * gst_thread_get_current (void);
G_END_DECLS
#endif /* __GST_THREAD_H__ */

View file

@ -41,6 +41,7 @@ typedef struct _GstBusClass GstBusClass;
typedef struct _GstScheduler GstScheduler;
typedef struct _GstSchedulerClass GstSchedulerClass;
typedef struct _GstEvent GstEvent;
typedef struct _GstMessage GstMessage;
typedef enum {
GST_STATE_VOID_PENDING = 0,

View file

@ -1,82 +1,15 @@
if GST_DISABLE_OMEGA_COTHREADS
omegaschedulers =
omegaschedulers_nola =
else
omegaschedulers = \
libgstbasicomegascheduler.la \
libgstentryomegascheduler.la \
libgstoptomegascheduler.la
omegaschedulers_nola = \
libgstbasicomegascheduler \
libgstentryomegascheduler \
libgstoptomegascheduler
endif
plugin_LTLIBRARIES = \
$(omegaschedulers) \
libgstbasicgthreadscheduler.la \
libgstentrygthreadscheduler.la \
libgstoptscheduler.la \
libgstoptgthreadscheduler.la \
libgstfairgthreadscheduler.la
libthreadscheduler.la
AS_LIBTOOL_LIBS = \
$(omegaschedulers_nola) \
libgstbasicgthreadscheduler \
libgstentrygthreadscheduler \
libgstoptscheduler \
libgstoptgthreadscheduler \
libgstfairgthreadscheduler
libthreadscheduler
if GST_DISABLE_OMEGA_COTHREADS
else
libgstbasicomegascheduler_la_SOURCES = gstbasicscheduler.c
libgstbasicomegascheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_OMEGA
libgstbasicomegascheduler_la_LIBADD = $(GST_OBJ_LIBS) ../libcothreads.la
libgstbasicomegascheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
endif
libthreadscheduler_la_SOURCES = threadscheduler.c
libthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS)
libthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
libthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstbasicgthreadscheduler_la_SOURCES = gstbasicscheduler.c
libgstbasicgthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD
libgstbasicgthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
libgstbasicgthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
libgstentrygthreadscheduler_la_SOURCES = entryscheduler.c
libgstentrygthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD
libgstentrygthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
libgstentrygthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
if GST_DISABLE_OMEGA_COTHREADS
else
libgstentryomegascheduler_la_SOURCES = entryscheduler.c
libgstentryomegascheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_OMEGA
libgstentryomegascheduler_la_LIBADD = $(GST_OBJ_LIBS) ../libcothreads.la
libgstentryomegascheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
endif
libgstoptscheduler_la_SOURCES = gstoptimalscheduler.c
libgstoptscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS)
libgstoptscheduler_la_LIBADD = $(GST_OBJ_LIBS)
libgstoptscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
if GST_DISABLE_OMEGA_COTHREADS
else
libgstoptomegascheduler_la_SOURCES = gstoptimalscheduler.c
libgstoptomegascheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_OMEGA -DUSE_COTHREADS
libgstoptomegascheduler_la_LIBADD = $(GST_OBJ_LIBS) ../libcothreads.la
libgstoptomegascheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
endif
libgstoptgthreadscheduler_la_SOURCES = gstoptimalscheduler.c
libgstoptgthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD -DUSE_COTHREADS
libgstoptgthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
libgstoptgthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
libgstfairgthreadscheduler_la_SOURCES = fairscheduler.c faircothreads.c
libgstfairgthreadscheduler_la_CFLAGS = $(GST_OBJ_CFLAGS) -D_COTHREADS_GTHREAD
libgstfairgthreadscheduler_la_LIBADD = $(GST_OBJ_LIBS)
libgstfairgthreadscheduler_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS)
noinst_HEADERS = cothreads_compat.h gthread-cothreads.h faircothreads.h
noinst_HEADERS =
if AS_LIBTOOL_WIN32

View file

@ -1,79 +0,0 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
*
* cothreads_compat.h: Compatibility macros between cothreads packages
*
* 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.
*/
/* use the old cothreads implementation in gst/cothreads.[ch] */
#if defined(_COTHREADS_OMEGA)
#include "../cothreads.h"
/* the name of this cothreads type */
#define COTHREADS_TYPE omega
#define COTHREADS_NAME "omega"
#define COTHREADS_NAME_CAPITAL "Omega"
/* unify the structs
*
* "cothread" and "cothread_context" need to be defined
*/
typedef struct _cothread_state cothread;
/* define functions
* the macros are prepended with "do_"
*/
#define do_cothreads_init(x) /* NOP */
#define do_cothreads_stackquery(stack,size) cothread_stackquery(stack,size)
#define do_cothread_switch(to) cothread_switch(to)
#define do_cothread_create(new_cothread, context, func, argc, argv) \
G_STMT_START{ \
new_cothread = cothread_create (context); \
if (new_cothread) { \
cothread_setfunc (new_cothread, (func), (argc), (argv)); \
} \
}G_STMT_END
#define do_cothread_setfunc(cothread, context, func, argc, argv) \
cothread_setfunc ((cothread), (func), (argc), (argv))
#define do_cothread_destroy(cothread) cothread_free(cothread)
#define do_cothread_context_init() (cothread_context_init ())
#define do_cothread_context_destroy(context) cothread_context_free (context)
#define do_cothread_get_current(context) (cothread_current())
#define do_cothread_get_main(context) (cothread_current_main())
/* use the gthread-based cothreads implementation */
#elif defined(_COTHREADS_GTHREAD)
#include "gthread-cothreads.h"
/* bail out with an error if no cothreads package is defined */
#else
#error "No cothreads package defined"
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,615 +0,0 @@
/* GStreamer
* Copyright (C) 2004 Martin Soto <martinsoto@users.sourceforge.net>
*
* faircothread.c: High level cothread implementation for the fair scheduler.
*
* 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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <glib.h>
#include <gst/gst.h>
#ifdef _COTHREADS_PTH
#include "pth-cothreads.h"
#else
#include "cothreads_compat.h"
#endif
#include "faircothreads.h"
#if !defined(GST_DISABLE_GST_DEBUG) && defined(FAIRSCHEDULER_USE_GETTID)
#include <sys/types.h>
#include <linux/unistd.h>
_syscall0 (pid_t, gettid)
#endif
GST_DEBUG_CATEGORY_EXTERN (debug_fair_ct);
#define GST_CAT_DEFAULT debug_fair_ct
/*
* Support for Asynchronous Operations
*/
enum
{
ASYNC_OP_CHANGE_STATE = 1,
ASYNC_OP_AWAKE
};
typedef struct _AsyncOp AsyncOp;
typedef struct _AsyncOpChangeState AsyncOpChangeState;
typedef struct _AsyncOpAwake AsyncOpAwake;
struct _AsyncOp
{
int type;
};
struct _AsyncOpChangeState
{
AsyncOp parent;
GstFairSchedulerCothread *ct; /* Cothread whose state will be
changed. */
gint new_state; /* New state for the cothread. */
};
struct _AsyncOpAwake
{
AsyncOp parent;
GstFairSchedulerCothread *ct; /* Cothread to awake. */
gint priority; /* Priority for the cothread. */
};
#ifndef GST_DISABLE_GST_DEBUG
static gchar *gst_fairscheduler_ct_state_names[] = {
"stopped",
"suspended",
"running"
};
#endif
/*
* Helpers
*/
static int
cothread_base_func (int argc, char **argv)
{
GstFairSchedulerCothread *ct;
g_return_val_if_fail (argc >= 1, -1);
ct = (GstFairSchedulerCothread *) argv[0];
GST_INFO ("queue %p: Cothread %p starting", ct->queue, ct);
#ifndef GST_DISABLE_GST_DEBUG
#ifdef FAIRSCHEDULER_USE_GETTID
ct->pid = gettid ();
#else
ct->pid = 0;
#endif
#endif
/* Call the thread function. This looks sort of funny, but there's
no other way I know of doing it. */
switch (argc - 1) {
case 0:
ct->func (ct, NULL);
break;
case 1:
ct->func (ct, argv[1], NULL);
break;
case 2:
ct->func (ct, argv[1], argv[2], NULL);
break;
case 3:
ct->func (ct, argv[1], argv[2], argv[3], NULL);
break;
case 4:
ct->func (ct, argv[1], argv[2], argv[3], argv[4], NULL);
break;
case 5:
ct->func (ct, argv[1], argv[2], argv[3], argv[4], argv[5], NULL);
break;
case 6:
ct->func (ct, argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], NULL);
break;
case 7:
ct->func (ct, argv[1], argv[2], argv[3], argv[4], argv[5],
argv[6], argv[7], NULL);
break;
default:
g_return_val_if_reached (-1);
break;
}
/* After the cothread function is finished, we go to the stopped
state. */
gst_fair_scheduler_cothread_change_state (ct,
GST_FAIRSCHEDULER_CTSTATE_STOPPED);
return 0;
}
static void
cothread_activate (GstFairSchedulerCothread * ct, gint priority)
{
GST_DEBUG ("queue %p: activating cothread %p", ct->queue, ct);
if (priority > 0) {
g_queue_push_head (ct->queue->ct_queue, ct);
} else {
g_queue_push_tail (ct->queue->ct_queue, ct);
}
}
static void
cothread_deactivate (GstFairSchedulerCothread * ct)
{
GList *node;
GST_DEBUG ("queue %p: deactivating cothread %p", ct->queue, ct);
/* Find the node. */
node = g_list_find (ct->queue->ct_queue->head, ct);
if (node == NULL) {
return;
}
if (node->next == NULL) {
g_queue_pop_tail (ct->queue->ct_queue);
} else {
ct->queue->ct_queue->head =
g_list_remove_link (ct->queue->ct_queue->head, node);
}
}
static void
queue_async_op (GstFairSchedulerCothreadQueue * queue, AsyncOp * op)
{
g_mutex_lock (queue->async_mutex);
g_queue_push_tail (queue->async_queue, op);
g_cond_signal (queue->new_async_op);
g_mutex_unlock (queue->async_mutex);
}
/*
* Cothreads API
*/
extern GstFairSchedulerCothreadQueue *
gst_fair_scheduler_cothread_queue_new (void)
{
GstFairSchedulerCothreadQueue *new;
new = g_malloc (sizeof (GstFairSchedulerCothreadQueue));
new->context = NULL;
new->ct_queue = g_queue_new ();
new->async_queue = g_queue_new ();
new->async_mutex = g_mutex_new ();
new->new_async_op = g_cond_new ();
return new;
}
extern void
gst_fair_scheduler_cothread_queue_destroy (GstFairSchedulerCothreadQueue *
queue)
{
GList *iter;
/* Destroy all remaining cothreads. */
for (iter = queue->ct_queue->head; iter != NULL; iter = iter->next) {
gst_fair_scheduler_cothread_destroy (
(GstFairSchedulerCothread *) iter->data);
}
g_queue_free (queue->ct_queue);
for (iter = queue->async_queue->head; iter != NULL; iter = iter->next) {
g_free (iter->data);
}
g_queue_free (queue->async_queue);
g_mutex_free (queue->async_mutex);
g_cond_free (queue->new_async_op);
g_free (queue);
}
extern void
gst_fair_scheduler_cothread_queue_start (GstFairSchedulerCothreadQueue * queue)
{
if (queue->context == NULL) {
do_cothreads_init (NULL);
queue->context = do_cothread_context_init ();
}
}
extern void
gst_fair_scheduler_cothread_queue_stop (GstFairSchedulerCothreadQueue * queue)
{
if (queue->context != NULL) {
do_cothread_context_destroy (queue->context);
}
}
gboolean
gst_fair_scheduler_cothread_queue_iterate (GstFairSchedulerCothreadQueue *
queue)
{
GstFairSchedulerCothread *ct;
g_return_val_if_fail (queue->context != NULL, FALSE);
GST_LOG ("queue %p: iterating", queue);
/* Perform any pending asynchronous operations. Checking the queue
is safe and more efficient without locking the mutex. */
if (!g_queue_is_empty (queue->async_queue)) {
AsyncOp *basic_op;
GST_LOG ("queue %p: processing asynchronous operations", queue);
g_mutex_lock (queue->async_mutex);
while (!g_queue_is_empty (queue->async_queue)) {
basic_op = (AsyncOp *) g_queue_pop_head (queue->async_queue);
switch (basic_op->type) {
case ASYNC_OP_CHANGE_STATE:
{
AsyncOpChangeState *op = (AsyncOpChangeState *) basic_op;
gst_fair_scheduler_cothread_change_state (op->ct, op->new_state);
}
break;
case ASYNC_OP_AWAKE:
{
AsyncOpAwake *op = (AsyncOpAwake *) basic_op;
gst_fair_scheduler_cothread_awake (op->ct, op->priority);
}
break;
default:
g_return_val_if_reached (FALSE);
break;
}
g_free (basic_op);
}
g_mutex_unlock (queue->async_mutex);
}
/* First cothread in the queue (if any) should get control. */
ct = g_queue_peek_head (queue->ct_queue);
if (ct == NULL) {
GTimeVal timeout;
g_get_current_time (&timeout);
g_time_val_add (&timeout, 5000);
/* No cothread available, wait until some other thread queues an
operation. */
g_mutex_lock (queue->async_mutex);
g_cond_timed_wait (queue->new_async_op, queue->async_mutex, &timeout);
g_mutex_unlock (queue->async_mutex);
return FALSE;
}
g_return_val_if_fail (ct->state == GST_FAIRSCHEDULER_CTSTATE_RUNNING, FALSE);
/* Check for a cothread mutex. */
if (ct->mutex != NULL) {
g_mutex_lock (ct->mutex);
ct->mutex = NULL;
}
GST_LOG ("queue %p: giving control to %p", queue, ct);
/* Handle control to the cothread. */
do_cothread_switch (ct->execst);
return TRUE;
}
void
gst_fair_scheduler_cothread_queue_show (GstFairSchedulerCothreadQueue * queue)
{
GList *iter;
GstFairSchedulerCothread *ct;
g_print ("\n Running cothreads (last is active):\n");
for (iter = queue->ct_queue->tail; iter != NULL; iter = iter->prev) {
ct = (GstFairSchedulerCothread *) iter->data;
#ifndef GST_DISABLE_GST_DEBUG
g_print (" %p: %s (%d)\n", ct, ct->readable_name->str, ct->pid);
#endif
}
}
GstFairSchedulerCothread *
gst_fair_scheduler_cothread_new (GstFairSchedulerCothreadQueue * queue,
GstFairSchedulerCtFunc function, gpointer first_arg, ...)
{
GstFairSchedulerCothread *new;
va_list ap;
gpointer arg;
new = g_malloc (sizeof (GstFairSchedulerCothread));
new->queue = queue;
new->func = function;
/* The first parameter is always the cothread structure itself. */
new->argv[0] = (char *) new;
new->argc = 1;
/* Store the parameters. */
va_start (ap, first_arg);
arg = first_arg;
while (new->argc < GST_FAIRSCHEDULER_MAX_CTARGS && arg != NULL) {
new->argv[new->argc] = (char *) arg;
new->argc++;
arg = va_arg (ap, gpointer);
}
/* Make sure we don't have more parameters than we can handle. */
g_return_val_if_fail (arg == NULL, NULL);
/* Creation of the actual execution state is defered to transition
to running/suspended. */
new->execst = NULL;
/* All cothreads are created in the stopped state. */
new->state = GST_FAIRSCHEDULER_CTSTATE_STOPPED;
new->mutex = NULL;
#ifndef GST_DISABLE_GST_DEBUG
new->readable_name = g_string_new ("");
new->pid = 0;
#endif
GST_DEBUG ("queue %p: cothread %p created", queue, new);
return new;
}
void
gst_fair_scheduler_cothread_destroy (GstFairSchedulerCothread * ct)
{
GST_DEBUG ("queue %p: destroying cothread %p", ct->queue, ct);
if (ct->state != GST_FAIRSCHEDULER_CTSTATE_STOPPED) {
cothread_deactivate (ct);
}
if (ct->execst != NULL) {
do_cothread_destroy (ct->execst);
}
#ifndef GST_DISABLE_GST_DEBUG
g_string_free (ct->readable_name, TRUE);
#endif
g_free (ct);
}
void
gst_fair_scheduler_cothread_change_state (GstFairSchedulerCothread * ct,
gint new_state)
{
if (new_state == ct->state) {
return;
}
GST_DEBUG ("queue %p: changing state of %p from %s to %s", ct->queue, ct,
gst_fairscheduler_ct_state_names[ct->state],
gst_fairscheduler_ct_state_names[new_state]);
switch (ct->state) {
case GST_FAIRSCHEDULER_CTSTATE_STOPPED:
/* (Re)Initialize the cothread. */
if (ct->execst == NULL) {
/* Initialize cothread's execution state. */
do_cothread_create (ct->execst, ct->queue->context,
cothread_base_func, ct->argc, ct->argv);
GST_LOG_OBJECT (ct->queue,
"cothread %p has exec state %p", ct, ct->execst);
} else {
/* Reset cothread's execution state. */
do_cothread_setfunc (ct->execst, ct->queue->context,
cothread_base_func, ct->argc, ct->argv);
}
ct->sleeping = FALSE;
if (new_state == GST_FAIRSCHEDULER_CTSTATE_RUNNING) {
cothread_activate (ct, 0);
}
break;
case GST_FAIRSCHEDULER_CTSTATE_RUNNING:
if (!ct->sleeping) {
cothread_deactivate (ct);
}
break;
case GST_FAIRSCHEDULER_CTSTATE_SUSPENDED:
if (new_state == GST_FAIRSCHEDULER_CTSTATE_RUNNING && !ct->sleeping) {
cothread_activate (ct, 0);
}
break;
}
ct->state = new_state;
}
void
gst_fair_scheduler_cothread_change_state_async (GstFairSchedulerCothread * ct,
gint new_state)
{
AsyncOpChangeState *op;
/* Queue an asynchronous operation. */
op = g_new (AsyncOpChangeState, 1);
op->parent.type = ASYNC_OP_CHANGE_STATE;
op->ct = ct;
op->new_state = new_state;
queue_async_op (ct->queue, (AsyncOp *) op);
}
void
gst_fair_scheduler_cothread_sleep (GstFairSchedulerCothreadQueue * queue)
{
gst_fair_scheduler_cothread_sleep_mutex (queue, NULL);
}
/*
* Go to sleep but unblock the mutex while sleeping.
*/
void
gst_fair_scheduler_cothread_sleep_mutex (GstFairSchedulerCothreadQueue * queue,
GMutex * mutex)
{
GstFairSchedulerCothread *ct;
g_return_if_fail (queue->context != NULL);
/* The sleep operation can be invoked when the cothread is already
deactivated. */
ct = gst_fair_scheduler_cothread_current (queue);
if (ct != NULL && ct->execst == do_cothread_get_current (queue->context)) {
ct = g_queue_pop_head (queue->ct_queue);
ct->sleeping = TRUE;
}
ct->mutex = mutex;
if (mutex != NULL) {
g_mutex_unlock (mutex);
}
GST_LOG ("queue %p: cothread going to sleep", queue);
/* Switch back to the main cothread. */
do_cothread_switch (do_cothread_get_main (queue->context));
}
void
gst_fair_scheduler_cothread_yield (GstFairSchedulerCothreadQueue * queue)
{
gst_fair_scheduler_cothread_yield_mutex (queue, NULL);
}
void
gst_fair_scheduler_cothread_yield_mutex (GstFairSchedulerCothreadQueue * queue,
GMutex * mutex)
{
GstFairSchedulerCothread *ct;
g_return_if_fail (queue->context != NULL);
/* The yield operation can be invoked when the cothread is already
deactivated. */
ct = gst_fair_scheduler_cothread_current (queue);
if (ct != NULL && ct->execst == do_cothread_get_current (queue->context)) {
ct = g_queue_pop_head (queue->ct_queue);
g_queue_push_tail (queue->ct_queue, ct);
}
ct->mutex = mutex;
if (mutex != NULL) {
g_mutex_unlock (mutex);
}
GST_LOG ("queue %p: cothread yielding control", queue);
/* Switch back to the main cothread. */
do_cothread_switch (do_cothread_get_main (queue->context));
}
void
gst_fair_scheduler_cothread_awake (GstFairSchedulerCothread * ct, gint priority)
{
g_return_if_fail (ct->state != GST_FAIRSCHEDULER_CTSTATE_STOPPED);
if (!ct->sleeping) {
/* Cothread is already awake. */
return;
}
ct->sleeping = FALSE;
if (ct->state == GST_FAIRSCHEDULER_CTSTATE_RUNNING) {
cothread_activate (ct, priority);
}
}
void
gst_fair_scheduler_cothread_awake_async (GstFairSchedulerCothread * ct,
gint priority)
{
AsyncOpAwake *op;
/* Queue an asynchronous operation. */
op = g_new (AsyncOpAwake, 1);
op->parent.type = ASYNC_OP_AWAKE;
op->ct = ct;
op->priority = priority;
queue_async_op (ct->queue, (AsyncOp *) op);
}
GstFairSchedulerCothread *
gst_fair_scheduler_cothread_current (GstFairSchedulerCothreadQueue * queue)
{
return g_queue_peek_head (queue->ct_queue);
}

View file

@ -1,163 +0,0 @@
/* GStreamer
* Copyright (C) 2004 Martin Soto <martinsoto@users.sourceforge.net>
*
* faircothread.h: High level cothread implementation for the fair scheduler.
*
* 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 __FAIRCOTHREADS_H__
#define __FAIRCOTHREADS_H__
#ifdef _COTHREADS_PTH
#include "pth-cothreads.h"
#else
#define GTHREAD_COTHREADS_NO_DEFINITIONS
#include "cothreads_compat.h"
#endif
typedef struct _GstFairSchedulerCothread GstFairSchedulerCothread;
typedef struct _GstFairSchedulerCothreadQueue GstFairSchedulerCothreadQueue;
/* Possible states of a cothread. */
enum
{
GST_FAIRSCHEDULER_CTSTATE_STOPPED,
GST_FAIRSCHEDULER_CTSTATE_SUSPENDED,
GST_FAIRSCHEDULER_CTSTATE_RUNNING,
};
/* Maximum number of cothread parameters. */
#define GST_FAIRSCHEDULER_MAX_CTARGS 7
/* Cothread function type. */
typedef void (*GstFairSchedulerCtFunc) (GstFairSchedulerCothread * ct,
gpointer first_arg, ...);
struct _GstFairSchedulerCothread {
GstFairSchedulerCothreadQueue *queue;
/* Cothread queue this cothread
belongs to. */
GstFairSchedulerCtFunc func; /* Cothread function. */
char *argv[1 + GST_FAIRSCHEDULER_MAX_CTARGS]; /*
Arguments for the cothread function.
argv[0] is always the cothread
object itself. */
int argc; /* Number of stored parameters. */
cothread *execst; /* Execution state for this cothread. */
gint state; /* Current cothread state. */
gboolean sleeping; /* Is this cothread sleeping? */
GMutex *mutex; /* If not null, a mutex to lock before
giving control to this cothread. */
#ifndef GST_DISABLE_GST_DEBUG
GString *readable_name; /* Readable name for this cothread. */
gint pid; /* Process or thread id associated to
this cothread. */
#endif
};
struct _GstFairSchedulerCothreadQueue {
cothread_context *context; /* Cothread context. */
GQueue *ct_queue; /* Queue of currently running
cothreads. New cothreads are pushed
on the tail. If a cothread is
executing, it is the one in the
head. */
/* Asynchronous support. */
GQueue *async_queue; /* Queue storing asynchronous
operations (operations on the queue
requested potentially from other
threads. */
GMutex *async_mutex; /* Mutex to protect acceses to
async_queue. */
GCond *new_async_op; /* Condition variable to signal the
presence of a new asynchronous
operation in the queue. */
};
extern GstFairSchedulerCothreadQueue *
gst_fair_scheduler_cothread_queue_new (void);
extern void
gst_fair_scheduler_cothread_queue_destroy (
GstFairSchedulerCothreadQueue * queue);
extern void
gst_fair_scheduler_cothread_queue_start (
GstFairSchedulerCothreadQueue * queue);
extern void
gst_fair_scheduler_cothread_queue_stop (
GstFairSchedulerCothreadQueue * queue);
extern gboolean
gst_fair_scheduler_cothread_queue_iterate (
GstFairSchedulerCothreadQueue * queue);
extern void
gst_fair_scheduler_cothread_queue_show (
GstFairSchedulerCothreadQueue * queue);
extern GstFairSchedulerCothread *
gst_fair_scheduler_cothread_new (GstFairSchedulerCothreadQueue * queue,
GstFairSchedulerCtFunc function, gpointer first_arg, ...);
extern void
gst_fair_scheduler_cothread_destroy (GstFairSchedulerCothread * ct);
extern void
gst_fair_scheduler_cothread_change_state (GstFairSchedulerCothread * ct,
gint new_state);
extern void
gst_fair_scheduler_cothread_change_state_async (
GstFairSchedulerCothread * ct, gint new_state);
extern void
gst_fair_scheduler_cothread_sleep (GstFairSchedulerCothreadQueue * queue);
extern void
gst_fair_scheduler_cothread_sleep_mutex (
GstFairSchedulerCothreadQueue * queue, GMutex * mutex);
extern void
gst_fair_scheduler_cothread_yield (GstFairSchedulerCothreadQueue * queue);
extern void
gst_fair_scheduler_cothread_yield_mutex (
GstFairSchedulerCothreadQueue * queue, GMutex * mutex);
extern void
gst_fair_scheduler_cothread_awake (GstFairSchedulerCothread * ct,
gint priority);
extern void
gst_fair_scheduler_cothread_awake_async (GstFairSchedulerCothread * ct,
gint priority);
extern GstFairSchedulerCothread *
gst_fair_scheduler_cothread_current (GstFairSchedulerCothreadQueue * queue);
#endif /* __FAIRCOTHREADS_H__ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,221 +0,0 @@
/* GStreamer
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
*
* gthread-cothreads.c: cothreads implemented via GThread for compatibility
* They're probably slooooooow
*
* 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 __GTHREAD_COTHREADS_H__
#define __GTHREAD_COTHREADS_H__
#include <glib.h>
#include <gst/gstthread.h>
/* the name of this cothreads */
#define COTHREADS_TYPE gthread
#define COTHREADS_NAME "gthread"
#define COTHREADS_NAME_CAPITAL "GThread"
/*
* Theory of operation:
* Instead of using cothreads, GThreads and 1 mutex are used.
* Every thread may only run if it holds the mutex. Otherwise it holds its own
* cond which has to be signaled to wakeit up.
*/
/* define "cothread", "cothread_context" and "cothread_func" */
typedef int (*cothread_func) (int, char **);
typedef struct _cothread cothread;
typedef struct _cothread_context cothread_context;
struct _cothread_context {
GSList * cothreads; /* contains all threads but main */
cothread * main;
cothread * current;
GMutex * mutex;
GstThread * gst_thread; /* the GstThread we're running from */
};
struct _cothread {
GThread * thread;
GCond * cond;
cothread_func run;
int argc;
char ** argv;
cothread * creator;
gboolean die;
cothread_context * context;
};
#ifndef GTHREAD_COTHREADS_NO_DEFINITIONS
/* define functions
* Functions starting with "do_" are used by the scheduler.
*/
static void do_cothreads_init (void *unused);
static cothread_context *do_cothread_context_init (void);
static void do_cothread_context_destroy (cothread_context *context);
static cothread * cothread_create (cothread_context *context,
cothread_func func,
int argc,
char **argv);
#define do_cothread_create(new_cothread, context, func, argc, argv) \
G_STMT_START{ \
new_cothread = cothread_create ((context), (func), argc, (char**) (argv)); \
}G_STMT_END
static void do_cothread_switch (cothread *to);
static void do_cothread_destroy (cothread *thread);
#define do_cothread_get_current(context) ((context)->current)
#define do_cothread_get_main(context) ((context)->main)
static void
do_cothreads_init (void *unused)
{
if (!g_thread_supported ()) g_thread_init (NULL);
}
static cothread_context *
do_cothread_context_init (void)
{
cothread_context *ret = g_new0 (cothread_context, 1);
ret->main = g_new0 (cothread, 1);
ret->main->thread = g_thread_self ();
ret->main->cond = g_cond_new ();
ret->main->die = FALSE;
ret->main->context = ret;
ret->mutex = g_mutex_new ();
ret->cothreads = NULL;
ret->current = ret->main;
ret->gst_thread = gst_thread_get_current();
g_mutex_lock (ret->mutex);
return ret;
}
static void
do_cothread_context_destroy (cothread_context *context)
{
g_assert (g_thread_self() == context->main->thread);
while (context->cothreads) {
do_cothread_destroy ((cothread *) context->cothreads->data);
}
g_mutex_unlock (context->mutex);
g_mutex_free (context->mutex);
g_cond_free (context->main->cond);
g_free (context->main);
g_free (context);
}
static void
die (cothread *to_die) {
g_cond_free (to_die->cond);
to_die->context->cothreads = g_slist_remove (to_die->context->cothreads, to_die);
g_free (to_die);
g_thread_exit (to_die);
/* don't unlock the mutex here, the thread waiting for us to die is gonna take it */
}
static gpointer
run_new_thread (gpointer data)
{
cothread *self = (cothread *) data;
g_mutex_lock (self->context->mutex);
g_private_set (gst_thread_current, self->context->gst_thread);
g_cond_signal (self->creator->cond);
g_cond_wait (self->cond, self->context->mutex);
if (self->die)
die (self);
while (TRUE) {
self->run (self->argc, self->argv);
/* compatibility */
do_cothread_switch (do_cothread_get_main (self->context));
}
g_assert_not_reached ();
return NULL;
}
static cothread *
cothread_create (cothread_context *context, cothread_func func, int argc, char **argv)
{
cothread *ret;
if ((ret = g_new (cothread, 1)) == NULL) {
goto out1;
}
ret->cond = g_cond_new ();
ret->run = func;
ret->argc = argc;
ret->argv = argv;
ret->creator = do_cothread_get_current (context);
ret->die = FALSE;
ret->context = context;
context->cothreads = g_slist_prepend (context->cothreads, ret);
ret->thread = g_thread_create (run_new_thread, ret, TRUE, NULL);
if (ret->thread == NULL) goto out2;
g_cond_wait (do_cothread_get_current (context)->cond, context->mutex);
return ret;
out2:
context->cothreads = g_slist_remove (context->cothreads, ret);
g_free (ret);
out1:
return NULL;
}
static void do_cothread_switch (cothread *to)
{
cothread *self = do_cothread_get_current(to->context);
if (self != to) {
self->context->current = to;
g_cond_signal (to->cond);
g_cond_wait (self->cond, self->context->mutex);
if (self->die)
die (self);
}
}
#define do_cothread_setfunc(thread,context,_func,_argc,_argv) G_STMT_START {\
((cothread *)(thread))->run = (_func); \
((cothread *)(thread))->argc = _argc; \
((cothread *)(thread))->argv = _argv; \
}G_STMT_END
static void
do_cothread_destroy (cothread *thread)
{
GThread *join;
cothread_context *context;
g_return_if_fail (thread != thread->context->main);
g_return_if_fail (thread != thread->context->current);
thread->die = TRUE;
join = thread->thread;
context = thread->context;
g_cond_signal (thread->cond);
g_mutex_unlock (thread->context->mutex);
g_thread_join (join);
/* the mutex was locked by the thread that we joined, no need to lock again */
}
#define do_cothread_get_current(context) ((context)->current)
#define do_cothread_get_main(context) ((context)->main)
#endif /* GTHREAD_COTHREADS_NO_DEFINITIONS */
#endif /* __GTHREAD_COTHREADS_H__ */

View file

@ -0,0 +1,347 @@
/* GStreamer2
* Copyright (C) 2004 Wim Taymans <wim@fluendo.com>
*
* threadscheduler.c: scheduler using threads
*
* 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.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gst/gst.h>
#include "../gst-i18n-lib.h"
GST_DEBUG_CATEGORY_STATIC (debug_scheduler);
#define GST_CAT_DEFAULT debug_scheduler
#define GST_TYPE_THREAD_SCHEDULER \
(gst_thread_scheduler_get_type ())
#define GST_THREAD_SCHEDULER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THREAD_SCHEDULER,GstThreadScheduler))
#define GST_THREAD_SCHEDULER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THREAD_SCHEDULER,GstThreadSchedulerClass))
#define GST_IS_THREAD_SCHEDULER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THREAD_SCHEDULER))
#define GST_IS_THREAD_SCHEDULER_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THREAD_SCHEDULER))
#define SCHED(element) (GST_THREAD_SCHEDULER ((element)->sched))
GType gst_thread_scheduler_get_type (void);
typedef struct _GstThreadScheduler GstThreadScheduler;
typedef struct _GstThreadSchedulerClass GstThreadSchedulerClass;
struct _GstThreadScheduler
{
GstScheduler scheduler;
GThreadPool *pool;
};
struct _GstThreadSchedulerClass
{
GstSchedulerClass scheduler_class;
};
#define ELEMENT_PRIVATE(element) GST_ELEMENT (element)->sched_private
#define PAD_PRIVATE(pad) (GST_REAL_PAD (pad))->sched_private
#define GST_TYPE_THREAD_SCHEDULER_TASK \
(gst_thread_scheduler_task_get_type ())
#define GST_THREAD_SCHEDULER_TASK(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_THREAD_SCHEDULER_TASK,GstThreadSchedulerTask))
#define GST_THREAD_SCHEDULER_TASK_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_THREAD_SCHEDULER_TASK,GstThreadSchedulerTaskClass))
#define GST_IS_THREAD_SCHEDULER_TASK(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_THREAD_SCHEDULER_TASK))
#define GST_IS_THREAD_SCHEDULER_TASK_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_THREAD_SCHEDULER_TASK))
typedef struct _GstThreadSchedulerTask GstThreadSchedulerTask;
typedef struct _GstThreadSchedulerTaskClass GstThreadSchedulerTaskClass;
struct _GstThreadSchedulerTask
{
GstTask task;
};
struct _GstThreadSchedulerTaskClass
{
GstTaskClass parent_class;
};
static void gst_thread_scheduler_task_class_init (gpointer g_class,
gpointer data);
static void gst_thread_scheduler_task_init (GstThreadSchedulerTask * object);
static gboolean gst_thread_scheduler_task_start (GstTask * task);
static gboolean gst_thread_scheduler_task_stop (GstTask * task);
static gboolean gst_thread_scheduler_task_pause (GstTask * task);
GType
gst_thread_scheduler_task_get_type (void)
{
static GType object_type = 0;
if (object_type == 0) {
static const GTypeInfo object_info = {
sizeof (GstThreadSchedulerTaskClass),
NULL,
NULL,
gst_thread_scheduler_task_class_init,
NULL,
NULL,
sizeof (GstThreadSchedulerTask),
0,
(GInstanceInitFunc) gst_thread_scheduler_task_init
};
object_type =
g_type_register_static (GST_TYPE_TASK,
"GstThreadSchedulerTask", &object_info, 0);
}
return object_type;
}
static void
gst_thread_scheduler_task_class_init (gpointer klass, gpointer class_data)
{
GstTaskClass *task = GST_TASK_CLASS (klass);
task->start = gst_thread_scheduler_task_start;
task->stop = gst_thread_scheduler_task_stop;
task->pause = gst_thread_scheduler_task_pause;
}
static void
gst_thread_scheduler_task_init (GstThreadSchedulerTask * task)
{
GST_TASK (task)->state = GST_TASK_STOPPED;
}
static gboolean
gst_thread_scheduler_task_start (GstTask * task)
{
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
GstThreadScheduler *tsched =
GST_THREAD_SCHEDULER (GST_OBJECT_PARENT (GST_OBJECT (task)));
GstTaskState old;
GST_DEBUG_OBJECT (task, "Starting task %p", task);
GST_LOCK (ttask);
old = GST_TASK_CAST (ttask)->state;
GST_TASK_CAST (ttask)->state = GST_TASK_STARTED;
switch (old) {
case GST_TASK_STOPPED:
g_thread_pool_push (tsched->pool, task, NULL);
break;
case GST_TASK_PAUSED:
GST_TASK_SIGNAL (ttask);
break;
case GST_TASK_STARTED:
break;
}
GST_UNLOCK (ttask);
return TRUE;
}
static gboolean
gst_thread_scheduler_task_stop (GstTask * task)
{
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
GstTaskState old;
GST_DEBUG_OBJECT (task, "Stopping task %p", task);
GST_LOCK (ttask);
old = GST_TASK_CAST (ttask)->state;
GST_TASK_CAST (ttask)->state = GST_TASK_STOPPED;
switch (old) {
case GST_TASK_STOPPED:
break;
case GST_TASK_PAUSED:
GST_TASK_SIGNAL (ttask);
break;
case GST_TASK_STARTED:
break;
}
GST_UNLOCK (ttask);
return TRUE;
}
static gboolean
gst_thread_scheduler_task_pause (GstTask * task)
{
GstThreadSchedulerTask *ttask = GST_THREAD_SCHEDULER_TASK (task);
GstThreadScheduler *tsched =
GST_THREAD_SCHEDULER (GST_OBJECT_PARENT (GST_OBJECT (task)));
GstTaskState old;
GST_DEBUG_OBJECT (task, "Pausing task %p", task);
GST_LOCK (ttask);
old = GST_TASK_CAST (ttask)->state;
GST_TASK_CAST (ttask)->state = GST_TASK_PAUSED;
switch (old) {
case GST_TASK_STOPPED:
g_thread_pool_push (tsched->pool, task, NULL);
break;
case GST_TASK_PAUSED:
break;
case GST_TASK_STARTED:
break;
}
GST_UNLOCK (ttask);
return TRUE;
}
static void gst_thread_scheduler_class_init (gpointer g_class, gpointer data);
static void gst_thread_scheduler_init (GstThreadScheduler * object);
GType
gst_thread_scheduler_get_type (void)
{
static GType object_type = 0;
if (object_type == 0) {
static const GTypeInfo object_info = {
sizeof (GstThreadSchedulerClass),
NULL,
NULL,
gst_thread_scheduler_class_init,
NULL,
NULL,
sizeof (GstThreadScheduler),
0,
(GInstanceInitFunc) gst_thread_scheduler_init
};
object_type =
g_type_register_static (GST_TYPE_SCHEDULER,
"GstThreadScheduler", &object_info, 0);
}
return object_type;
}
static void gst_thread_scheduler_setup (GstScheduler * sched);
static void gst_thread_scheduler_reset (GstScheduler * sched);
static GstTask *gst_thread_scheduler_create_task (GstScheduler * sched,
GstTaskFunction func, gpointer data);
static void
gst_thread_scheduler_class_init (gpointer klass, gpointer class_data)
{
GstSchedulerClass *scheduler = GST_SCHEDULER_CLASS (klass);
scheduler->setup = gst_thread_scheduler_setup;
scheduler->reset = gst_thread_scheduler_reset;
scheduler->create_task = gst_thread_scheduler_create_task;
}
static void
gst_thread_scheduler_func (GstThreadSchedulerTask * ttask,
GstThreadScheduler * sched)
{
GstTask *task = GST_TASK (ttask);
gst_object_ref (GST_OBJECT (task));
GST_DEBUG_OBJECT (sched, "Entering task %p, thread %p", task,
g_thread_self ());
GST_LOCK (task);
while (G_LIKELY (task->state != GST_TASK_STOPPED)) {
while (G_UNLIKELY (task->state == GST_TASK_PAUSED)) {
GST_TASK_SIGNAL (task);
GST_TASK_WAIT (task);
if (task->state == GST_TASK_STOPPED)
goto done;
}
GST_UNLOCK (task);
task->func (task->data);
GST_LOCK (task);
}
done:
GST_UNLOCK (task);
GST_DEBUG_OBJECT (sched, "Exit task %p, thread %p", task, g_thread_self ());
gst_object_unref (GST_OBJECT (task));
}
static void
gst_thread_scheduler_init (GstThreadScheduler * scheduler)
{
scheduler->pool = g_thread_pool_new (
(GFunc) gst_thread_scheduler_func, scheduler, -1, FALSE, NULL);
}
static GstTask *
gst_thread_scheduler_create_task (GstScheduler * sched, GstTaskFunction func,
gpointer data)
{
GstThreadSchedulerTask *task;
task =
GST_THREAD_SCHEDULER_TASK (g_object_new (GST_TYPE_THREAD_SCHEDULER_TASK,
NULL));
gst_object_set_parent (GST_OBJECT (task), GST_OBJECT (sched));
GST_TASK_CAST (task)->func = func;
GST_TASK_CAST (task)->data = data;
GST_DEBUG_OBJECT (sched, "Created task %p", task);
return GST_TASK_CAST (task);
}
static void
gst_thread_scheduler_setup (GstScheduler * sched)
{
}
static void
gst_thread_scheduler_reset (GstScheduler * sched)
{
}
static gboolean
plugin_init (GstPlugin * plugin)
{
GstSchedulerFactory *factory;
GST_DEBUG_CATEGORY_INIT (debug_scheduler, "thread", 0, "thread scheduler");
factory = gst_scheduler_factory_new ("thread",
"A scheduler using threads", GST_TYPE_THREAD_SCHEDULER);
if (factory == NULL)
return FALSE;
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "gstthreadscheduler",
"a thread scheduler", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE,
GST_ORIGIN)

View file

@ -1 +1 @@
SUBDIRS = bytestream control dataprotocol getbits
SUBDIRS = control dataprotocol getbits

View file

@ -154,7 +154,7 @@ gst_bytestream_get_next_buf (GstByteStream * bs)
return FALSE;
GST_DEBUG ("get_next_buf: pulling buffer");
nextbuf = GST_BUFFER (gst_pad_pull (bs->pad));
gst_pad_pull (bs->pad, &nextbuf);
if (!nextbuf)
return FALSE;

View file

@ -39,7 +39,7 @@ GST_BOILERPLATE_FULL (GstFilePad, gst_file_pad, GstRealPad, GST_TYPE_REAL_PAD,
static void gst_file_pad_dispose (GObject * object);
static void gst_file_pad_finalize (GObject * object);
static void gst_file_pad_chain (GstPad * pad, GstData * data);
//static void gst_file_pad_chain (GstPad * pad, GstData * data);
static void gst_file_pad_parent_set (GstObject * object,
GstObject * parent);
@ -68,7 +68,7 @@ gst_file_pad_init (GstFilePad * pad)
/* must do this for set_chain_function to work */
real->direction = GST_PAD_SINK;
gst_pad_set_chain_function (GST_PAD (real), gst_file_pad_chain);
//gst_pad_set_chain_function (GST_PAD (real), gst_file_pad_chain);
pad->adapter = gst_adapter_new ();
pad->in_seek = FALSE;
@ -98,6 +98,7 @@ gst_file_pad_finalize (GObject * object)
GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
}
#if 0
static void
gst_file_pad_chain (GstPad * gst_pad, GstData * data)
{
@ -174,6 +175,7 @@ gst_file_pad_chain (GstPad * gst_pad, GstData * data)
}
}
}
#endif
static void
gst_file_pad_parent_set (GstObject * object, GstObject * parent)
@ -183,10 +185,8 @@ gst_file_pad_parent_set (GstObject * object, GstObject * parent)
/* FIXME: we can only be added to elements, right? */
element = GST_ELEMENT (parent);
if (element->loopfunc)
g_warning ("attempt to add a GstFilePad to a loopbased element.");
if (!GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE))
g_warning ("elements using GstFilePad must be event-aware.");
//if (element->loopfunc)
// g_warning ("attempt to add a GstFilePad to a loopbased element.");
GST_CALL_PARENT (GST_OBJECT_CLASS, parent_set, (object, parent));
}

View file

@ -324,22 +324,12 @@ gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
return FALSE;
case GST_EVENT_EOS:
case GST_EVENT_FLUSH:
case GST_EVENT_EMPTY:
case GST_EVENT_DISCONTINUOUS:
GST_WRITE_UINT64_BE (h + 8, GST_EVENT_TIMESTAMP (event));
pl_length = 0;
*payload = NULL;
break;
case GST_EVENT_SEEK:
pl_length = 4 + 8 + 4;
*payload = g_malloc0 (pl_length);
GST_WRITE_UINT32_BE (*payload, (guint32) GST_EVENT_SEEK_TYPE (event));
GST_WRITE_UINT64_BE (*payload + 4,
(guint64) GST_EVENT_SEEK_OFFSET (event));
GST_WRITE_UINT32_BE (*payload + 12,
(guint32) GST_EVENT_SEEK_ACCURACY (event));
break;
case GST_EVENT_SEEK_SEGMENT:
pl_length = 4 + 8 + 8 + 4;
*payload = g_malloc0 (pl_length);
GST_WRITE_UINT32_BE (*payload, (guint32) GST_EVENT_SEEK_TYPE (event));
@ -351,12 +341,8 @@ gst_dp_packet_from_event (const GstEvent * event, GstDPHeaderFlag flags,
(guint32) GST_EVENT_SEEK_ACCURACY (event));
break;
case GST_EVENT_QOS:
case GST_EVENT_SEGMENT_DONE:
case GST_EVENT_SIZE:
case GST_EVENT_RATE:
case GST_EVENT_FILLER:
case GST_EVENT_TS_OFFSET:
case GST_EVENT_INTERRUPT:
case GST_EVENT_NAVIGATION:
case GST_EVENT_TAG:
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));
@ -489,26 +475,11 @@ gst_dp_event_from_packet (guint header_length, const guint8 * header,
return FALSE;
case GST_EVENT_EOS:
case GST_EVENT_FLUSH:
case GST_EVENT_EMPTY:
case GST_EVENT_DISCONTINUOUS:
event = gst_event_new (type);
GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
break;
case GST_EVENT_SEEK:
{
GstSeekType type;
gint64 offset;
GstSeekAccuracy accuracy;
type = (GstSeekType) GST_READ_UINT32_BE (payload);
offset = (gint64) GST_READ_UINT64_BE (payload + 4);
accuracy = (GstSeekAccuracy) GST_READ_UINT32_BE (payload + 12);
event = gst_event_new_seek (type, offset);
GST_EVENT_TIMESTAMP (event) = GST_DP_HEADER_TIMESTAMP (header);
GST_EVENT_SEEK_ACCURACY (event) = accuracy;
break;
}
case GST_EVENT_SEEK_SEGMENT:
{
GstSeekType type;
gint64 offset, endoffset;
@ -524,12 +495,8 @@ gst_dp_event_from_packet (guint header_length, const guint8 * header,
break;
}
case GST_EVENT_QOS:
case GST_EVENT_SEGMENT_DONE:
case GST_EVENT_SIZE:
case GST_EVENT_RATE:
case GST_EVENT_FILLER:
case GST_EVENT_TS_OFFSET:
case GST_EVENT_INTERRUPT:
case GST_EVENT_NAVIGATION:
case GST_EVENT_TAG:
g_warning ("Unhandled event type %d, ignoring", GST_EVENT_TYPE (event));

View file

@ -24,23 +24,24 @@ endif
libgstelements_la_DEPENDENCIES = ../libgstreamer-@GST_MAJORMINOR@.la
libgstelements_la_SOURCES = \
gstaggregator.c \
gstbufferstore.c \
gstelements.c \
gstfakesink.c \
gstfakesrc.c \
gstfilesink.c \
gstfakesink.c \
gstfilesrc.c \
gstfdsink.c \
gstfdsrc.c \
gstidentity.c \
gstmd5sink.c \
$(multifilesrc) \
$(pipefilter) \
gstshaper.c \
gststatistics.c \
gsttee.c \
gsttypefindelement.c
gstelements.c \
gsttee.c
# gstaggregator.c \
# gstbufferstore.c \
# gstfilesink.c \
# gstfdsink.c \
# gstfdsrc.c \
# gstmd5sink.c \
# $(multifilesrc) \
# $(pipefilter) \
# gstshaper.c \
# gststatistics.c \
# gsttypefindelement.c
libgstelements_la_CFLAGS = $(GST_OBJ_CFLAGS)
libgstelements_la_LIBADD = $(GST_OBJ_LIBS)

View file

@ -55,24 +55,24 @@ extern GType gst_filesrc_get_type (void);
extern GstElementDetails gst_filesrc_details;
static struct _elements_entry _elements[] = {
{"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
// {"aggregator", GST_RANK_NONE, gst_aggregator_get_type},
{"fakesrc", GST_RANK_NONE, gst_fakesrc_get_type},
{"fakesink", GST_RANK_NONE, gst_fakesink_get_type},
{"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
{"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
{"filesrc", GST_RANK_NONE, gst_filesrc_get_type},
{"filesink", GST_RANK_NONE, gst_filesink_get_type},
{"identity", GST_RANK_NONE, gst_identity_get_type},
{"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
// {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
// {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
// {"filesink", GST_RANK_NONE, gst_filesink_get_type},
// {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
#ifndef HAVE_WIN32
{"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
{"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
// {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},
// {"pipefilter", GST_RANK_NONE, gst_pipefilter_get_type},
#endif
{"shaper", GST_RANK_NONE, gst_shaper_get_type},
{"statistics", GST_RANK_NONE, gst_statistics_get_type},
// {"shaper", GST_RANK_NONE, gst_shaper_get_type},
// {"statistics", GST_RANK_NONE, gst_statistics_get_type},
{"tee", GST_RANK_NONE, gst_tee_get_type},
{"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
{NULL, 0},
// {"typefind", GST_RANK_NONE, gst_type_find_element_get_type},
// {NULL, 0},
};
static gboolean

View file

@ -113,7 +113,8 @@ static void gst_fakesink_get_property (GObject * object, guint prop_id,
static GstElementStateReturn gst_fakesink_change_state (GstElement * element);
static void gst_fakesink_chain (GstPad * pad, GstData * _data);
static GstFlowReturn gst_fakesink_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_fakesink_event (GstPad * pad, GstEvent * event);
static guint gst_fakesink_signals[LAST_SIGNAL] = { 0 };
@ -188,6 +189,7 @@ gst_fakesink_init (GstFakeSink * fakesink)
"sink");
gst_element_add_pad (GST_ELEMENT (fakesink), pad);
gst_pad_set_chain_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_chain));
gst_pad_set_event_function (pad, GST_DEBUG_FUNCPTR (gst_fakesink_event));
fakesink->silent = FALSE;
fakesink->dump = FALSE;
@ -195,8 +197,6 @@ gst_fakesink_init (GstFakeSink * fakesink)
fakesink->last_message = NULL;
fakesink->state_error = FAKESINK_STATE_ERROR_NONE;
fakesink->signal_handoffs = FALSE;
GST_FLAG_SET (fakesink, GST_ELEMENT_EVENT_AWARE);
}
static void
@ -307,47 +307,43 @@ gst_fakesink_get_property (GObject * object, guint prop_id, GValue * value,
}
}
static void
gst_fakesink_chain (GstPad * pad, GstData * _data)
static gboolean
gst_fakesink_event (GstPad * pad, GstEvent * event)
{
GstBuffer *buf = GST_BUFFER (_data);
GstFakeSink *fakesink;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
if (!fakesink->silent) {
g_free (fakesink->last_message);
if (!fakesink->silent) {
g_free (fakesink->last_message);
fakesink->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
fakesink->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
g_object_notify (G_OBJECT (fakesink), "last_message");
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
if (fakesink->sync && fakesink->clock) {
gint64 value = GST_EVENT_DISCONT_OFFSET (event, 0).value;
gst_element_set_time (GST_ELEMENT (fakesink), value);
}
default:
gst_pad_event_default (pad, event);
break;
}
return;
g_object_notify (G_OBJECT (fakesink), "last_message");
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
default:
gst_pad_event_default (pad, event);
break;
}
return TRUE;
}
static GstFlowReturn
gst_fakesink_chain (GstPad * pad, GstBuffer * buffer)
{
GstBuffer *buf = GST_BUFFER (buffer);
GstFakeSink *fakesink;
fakesink = GST_FAKESINK (GST_OBJECT_PARENT (pad));
if (fakesink->sync && fakesink->clock) {
gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
//gst_element_wait (GST_ELEMENT (fakesink), GST_BUFFER_TIMESTAMP (buf));
}
if (!fakesink->silent) {
@ -374,6 +370,8 @@ gst_fakesink_chain (GstPad * pad, GstData * _data)
}
gst_buffer_unref (buf);
return GST_FLOW_OK;
}
static GstElementStateReturn

View file

@ -64,7 +64,8 @@ enum
{
ARG_0,
ARG_NUM_SOURCES,
ARG_LOOP_BASED,
ARG_HAS_LOOP,
ARG_HAS_GETRANGE,
ARG_OUTPUT,
ARG_DATA,
ARG_SIZETYPE,
@ -179,7 +180,7 @@ GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstElement, GST_TYPE_ELEMENT,
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused);
static void gst_fakesrc_update_functions (GstFakeSrc * src);
static gboolean gst_fakesrc_activate (GstPad * pad, GstActivateMode mode);
static void gst_fakesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_fakesrc_get_property (GObject * object, guint prop_id,
@ -188,8 +189,9 @@ static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
static GstData *gst_fakesrc_get (GstPad * pad);
static void gst_fakesrc_loop (GstElement * element);
static void gst_fakesrc_loop (GstPad * pad);
static GstFlowReturn gst_fakesrc_get_range (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buf);
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
@ -220,9 +222,14 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
g_param_spec_int ("num-sources", "num-sources", "Number of sources",
1, G_MAXINT, 1, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
g_param_spec_boolean ("loop-based", "loop-based",
"Enable loop-based operation", FALSE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
g_param_spec_boolean ("has-loop", "has-loop",
"Enable loop-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_GETRANGE,
g_param_spec_boolean ("has-getrange", "has-getrange",
"Enable getrange-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OUTPUT,
g_param_spec_enum ("output", "output", "Output method (currently unused)",
GST_TYPE_FAKESRC_OUTPUT, FAKESRC_FIRST_LAST_LOOP, G_PARAM_READWRITE));
@ -300,9 +307,6 @@ gst_fakesrc_init (GstFakeSrc * fakesrc)
"src");
gst_element_add_pad (GST_ELEMENT (fakesrc), pad);
fakesrc->loop_based = FALSE;
gst_fakesrc_update_functions (fakesrc);
fakesrc->output = FAKESRC_FIRST_LAST_LOOP;
fakesrc->segment_start = -1;
fakesrc->segment_end = -1;
@ -324,6 +328,7 @@ gst_fakesrc_init (GstFakeSrc * fakesrc)
fakesrc->last_message = NULL;
fakesrc->datarate = DEFAULT_DATARATE;
fakesrc->sync = DEFAULT_SYNC;
fakesrc->pad_mode = GST_ACTIVATE_NONE;
}
static void
@ -336,35 +341,6 @@ gst_fakesrc_set_clock (GstElement * element, GstClock * clock)
src->clock = clock;
}
static GstPad *
gst_fakesrc_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
gchar *name;
GstPad *srcpad;
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
return NULL;
}
fakesrc = GST_FAKESRC (element);
name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
srcpad = gst_pad_new_from_template (templ, name);
gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
gst_fakesrc_update_functions (fakesrc);
g_free (name);
return srcpad;
}
static const GstFormat *
gst_fakesrc_get_formats (GstPad * pad)
{
@ -419,8 +395,7 @@ static const GstEventMask *
gst_fakesrc_get_event_mask (GstPad * pad)
{
static const GstEventMask masks[] = {
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH},
{GST_EVENT_SEEK_SEGMENT, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_FLUSH, 0},
{0, 0},
};
@ -433,22 +408,16 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
{
GstFakeSrc *src;
src = GST_FAKESRC (gst_pad_get_parent (pad));
src = GST_FAKESRC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
src->buffer_count = GST_EVENT_SEEK_OFFSET (event);
if (!GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
break;
}
/* else we do a flush too */
case GST_EVENT_SEEK_SEGMENT:
src->segment_start = GST_EVENT_SEEK_OFFSET (event);
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
src->buffer_count = src->segment_start;
src->segment_loop =
GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
src->need_flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
break;
case GST_EVENT_FLUSH:
src->need_flush = TRUE;
@ -462,34 +431,61 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
}
static void
gst_fakesrc_update_functions (GstFakeSrc * src)
gst_fakesrc_set_pad_functions (GstFakeSrc * src, GstPad * pad)
{
GList *pads;
gst_pad_set_activate_function (pad, gst_fakesrc_activate);
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_fakesrc_query);
gst_pad_set_query_type_function (pad, gst_fakesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_fakesrc_get_formats);
if (src->loop_based) {
gst_element_set_loop_function (GST_ELEMENT (src),
GST_DEBUG_FUNCPTR (gst_fakesrc_loop));
} else {
gst_element_set_loop_function (GST_ELEMENT (src), NULL);
if (src->has_loop)
gst_pad_set_loop_function (pad, gst_fakesrc_loop);
else
gst_pad_set_loop_function (pad, NULL);
if (src->has_getrange)
gst_pad_set_getrange_function (pad, gst_fakesrc_get_range);
else
gst_pad_set_getrange_function (pad, NULL);
}
static void
gst_fakesrc_set_all_pad_functions (GstFakeSrc * src)
{
GList *l;
for (l = GST_ELEMENT_PADS (src); l; l = l->next)
gst_fakesrc_set_pad_functions (src, (GstPad *) l->data);
}
static GstPad *
gst_fakesrc_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
gchar *name;
GstPad *srcpad;
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
return NULL;
}
pads = GST_ELEMENT (src)->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);
fakesrc = GST_FAKESRC (element);
if (src->loop_based) {
gst_pad_set_get_function (pad, NULL);
} else {
gst_pad_set_get_function (pad, GST_DEBUG_FUNCPTR (gst_fakesrc_get));
}
name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_fakesrc_query);
gst_pad_set_query_type_function (pad, gst_fakesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_fakesrc_get_formats);
pads = g_list_next (pads);
}
srcpad = gst_pad_new_from_template (templ, name);
gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
gst_fakesrc_set_pad_functions (fakesrc, srcpad);
g_free (name);
return srcpad;
}
static void
@ -511,13 +507,16 @@ gst_fakesrc_set_property (GObject * object, guint prop_id, const GValue * value,
{
GstFakeSrc *src;
/* it's not null if we got it, but it might not be ours */
src = GST_FAKESRC (object);
switch (prop_id) {
case ARG_LOOP_BASED:
src->loop_based = g_value_get_boolean (value);
gst_fakesrc_update_functions (src);
case ARG_HAS_LOOP:
src->has_loop = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_HAS_GETRANGE:
src->has_getrange = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_OUTPUT:
g_warning ("not yet implemented");
@ -595,8 +594,11 @@ gst_fakesrc_get_property (GObject * object, guint prop_id, GValue * value,
case ARG_NUM_SOURCES:
g_value_set_int (value, GST_ELEMENT (src)->numsrcpads);
break;
case ARG_LOOP_BASED:
g_value_set_boolean (value, src->loop_based);
case ARG_HAS_LOOP:
g_value_set_boolean (value, src->has_loop);
break;
case ARG_HAS_GETRANGE:
g_value_set_boolean (value, src->has_getrange);
break;
case ARG_OUTPUT:
g_value_set_enum (value, src->output);
@ -789,36 +791,28 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
return buf;
}
static GstData *
gst_fakesrc_get (GstPad * pad)
static GstFlowReturn
gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFakeSrc *src;
GstBuffer *buf;
GstClockTime time;
g_return_val_if_fail (pad != NULL, NULL);
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
g_return_val_if_fail (GST_IS_FAKESRC (src), NULL);
if (src->need_flush) {
src->need_flush = FALSE;
return GST_DATA (gst_event_new (GST_EVENT_FLUSH));
}
if (src->buffer_count == src->segment_end) {
if (src->segment_loop) {
return GST_DATA (gst_event_new (GST_EVENT_SEGMENT_DONE));
//gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
} else {
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED;
}
}
if (src->rt_num_buffers == 0) {
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED;
} else {
if (src->rt_num_buffers > 0)
src->rt_num_buffers--;
@ -826,8 +820,8 @@ gst_fakesrc_get (GstPad * pad)
if (src->eos) {
GST_INFO ("fakesrc is setting eos on pad");
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED;
}
buf = gst_fakesrc_create_buffer (src);
@ -838,7 +832,7 @@ gst_fakesrc_get (GstPad * pad)
if (src->datarate > 0) {
time = (src->bytes_sent * GST_SECOND) / src->datarate;
if (src->sync) {
gst_element_wait (GST_ELEMENT (src), time);
/* gst_element_wait (GST_ELEMENT (src), time); */
}
GST_BUFFER_DURATION (buf) =
@ -866,49 +860,121 @@ gst_fakesrc_get (GstPad * pad)
src->bytes_sent += GST_BUFFER_SIZE (buf);
return GST_DATA (buf);
*ret = buf;
return GST_FLOW_OK;
}
static GstFlowReturn
gst_fakesrc_get_range (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFlowReturn fret;
g_assert (GST_FAKESRC (GST_OBJECT_PARENT (pad))->pad_mode ==
GST_ACTIVATE_PULL);
GST_STREAM_LOCK (pad);
fret = gst_fakesrc_get_range_unlocked (pad, offset, length, ret);
GST_STREAM_UNLOCK (pad);
return fret;
}
/**
* gst_fakesrc_loop:
* @element: the faksesrc to loop
*
* generate an empty buffer and push it to the next element.
*/
static void
gst_fakesrc_loop (GstElement * element)
gst_fakesrc_loop (GstPad * pad)
{
GstFakeSrc *src;
const GList *pads;
GstBuffer *buf = NULL;
GstFlowReturn ret;
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_FAKESRC (element));
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
src = GST_FAKESRC (element);
g_assert (src->pad_mode == GST_ACTIVATE_PUSH);
pads = element->pads;
while (pads) {
GstPad *pad = GST_PAD (pads->data);
GstData *data;
data = gst_fakesrc_get (pad);
gst_pad_push (pad, data);
if (src->eos) {
return;
}
pads = g_list_next (pads);
GST_STREAM_LOCK (pad);
if (src->need_flush) {
src->need_flush = FALSE;
gst_pad_push_event (pad, gst_event_new (GST_EVENT_FLUSH));
}
ret = gst_fakesrc_get_range_unlocked (pad, src->buffer_count,
DEFAULT_SIZEMAX, &buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
ret = gst_pad_push (pad, buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
GST_STREAM_UNLOCK (pad);
return;
pause:
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
static gboolean
gst_fakesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstFakeSrc *fakesrc;
fakesrc = GST_FAKESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
g_return_val_if_fail (fakesrc->has_loop, FALSE);
if (GST_ELEMENT_SCHEDULER (fakesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (fakesrc),
(GstTaskFunction) gst_fakesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_PULL:
g_return_val_if_fail (fakesrc->has_getrange, FALSE);
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
if (GST_RPAD_TASK (pad)) {
gst_task_stop (GST_RPAD_TASK (pad));
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
fakesrc->pad_mode = mode;
return result;
}
static GstElementStateReturn
gst_fakesrc_change_state (GstElement * element)
{
GstFakeSrc *fakesrc;
GstElementStateReturn result = GST_STATE_FAILURE;
g_return_val_if_fail (GST_IS_FAKESRC (element), GST_STATE_FAILURE);
g_return_val_if_fail (GST_IS_FAKESRC (element), result);
fakesrc = GST_FAKESRC (element);
@ -916,6 +982,7 @@ gst_fakesrc_change_state (GstElement * element)
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
{
fakesrc->buffer_count = 0;
fakesrc->pattern_byte = 0x00;
fakesrc->need_flush = FALSE;
@ -923,7 +990,14 @@ gst_fakesrc_change_state (GstElement * element)
fakesrc->bytes_sent = 0;
fakesrc->rt_num_buffers = fakesrc->num_buffers;
break;
}
case GST_STATE_PAUSED_TO_PLAYING:
break;
}
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
@ -940,8 +1014,5 @@ gst_fakesrc_change_state (GstElement * element)
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
return result;
}

View file

@ -76,13 +76,15 @@ typedef struct _GstFakeSrcClass GstFakeSrcClass;
struct _GstFakeSrc {
GstElement element;
gboolean loop_based;
gboolean has_loop;
gboolean has_getrange;
gboolean eos;
GstFakeSrcOutputType output;
GstFakeSrcDataType data;
GstFakeSrcSizeType sizetype;
GstFakeSrcFillType filltype;
GstActivateMode pad_mode;
guint sizemin;
guint sizemax;

View file

@ -170,13 +170,17 @@ static void gst_filesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_filesrc_check_filesize (GstFileSrc * src);
static GstData *gst_filesrc_get (GstPad * pad);
static GstFlowReturn gst_filesrc_get (GstPad * pad, GstBuffer ** buffer);
static GstFlowReturn gst_filesrc_getrange (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buffer);
static gboolean gst_filesrc_srcpad_event (GstPad * pad, GstEvent * event);
static gboolean gst_filesrc_srcpad_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value);
static gboolean gst_filesrc_activate (GstPad * pad, GstActivateMode mode);
static GstElementStateReturn gst_filesrc_change_state (GstElement * element);
static GstCaps *gst_filesrc_type_find (GstFileSrc * src);
static void gst_filesrc_uri_handler_init (gpointer g_iface,
gpointer iface_data);
@ -247,7 +251,8 @@ gst_filesrc_init (GstFileSrc * src)
src->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_pad_set_get_function (src->srcpad, gst_filesrc_get);
gst_pad_set_getrange_function (src->srcpad, gst_filesrc_getrange);
gst_pad_set_activate_function (src->srcpad, gst_filesrc_activate);
gst_pad_set_event_function (src->srcpad, gst_filesrc_srcpad_event);
gst_pad_set_event_mask_function (src->srcpad, gst_filesrc_get_event_mask);
gst_pad_set_query_function (src->srcpad, gst_filesrc_srcpad_query);
@ -672,7 +677,7 @@ gst_filesrc_get_read (GstFileSrc * src)
if (ret == 0) {
GST_DEBUG ("non-regular file hits EOS");
gst_buffer_unref (buf);
gst_element_set_eos (GST_ELEMENT (src));
//gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
}
readsize = ret;
@ -686,20 +691,36 @@ gst_filesrc_get_read (GstFileSrc * src)
return GST_DATA (buf);
}
static GstData *
gst_filesrc_get (GstPad * pad)
static GstFlowReturn
gst_filesrc_getrange (GstPad * pad, guint64 offset, guint length,
GstBuffer ** buffer)
{
GstFileSrc *src;
g_return_val_if_fail (pad != NULL, NULL);
src = GST_FILESRC (gst_pad_get_parent (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN), NULL);
src = GST_FILESRC (GST_PAD_PARENT (pad));
src->curoffset = offset;
src->block_size = length;
return gst_filesrc_get (pad, buffer);
}
static GstFlowReturn
gst_filesrc_get (GstPad * pad, GstBuffer ** buffer)
{
GstFileSrc *src;
GstData *data;
src = GST_FILESRC (GST_PAD_PARENT (pad));
g_return_val_if_fail (GST_FLAG_IS_SET (src, GST_FILESRC_OPEN),
GST_FLOW_WRONG_STATE);
/* check for flush */
if (src->need_flush) {
src->need_flush = FALSE;
GST_DEBUG_OBJECT (src, "sending flush");
return GST_DATA (gst_event_new_flush ());
gst_pad_push_event (pad, gst_event_new_flush (TRUE));
}
/* check for seek */
if (src->need_discont) {
@ -710,7 +731,7 @@ gst_filesrc_get (GstPad * pad)
gst_event_new_discontinuous (src->need_discont > 1, GST_FORMAT_BYTES,
(guint64) src->curoffset, GST_FORMAT_UNDEFINED);
src->need_discont = 0;
return GST_DATA (event);
gst_pad_push_event (pad, event);
}
/* check for EOF if it's a regular file */
@ -721,20 +742,33 @@ gst_filesrc_get (GstPad * pad)
GST_DEBUG_OBJECT (src, "eos %" G_GINT64_FORMAT " %" G_GINT64_FORMAT,
src->curoffset, src->filelen);
}
gst_element_set_eos (GST_ELEMENT (src));
return GST_DATA (gst_event_new (GST_EVENT_EOS));
//gst_element_set_eos (GST_ELEMENT (src));
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_WRONG_STATE;
}
}
#ifdef HAVE_MMAP
if (src->using_mmap) {
return gst_filesrc_get_mmap (src);
data = gst_filesrc_get_mmap (src);
} else {
return gst_filesrc_get_read (src);
data = gst_filesrc_get_read (src);
}
#else
return gst_filesrc_get_read (src);
data = gst_filesrc_get_read (src);
#endif
if (data == NULL) {
GST_DEBUG_OBJECT (src, "could not get data");
return GST_FLOW_ERROR;
}
if (GST_IS_EVENT (data)) {
gst_pad_push_event (pad, GST_EVENT (data));
} else {
*buffer = GST_BUFFER (data);
}
return GST_FLOW_OK;
}
/* TRUE if the filesize of the file was updated */
@ -821,6 +855,22 @@ gst_filesrc_open_file (GstFileSrc * src)
src->curoffset = 0;
GST_FLAG_SET (src, GST_FILESRC_OPEN);
{
GstCaps *caps;
guint64 offset;
guint length;
offset = src->curoffset;
length = src->block_size;
caps = gst_filesrc_type_find (src);
gst_pad_set_caps (src->srcpad, caps);
src->curoffset = offset;
src->block_size = length;
}
}
return TRUE;
}
@ -848,10 +898,77 @@ gst_filesrc_close_file (GstFileSrc * src)
GST_FLAG_UNSET (src, GST_FILESRC_OPEN);
}
static void
gst_filesrc_loop (GstPad * pad)
{
GstFileSrc *filesrc;
gboolean result;
GstBuffer *buffer;
filesrc = GST_FILESRC (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
result = gst_filesrc_get (pad, &buffer);
if (result != GST_FLOW_OK) {
gst_task_pause (GST_RPAD_TASK (pad));
goto done;
}
result = gst_pad_push (pad, buffer);
if (result != GST_FLOW_OK) {
gst_task_pause (GST_RPAD_TASK (pad));
}
done:
GST_STREAM_UNLOCK (pad);
}
static gboolean
gst_filesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstFileSrc *filesrc;
filesrc = GST_FILESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
if (GST_ELEMENT_SCHEDULER (filesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (filesrc),
(GstTaskFunction) gst_filesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
result = TRUE;
GST_STREAM_UNLOCK (pad);
}
break;
case GST_ACTIVATE_PULL:
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
gst_task_stop (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
return result;
}
static GstElementStateReturn
gst_filesrc_change_state (GstElement * element)
{
GstElementStateReturn result = GST_STATE_SUCCESS;
GstFileSrc *src = GST_FILESRC (element);
switch (GST_STATE_TRANSITION (element)) {
@ -866,6 +983,17 @@ gst_filesrc_change_state (GstElement * element)
}
src->need_discont = 2;
break;
case GST_STATE_PAUSED_TO_PLAYING:
gst_task_start (GST_RPAD_TASK (src->srcpad));
break;
}
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_PLAYING_TO_PAUSED:
gst_task_start (GST_RPAD_TASK (src->srcpad));
break;
case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_FILESRC_OPEN))
gst_filesrc_close_file (GST_FILESRC (element));
@ -874,10 +1002,7 @@ gst_filesrc_change_state (GstElement * element)
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
return result;
}
static gboolean
@ -1013,6 +1138,90 @@ error:
return FALSE;
}
typedef struct
{
GstFileSrc *src;
guint best_probability;
GstCaps *caps;
GstBuffer *buffer;
}
FileSrcTypeFind;
static guint8 *
filesrc_find_peek (gpointer data, gint64 offset, guint size)
{
FileSrcTypeFind *find;
GstBuffer *buffer;
GstFileSrc *src;
if (size == 0)
return NULL;
find = (FileSrcTypeFind *) data;
src = find->src;
if (offset < 0) {
offset += src->filelen;
}
buffer = NULL;
gst_filesrc_getrange (src->srcpad, offset, size, &buffer);
if (find->buffer) {
gst_buffer_unref (find->buffer);
}
find->buffer = buffer;
return GST_BUFFER_DATA (buffer);
}
static void
filesrc_find_suggest (gpointer data, guint probability, const GstCaps * caps)
{
FileSrcTypeFind *find = (FileSrcTypeFind *) data;
if (probability > find->best_probability) {
gst_caps_replace (&find->caps, gst_caps_copy (caps));
find->best_probability = probability;
}
}
static GstCaps *
gst_filesrc_type_find (GstFileSrc * src)
{
GstTypeFind gst_find;
FileSrcTypeFind find;
GList *walk, *type_list = NULL;
GstCaps *result = NULL;
walk = type_list = gst_type_find_factory_get_list ();
find.src = src;
find.best_probability = 0;
find.caps = NULL;
find.buffer = NULL;
gst_find.data = &find;
gst_find.peek = filesrc_find_peek;
gst_find.suggest = filesrc_find_suggest;
gst_find.get_length = NULL;
while (walk) {
GstTypeFindFactory *factory = GST_TYPE_FIND_FACTORY (walk->data);
gst_type_find_factory_call_function (factory, &gst_find);
if (find.best_probability >= GST_TYPE_FIND_MAXIMUM)
break;
walk = g_list_next (walk);
}
if (find.best_probability > 0)
result = find.caps;
return result;
}
/*** GSTURIHANDLER INTERFACE *************************************************/
static guint

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstidentity.c:
*
@ -71,21 +72,28 @@ enum
enum
{
ARG_0,
ARG_LOOP_BASED,
ARG_SLEEP_TIME,
ARG_DUPLICATE,
ARG_ERROR_AFTER,
ARG_DROP_PROBABILITY,
ARG_DATARATE,
ARG_SILENT,
ARG_LAST_MESSAGE,
ARG_DUMP,
ARG_SYNC,
ARG_CHECK_PERFECT
PROP_0,
PROP_HAS_GETRANGE,
PROP_HAS_CHAIN,
PROP_HAS_SINK_LOOP,
PROP_HAS_SRC_LOOP,
PROP_LOOP_BASED,
PROP_SLEEP_TIME,
PROP_DUPLICATE,
PROP_ERROR_AFTER,
PROP_DROP_PROBABILITY,
PROP_DATARATE,
PROP_SILENT,
PROP_LAST_MESSAGE,
PROP_DUMP,
PROP_SYNC,
PROP_CHECK_PERFECT
};
typedef GstFlowReturn (*IdentityPushFunc) (GstIdentity *, GstBuffer *);
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_identity_debug, "identity", 0, "identity element");
@ -99,8 +107,16 @@ static void gst_identity_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstElementStateReturn gst_identity_change_state (GstElement * element);
static void gst_identity_chain (GstPad * pad, GstData * _data);
static gboolean gst_identity_event (GstPad * pad, GstEvent * event);
static GstFlowReturn gst_identity_getrange (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buffer);
static GstFlowReturn gst_identity_chain (GstPad * pad, GstBuffer * buffer);
static void gst_identity_src_loop (GstPad * pad);
static void gst_identity_sink_loop (GstPad * pad);
static GstFlowReturn gst_identity_handle_buffer (GstIdentity * identity,
GstBuffer * buf);
static void gst_identity_set_clock (GstElement * element, GstClock * clock);
static GstCaps *gst_identity_proxy_getcaps (GstPad * pad);
static guint gst_identity_signals[LAST_SIGNAL] = { 0 };
@ -124,6 +140,9 @@ gst_identity_finalize (GObject * object)
identity = GST_IDENTITY (object);
g_mutex_free (identity->pen_lock);
g_cond_free (identity->pen_cond);
g_free (identity->last_message);
G_OBJECT_CLASS (parent_class)->finalize (object);
@ -141,42 +160,54 @@ gst_identity_class_init (GstIdentityClass * klass)
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_identity_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_identity_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOOP_BASED,
g_param_spec_boolean ("loop-based", "Loop-based",
"Set to TRUE to use loop-based rather than chain-based scheduling",
DEFAULT_LOOP_BASED, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SLEEP_TIME,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_GETRANGE,
g_param_spec_boolean ("has-getrange", "Has getrange",
"If the src pad will implement a getrange function",
TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
g_param_spec_boolean ("has-chain", "Has chain",
"If the sink pad will implement a chain function",
TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SRC_LOOP,
g_param_spec_boolean ("has-src-loop", "Has src loop",
"If the src pad will implement a loop function",
FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
g_param_spec_boolean ("has-sink-loop", "Has sink loop",
"If the sink pad will implement a loop function",
FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SLEEP_TIME,
g_param_spec_uint ("sleep-time", "Sleep time",
"Microseconds to sleep between processing", 0, G_MAXUINT,
DEFAULT_SLEEP_TIME, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUPLICATE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUPLICATE,
g_param_spec_uint ("duplicate", "Duplicate Buffers",
"Push the buffers N times", 0, G_MAXUINT, DEFAULT_DUPLICATE,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ERROR_AFTER,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ERROR_AFTER,
g_param_spec_int ("error_after", "Error After", "Error after N buffers",
G_MININT, G_MAXINT, DEFAULT_ERROR_AFTER, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DROP_PROBABILITY,
g_param_spec_float ("drop_probability", "Drop Probability",
"The Probability a buffer is dropped", 0.0, 1.0,
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_DROP_PROBABILITY, g_param_spec_float ("drop_probability",
"Drop Probability", "The Probability a buffer is dropped", 0.0, 1.0,
DEFAULT_DROP_PROBABILITY, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DATARATE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DATARATE,
g_param_spec_int ("datarate", "Datarate",
"(Re)timestamps buffers with number of bytes per second (0 = inactive)",
0, G_MAXINT, DEFAULT_DATARATE, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
g_param_spec_boolean ("silent", "silent", "silent", DEFAULT_SILENT,
G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
g_param_spec_string ("last-message", "last-message", "last-message", NULL,
G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DUMP,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DUMP,
g_param_spec_boolean ("dump", "Dump", "Dump buffer contents",
DEFAULT_DUMP, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SYNC,
g_param_spec_boolean ("sync", "Synchronize",
"Synchronize to pipeline clock", DEFAULT_SYNC, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_CHECK_PERFECT,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_CHECK_PERFECT,
g_param_spec_boolean ("check-perfect", "Check For Perfect Stream",
"Verify that the stream is time- and data-contiguous",
DEFAULT_CHECK_PERFECT, G_PARAM_READWRITE));
@ -202,19 +233,20 @@ gst_identity_init (GstIdentity * identity)
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (identity), identity->sinkpad);
gst_pad_set_chain_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_chain));
//gst_pad_set_link_function (identity->sinkpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->sinkpad, gst_pad_proxy_getcaps);
gst_pad_set_getcaps_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
gst_pad_set_event_function (identity->sinkpad,
GST_DEBUG_FUNCPTR (gst_identity_event));
identity->srcpad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_pad_set_getcaps_function (identity->srcpad,
GST_DEBUG_FUNCPTR (gst_identity_proxy_getcaps));
gst_pad_set_getrange_function (identity->srcpad,
GST_DEBUG_FUNCPTR (gst_identity_getrange));
gst_element_add_pad (GST_ELEMENT (identity), identity->srcpad);
//gst_pad_set_link_function (identity->srcpad, gst_pad_proxy_pad_link);
gst_pad_set_getcaps_function (identity->srcpad, gst_pad_proxy_getcaps);
identity->loop_based = DEFAULT_LOOP_BASED;
identity->sleep_time = DEFAULT_SLEEP_TIME;
identity->duplicate = DEFAULT_DUPLICATE;
identity->error_after = DEFAULT_ERROR_AFTER;
@ -227,7 +259,10 @@ gst_identity_init (GstIdentity * identity)
identity->last_message = NULL;
identity->srccaps = NULL;
GST_FLAG_SET (identity, GST_ELEMENT_EVENT_AWARE);
identity->pen_data = NULL;
identity->pen_lock = g_mutex_new ();
identity->pen_cond = g_cond_new ();
identity->pen_flushing = FALSE;
}
static void
@ -238,36 +273,230 @@ gst_identity_set_clock (GstElement * element, GstClock * clock)
gst_object_replace ((GstObject **) & identity->clock, (GstObject *) clock);
}
static GstCaps *
gst_identity_proxy_getcaps (GstPad * pad)
{
GstPad *otherpad;
GstIdentity *identity = GST_IDENTITY (GST_OBJECT_PARENT (pad));
otherpad = pad == identity->srcpad ? identity->sinkpad : identity->srcpad;
return gst_pad_peer_get_caps (otherpad);
}
static gboolean
identity_queue_push (GstIdentity * identity, GstData * data)
{
gboolean ret;
g_mutex_lock (identity->pen_lock);
while (identity->pen_data && !identity->pen_flushing)
g_cond_wait (identity->pen_cond, identity->pen_lock);
if (identity->pen_flushing) {
gst_data_unref (identity->pen_data);
identity->pen_data = NULL;
gst_data_unref (data);
ret = FALSE;
} else {
identity->pen_data = data;
ret = TRUE;
}
g_cond_signal (identity->pen_cond);
g_mutex_unlock (identity->pen_lock);
return ret;
}
static GstData *
identity_queue_pop (GstIdentity * identity)
{
GstData *ret;
g_mutex_lock (identity->pen_lock);
while (!(ret = identity->pen_data) && !identity->pen_flushing)
g_cond_wait (identity->pen_cond, identity->pen_lock);
g_cond_signal (identity->pen_cond);
g_mutex_unlock (identity->pen_lock);
return ret;
}
static void
gst_identity_chain (GstPad * pad, GstData * _data)
identity_queue_flush (GstIdentity * identity)
{
g_mutex_lock (identity->pen_lock);
identity->pen_flushing = TRUE;
g_cond_signal (identity->pen_cond);
g_mutex_unlock (identity->pen_lock);
}
static gboolean
gst_identity_event (GstPad * pad, GstEvent * event)
{
GstBuffer *buf = GST_BUFFER (_data);
GstIdentity *identity;
guint i;
gboolean ret;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
identity = GST_IDENTITY (gst_pad_get_parent (pad));
GST_STREAM_LOCK (pad);
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
if (!identity->silent) {
g_free (identity->last_message);
if (!identity->silent) {
g_free (identity->last_message);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
identity->last_message =
g_strdup_printf ("chain ******* (%s:%s)E (type: %d) %p",
GST_DEBUG_PAD_NAME (pad), GST_EVENT_TYPE (event), event);
g_object_notify (G_OBJECT (identity), "last_message");
}
gst_pad_event_default (pad, event);
return;
g_object_notify (G_OBJECT (identity), "last_message");
}
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH:
/* forward event */
gst_pad_event_default (pad, event);
if (GST_EVENT_FLUSH_DONE (event)) {
if (identity->sink_mode == GST_ACTIVATE_PULL) {
/* already have the sink stream lock */
gst_task_start (GST_RPAD_TASK (identity->sinkpad));
}
if (identity->src_mode == GST_ACTIVATE_PUSH) {
GST_STREAM_LOCK (identity->srcpad);
gst_task_start (GST_RPAD_TASK (identity->srcpad));
GST_STREAM_UNLOCK (identity->srcpad);
}
} else {
/* unblock both functions */
identity_queue_flush (identity);
}
ret = TRUE;
goto done;
case GST_EVENT_EOS:
if (identity->sink_mode == GST_ACTIVATE_PULL) {
/* already have the sink stream lock */
gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
}
break;
default:
break;
}
if (identity->decoupled) {
ret = identity_queue_push (identity, (GstData *) event);
} else {
ret = gst_pad_push_event (identity->srcpad, event);
}
done:
GST_STREAM_UNLOCK (pad);
return ret;
}
static GstFlowReturn
gst_identity_getrange (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buffer)
{
GstIdentity *identity;
GstFlowReturn ret;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
ret = gst_pad_pull_range (identity->sinkpad, offset, length, buffer);
GST_STREAM_UNLOCK (pad);
return ret;
}
static GstFlowReturn
gst_identity_chain (GstPad * pad, GstBuffer * buffer)
{
GstIdentity *identity;
GstFlowReturn ret = GST_FLOW_OK;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
ret = gst_identity_handle_buffer (identity, buffer);
GST_STREAM_UNLOCK (pad);
return ret;
}
#define DEFAULT_PULL_SIZE 1024
static void
gst_identity_sink_loop (GstPad * pad)
{
GstIdentity *identity;
GstBuffer *buffer;
GstFlowReturn ret;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
ret = gst_pad_pull_range (pad, identity->offset, DEFAULT_PULL_SIZE, &buffer);
if (ret != GST_FLOW_OK)
goto sink_loop_pause;
ret = gst_identity_handle_buffer (identity, buffer);
if (ret != GST_FLOW_OK)
goto sink_loop_pause;
GST_STREAM_UNLOCK (pad);
return;
sink_loop_pause:
gst_task_pause (GST_RPAD_TASK (identity->sinkpad));
GST_STREAM_UNLOCK (pad);
return;
}
static void
gst_identity_src_loop (GstPad * pad)
{
GstIdentity *identity;
GstData *data;
GstFlowReturn ret;
identity = GST_IDENTITY (GST_PAD_PARENT (pad));
GST_STREAM_LOCK (pad);
data = identity_queue_pop (identity);
if (!data) /* we're getting flushed */
goto src_loop_pause;
if (GST_IS_EVENT (data)) {
if (GST_EVENT_TYPE (data) == GST_EVENT_EOS)
gst_task_pause (GST_RPAD_TASK (identity->srcpad));
gst_pad_push_event (identity->srcpad, GST_EVENT (data));
} else {
ret = gst_pad_push (identity->srcpad, (GstBuffer *) data);
if (ret != GST_FLOW_OK)
goto src_loop_pause;
}
GST_STREAM_UNLOCK (pad);
return;
src_loop_pause:
gst_task_pause (GST_RPAD_TASK (identity->srcpad));
GST_STREAM_UNLOCK (pad);
return;
}
static GstFlowReturn
gst_identity_handle_buffer (GstIdentity * identity, GstBuffer * buf)
{
GstFlowReturn ret = GST_FLOW_OK;
guint i;
/* see if we need to do perfect stream checking */
/* invalid timestamp drops us out of check. FIXME: maybe warn ? */
if (identity->check_perfect &&
@ -303,7 +532,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
gst_buffer_unref (buf);
GST_ELEMENT_ERROR (identity, CORE, FAILED,
(_("Failed after iterations as requested.")), (NULL));
return;
return GST_FLOW_ERROR;
}
}
@ -320,9 +549,10 @@ gst_identity_chain (GstPad * pad, GstData * _data)
GST_BUFFER_OFFSET_END (buf), GST_BUFFER_FLAGS (buf), buf);
g_object_notify (G_OBJECT (identity), "last-message");
gst_buffer_unref (buf);
return;
return GST_FLOW_OK;
}
}
if (identity->dump) {
gst_util_dump_mem (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
}
@ -346,7 +576,7 @@ gst_identity_chain (GstPad * pad, GstData * _data)
time = GST_BUFFER_TIMESTAMP (buf);
if (identity->datarate > 0) {
time = identity->bytes_handled * GST_SECOND / identity->datarate;
time = identity->offset * GST_SECOND / identity->datarate;
GST_BUFFER_TIMESTAMP (buf) = time;
GST_BUFFER_DURATION (buf) =
@ -361,41 +591,49 @@ gst_identity_chain (GstPad * pad, GstData * _data)
if (identity->sync) {
if (identity->clock) {
gst_element_wait (GST_ELEMENT (identity), time);
/* gst_element_wait (GST_ELEMENT (identity), time); */
}
}
identity->bytes_handled += GST_BUFFER_SIZE (buf);
gst_pad_push (identity->srcpad, GST_DATA (buf));
identity->offset += GST_BUFFER_SIZE (buf);
if (identity->decoupled) {
if (!identity_queue_push (identity, (GstData *) buf))
return GST_FLOW_UNEXPECTED;
} else {
ret = gst_pad_push (identity->srcpad, buf);
if (ret != GST_FLOW_OK)
return ret;
}
if (identity->sleep_time)
g_usleep (identity->sleep_time);
}
return ret;
}
static void
gst_identity_loop (GstElement * element)
gst_identity_set_dataflow_funcs (GstIdentity * identity)
{
GstIdentity *identity;
GstBuffer *buf;
if (identity->has_getrange)
gst_pad_set_getrange_function (identity->srcpad, gst_identity_getrange);
else
gst_pad_set_getrange_function (identity->srcpad, NULL);
g_return_if_fail (element != NULL);
g_return_if_fail (GST_IS_IDENTITY (element));
if (identity->has_chain)
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
else
gst_pad_set_chain_function (identity->sinkpad, NULL);
identity = GST_IDENTITY (element);
if (identity->has_src_loop)
gst_pad_set_loop_function (identity->srcpad, gst_identity_src_loop);
else
gst_pad_set_loop_function (identity->srcpad, NULL);
buf = GST_BUFFER (gst_pad_pull (identity->sinkpad));
if (GST_IS_EVENT (buf)) {
GstEvent *event = GST_EVENT (buf);
if (GST_EVENT_IS_INTERRUPT (event)) {
gst_event_unref (event);
} else {
gst_pad_event_default (identity->sinkpad, event);
}
} else {
gst_identity_chain (identity->sinkpad, GST_DATA (buf));
}
if (identity->has_sink_loop)
gst_pad_set_loop_function (identity->sinkpad, gst_identity_sink_loop);
else
gst_pad_set_loop_function (identity->sinkpad, NULL);
}
static void
@ -404,48 +642,50 @@ gst_identity_set_property (GObject * object, guint prop_id,
{
GstIdentity *identity;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_IDENTITY (object));
identity = GST_IDENTITY (object);
switch (prop_id) {
case ARG_LOOP_BASED:
identity->loop_based = g_value_get_boolean (value);
if (identity->loop_based) {
gst_element_set_loop_function (GST_ELEMENT (identity),
gst_identity_loop);
gst_pad_set_chain_function (identity->sinkpad, NULL);
} else {
gst_pad_set_chain_function (identity->sinkpad, gst_identity_chain);
gst_element_set_loop_function (GST_ELEMENT (identity), NULL);
}
case PROP_HAS_GETRANGE:
identity->has_getrange = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case ARG_SLEEP_TIME:
case PROP_HAS_CHAIN:
identity->has_chain = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case PROP_HAS_SRC_LOOP:
identity->has_src_loop = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case PROP_HAS_SINK_LOOP:
identity->has_sink_loop = g_value_get_boolean (value);
gst_identity_set_dataflow_funcs (identity);
break;
case PROP_SLEEP_TIME:
identity->sleep_time = g_value_get_uint (value);
break;
case ARG_SILENT:
case PROP_SILENT:
identity->silent = g_value_get_boolean (value);
break;
case ARG_DUPLICATE:
case PROP_DUPLICATE:
identity->duplicate = g_value_get_uint (value);
break;
case ARG_DUMP:
case PROP_DUMP:
identity->dump = g_value_get_boolean (value);
break;
case ARG_ERROR_AFTER:
case PROP_ERROR_AFTER:
identity->error_after = g_value_get_int (value);
break;
case ARG_DROP_PROBABILITY:
case PROP_DROP_PROBABILITY:
identity->drop_probability = g_value_get_float (value);
break;
case ARG_DATARATE:
case PROP_DATARATE:
identity->datarate = g_value_get_int (value);
break;
case ARG_SYNC:
case PROP_SYNC:
identity->sync = g_value_get_boolean (value);
break;
case ARG_CHECK_PERFECT:
case PROP_CHECK_PERFECT:
identity->check_perfect = g_value_get_boolean (value);
break;
default:
@ -460,43 +700,49 @@ gst_identity_get_property (GObject * object, guint prop_id, GValue * value,
{
GstIdentity *identity;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_IDENTITY (object));
identity = GST_IDENTITY (object);
switch (prop_id) {
case ARG_LOOP_BASED:
g_value_set_boolean (value, identity->loop_based);
case PROP_HAS_GETRANGE:
g_value_set_boolean (value, identity->has_getrange);
break;
case ARG_SLEEP_TIME:
case PROP_HAS_CHAIN:
g_value_set_boolean (value, identity->has_chain);
break;
case PROP_HAS_SRC_LOOP:
g_value_set_boolean (value, identity->has_src_loop);
break;
case PROP_HAS_SINK_LOOP:
g_value_set_boolean (value, identity->has_sink_loop);
break;
case PROP_SLEEP_TIME:
g_value_set_uint (value, identity->sleep_time);
break;
case ARG_DUPLICATE:
case PROP_DUPLICATE:
g_value_set_uint (value, identity->duplicate);
break;
case ARG_ERROR_AFTER:
case PROP_ERROR_AFTER:
g_value_set_int (value, identity->error_after);
break;
case ARG_DROP_PROBABILITY:
case PROP_DROP_PROBABILITY:
g_value_set_float (value, identity->drop_probability);
break;
case ARG_DATARATE:
case PROP_DATARATE:
g_value_set_int (value, identity->datarate);
break;
case ARG_SILENT:
case PROP_SILENT:
g_value_set_boolean (value, identity->silent);
break;
case ARG_DUMP:
case PROP_DUMP:
g_value_set_boolean (value, identity->dump);
break;
case ARG_LAST_MESSAGE:
case PROP_LAST_MESSAGE:
g_value_set_string (value, identity->last_message);
break;
case ARG_SYNC:
case PROP_SYNC:
g_value_set_boolean (value, identity->sync);
break;
case ARG_CHECK_PERFECT:
case PROP_CHECK_PERFECT:
g_value_set_boolean (value, identity->check_perfect);
break;
default:
@ -518,7 +764,7 @@ gst_identity_change_state (GstElement * element)
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
identity->bytes_handled = 0;
identity->offset = 0;
identity->prev_timestamp = GST_CLOCK_TIME_NONE;
identity->prev_duration = GST_CLOCK_TIME_NONE;
identity->prev_offset_end = -1;

View file

@ -50,7 +50,19 @@ struct _GstIdentity {
GstPad *sinkpad;
GstPad *srcpad;
gboolean loop_based;
GstData *pen_data;
GMutex *pen_lock;
GCond *pen_cond;
gboolean pen_flushing;
gboolean has_chain;
gboolean has_getrange;
gboolean has_src_loop;
gboolean has_sink_loop;
GstActivateMode sink_mode;
GstActivateMode src_mode;
gboolean decoupled;
guint duplicate;
gint error_after;
gfloat drop_probability;
@ -67,7 +79,7 @@ struct _GstIdentity {
gchar *last_message;
GstCaps *srccaps;
guint64 bytes_handled;
guint64 offset;
};
struct _GstIdentityClass {

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,6 @@
#include <gst/gstelement.h>
G_BEGIN_DECLS
#define GST_TYPE_QUEUE \
@ -80,23 +79,14 @@ struct _GstQueue {
/* it the queue should fail on possible deadlocks */
gboolean may_deadlock;
gboolean interrupt;
gboolean flush;
GMutex *qlock; /* lock for queue (vs object lock) */
GCond *item_add; /* signals buffers now available for reading */
GCond *item_del; /* signals space now available for writing */
GCond *event_done; /* upstream event signaller */
GTimeVal *timeval; /* the timeout for the queue locking */
GQueue *events; /* upstream events get decoupled here */
GstCaps *negotiated_caps;
GMutex *event_lock; /* lock when handling the events queue */
gpointer _gst_reserved[GST_PADDING - 1];
gpointer _gst_reserved[GST_PADDING];
};
struct _GstQueueClass {

View file

@ -1,6 +1,7 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wim.taymans@chello.be>
* 2000,2001,2002,2003,2004,2005 Wim Taymans <wim@fluendo.com>
*
*
* gsttee.c: Tee element, one in N out
*
@ -40,21 +41,16 @@ GstElementDetails gst_tee_details = GST_ELEMENT_DETAILS ("Tee pipe fitting",
"Generic",
"1-to-N pipe fitting",
"Erik Walthinsen <omega@cse.ogi.edu>, "
"Wim Taymans <wim.taymans@chello.be>");
/* Tee signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
"Wim \"Tim\" Taymans <wim@fluendo.com>");
enum
{
ARG_0,
ARG_SILENT,
ARG_NUM_PADS,
ARG_LAST_MESSAGE
PROP_0,
PROP_NUM_SRC_PADS,
PROP_HAS_SINK_LOOP,
PROP_HAS_CHAIN,
PROP_SILENT,
PROP_LAST_MESSAGE
/* FILL ME */
};
@ -77,7 +73,9 @@ static void gst_tee_set_property (GObject * object, guint prop_id,
static void gst_tee_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_tee_chain (GstPad * pad, GstData * _data);
static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer);
static void gst_tee_loop (GstPad * pad);
static gboolean gst_tee_sink_activate (GstPad * pad, GstActivateMode mode);
static void
@ -113,22 +111,26 @@ gst_tee_class_init (GstTeeClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tee_finalize);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_tee_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_tee_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_PADS,
g_param_spec_int ("num_pads", "num_pads", "num_pads",
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NUM_SRC_PADS,
g_param_spec_int ("num-src-pads", "num-src-pads", "num-src-pads",
0, G_MAXINT, 0, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_SINK_LOOP,
g_param_spec_boolean ("has-sink-loop", "has-sink-loop", "has-sink-loop",
FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_HAS_CHAIN,
g_param_spec_boolean ("has-chain", "has-chain", "has-chain",
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SILENT,
g_param_spec_boolean ("silent", "silent", "silent",
TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LAST_MESSAGE,
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LAST_MESSAGE,
g_param_spec_string ("last_message", "last_message", "last_message",
NULL, G_PARAM_READABLE));
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tee_finalize);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_tee_request_new_pad);
}
@ -140,72 +142,30 @@ gst_tee_init (GstTee * tee)
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (tee), tee->sinkpad);
gst_pad_set_chain_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_chain));
//gst_pad_set_link_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_pad_proxy_pad_link));
gst_pad_set_setcaps_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
gst_pad_set_getcaps_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
tee->last_message = NULL;
}
/* helper compare function */
gint
name_pad_compare (gconstpointer a, gconstpointer b)
static void
gst_tee_update_pad_functions (GstTee * tee)
{
GstPad *pad = (GstPad *) a;
gchar *name = (gchar *) b;
gst_pad_set_activate_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_tee_sink_activate));
g_assert (GST_IS_PAD (pad));
if (tee->has_chain)
gst_pad_set_chain_function (tee->sinkpad,
GST_DEBUG_FUNCPTR (gst_tee_chain));
else
gst_pad_set_chain_function (tee->sinkpad, NULL);
return strcmp (name, gst_pad_get_name (pad)); /* returns 0 if match */
}
static GstCaps *
gst_tee_getcaps (GstPad * _pad)
{
GstTee *tee = GST_TEE (gst_pad_get_parent (_pad));
GstCaps *caps = gst_caps_new_any (), *tmp, *res;
GstPad *pad;
const GList *pads;
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
tmp = gst_pad_get_allowed_caps (pad);
res = gst_caps_intersect (caps, tmp);
gst_caps_unref (tmp);
gst_caps_unref (caps);
caps = res;
}
return caps;
}
static GstPadLinkReturn
gst_tee_link (GstPad * _pad, const GstCaps * caps)
{
GstTee *tee = GST_TEE (gst_pad_get_parent (_pad));
GstPadLinkReturn res;
GstPad *pad;
const GList *pads;
GST_DEBUG_OBJECT (tee, "Forwarding link to all other pads");
for (pads = GST_ELEMENT (tee)->pads; pads != NULL; pads = pads->next) {
pad = GST_PAD (pads->data);
if (pad == _pad)
continue;
res = gst_pad_try_set_caps (pad, caps);
GST_DEBUG_OBJECT (tee, "Pad %s:%s gave response %d",
GST_DEBUG_PAD_NAME (pad), res);
if (GST_PAD_LINK_FAILED (res))
return res;
}
return GST_PAD_LINK_OK;
if (tee->has_sink_loop)
gst_pad_set_loop_function (tee->sinkpad, GST_DEBUG_FUNCPTR (gst_tee_loop));
else
gst_pad_set_loop_function (tee->sinkpad, NULL);
}
static GstPad *
@ -215,48 +175,21 @@ gst_tee_request_new_pad (GstElement * element, GstPadTemplate * templ,
gchar *name;
GstPad *srcpad;
GstTee *tee;
gint i = 0;
const GList *pads;
g_return_val_if_fail (GST_IS_TEE (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gsttee: request new pad that is not a SRC pad\n");
return NULL;
}
tee = GST_TEE (element);
/* try names in order and find one that's not in use atm */
pads = element->pads;
name = NULL;
while (!name) {
name = g_strdup_printf ("src%d", i);
if (g_list_find_custom ((GList *) pads, (gconstpointer) name,
name_pad_compare) != NULL) {
/* this name is taken, use the next one */
++i;
g_free (name);
name = NULL;
}
}
if (!tee->silent) {
g_free (tee->last_message);
tee->last_message = g_strdup_printf ("new pad %s", name);
g_object_notify (G_OBJECT (tee), "last_message");
}
GST_LOCK (tee);
name = g_strdup_printf ("src%d", tee->pad_counter++);
GST_UNLOCK (tee);
srcpad = gst_pad_new_from_template (templ, name);
g_free (name);
gst_pad_set_link_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_link));
gst_pad_set_getcaps_function (srcpad, GST_DEBUG_FUNCPTR (gst_tee_getcaps));
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
GST_PAD_ELEMENT_PRIVATE (srcpad) = NULL;
if (GST_PAD_CAPS (tee->sinkpad)) {
gst_pad_try_set_caps (srcpad, GST_PAD_CAPS (tee->sinkpad));
}
gst_pad_set_setcaps_function (srcpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps));
gst_pad_set_getcaps_function (srcpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_element_add_pad (GST_ELEMENT (tee), srcpad);
return srcpad;
}
@ -265,95 +198,202 @@ static void
gst_tee_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstTee *tee;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_TEE (object));
tee = GST_TEE (object);
GstTee *tee = GST_TEE (object);
GST_LOCK (tee);
switch (prop_id) {
case ARG_SILENT:
case PROP_HAS_SINK_LOOP:
tee->has_sink_loop = g_value_get_boolean (value);
gst_tee_update_pad_functions (tee);
break;
case PROP_HAS_CHAIN:
tee->has_chain = g_value_get_boolean (value);
gst_tee_update_pad_functions (tee);
break;
case PROP_SILENT:
tee->silent = g_value_get_boolean (value);
g_object_notify (G_OBJECT (tee), "silent");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_UNLOCK (tee);
}
static void
gst_tee_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstTee *tee;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_TEE (object));
tee = GST_TEE (object);
GstTee *tee = GST_TEE (object);
GST_LOCK (tee);
switch (prop_id) {
case ARG_NUM_PADS:
case PROP_NUM_SRC_PADS:
g_value_set_int (value, GST_ELEMENT (tee)->numsrcpads);
break;
case ARG_SILENT:
case PROP_HAS_SINK_LOOP:
g_value_set_boolean (value, tee->has_sink_loop);
break;
case PROP_HAS_CHAIN:
g_value_set_boolean (value, tee->has_chain);
break;
case PROP_SILENT:
g_value_set_boolean (value, tee->silent);
break;
case ARG_LAST_MESSAGE:
case PROP_LAST_MESSAGE:
g_value_set_string (value, tee->last_message);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
GST_UNLOCK (tee);
}
/**
* gst_tee_chain:
* @pad: the pad to follow
* @buf: the buffer to pass
*
* Chain a buffer on a pad.
*/
static void
gst_tee_chain (GstPad * pad, GstData * _data)
typedef struct
{
GstBuffer *buf = GST_BUFFER (_data);
GstTee *tee;
const GList *pads;
GstBuffer *buffer;
} PushData;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
static gboolean
gst_tee_do_push (GstPad * pad, GValue * ret, PushData * data)
{
GstFlowReturn res;
if (GST_PAD_DIRECTION (pad) != GST_PAD_SRC || !GST_PAD_IS_USABLE (pad))
return TRUE;
if (G_UNLIKELY (!data->tee->silent)) {
GstTee *tee = data->tee;
GstBuffer *buf = data->buffer;
g_free (tee->last_message);
tee->last_message =
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (pad),
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (tee), "last_message");
}
res = gst_pad_push (pad, gst_buffer_ref (data->buffer));
g_value_set_enum (ret, res);
return (res == GST_FLOW_OK);
}
static GstFlowReturn
gst_tee_handle_buffer (GstTee * tee, GstBuffer * buffer)
{
GstIterator *iter;
PushData data;
GValue ret = { 0, };
GstIteratorResult res;
tee->offset += GST_BUFFER_SIZE (buffer);
g_value_init (&ret, GST_TYPE_FLOW_RETURN);
iter = gst_element_iterate_pads (GST_ELEMENT (tee));
data.tee = tee;
data.buffer = buffer;
res = gst_iterator_fold (iter, (GstIteratorFoldFunction) gst_tee_do_push,
&ret, &data);
gst_iterator_free (iter);
gst_buffer_unref (buffer);
/* no need to unset gvalue */
return g_value_get_enum (&ret);
}
#define WITH_STREAM_LOCK(pad, expr) G_STMT_START {\
GST_STREAM_LOCK (pad); \
expr; \
GST_STREAM_UNLOCK (pad); \
}G_STMT_END
static GstFlowReturn
gst_tee_chain (GstPad * pad, GstBuffer * buffer)
{
GstFlowReturn res;
GstTee *tee;
tee = GST_TEE (gst_pad_get_parent (pad));
gst_buffer_ref_by_count (buf, GST_ELEMENT (tee)->numsrcpads - 1);
WITH_STREAM_LOCK (pad, res = gst_tee_handle_buffer (tee, buffer));
pads = GST_ELEMENT (tee)->pads;
while (pads) {
GstPad *outpad = GST_PAD (pads->data);
pads = g_list_next (pads);
if (GST_PAD_DIRECTION (outpad) != GST_PAD_SRC)
continue;
if (!tee->silent) {
g_free (tee->last_message);
tee->last_message =
g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %"
G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (outpad),
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (tee), "last_message");
}
if (GST_PAD_IS_USABLE (outpad))
gst_pad_push (outpad, GST_DATA (buf));
else
gst_buffer_unref (buf);
}
return res;
}
#define DEFAULT_SIZE 1024
static void
gst_tee_loop (GstPad * pad)
{
GstBuffer *buffer;
GstFlowReturn res;
GstTee *tee;
GST_STREAM_LOCK (pad);
tee = GST_TEE (gst_pad_get_parent (pad));
res = gst_pad_pull_range (pad, tee->offset, DEFAULT_SIZE, &buffer);
if (res != GST_FLOW_OK)
goto pause_task;
res = gst_tee_handle_buffer (tee, buffer);
if (res != GST_FLOW_OK)
goto pause_task;
GST_STREAM_UNLOCK (pad);
return;
pause_task:
gst_pad_pause_task (pad);
GST_STREAM_UNLOCK (pad);
return;
}
static gboolean
gst_tee_sink_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstTee *tee;
tee = GST_TEE (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
g_return_val_if_fail (tee->has_chain, FALSE);
result = TRUE;
break;
case GST_ACTIVATE_PULL:
g_return_val_if_fail (tee->has_sink_loop, FALSE);
if (GST_ELEMENT_SCHEDULER (tee)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (tee),
(GstTaskFunction) gst_tee_loop, pad);
gst_pad_start_task (pad);
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_NONE:
GST_STREAM_LOCK (pad);
if (GST_RPAD_TASK (pad)) {
gst_pad_stop_task (pad);
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
tee->sink_mode = mode;
return result;
}

View file

@ -49,6 +49,12 @@ struct _GstTee {
GstPad *sinkpad;
gboolean silent;
gboolean has_chain;
gboolean has_sink_loop;
gint pad_counter;
guint64 offset;
GstActivateMode sink_mode;
gchar *last_message;
};

View file

@ -114,7 +114,8 @@ main (gint argc, gchar * argv[])
GST_TIME_ARGS (end - start));
start = gst_get_current_time ();
while (gst_bin_iterate (GST_BIN (pipeline)));
gst_bus_poll (gst_element_get_bus (pipeline),
GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
end = gst_get_current_time ();
g_print ("%" GST_TIME_FORMAT " - putting %u buffers through\n",
GST_TIME_ARGS (end - start), BUFFER_COUNT);

View file

@ -95,7 +95,8 @@ main (gint argc, gchar * argv[])
GST_TIME_ARGS (end - start));
start = gst_get_current_time ();
while (gst_bin_iterate (GST_BIN (pipeline)));
gst_bus_poll (gst_element_get_bus (pipeline),
GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
end = gst_get_current_time ();
g_print ("%" GST_TIME_FORMAT " - putting %u buffers through\n",
GST_TIME_ARGS (end - start), buffers);

View file

@ -20,6 +20,7 @@ CLEANFILES = core.*
TESTS = $(top_builddir)/tools/gst-register-@GST_MAJORMINOR@ \
gst/gstbin \
gst/gstbus \
gst/gstcaps \
gst/gstdata \
gst/gstiterator \

View file

@ -114,7 +114,8 @@ main (gint argc, gchar * argv[])
GST_TIME_ARGS (end - start));
start = gst_get_current_time ();
while (gst_bin_iterate (GST_BIN (pipeline)));
gst_bus_poll (gst_element_get_bus (pipeline),
GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
end = gst_get_current_time ();
g_print ("%" GST_TIME_FORMAT " - putting %u buffers through\n",
GST_TIME_ARGS (end - start), BUFFER_COUNT);

View file

@ -95,7 +95,8 @@ main (gint argc, gchar * argv[])
GST_TIME_ARGS (end - start));
start = gst_get_current_time ();
while (gst_bin_iterate (GST_BIN (pipeline)));
gst_bus_poll (gst_element_get_bus (pipeline),
GST_MESSAGE_EOS | GST_MESSAGE_ERROR, -1);
end = gst_get_current_time ();
g_print ("%" GST_TIME_FORMAT " - putting %u buffers through\n",
GST_TIME_ARGS (end - start), buffers);

View file

@ -17,50 +17,85 @@
* Boston, MA 02111-1307, USA.
*/
#include "unistd.h"
#include <gst/gst.h>
static GMainLoop *loop;
static gboolean
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
g_print ("message %p\n", message);
if (message->type == GST_MESSAGE_EOS) {
g_print ("EOS!!\n");
if (g_main_loop_is_running (loop))
g_main_loop_quit (loop);
}
gst_message_unref (message);
return TRUE;
}
gint
main (gint argc, gchar * argv[])
{
GstElement *pipeline;
GstElement *fakesrc1, *fakesink1;
GstElement *fakesrc2, *fakesink2;
GstBus *bus;
gst_init (&argc, &argv);
pipeline = gst_pipeline_new ("pipeline");
loop = g_main_loop_new (NULL, FALSE);
bus = gst_element_get_bus (pipeline);
gst_bus_add_watch (bus, (GstBusHandler) message_received, pipeline);
gst_object_unref (GST_OBJECT (bus));
fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1");
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
fakesink1 = gst_element_factory_make ("fakesink", "fakesink1");
gst_bin_add_many (GST_BIN (pipeline), fakesrc1, fakesink1, NULL);
gst_element_link_pads (fakesrc1, "src", fakesink1, "sink");
gst_bin_add (GST_BIN (pipeline), fakesrc1);
gst_bin_add (GST_BIN (pipeline), fakesink1);
gst_pad_link (gst_element_get_pad (fakesrc1, "src"),
gst_element_get_pad (fakesink1, "sink"));
fakesrc2 = gst_element_factory_make ("fakesrc", "fakesrc2");
g_object_set (G_OBJECT (fakesrc2), "num_buffers", 5, NULL);
fakesink2 = gst_element_factory_make ("fakesink", "fakesink2");
gst_bin_add_many (GST_BIN (pipeline), fakesrc2, fakesink2, NULL);
gst_element_link_pads (fakesrc2, "src", fakesink2, "sink");
gst_bin_add (GST_BIN (pipeline), fakesrc2);
gst_bin_add (GST_BIN (pipeline), fakesink2);
gst_pad_link (gst_element_get_pad (fakesrc2, "src"),
gst_element_get_pad (fakesink2, "sink"));
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
G_CALLBACK (gst_element_default_deep_notify), NULL);
G_CALLBACK (gst_object_default_deep_notify), NULL);
GST_FLAG_SET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
GST_FLAG_SET (fakesink2, GST_ELEMENT_LOCKED_STATE);
g_print ("play..\n");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
while (gst_bin_iterate (GST_BIN (pipeline)));
gst_element_set_state (pipeline, GST_STATE_READY);
g_main_loop_run (loop);
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
gst_element_set_state (pipeline, GST_STATE_READY);
GST_FLAG_UNSET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
GST_FLAG_UNSET (fakesink2, GST_ELEMENT_LOCKED_STATE);
g_print ("play..\n");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
while (gst_bin_iterate (GST_BIN (pipeline)));
g_main_loop_run (loop);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));

View file

@ -67,7 +67,7 @@ main (gint argc, gchar * argv[])
gst_bin_add (GST_BIN (pipeline), bin2);
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
G_CALLBACK (gst_element_default_deep_notify), NULL);
G_CALLBACK (gst_object_default_deep_notify), NULL);
/* setting pipeline to READY should bring in all children to READY */
gst_element_set_state (pipeline, GST_STATE_READY);
@ -77,31 +77,35 @@ main (gint argc, gchar * argv[])
g_assert (GST_STATE (identity) == GST_STATE_READY);
g_assert (GST_STATE (fakesink) == GST_STATE_READY);
/* setting fakesink to PAUSED should set pipeline and bin2 to PAUSED */
/* setting fakesink to PAUSED should not affect pipeline and bin2 */
gst_element_set_state (fakesink, GST_STATE_PAUSED);
g_assert (GST_STATE (bin1) == GST_STATE_READY);
g_assert (GST_STATE (bin2) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_READY);
g_assert (GST_STATE (fakesrc) == GST_STATE_READY);
g_assert (GST_STATE (identity) == GST_STATE_READY);
g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED);
g_assert (GST_STATE (fakesink) == GST_STATE_READY);
/* setting fakesrc to PAUSED should set bin1 and fakesrc to PAUSED */
/* setting fakesrc to PAUSED should not affect bin1 */
gst_element_set_state (fakesrc, GST_STATE_PAUSED);
g_assert (GST_STATE (bin1) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin1) == GST_STATE_READY);
g_assert (GST_STATE (bin2) == GST_STATE_READY);
g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED);
g_assert (GST_STATE (identity) == GST_STATE_READY);
g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED);
g_assert (GST_STATE (fakesink) == GST_STATE_READY);
/* setting bin1 to PAUSED, even though it is already, should set
* identity to PAUSED as well */
gst_element_set_state (bin1, GST_STATE_PAUSED);
gst_element_get_state (bin2, NULL, NULL, NULL);
g_assert (GST_STATE (bin1) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_READY);
g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED);
g_assert (GST_STATE (identity) == GST_STATE_PAUSED);
g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_usleep (1000000);
g_print ("passed.\n");
return 0;
}

View file

@ -17,50 +17,85 @@
* Boston, MA 02111-1307, USA.
*/
#include "unistd.h"
#include <gst/gst.h>
static GMainLoop *loop;
static gboolean
message_received (GstBus * bus, GstMessage * message, GstPipeline * pipeline)
{
g_print ("message %p\n", message);
if (message->type == GST_MESSAGE_EOS) {
g_print ("EOS!!\n");
if (g_main_loop_is_running (loop))
g_main_loop_quit (loop);
}
gst_message_unref (message);
return TRUE;
}
gint
main (gint argc, gchar * argv[])
{
GstElement *pipeline;
GstElement *fakesrc1, *fakesink1;
GstElement *fakesrc2, *fakesink2;
GstBus *bus;
gst_init (&argc, &argv);
pipeline = gst_pipeline_new ("pipeline");
loop = g_main_loop_new (NULL, FALSE);
bus = gst_element_get_bus (pipeline);
gst_bus_add_watch (bus, (GstBusHandler) message_received, pipeline);
gst_object_unref (GST_OBJECT (bus));
fakesrc1 = gst_element_factory_make ("fakesrc", "fakesrc1");
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
fakesink1 = gst_element_factory_make ("fakesink", "fakesink1");
gst_bin_add_many (GST_BIN (pipeline), fakesrc1, fakesink1, NULL);
gst_element_link_pads (fakesrc1, "src", fakesink1, "sink");
gst_bin_add (GST_BIN (pipeline), fakesrc1);
gst_bin_add (GST_BIN (pipeline), fakesink1);
gst_pad_link (gst_element_get_pad (fakesrc1, "src"),
gst_element_get_pad (fakesink1, "sink"));
fakesrc2 = gst_element_factory_make ("fakesrc", "fakesrc2");
g_object_set (G_OBJECT (fakesrc2), "num_buffers", 5, NULL);
fakesink2 = gst_element_factory_make ("fakesink", "fakesink2");
gst_bin_add_many (GST_BIN (pipeline), fakesrc2, fakesink2, NULL);
gst_element_link_pads (fakesrc2, "src", fakesink2, "sink");
gst_bin_add (GST_BIN (pipeline), fakesrc2);
gst_bin_add (GST_BIN (pipeline), fakesink2);
gst_pad_link (gst_element_get_pad (fakesrc2, "src"),
gst_element_get_pad (fakesink2, "sink"));
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
G_CALLBACK (gst_element_default_deep_notify), NULL);
G_CALLBACK (gst_object_default_deep_notify), NULL);
GST_FLAG_SET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
GST_FLAG_SET (fakesink2, GST_ELEMENT_LOCKED_STATE);
g_print ("play..\n");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
while (gst_bin_iterate (GST_BIN (pipeline)));
gst_element_set_state (pipeline, GST_STATE_READY);
g_main_loop_run (loop);
g_object_set (G_OBJECT (fakesrc1), "num_buffers", 5, NULL);
gst_element_set_state (pipeline, GST_STATE_READY);
GST_FLAG_UNSET (fakesrc2, GST_ELEMENT_LOCKED_STATE);
GST_FLAG_UNSET (fakesink2, GST_ELEMENT_LOCKED_STATE);
g_print ("play..\n");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
while (gst_bin_iterate (GST_BIN (pipeline)));
g_main_loop_run (loop);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));

View file

@ -67,7 +67,7 @@ main (gint argc, gchar * argv[])
gst_bin_add (GST_BIN (pipeline), bin2);
g_signal_connect (G_OBJECT (pipeline), "deep_notify",
G_CALLBACK (gst_element_default_deep_notify), NULL);
G_CALLBACK (gst_object_default_deep_notify), NULL);
/* setting pipeline to READY should bring in all children to READY */
gst_element_set_state (pipeline, GST_STATE_READY);
@ -77,31 +77,35 @@ main (gint argc, gchar * argv[])
g_assert (GST_STATE (identity) == GST_STATE_READY);
g_assert (GST_STATE (fakesink) == GST_STATE_READY);
/* setting fakesink to PAUSED should set pipeline and bin2 to PAUSED */
/* setting fakesink to PAUSED should not affect pipeline and bin2 */
gst_element_set_state (fakesink, GST_STATE_PAUSED);
g_assert (GST_STATE (bin1) == GST_STATE_READY);
g_assert (GST_STATE (bin2) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_READY);
g_assert (GST_STATE (fakesrc) == GST_STATE_READY);
g_assert (GST_STATE (identity) == GST_STATE_READY);
g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED);
g_assert (GST_STATE (fakesink) == GST_STATE_READY);
/* setting fakesrc to PAUSED should set bin1 and fakesrc to PAUSED */
/* setting fakesrc to PAUSED should not affect bin1 */
gst_element_set_state (fakesrc, GST_STATE_PAUSED);
g_assert (GST_STATE (bin1) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin1) == GST_STATE_READY);
g_assert (GST_STATE (bin2) == GST_STATE_READY);
g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED);
g_assert (GST_STATE (identity) == GST_STATE_READY);
g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED);
g_assert (GST_STATE (fakesink) == GST_STATE_READY);
/* setting bin1 to PAUSED, even though it is already, should set
* identity to PAUSED as well */
gst_element_set_state (bin1, GST_STATE_PAUSED);
gst_element_get_state (bin2, NULL, NULL, NULL);
g_assert (GST_STATE (bin1) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_PAUSED);
g_assert (GST_STATE (bin2) == GST_STATE_READY);
g_assert (GST_STATE (fakesrc) == GST_STATE_PAUSED);
g_assert (GST_STATE (identity) == GST_STATE_PAUSED);
g_assert (GST_STATE (fakesink) == GST_STATE_PAUSED);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_usleep (1000000);
g_print ("passed.\n");
return 0;
}

View file

@ -505,28 +505,12 @@ print_element_flag_info (GstElement * element)
n_print ("\n");
n_print ("Element Flags:\n");
if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
n_print (" GST_ELEMENT_DECOUPLED\n");
have_flags = TRUE;
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) {
n_print (" GST_ELEMENT_EVENT_AWARE\n");
have_flags = TRUE;
}
if (!have_flags)
n_print (" no flags set\n");
if (GST_IS_BIN (element)) {
n_print ("\n");
n_print ("Bin Flags:\n");
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
n_print (" GST_BIN_FLAG_MANAGER\n");
have_flags = TRUE;
}
if (GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) {
n_print (" GST_BIN_SELF_SCHEDULABLE\n");
have_flags = TRUE;
}
if (!have_flags)
n_print (" no flags set\n");
}
@ -544,11 +528,7 @@ print_implementation_info (GstElement * element)
n_print ("\n");
n_print ("Element Implementation:\n");
if (element->loopfunc)
n_print (" loopfunc()-based element: %s\n",
GST_DEBUG_FUNCPTR_NAME (element->loopfunc));
else
n_print (" No loopfunc(), must be chain-based or not configured yet\n");
n_print (" No loopfunc(), must be chain-based or not configured yet\n");
n_print (" Has change_state() function: %s\n",
GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
@ -647,9 +627,9 @@ print_pad_info (GstElement * element)
if (realpad->chainfunc)
n_print (" Has chainfunc(): %s\n",
GST_DEBUG_FUNCPTR_NAME (realpad->chainfunc));
if (realpad->getfunc)
n_print (" Has getfunc(): %s\n",
GST_DEBUG_FUNCPTR_NAME (realpad->getfunc));
if (realpad->getrangefunc)
n_print (" Has getrangefunc(): %s\n",
GST_DEBUG_FUNCPTR_NAME (realpad->getrangefunc));
if (realpad->formatsfunc != gst_pad_get_formats_default) {
n_print (" Supports seeking/conversion/query formats:\n");
print_formats (gst_pad_get_formats (GST_PAD (realpad)));

View file

@ -59,72 +59,11 @@ static void sigint_restore (void);
#endif
static gint max_iterations = 0;
static guint64 iterations = 0;
static guint64 sum = 0;
static guint64 min = G_MAXINT64;
static guint64 max = 0;
static GstClock *s_clock;
static GstElement *pipeline;
static gboolean caught_intr = FALSE;
static gboolean caught_error = FALSE;
static gboolean need_new_state = FALSE;
static GstElementState new_state;
static GMainLoop *loop;
gboolean caught_intr = FALSE;
gboolean caught_error = FALSE;
gboolean tags = FALSE;
gboolean
idle_func (gpointer data)
{
gboolean busy;
GTimeVal tfthen, tfnow;
GstClockTimeDiff diff;
g_get_current_time (&tfthen);
busy = gst_bin_iterate (GST_BIN (data));
iterations++;
g_get_current_time (&tfnow);
diff = GST_TIMEVAL_TO_TIME (tfnow) - GST_TIMEVAL_TO_TIME (tfthen);
sum += diff;
min = MIN (min, diff);
max = MAX (max, diff);
if (need_new_state) {
gst_element_set_state (pipeline, new_state);
need_new_state = FALSE;
}
if (!busy || caught_intr || caught_error ||
(max_iterations > 0 && iterations >= max_iterations)) {
char *s_iterations;
char *s_sum;
char *s_ave;
char *s_min;
char *s_max;
g_main_loop_quit (loop);
g_main_loop_unref (loop);
/* We write these all to strings first because
* G_GUINT64_FORMAT and gettext mix very poorly */
s_iterations = g_strdup_printf ("%" G_GUINT64_FORMAT, iterations);
s_sum = g_strdup_printf ("%" G_GUINT64_FORMAT, sum);
s_ave = g_strdup_printf ("%" G_GUINT64_FORMAT, sum / iterations);
s_min = g_strdup_printf ("%" G_GUINT64_FORMAT, min);
s_max = g_strdup_printf ("%" G_GUINT64_FORMAT, max);
g_print (_("Execution ended after %s iterations (sum %s ns, "
"average %s ns, min %s ns, max %s ns).\n"),
s_iterations, s_sum, s_ave, s_min, s_max);
g_free (s_iterations);
g_free (s_sum);
g_free (s_ave);
g_free (s_min);
g_free (s_max);
}
return busy;
}
#ifndef GST_DISABLE_LOADSAVE
static GstElement *
@ -323,21 +262,6 @@ print_tag (const GstTagList * list, const gchar * tag, gpointer unused)
}
}
static void
found_tag (GObject * pipeline, GstElement * source, GstTagList * tags)
{
g_print (_("FOUND TAG : found by element \"%s\".\n"),
GST_STR_NULL (GST_ELEMENT_NAME (source)));
gst_tag_list_foreach (tags, print_tag, NULL);
}
static void
error_cb (GObject * object, GstObject * source, GError * error, gchar * debug)
{
gst_element_default_error (object, source, error, debug);
caught_error = TRUE;
}
#ifndef DISABLE_FAULT_HANDLER
/* we only use sighandler here because the registers are not important */
static void
@ -350,6 +274,20 @@ sigint_handler_sighandler (int signum)
caught_intr = TRUE;
}
static gboolean
check_intr (GstElement * pipeline)
{
if (!caught_intr) {
return TRUE;
} else {
caught_intr = FALSE;
g_print ("Pausing pipeline.\n");
gst_element_set_state (pipeline, GST_STATE_PAUSED);
return FALSE;
}
}
static void
sigint_setup (void)
{
@ -377,12 +315,12 @@ play_handler (int signum)
{
switch (signum) {
case SIGUSR1:
new_state = GST_STATE_PLAYING;
need_new_state = TRUE;
g_print ("Caught SIGUSR1 - Play request.\n");
gst_element_set_state (pipeline, GST_STATE_PLAYING);
break;
case SIGUSR2:
new_state = GST_STATE_NULL;
need_new_state = TRUE;
g_print ("Caught SIGUSR2 - Stop request.\n");
gst_element_set_state (pipeline, GST_STATE_NULL);
break;
}
}
@ -397,7 +335,80 @@ play_signal_setup (void)
sigaction (SIGUSR1, &action, NULL);
sigaction (SIGUSR2, &action, NULL);
}
#endif
#endif /* DISABLE_FAULT_HANDLER */
static gboolean
event_loop (GstElement * pipeline, gboolean blocking)
{
GstBus *bus;
GstMessageType revent;
GstMessage *message = NULL;
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
g_timeout_add (50, (GSourceFunc) check_intr, pipeline);
while (TRUE) {
revent = gst_bus_poll (bus, GST_MESSAGE_ANY, blocking ? -1 : 0);
/* if the poll timed out, only when !blocking */
if (revent == GST_MESSAGE_UNKNOWN)
return FALSE;
message = gst_bus_pop (bus);
g_return_val_if_fail (message != NULL, TRUE);
switch (revent) {
case GST_MESSAGE_EOS:
gst_message_unref (message);
return FALSE;
case GST_MESSAGE_TAG:
if (tags) {
GstTagList *tags;
gst_message_parse_tag (message, &tags);
g_print (_("FOUND TAG : found by element \"%s\".\n"),
GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
gst_tag_list_foreach (tags, print_tag, NULL);
gst_tag_list_free (tags);
}
gst_message_unref (message);
break;
case GST_MESSAGE_WARNING:
case GST_MESSAGE_ERROR:{
GError *gerror;
gchar *debug;
gst_message_parse_error (message, &gerror, &debug);
gst_message_unref (message);
gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
g_error_free (gerror);
g_free (debug);
return TRUE;
}
case GST_MESSAGE_STATE_CHANGED:{
GstElementState old, new;
gst_message_parse_state_changed (message, &old, &new);
gst_message_unref (message);
if (!(old == GST_STATE_PLAYING && new == GST_STATE_PAUSED))
break;
g_print (_
("Element \"%s\" has gone from PLAYING to PAUSED, quitting.\n"),
GST_STR_NULL (GST_ELEMENT_NAME (GST_MESSAGE_SRC (message))));
/* cut out of the event loop if check_intr set us to PAUSED */
return FALSE;
}
default:
/* just be quiet by default */
gst_message_unref (message);
break;
}
}
g_assert_not_reached ();
return TRUE;
}
int
main (int argc, char *argv[])
@ -406,7 +417,6 @@ main (int argc, char *argv[])
/* options */
gboolean verbose = FALSE;
gboolean tags = FALSE;
gboolean no_fault = FALSE;
gboolean trace = FALSE;
gchar *savefile = NULL;
@ -514,13 +524,8 @@ main (int argc, char *argv[])
gchar **exclude_list =
exclude_args ? g_strsplit (exclude_args, ",", 0) : NULL;
g_signal_connect (pipeline, "deep_notify",
G_CALLBACK (gst_element_default_deep_notify), exclude_list);
G_CALLBACK (gst_object_default_deep_notify), exclude_list);
}
if (tags) {
g_signal_connect (pipeline, "found-tag", G_CALLBACK (found_tag), NULL);
}
g_signal_connect (pipeline, "error", G_CALLBACK (error_cb), NULL);
#ifndef GST_DISABLE_LOADSAVE
if (savefile) {
gst_xml_write_file (GST_ELEMENT (pipeline), fopen (savefile, "w"));
@ -528,6 +533,7 @@ main (int argc, char *argv[])
#endif
if (!savefile) {
GstElementState state, pending;
if (!GST_IS_BIN (pipeline)) {
GstElement *real_pipeline = gst_element_factory_make ("pipeline", NULL);
@ -540,37 +546,55 @@ main (int argc, char *argv[])
pipeline = real_pipeline;
}
fprintf (stderr, _("RUNNING pipeline ...\n"));
if (gst_element_set_state (pipeline,
GST_STATE_PLAYING) == GST_STATE_FAILURE) {
fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n"));
fprintf (stderr, _("PREROLL pipeline ...\n"));
if (gst_element_set_state (pipeline, GST_STATE_PAUSED) == GST_STATE_FAILURE) {
fprintf (stderr, _("ERROR: pipeline doesn't want to pause.\n"));
res = -1;
goto end;
}
s_clock = gst_element_get_clock (GST_ELEMENT (pipeline));
gst_element_get_state (pipeline, &state, &pending, NULL);
caught_error = event_loop (pipeline, FALSE);
if (!GST_FLAG_IS_SET (GST_OBJECT (pipeline), GST_BIN_SELF_SCHEDULABLE)) {
g_idle_add (idle_func, pipeline);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
/* see if we got any messages */
while (g_main_context_iteration (NULL, FALSE));
if (caught_error) {
fprintf (stderr, _("ERROR: pipeline doesn't want to preroll.\n"));
} else {
g_print ("Waiting for the state change... ");
gst_element_wait_state_change (pipeline);
g_print ("got the state change.\n");
}
if (caught_intr) {
g_print ("Caught interrupt.\n");
res = 2;
}
if (caught_error)
res = 3;
GTimeVal tfthen, tfnow;
GstClockTimeDiff diff;
fprintf (stderr, _("RUNNING pipeline ...\n"));
if (gst_element_set_state (pipeline,
GST_STATE_PLAYING) == GST_STATE_FAILURE) {
fprintf (stderr, _("ERROR: pipeline doesn't want to play.\n"));
res = -1;
goto end;
}
g_get_current_time (&tfthen);
caught_error = event_loop (pipeline, TRUE);
g_get_current_time (&tfnow);
diff = GST_TIMEVAL_TO_TIME (tfnow) - GST_TIMEVAL_TO_TIME (tfthen);
g_print (_("Execution ended after %" G_GUINT64_FORMAT " ns.\n"), diff);
}
fprintf (stderr, _("PAUSE pipeline ...\n"));
gst_element_set_state (pipeline, GST_STATE_PAUSED);
gst_element_get_state (pipeline, &state, &pending, NULL);
fprintf (stderr, _("READY pipeline ...\n"));
gst_element_set_state (pipeline, GST_STATE_READY);
gst_element_get_state (pipeline, &state, &pending, NULL);
fprintf (stderr, _("NULL pipeline ...\n"));
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_element_get_state (pipeline, &state, &pending, NULL);
}
end:
fprintf (stderr, _("FREEING pipeline ...\n"));
gst_object_unref (GST_OBJECT (pipeline));
if (trace)

View file

@ -7,77 +7,65 @@
#include <gst/gst.h>
#include <locale.h>
static guint64 iterations = 0;
static guint64 sum = 0;
static guint64 min = G_MAXINT64;
static guint64 max = 0;
static GstClock *s_clock;
static GMainLoop *loop;
gboolean
idle_func (gpointer data)
/* blocking */
static gboolean
event_loop (GstElement * pipeline)
{
gboolean busy;
GTimeVal tfthen, tfnow;
GstClockTimeDiff diff;
GstBus *bus;
GstMessageType revent;
GstMessage *message = NULL;
if (s_clock) {
//g_print ("%lld\n", gst_clock_get_time (s_clock));
bus = gst_element_get_bus (GST_ELEMENT (pipeline));
while (TRUE) {
revent = gst_bus_poll (bus, GST_MESSAGE_ANY, -1);
message = gst_bus_pop (bus);
g_return_val_if_fail (message != NULL, TRUE);
switch (revent) {
case GST_MESSAGE_EOS:
gst_message_unref (message);
return FALSE;
case GST_MESSAGE_WARNING:
case GST_MESSAGE_ERROR:{
GError *gerror;
gchar *debug;
gst_message_parse_error (message, &gerror, &debug);
gst_message_unref (message);
gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
g_error_free (gerror);
g_free (debug);
return TRUE;
}
default:
gst_message_unref (message);
break;
}
}
g_get_current_time (&tfthen);
busy = gst_bin_iterate (GST_BIN (data));
iterations++;
g_get_current_time (&tfnow);
diff = GST_TIMEVAL_TO_TIME (tfnow) - GST_TIMEVAL_TO_TIME (tfthen);
sum += diff;
min = MIN (min, diff);
max = MAX (max, diff);
if (!busy) {
g_main_loop_quit (loop);
g_main_loop_unref (loop);
/*
g_print ("execution ended after %llu iterations (sum %llu ns, average %llu ns, min %llu ns, max %llu ns)\n",
iterations, sum, sum/iterations, min, max);
*/
}
return busy;
g_assert_not_reached ();
return TRUE;
}
int
main (int argc, char *argv[])
{
/* options */
gboolean verbose = FALSE;
gchar *exclude_args = NULL;
struct poptOption options[] = {
{"verbose", 'v', POPT_ARG_NONE | POPT_ARGFLAG_STRIP, &verbose, 0,
"do not output status information", NULL},
POPT_TABLEEND
};
GstElement *pipeline = NULL;
gchar **argvn;
GError *error = NULL;
GstElement *md5sink;
gchar **argvn;
gchar *md5string = g_malloc0 (33);
free (malloc (8)); /* -lefence */
setlocale (LC_ALL, "");
gst_init_with_popt_table (&argc, &argv, options);
gst_init (&argc, &argv);
/* make a parseable argvn array */
argvn = g_new0 (char *, argc);
memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
/* Check if we have an element already that is called md5sink0
in the pipeline; if not, add one */
pipeline = (GstElement *) gst_parse_launchv ((const gchar **) argvn, &error);
if (!pipeline) {
if (error) {
@ -90,17 +78,9 @@ main (int argc, char *argv[])
md5sink = gst_bin_get_by_name (GST_BIN (pipeline), "md5sink0");
if (md5sink == NULL) {
g_print ("adding an md5sink element to the pipeline\n");
/* make a null-terminated version of argv with ! md5sink appended
* ! is stored in argvn[argc - 1], md5sink in argvn[argc],
* NULL pointer in argvn[argc + 1] */
g_free (argvn);
argvn = g_new0 (char *, argc + 2);
memcpy (argvn, argv + 1, sizeof (char *) * (argc - 1));
argvn[argc - 1] = g_strdup_printf ("!");
argvn[argc] = g_strdup_printf ("md5sink");
pipeline =
(GstElement *) gst_parse_launchv ((const gchar **) argvn, &error);
g_print ("ERROR: pipeline has no element named md5sink0.\n");
g_print ("Did you forget to put an md5sink in the pipeline?\n");
return 1;
}
if (!pipeline) {
@ -112,28 +92,12 @@ main (int argc, char *argv[])
return 1;
}
if (verbose) {
gchar **exclude_list = exclude_args ? g_strsplit (exclude_args, ",", 0)
: NULL;
g_signal_connect (pipeline, "deep_notify",
G_CALLBACK (gst_element_default_deep_notify), exclude_list);
}
g_signal_connect (pipeline, "error",
G_CALLBACK (gst_element_default_error), NULL);
if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) {
g_warning ("pipeline doesn't want to play\n");
return 0;
return 1;
}
if (!GST_FLAG_IS_SET (GST_OBJECT (pipeline), GST_BIN_SELF_SCHEDULABLE)) {
g_idle_add (idle_func, pipeline);
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
} else {
gst_element_wait_state_change (pipeline);
}
event_loop (pipeline);
gst_element_set_state (pipeline, GST_STATE_NULL);

View file

@ -68,8 +68,6 @@ main (int argc, char *argv[])
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
while (!FOUND) {
if (!gst_bin_iterate (GST_BIN (pipeline)))
break;
}
if (!FOUND) {
g_print ("%s - No type found\n", argv[i]);

View file

@ -472,8 +472,6 @@ print_element_info (GstElementFactory * factory)
GstPad *pad;
GstRealPad *realpad;
GstPadTemplate *padtemplate;
GList *children;
GstElement *child;
gint maxlevel = 0;
element = gst_element_factory_create (factory, "element");
@ -533,31 +531,16 @@ print_element_info (GstElementFactory * factory)
PUT_END_TAG (1, "pad-templates");
PUT_START_TAG (1, "element-flags");
if (GST_FLAG_IS_SET (element, GST_ELEMENT_DECOUPLED)) {
PUT_ESCAPED (2, "flag", "GST_ELEMENT_DECOUPLED");
}
if (GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) {
PUT_ESCAPED (2, "flag", "GST_ELEMENT_EVENT_AWARE");
}
PUT_END_TAG (1, "element-flags");
if (GST_IS_BIN (element)) {
PUT_START_TAG (1, "bin-flags");
if (GST_FLAG_IS_SET (element, GST_BIN_FLAG_MANAGER)) {
PUT_ESCAPED (2, "flag", "GST_BIN_FLAG_MANAGER");
}
if (GST_FLAG_IS_SET (element, GST_BIN_SELF_SCHEDULABLE)) {
PUT_ESCAPED (2, "flag", "GST_BIN_SELF_SCHEDULABLE");
}
PUT_END_TAG (1, "bin-flags");
}
PUT_START_TAG (1, "element-implementation");
if (element->loopfunc)
PUT_STRING (2, "<loop-based function=\"%s\"/>",
GST_DEBUG_FUNCPTR_NAME (element->loopfunc));
PUT_STRING (2, "<state-change function=\"%s\"/>",
GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state));
@ -619,9 +602,9 @@ print_element_info (GstElementFactory * factory)
if (realpad->chainfunc)
PUT_STRING (4, "<chain-based function=\"%s\"/>",
GST_DEBUG_FUNCPTR_NAME (realpad->chainfunc));
if (realpad->getfunc)
PUT_STRING (4, "<get-based function=\"%s\"/>",
GST_DEBUG_FUNCPTR_NAME (realpad->getfunc));
if (realpad->getrangefunc)
PUT_STRING (4, "<get-range-based function=\"%s\"/>",
GST_DEBUG_FUNCPTR_NAME (realpad->getrangefunc));
if (realpad->formatsfunc != gst_pad_get_formats_default) {
PUT_STRING (4, "<formats-function function=\"%s\">",
GST_DEBUG_FUNCPTR_NAME (realpad->formatsfunc));
@ -672,17 +655,21 @@ print_element_info (GstElementFactory * factory)
print_element_signals (element, 1);
/* for compound elements */
if (GST_IS_BIN (element)) {
PUT_START_TAG (1, "children");
children = (GList *) GST_BIN (element)->children;
while (children) {
child = GST_ELEMENT (children->data);
children = g_list_next (children);
/* FIXME: gst_bin_get_list does not exist anymore
if (GST_IS_BIN (element)) {
GList *children;
GstElement *child;
PUT_START_TAG (1, "children");
children = (GList *) gst_bin_get_list (GST_BIN (element));
while (children) {
child = GST_ELEMENT (children->data);
children = g_list_next (children);
PUT_ESCAPED (2, "child", GST_ELEMENT_NAME (child));
}
PUT_END_TAG (1, "children");
}
PUT_ESCAPED (2, "child", GST_ELEMENT_NAME (child));
}
PUT_END_TAG (1, "children");
}
*/
PUT_END_TAG (0, "element");
return 0;