*/
/**
* SECTION:element-typefind
+ * @title: typefind
*
* Determines the media-type of a stream. It applies typefind functions in the
- * order of their rank. One the type has been deteted it sets its src pad caps
+ * order of their rank. Once the type has been detected it sets its src pad caps
* to the found media type.
*
* Whenever a type is found the #GstTypeFindElement::have-type signal is
static void gst_type_find_element_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-#if 0
-static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
-#endif
-
static gboolean gst_type_find_element_src_event (GstPad * pad,
GstObject * parent, GstEvent * event);
static gboolean gst_type_find_handle_src_query (GstPad * pad,
GstObject * parent, GstPadMode mode, gboolean active);
static GstFlowReturn
gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind,
- gboolean check_avail);
+ gboolean check_avail, gboolean at_eos);
static void gst_type_find_element_send_cached_events (GstTypeFindElement *
typefind);
gst_type_find_element_have_type (GstTypeFindElement * typefind,
guint probability, GstCaps * caps)
{
+ GstEvent *event;
+
g_assert (caps != NULL);
GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
caps, probability);
+ /* Do nothing if downstream is pulling from us */
+ if (GST_PAD_MODE (typefind->src) == GST_PAD_MODE_PULL)
+ return;
+
+ GST_OBJECT_LOCK (typefind);
+
+ /* Now actually send the CAPS event downstream.
+ *
+ * Try to directly send the CAPS event downstream that we created in
+ * gst_type_find_element_emit_have_type() if it is still there, instead
+ * of creating a new one. No need to create an equivalent one, replacing
+ * it in the sticky event list and possibly causing renegotiation
+ */
+ event = gst_pad_get_sticky_event (typefind->src, GST_EVENT_CAPS, 0);
+ if (event) {
+ GstCaps *event_caps;
+
+ gst_event_parse_caps (event, &event_caps);
+ if (caps != event_caps) {
+ gst_event_unref (event);
+ event = gst_event_new_caps (caps);
+ }
+ } else {
+ event = gst_event_new_caps (caps);
+ }
+
+ GST_OBJECT_UNLOCK (typefind);
+
+ gst_pad_push_event (typefind->src, event);
+}
+
+static void
+gst_type_find_element_emit_have_type (GstTypeFindElement * typefind,
+ guint probability, GstCaps * caps)
+{
+ GstEvent *event;
+
+ /* Update caps field immediately so that caps queries and properties can be
+ * honored in all "have-type" signal handlers.
+ */
GST_OBJECT_LOCK (typefind);
if (typefind->caps)
gst_caps_unref (typefind->caps);
typefind->caps = gst_caps_ref (caps);
GST_OBJECT_UNLOCK (typefind);
- gst_pad_set_caps (typefind->src, caps);
+ /* Only store the caps event at this point. We give signal handlers
+ * the chance to look at the caps before they are sent downstream.
+ * They are only forwarded downstream later in the default signal
+ * handler after all application signal handlers
+ */
+ event = gst_event_new_caps (caps);
+ gst_pad_store_sticky_event (typefind->src, event);
+ gst_event_unref (event);
+
+ g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
+ probability, caps);
}
static void
* been found.
*/
gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have-type",
- G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
+ G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_NONE, 2,
G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
"Generic",
"Finds the media type of a stream",
"Benjamin Otte <in7y118@public.uni-hamburg.de>");
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&type_find_element_src_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&type_find_element_sink_template));
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &type_find_element_src_template);
+ gst_element_class_add_static_pad_template (gstelement_class,
+ &type_find_element_sink_template);
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
switch (format) {
case GST_FORMAT_BYTES:
peer_pos -= gst_adapter_available (typefind->adapter);
+ if (peer_pos < 0) /* Clamp result to 0 */
+ peer_pos = 0;
break;
default:
/* FIXME */
GstEvent * event)
{
GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (parent);
+ gboolean result;
if (typefind->mode != MODE_NORMAL) {
/* need to do more? */
- gst_mini_object_unref (GST_MINI_OBJECT_CAST (event));
+ GST_LOG_OBJECT (typefind, "Still typefinding. Not passing event upstream");
+ gst_event_unref (event);
return FALSE;
}
/* Only handle seeks here if driving the pipeline */
if (typefind->segment.format != GST_FORMAT_UNDEFINED &&
GST_EVENT_TYPE (event) == GST_EVENT_SEEK) {
- return gst_type_find_element_seek (typefind, event);
+ result = gst_type_find_element_seek (typefind, event);
+ gst_event_unref (event);
+ return result;
} else {
return gst_pad_push_event (typefind->sink, event);
}
GST_OBJECT_LOCK (typefind);
if (typefind->caps)
gst_caps_replace (&typefind->caps, NULL);
+ typefind->initial_offset = GST_BUFFER_OFFSET_NONE;
GST_OBJECT_UNLOCK (typefind);
typefind->mode = MODE_TYPEFIND;
gboolean push_cached_buffers;
gsize avail;
GstBuffer *buffer;
+ GstClockTime pts, dts;
gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
if (avail == 0)
goto no_data;
+ pts = gst_adapter_prev_pts (typefind->adapter, NULL);
+ dts = gst_adapter_prev_dts (typefind->adapter, NULL);
buffer = gst_adapter_take_buffer (typefind->adapter, avail);
+ GST_BUFFER_PTS (buffer) = pts;
+ GST_BUFFER_DTS (buffer) = dts;
+ GST_BUFFER_OFFSET (buffer) = typefind->initial_offset;
GST_OBJECT_UNLOCK (typefind);
if (!push_cached_buffers) {
*/
gst_event_unref (event);
res = TRUE;
+ break;
}
case GST_EVENT_EOS:
{
GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
- gst_type_find_element_chain_do_typefinding (typefind, FALSE);
+ gst_type_find_element_chain_do_typefinding (typefind, FALSE, TRUE);
res = gst_pad_push_event (typefind->src, event);
break;
}
- case GST_EVENT_FLUSH_STOP:
+ case GST_EVENT_FLUSH_STOP:{
+ GList *l;
+
GST_OBJECT_LOCK (typefind);
- g_list_foreach (typefind->cached_events,
- (GFunc) gst_mini_object_unref, NULL);
+
+ for (l = typefind->cached_events; l; l = l->next) {
+ if (GST_EVENT_IS_STICKY (l->data) &&
+ GST_EVENT_TYPE (l->data) != GST_EVENT_SEGMENT &&
+ GST_EVENT_TYPE (l->data) != GST_EVENT_EOS) {
+ gst_pad_store_sticky_event (typefind->src, l->data);
+ }
+ gst_event_unref (l->data);
+ }
+
g_list_free (typefind->cached_events);
typefind->cached_events = NULL;
gst_adapter_clear (typefind->adapter);
GST_OBJECT_UNLOCK (typefind);
/* fall through */
+ }
case GST_EVENT_FLUSH_START:
res = gst_pad_push_event (typefind->src, event);
break;
if (gst_caps_is_any (caps))
return TRUE;
- g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
- GST_TYPE_FIND_MAXIMUM, caps);
+ /* Set to MODE_NORMAL before emitting have-type, in case it triggers a seek */
+ typefind->mode = MODE_NORMAL;
+ gst_type_find_element_emit_have_type (typefind, GST_TYPE_FIND_MAXIMUM, caps);
/* Shortcircuit typefinding if we get caps */
GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
case MODE_TYPEFIND:
{
GST_OBJECT_LOCK (typefind);
+ if (typefind->initial_offset == GST_BUFFER_OFFSET_NONE)
+ typefind->initial_offset = GST_BUFFER_OFFSET (buffer);
gst_adapter_push (typefind->adapter, buffer);
GST_OBJECT_UNLOCK (typefind);
- res = gst_type_find_element_chain_do_typefinding (typefind, TRUE);
+ res = gst_type_find_element_chain_do_typefinding (typefind, TRUE, FALSE);
if (typefind->mode == MODE_ERROR)
res = GST_FLOW_ERROR;
static GstFlowReturn
gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind,
- gboolean check_avail)
+ gboolean check_avail, gboolean at_eos)
{
GstTypeFindProbability probability;
GstCaps *caps = NULL;
gsize avail;
const guint8 *data;
gboolean have_min, have_max;
+ gchar *ext;
GST_OBJECT_LOCK (typefind);
if (typefind->force_caps) {
if (!have_min)
goto not_enough_data;
+ ext = gst_type_find_get_extension (typefind, typefind->sink);
/* map all available data */
data = gst_adapter_map (typefind->adapter, avail);
- caps = gst_type_find_helper_for_data (GST_OBJECT (typefind),
- data, avail, &probability);
+ caps = gst_type_find_helper_for_data_with_extension (GST_OBJECT (typefind),
+ data, avail, ext, &probability);
gst_adapter_unmap (typefind->adapter);
+ g_free (ext);
if (caps == NULL && have_max)
goto no_type_found;
GST_OBJECT_UNLOCK (typefind);
- /* probability is good enough too, so let's make it known ... emiting this
+ /* probability is good enough too, so let's make it known ... emitting this
* signal calls our object handler which sets the caps. */
- g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
- probability, caps);
+ /* Set to MODE_NORMAL before emitting have-type, in case it triggers a seek */
+ typefind->mode = MODE_NORMAL;
+ gst_type_find_element_emit_have_type (typefind, probability, caps);
/* .. and send out the accumulated data */
stop_typefinding (typefind);
not_enough_data:
{
- GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
- "(%" G_GSIZE_FORMAT " bytes)", avail);
GST_OBJECT_UNLOCK (typefind);
- return GST_FLOW_OK;
+
+ if (at_eos) {
+ GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
+ (_("Stream doesn't contain enough data.")),
+ ("Can't typefind stream"));
+ return GST_FLOW_ERROR;
+ } else {
+ GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
+ "(%" G_GSIZE_FORMAT " bytes)", avail);
+ return GST_FLOW_OK;
+ }
}
no_type_found:
{
}
wait_for_data:
{
- GST_DEBUG_OBJECT (typefind,
- "no caps found with %" G_GSIZE_FORMAT " bytes of data, "
- "waiting for more data", avail);
GST_OBJECT_UNLOCK (typefind);
- return GST_FLOW_OK;
+
+ if (at_eos) {
+ GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
+ (_("Stream doesn't contain enough data.")),
+ ("Can't typefind stream"));
+ return GST_FLOW_ERROR;
+ } else {
+ GST_DEBUG_OBJECT (typefind,
+ "no caps found with %" G_GSIZE_FORMAT " bytes of data, "
+ "waiting for more data", avail);
+ return GST_FLOW_OK;
+ }
}
low_probability:
{
if (typefind->need_stream_start) {
gchar *stream_id;
+ GstEvent *event;
stream_id = gst_pad_create_stream_id (typefind->src,
GST_ELEMENT_CAST (typefind), NULL);
GST_DEBUG_OBJECT (typefind, "Pushing STREAM_START");
- gst_pad_push_event (typefind->src, gst_event_new_stream_start (stream_id));
+ event = gst_event_new_stream_start (stream_id);
+ gst_event_set_group_id (event, gst_util_group_id_next ());
+ gst_pad_push_event (typefind->src, event);
typefind->need_stream_start = FALSE;
g_free (stream_id);
}
ext = gst_type_find_get_extension (typefind, pad);
- found_caps =
- gst_type_find_helper_get_range (GST_OBJECT_CAST (peer),
+ ret =
+ gst_type_find_helper_get_range_full (GST_OBJECT_CAST (peer),
GST_OBJECT_PARENT (peer),
(GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
- (guint64) size, ext, &probability);
+ (guint64) size, ext, &found_caps, &probability);
g_free (ext);
GST_DEBUG ("Found caps %" GST_PTR_FORMAT, found_caps);
gst_object_unref (peer);
+
+ if (ret != GST_FLOW_OK)
+ goto pause;
}
}
goto pause;
}
- GST_DEBUG ("Emiting found caps %" GST_PTR_FORMAT, found_caps);
- g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
- 0, probability, found_caps);
+ GST_DEBUG ("Emitting found caps %" GST_PTR_FORMAT, found_caps);
+ /* Set to MODE_NORMAL before emitting have-type, in case it triggers a seek */
typefind->mode = MODE_NORMAL;
+ gst_type_find_element_emit_have_type (typefind, probability, found_caps);
gst_caps_unref (found_caps);
} else if (typefind->mode == MODE_NORMAL) {
GstBuffer *outbuf = NULL;
if (ret != GST_FLOW_OK)
goto pause;
- typefind->offset += 4096;
+ typefind->offset += gst_buffer_get_size (outbuf);
ret = gst_pad_push (typefind->src, outbuf);
if (ret != GST_FLOW_OK)
}
} else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
/* for fatal errors we post an error message */
- GST_ELEMENT_ERROR (typefind, STREAM, FAILED, (NULL),
- ("stream stopped, reason %s", reason));
+ GST_ELEMENT_FLOW_ERROR (typefind, ret);
push_eos = TRUE;
}
if (push_eos) {
res = TRUE;
} else {
res = gst_pad_stop_task (pad);
+ gst_segment_init (&typefind->segment, GST_FORMAT_UNDEFINED);
}
break;
case GST_PAD_MODE_PUSH:
- if (active)
+ if (active) {
+ gst_segment_init (&typefind->segment, GST_FORMAT_UNDEFINED);
start_typefinding (typefind);
- else
+ } else {
stop_typefinding (typefind);
-
+ gst_segment_init (&typefind->segment, GST_FORMAT_UNDEFINED);
+ }
res = TRUE;
break;
default:
{
GstQuery *query;
gboolean pull_mode;
- GstSchedulingFlags sched_flags;
query = gst_query_new_scheduling ();
goto typefind_push;
}
- gst_query_parse_scheduling (query, &sched_flags, NULL, NULL, NULL);
-
- pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL)
- && ((sched_flags & GST_SCHEDULING_FLAG_SEEKABLE) != 0);
+ pull_mode = gst_query_has_scheduling_mode_with_flags (query,
+ GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
gst_query_unref (query);