static void print_implementation_info (GstElement * element) { n_print ("\n"); n_print ("Element Implementation:\n"); { GstElementClass *gstelement_class; gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); n_print (" Has change_state() function: %s\n", GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state)); } #ifndef GST_DISABLE_LOADSAVE { GstObjectClass *gstobject_class; gstobject_class = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS (element)); n_print (" Has custom save_thyself() function: %s\n", GST_DEBUG_FUNCPTR_NAME (gstobject_class->save_thyself)); n_print (" Has custom restore_thyself() function: %s\n", GST_DEBUG_FUNCPTR_NAME (gstobject_class->restore_thyself)); } #endif }
/* checks if all the pads are collected and call the collectfunction * * Should be called with LOCK. * * Returns: The #GstFlowReturn of collection. */ static GstFlowReturn gst_collect_pads_check_collected (GstCollectPads * pads) { GstFlowReturn flow_ret = GST_FLOW_OK; g_return_val_if_fail (GST_IS_COLLECT_PADS (pads), GST_FLOW_ERROR); g_return_val_if_fail (pads->func != NULL, GST_FLOW_NOT_SUPPORTED); /* check for new pads, update stats etc.. */ gst_collect_pads_check_pads (pads); if (G_UNLIKELY (pads->eospads == pads->numpads)) { /* If all our pads are EOS just collect once to let the element * do its final EOS handling. */ GST_DEBUG ("All active pads (%d) are EOS, calling %s", pads->numpads, GST_DEBUG_FUNCPTR_NAME (pads->func)); flow_ret = pads->func (pads, pads->user_data); } else { gboolean collected = FALSE; /* We call the collected function as long as our condition matches. * FIXME: should we error out if the collect function did not pop anything ? * we can get a busy loop here if the element does not pop from the collect * function */ while (((pads->queuedpads + pads->eospads) >= pads->numpads)) { GST_DEBUG ("All active pads (%d + %d >= %d) have data, calling %s", pads->queuedpads, pads->eospads, pads->numpads, GST_DEBUG_FUNCPTR_NAME (pads->func)); flow_ret = pads->func (pads, pads->user_data); collected = TRUE; /* break on error */ if (flow_ret != GST_FLOW_OK) break; /* Don't keep looping after telling the element EOS or flushing */ if (pads->queuedpads == 0) break; } if (!collected) GST_DEBUG ("Not all active pads (%d) have data, continuing", pads->numpads); } return flow_ret; }
static void print_implementation_info (GstElement * element) { GstElementClass *gstelement_class; gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); n_print ("\n"); n_print ("Element Implementation:\n"); n_print (" Has change_state() function: %s\n", GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state)); }
static void print_pad_templates_info (GstElement * element, GstElementFactory * factory) { GstElementClass *gstelement_class; const GList *pads; GstStaticPadTemplate *padtemplate; n_print ("Pad Templates:\n"); if (gst_element_factory_get_num_pad_templates (factory) == 0) { n_print (" none\n"); return; } gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); pads = gst_element_factory_get_static_pad_templates (factory); while (pads) { padtemplate = (GstStaticPadTemplate *) (pads->data); pads = g_list_next (pads); if (padtemplate->direction == GST_PAD_SRC) n_print (" SRC template: '%s'\n", padtemplate->name_template); else if (padtemplate->direction == GST_PAD_SINK) n_print (" SINK template: '%s'\n", padtemplate->name_template); else n_print (" UNKNOWN!!! template: '%s'\n", padtemplate->name_template); if (padtemplate->presence == GST_PAD_ALWAYS) n_print (" Availability: Always\n"); else if (padtemplate->presence == GST_PAD_SOMETIMES) n_print (" Availability: Sometimes\n"); else if (padtemplate->presence == GST_PAD_REQUEST) { n_print (" Availability: On request\n"); n_print (" Has request_new_pad() function: %s\n", GST_DEBUG_FUNCPTR_NAME (gstelement_class->request_new_pad)); } else n_print (" Availability: UNKNOWN!!!\n"); if (padtemplate->static_caps.string) { n_print (" Capabilities:\n"); print_caps (gst_static_caps_get (&padtemplate->static_caps), " "); } n_print ("\n"); } }
/* this internal thread does nothing else but write samples to the audio device. * It will write each segment in the ringbuffer and will update the play * pointer. * The start/stop methods control the thread. */ static void audioringbuffer_thread_func (GstRingBuffer * buf) { GstAudioSink *sink; GstAudioSinkClass *csink; GstAudioRingBuffer *abuf = GST_AUDIORING_BUFFER_CAST (buf); WriteFunc writefunc; GstMessage *message; GValue val = { 0 }; sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf)); csink = GST_AUDIO_SINK_GET_CLASS (sink); GST_DEBUG_OBJECT (sink, "enter thread"); GST_OBJECT_LOCK (abuf); GST_DEBUG_OBJECT (sink, "signal wait"); GST_AUDIORING_BUFFER_SIGNAL (buf); GST_OBJECT_UNLOCK (abuf); writefunc = csink->write; if (writefunc == NULL) goto no_function; g_value_init (&val, G_TYPE_POINTER); g_value_set_pointer (&val, sink->thread); message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink)); gst_message_set_stream_status_object (message, &val); GST_DEBUG_OBJECT (sink, "posting ENTER stream status"); gst_element_post_message (GST_ELEMENT_CAST (sink), message); while (TRUE) { gint left, len; guint8 *readptr; gint readseg; /* buffer must be started */ if (gst_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) { gint written; left = len; do { written = writefunc (sink, readptr, left); GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d", written, left, readseg); if (written < 0 || written > left) { /* might not be critical, it e.g. happens when aborting playback */ GST_WARNING_OBJECT (sink, "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)", GST_DEBUG_FUNCPTR_NAME (writefunc), (errno > 1 ? g_strerror (errno) : "unknown"), left, written); break; } left -= written; readptr += written; } while (left > 0); /* clear written samples */ gst_ring_buffer_clear (buf, readseg); /* we wrote one segment */ gst_ring_buffer_advance (buf, 1); } else { GST_OBJECT_LOCK (abuf); if (!abuf->running) goto stop_running; GST_DEBUG_OBJECT (sink, "signal wait"); GST_AUDIORING_BUFFER_SIGNAL (buf); GST_DEBUG_OBJECT (sink, "wait for action"); #ifndef GSTREAMER_LITE GST_AUDIORING_BUFFER_WAIT (buf); #else // GSTREAMER_LITE // In same cases we may have condition when we waiting here for ring buffer to start, // while ring buffer is started and data is available. So, lets use wait with timeout // and recheck if we good to go. wait_segment() will start ring buffer when data is available. { GTimeVal timeout; g_get_current_time(&timeout); g_time_val_add(&timeout, 100000); // 100 millisecond GST_AUDIORING_BUFFER_TIMED_WAIT (buf, &timeout); } #endif // GSTREAMER_LITE GST_DEBUG_OBJECT (sink, "got signal"); if (!abuf->running) goto stop_running; GST_DEBUG_OBJECT (sink, "continue running"); GST_OBJECT_UNLOCK (abuf); } } /* Will never be reached */ g_assert_not_reached (); return; /* ERROR */ no_function: { GST_DEBUG_OBJECT (sink, "no write function, exit thread"); return; } stop_running: { GST_OBJECT_UNLOCK (abuf); GST_DEBUG_OBJECT (sink, "stop running, exit thread"); message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink)); gst_message_set_stream_status_object (message, &val); GST_DEBUG_OBJECT (sink, "posting LEAVE stream status"); gst_element_post_message (GST_ELEMENT_CAST (sink), message); return; } }
static gint print_element_info (GstElementFactory * factory) { GstElement *element; #ifndef GST_DISABLE_LOADSAVE GstObjectClass *gstobject_class; #endif GstElementClass *gstelement_class; GList *pads; GstPad *pad; GstStaticPadTemplate *padtemplate; gint maxlevel = 0; element = gst_element_factory_create (factory, "element"); if (!element) { g_print ("couldn't construct element for some reason\n"); return -1; } PUT_START_TAG (0, "element"); PUT_ESCAPED (1, "name", GST_PLUGIN_FEATURE_NAME (factory)); #ifndef GST_DISABLE_LOADSAVE gstobject_class = GST_OBJECT_CLASS (G_OBJECT_GET_CLASS (element)); #endif gstelement_class = GST_ELEMENT_CLASS (G_OBJECT_GET_CLASS (element)); PUT_START_TAG (1, "details"); PUT_ESCAPED (2, "long-name", factory->details.longname); PUT_ESCAPED (2, "class", factory->details.klass); PUT_ESCAPED (2, "description", factory->details.description); PUT_ESCAPED (2, "authors", factory->details.author); PUT_END_TAG (1, "details"); output_hierarchy (G_OBJECT_TYPE (element), 0, &maxlevel); PUT_START_TAG (1, "pad-templates"); if (factory->numpadtemplates) { pads = factory->staticpadtemplates; while (pads) { padtemplate = (GstStaticPadTemplate *) (pads->data); pads = g_list_next (pads); PUT_START_TAG (2, "pad-template"); PUT_ESCAPED (3, "name", padtemplate->name_template); if (padtemplate->direction == GST_PAD_SRC) PUT_ESCAPED (3, "direction", "src"); else if (padtemplate->direction == GST_PAD_SINK) PUT_ESCAPED (3, "direction", "sink"); else PUT_ESCAPED (3, "direction", "unknown"); if (padtemplate->presence == GST_PAD_ALWAYS) PUT_ESCAPED (3, "presence", "always"); else if (padtemplate->presence == GST_PAD_SOMETIMES) PUT_ESCAPED (3, "presence", "sometimes"); else if (padtemplate->presence == GST_PAD_REQUEST) { PUT_ESCAPED (3, "presence", "request"); PUT_ESCAPED (3, "request-function", GST_DEBUG_FUNCPTR_NAME (gstelement_class->request_new_pad)); } else PUT_ESCAPED (3, "presence", "unknown"); if (padtemplate->static_caps.string) { print_caps (gst_static_caps_get (&padtemplate->static_caps), 3); } PUT_END_TAG (2, "pad-template"); } } PUT_END_TAG (1, "pad-templates"); PUT_START_TAG (1, "element-flags"); PUT_END_TAG (1, "element-flags"); if (GST_IS_BIN (element)) { PUT_START_TAG (1, "bin-flags"); PUT_END_TAG (1, "bin-flags"); } PUT_START_TAG (1, "element-implementation"); PUT_STRING (2, "<state-change function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (gstelement_class->change_state)); #ifndef GST_DISABLE_LOADSAVE PUT_STRING (2, "<save function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (gstobject_class->save_thyself)); PUT_STRING (2, "<load function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (gstobject_class->restore_thyself)); #endif PUT_END_TAG (1, "element-implementation"); PUT_START_TAG (1, "clocking-interaction"); if (gst_element_requires_clock (element)) { PUT_STRING (2, "<requires-clock/>"); } if (gst_element_provides_clock (element)) { GstClock *clock; clock = gst_element_get_clock (element); if (clock) PUT_STRING (2, "<provides-clock name=\"%s\"/>", GST_OBJECT_NAME (clock)); } PUT_END_TAG (1, "clocking-interaction"); if (gst_element_is_indexable (element)) { PUT_STRING (1, "<indexing-capabilities/>"); } PUT_START_TAG (1, "pads"); if (element->numpads) { const GList *pads; pads = element->pads; while (pads) { pad = GST_PAD (pads->data); pads = g_list_next (pads); PUT_START_TAG (2, "pad"); PUT_ESCAPED (3, "name", gst_pad_get_name (pad)); if (gst_pad_get_direction (pad) == GST_PAD_SRC) PUT_ESCAPED (3, "direction", "src"); else if (gst_pad_get_direction (pad) == GST_PAD_SINK) PUT_ESCAPED (3, "direction", "sink"); else PUT_ESCAPED (3, "direction", "unknown"); if (pad->padtemplate) PUT_ESCAPED (3, "template", pad->padtemplate->name_template); PUT_START_TAG (3, "implementation"); if (pad->chainfunc) PUT_STRING (4, "<chain-based function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (pad->chainfunc)); if (pad->getrangefunc) PUT_STRING (4, "<get-range-based function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (pad->getrangefunc)); if (pad->eventfunc != gst_pad_event_default) PUT_STRING (4, "<event-function function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (pad->eventfunc)); if (pad->queryfunc != gst_pad_query_default) PUT_STRING (4, "<query-function function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (pad->queryfunc)); if (pad->querytypefunc != gst_pad_get_query_types_default) { PUT_STRING (4, "<query-type-func function=\"%s\">", GST_DEBUG_FUNCPTR_NAME (pad->querytypefunc)); print_query_types (gst_pad_get_query_types (pad), 5); PUT_END_TAG (4, "query-type-func"); } if (pad->iterintlinkfunc != gst_pad_iterate_internal_links_default) PUT_STRING (4, "<iterintlink-function function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (pad->iterintlinkfunc)); if (pad->bufferallocfunc) PUT_STRING (4, "<bufferalloc-function function=\"%s\"/>", GST_DEBUG_FUNCPTR_NAME (pad->bufferallocfunc)); PUT_END_TAG (3, "implementation"); if (pad->caps) { print_caps (pad->caps, 3); } PUT_END_TAG (2, "pad"); } } PUT_END_TAG (1, "pads"); print_element_properties (element, 1); print_element_signals (element, 1); /* for compound elements */ /* 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_END_TAG (0, "element"); return 0; }
static void print_pad_info (GstElement * element) { const GList *pads; GstPad *pad; n_print ("\n"); n_print ("Pads:\n"); if (!element->numpads) { n_print (" none\n"); return; } pads = element->pads; while (pads) { gchar *name; pad = GST_PAD (pads->data); pads = g_list_next (pads); n_print (""); name = gst_pad_get_name (pad); if (gst_pad_get_direction (pad) == GST_PAD_SRC) g_print (" SRC: '%s'", name); else if (gst_pad_get_direction (pad) == GST_PAD_SINK) g_print (" SINK: '%s'", name); else g_print (" UNKNOWN!!!: '%s'", name); g_free (name); g_print ("\n"); n_print (" Implementation:\n"); if (pad->chainfunc) n_print (" Has chainfunc(): %s\n", GST_DEBUG_FUNCPTR_NAME (pad->chainfunc)); if (pad->getrangefunc) n_print (" Has getrangefunc(): %s\n", GST_DEBUG_FUNCPTR_NAME (pad->getrangefunc)); if (pad->eventfunc != gst_pad_event_default) n_print (" Has custom eventfunc(): %s\n", GST_DEBUG_FUNCPTR_NAME (pad->eventfunc)); if (pad->queryfunc != gst_pad_query_default) n_print (" Has custom queryfunc(): %s\n", GST_DEBUG_FUNCPTR_NAME (pad->queryfunc)); if (pad->querytypefunc != gst_pad_get_query_types_default) { n_print (" Provides query types:\n"); print_query_types (gst_pad_get_query_types (pad)); } if (pad->intlinkfunc != gst_pad_get_internal_links_default) n_print (" Has custom intconnfunc(): %s\n", GST_DEBUG_FUNCPTR_NAME (pad->intlinkfunc)); if (pad->bufferallocfunc) n_print (" Has bufferallocfunc(): %s\n", GST_DEBUG_FUNCPTR_NAME (pad->bufferallocfunc)); if (pad->padtemplate) n_print (" Pad Template: '%s'\n", pad->padtemplate->name_template); if (pad->caps) { n_print (" Capabilities:\n"); print_caps (pad->caps, " "); } } }
/* this internal thread does nothing else but write samples to the audio device. * It will write each segment in the ringbuffer and will update the play * pointer. * The start/stop methods control the thread. */ static void audioringbuffer_thread_func (GstAudioRingBuffer * buf) { GstAudioSink *sink; GstAudioSinkClass *csink; GstAudioSinkRingBuffer *abuf = GST_AUDIO_SINK_RING_BUFFER_CAST (buf); WriteFunc writefunc; GstMessage *message; GValue val = { 0 }; sink = GST_AUDIO_SINK (GST_OBJECT_PARENT (buf)); csink = GST_AUDIO_SINK_GET_CLASS (sink); GST_DEBUG_OBJECT (sink, "enter thread"); GST_OBJECT_LOCK (abuf); GST_DEBUG_OBJECT (sink, "signal wait"); GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf); GST_OBJECT_UNLOCK (abuf); writefunc = csink->write; if (writefunc == NULL) goto no_function; message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), GST_STREAM_STATUS_TYPE_ENTER, GST_ELEMENT_CAST (sink)); g_value_init (&val, GST_TYPE_G_THREAD); g_value_set_boxed (&val, g_thread_self ()); gst_message_set_stream_status_object (message, &val); g_value_unset (&val); GST_DEBUG_OBJECT (sink, "posting ENTER stream status"); gst_element_post_message (GST_ELEMENT_CAST (sink), message); while (TRUE) { gint left, len; guint8 *readptr; gint readseg; /* buffer must be started */ if (gst_audio_ring_buffer_prepare_read (buf, &readseg, &readptr, &len)) { gint written; left = len; do { written = writefunc (sink, readptr, left); GST_LOG_OBJECT (sink, "transfered %d bytes of %d from segment %d", written, left, readseg); if (written < 0 || written > left) { /* might not be critical, it e.g. happens when aborting playback */ GST_WARNING_OBJECT (sink, "error writing data in %s (reason: %s), skipping segment (left: %d, written: %d)", GST_DEBUG_FUNCPTR_NAME (writefunc), (errno > 1 ? g_strerror (errno) : "unknown"), left, written); break; } left -= written; readptr += written; } while (left > 0); /* clear written samples */ gst_audio_ring_buffer_clear (buf, readseg); /* we wrote one segment */ gst_audio_ring_buffer_advance (buf, 1); } else { GST_OBJECT_LOCK (abuf); if (!abuf->running) goto stop_running; if (G_UNLIKELY (g_atomic_int_get (&buf->state) == GST_AUDIO_RING_BUFFER_STATE_STARTED)) { GST_OBJECT_UNLOCK (abuf); continue; } GST_DEBUG_OBJECT (sink, "signal wait"); GST_AUDIO_SINK_RING_BUFFER_SIGNAL (buf); GST_DEBUG_OBJECT (sink, "wait for action"); GST_AUDIO_SINK_RING_BUFFER_WAIT (buf); GST_DEBUG_OBJECT (sink, "got signal"); if (!abuf->running) goto stop_running; GST_DEBUG_OBJECT (sink, "continue running"); GST_OBJECT_UNLOCK (abuf); } } /* Will never be reached */ g_assert_not_reached (); return; /* ERROR */ no_function: { GST_DEBUG_OBJECT (sink, "no write function, exit thread"); return; } stop_running: { GST_OBJECT_UNLOCK (abuf); GST_DEBUG_OBJECT (sink, "stop running, exit thread"); message = gst_message_new_stream_status (GST_OBJECT_CAST (buf), GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (sink)); g_value_init (&val, GST_TYPE_G_THREAD); g_value_set_boxed (&val, g_thread_self ()); gst_message_set_stream_status_object (message, &val); g_value_unset (&val); GST_DEBUG_OBJECT (sink, "posting LEAVE stream status"); gst_element_post_message (GST_ELEMENT_CAST (sink), message); return; } }