urisourcebin: Add 'about-to-finish' signal

With push-based sources, urisourcebin will emit this signal when
the stream has been fully consumed.

This signal can be used to know when the source is done providing
data.
This commit is contained in:
Edward Hervey 2017-11-09 10:53:24 +01:00 committed by Edward Hervey
parent 08044ab7e6
commit ebf138e29e

View file

@ -167,8 +167,12 @@ struct _GstURISourceBinClass
{ {
GstBinClass parent_class; GstBinClass parent_class;
/* emitted when all data is decoded */ /* emitted when all data has been drained out
* FIXME : What do we need this for ?? */
void (*drained) (GstElement * element); void (*drained) (GstElement * element);
/* emitted when all data has been fed into buffering slots (i.e the
* actual sources are done) */
void (*about_to_finish) (GstElement * element);
}; };
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src_%u", static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src_%u",
@ -185,6 +189,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_uri_source_bin_debug);
enum enum
{ {
SIGNAL_DRAINED, SIGNAL_DRAINED,
SIGNAL_ABOUT_TO_FINISH,
SIGNAL_SOURCE_SETUP, SIGNAL_SOURCE_SETUP,
LAST_SIGNAL LAST_SIGNAL
}; };
@ -336,6 +341,17 @@ gst_uri_source_bin_class_init (GstURISourceBinClass * klass)
G_STRUCT_OFFSET (GstURISourceBinClass, drained), NULL, NULL, G_STRUCT_OFFSET (GstURISourceBinClass, drained), NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE); g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
/**
* GstURISourceBin::about-to-finish:
*
* This signal is emitted when the data for the current uri is played.
*/
gst_uri_source_bin_signals[SIGNAL_ABOUT_TO_FINISH] =
g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstURISourceBinClass, about_to_finish), NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
/** /**
* GstURISourceBin::source-setup: * GstURISourceBin::source-setup:
* @bin: the urisourcebin. * @bin: the urisourcebin.
@ -695,6 +711,20 @@ link_pending_pad_to_output (GstURISourceBin * urisrc, OutputSlotInfo * slot)
return res; return res;
} }
/* Called with lock held */
static gboolean
all_slots_are_eos (GstURISourceBin * urisrc)
{
GSList *tmp;
for (tmp = urisrc->out_slots; tmp; tmp = tmp->next) {
OutputSlotInfo *slot = (OutputSlotInfo *) tmp->data;
if (slot->is_eos == FALSE)
return FALSE;
}
return TRUE;
}
static GstPadProbeReturn static GstPadProbeReturn
demux_pad_events (GstPad * pad, GstPadProbeInfo * info, gpointer user_data) demux_pad_events (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{ {
@ -718,6 +748,7 @@ demux_pad_events (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
case GST_EVENT_EOS: case GST_EVENT_EOS:
{ {
GstStructure *s; GstStructure *s;
gboolean all_streams_eos;
GST_LOG_OBJECT (urisrc, "EOS on pad %" GST_PTR_FORMAT, pad); GST_LOG_OBJECT (urisrc, "EOS on pad %" GST_PTR_FORMAT, pad);
@ -732,6 +763,7 @@ demux_pad_events (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
BUFFERING_LOCK (urisrc); BUFFERING_LOCK (urisrc);
/* Mark that we fed an EOS to this slot */ /* Mark that we fed an EOS to this slot */
child_info->output_slot->is_eos = TRUE; child_info->output_slot->is_eos = TRUE;
all_streams_eos = all_slots_are_eos (urisrc);
BUFFERING_UNLOCK (urisrc); BUFFERING_UNLOCK (urisrc);
/* EOS means this element is no longer buffering */ /* EOS means this element is no longer buffering */
@ -744,6 +776,11 @@ demux_pad_events (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
s = gst_event_writable_structure (ev); s = gst_event_writable_structure (ev);
gst_structure_set (s, "urisourcebin-custom-eos", G_TYPE_BOOLEAN, TRUE, gst_structure_set (s, "urisourcebin-custom-eos", G_TYPE_BOOLEAN, TRUE,
NULL); NULL);
if (all_streams_eos) {
GST_DEBUG_OBJECT (urisrc, "POSTING ABOUT TO FINISH");
g_signal_emit (urisrc,
gst_uri_source_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
}
} }
break; break;
case GST_EVENT_CAPS: case GST_EVENT_CAPS:
@ -769,6 +806,28 @@ done:
return ret; return ret;
} }
static GstPadProbeReturn
pre_queue_event_probe (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
GstURISourceBin *urisrc = GST_URI_SOURCE_BIN (user_data);
GstPadProbeReturn ret = GST_PAD_PROBE_OK;
GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info);
switch (GST_EVENT_TYPE (ev)) {
case GST_EVENT_EOS:
{
GST_LOG_OBJECT (urisrc, "EOS on pad %" GST_PTR_FORMAT, pad);
GST_DEBUG_OBJECT (urisrc, "POSTING ABOUT TO FINISH");
g_signal_emit (urisrc,
gst_uri_source_bin_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
}
break;
default:
break;
}
return ret;
}
/* Called with lock held */ /* Called with lock held */
static OutputSlotInfo * static OutputSlotInfo *
get_output_slot (GstURISourceBin * urisrc, gboolean do_download, get_output_slot (GstURISourceBin * urisrc, gboolean do_download,
@ -976,6 +1035,9 @@ create_output_pad (GstURISourceBin * urisrc, GstPad * pad)
gst_object_unref (pad_tmpl); gst_object_unref (pad_tmpl);
g_free (padname); g_free (padname);
GST_DEBUG_OBJECT (urisrc, "Created output pad %s:%s for pad %s:%s",
GST_DEBUG_PAD_NAME (newpad), GST_DEBUG_PAD_NAME (pad));
return newpad; return newpad;
} }
@ -1595,7 +1657,7 @@ handle_new_pad (GstURISourceBin * urisrc, GstPad * srcpad, GstCaps * caps)
gst_query_unref (query); gst_query_unref (query);
} }
GST_DEBUG_OBJECT (urisrc, "check media-type %s, %d", media_type, GST_DEBUG_OBJECT (urisrc, "check media-type %s, do_download:%d", media_type,
do_download); do_download);
GST_URI_SOURCE_BIN_LOCK (urisrc); GST_URI_SOURCE_BIN_LOCK (urisrc);
@ -1604,6 +1666,9 @@ handle_new_pad (GstURISourceBin * urisrc, GstPad * srcpad, GstCaps * caps)
if (slot == NULL || gst_pad_link (srcpad, slot->sinkpad) != GST_PAD_LINK_OK) if (slot == NULL || gst_pad_link (srcpad, slot->sinkpad) != GST_PAD_LINK_OK)
goto could_not_link; goto could_not_link;
gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
pre_queue_event_probe, urisrc, NULL);
expose_output_pad (urisrc, slot->srcpad); expose_output_pad (urisrc, slot->srcpad);
GST_URI_SOURCE_BIN_UNLOCK (urisrc); GST_URI_SOURCE_BIN_UNLOCK (urisrc);
} }