0a32c6b395fc0408c848f5d290d2c2abda946a90
1 /* GStreamer
2 * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3 *
4 * gsttypefindelement.c: element that detects type of stream
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21 /**
22 * SECTION:element-typefind
23 *
24 * Determines the media-type of a stream. It applies typefind functions in the
25 * order of their rank. One the type has been deteted it sets its src pad caps
26 * to the found media type.
27 *
28 * Plugins can register custom typefinders by using #GstTypeFindFactory.
29 */
31 /* FIXME: need a better solution for non-seekable streams */
33 /* way of operation:
34 * 1) get a list of all typefind functions sorted best to worst
35 * 2) if all elements have been called with all requested data goto 8
36 * 3) call all functions once with all available data
37 * 4) if a function returns a value >= PROP_MAXIMUM goto 8
38 * 5) all functions with a result > PROP_MINIMUM or functions that did not get
39 * all requested data (where peek returned NULL) stay in list
40 * 6) seek to requested offset of best function that still has open data
41 * requests
42 * 7) goto 2
43 * 8) take best available result and use its caps
44 *
45 * The element has two scheduling modes:
46 *
47 * 1) chain based, it will collect buffers and run the typefind function on
48 * the buffer until something is found.
49 * 2) getrange based, it will proxy the getrange function to the sinkpad. It
50 * is assumed that the peer element is happy with whatever format we
51 * eventually read.
52 *
53 * When the element has no connected srcpad, and the sinkpad can operate in
54 * getrange based mode, the element starts its own task to figure out the
55 * type of the stream.
56 *
57 */
59 #ifdef HAVE_CONFIG_H
60 # include "config.h"
61 #endif
63 #include "gsttypefindelement.h"
64 #include "gst/gst_private.h"
65 #include "gst/gst-i18n-lib.h"
66 #include "gst/base/gsttypefindhelper.h"
68 #include <gst/gsttypefind.h>
69 #include <gst/gstutils.h>
70 #include <gst/gsterror.h>
72 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
73 #define GST_CAT_DEFAULT gst_type_find_element_debug
75 /* generic templates */
76 static GstStaticPadTemplate type_find_element_sink_template =
77 GST_STATIC_PAD_TEMPLATE ("sink",
78 GST_PAD_SINK,
79 GST_PAD_ALWAYS,
80 GST_STATIC_CAPS_ANY);
82 static GstStaticPadTemplate type_find_element_src_template =
83 GST_STATIC_PAD_TEMPLATE ("src",
84 GST_PAD_SRC,
85 GST_PAD_ALWAYS,
86 GST_STATIC_CAPS_ANY);
88 /* Require at least 2kB of data before we attempt typefinding in chain-mode.
89 * 128kB is massive overkill for the maximum, but doesn't do any harm */
90 #define TYPE_FIND_MIN_SIZE (2*1024)
91 #define TYPE_FIND_MAX_SIZE (128*1024)
93 /* TypeFind signals and args */
94 enum
95 {
96 HAVE_TYPE,
97 LAST_SIGNAL
98 };
99 enum
100 {
101 PROP_0,
102 PROP_CAPS,
103 PROP_MINIMUM,
104 PROP_MAXIMUM,
105 PROP_FORCE_CAPS,
106 PROP_LAST
107 };
108 enum
109 {
110 MODE_NORMAL, /* act as identity */
111 MODE_TYPEFIND, /* do typefinding */
112 MODE_ERROR /* had fatal error */
113 };
116 #define _do_init(bla) \
117 GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", \
118 GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
120 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
121 GST_TYPE_ELEMENT, _do_init);
123 static void gst_type_find_element_dispose (GObject * object);
124 static void gst_type_find_element_set_property (GObject * object,
125 guint prop_id, const GValue * value, GParamSpec * pspec);
126 static void gst_type_find_element_get_property (GObject * object,
127 guint prop_id, GValue * value, GParamSpec * pspec);
129 #if 0
130 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
131 #endif
133 static gboolean gst_type_find_element_src_event (GstPad * pad,
134 GstEvent * event);
135 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
137 static gboolean gst_type_find_element_handle_event (GstPad * pad,
138 GstEvent * event);
139 static gboolean gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps);
140 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
141 GstBuffer * buffer);
142 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
143 guint64 offset, guint length, GstBuffer ** buffer);
144 static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
146 static GstStateChangeReturn
147 gst_type_find_element_change_state (GstElement * element,
148 GstStateChange transition);
149 static gboolean gst_type_find_element_activate (GstPad * pad);
150 static gboolean
151 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
152 static GstFlowReturn
153 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
154 static void
155 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind);
157 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
159 static void
160 gst_type_find_element_have_type (GstTypeFindElement * typefind,
161 guint probability, const GstCaps * caps)
162 {
163 g_assert (caps != NULL);
165 GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
166 caps, probability);
167 if (typefind->caps)
168 gst_caps_unref (typefind->caps);
169 typefind->caps = gst_caps_copy (caps);
170 gst_pad_set_caps (typefind->src, (GstCaps *) caps);
171 }
173 static void
174 gst_type_find_element_base_init (gpointer g_class)
175 {
176 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
178 gst_element_class_set_details_simple (gstelement_class,
179 "TypeFind",
180 "Generic",
181 "Finds the media type of a stream",
182 "Benjamin Otte <in7y118@public.uni-hamburg.de>");
183 gst_element_class_add_pad_template (gstelement_class,
184 gst_static_pad_template_get (&type_find_element_src_template));
185 gst_element_class_add_pad_template (gstelement_class,
186 gst_static_pad_template_get (&type_find_element_sink_template));
187 }
189 static void
190 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
191 {
192 GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
193 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
195 gobject_class->set_property = gst_type_find_element_set_property;
196 gobject_class->get_property = gst_type_find_element_get_property;
197 gobject_class->dispose = gst_type_find_element_dispose;
199 g_object_class_install_property (gobject_class, PROP_CAPS,
200 g_param_spec_boxed ("caps", _("caps"),
201 _("detected capabilities in stream"), gst_caps_get_type (),
202 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
203 g_object_class_install_property (gobject_class, PROP_MINIMUM,
204 g_param_spec_uint ("minimum", _("minimum"),
205 "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
206 GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM,
207 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
208 g_object_class_install_property (gobject_class, PROP_MAXIMUM,
209 g_param_spec_uint ("maximum", _("maximum"),
210 "probability to stop typefinding (deprecated; non-functional)",
211 GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM,
212 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213 g_object_class_install_property (gobject_class, PROP_FORCE_CAPS,
214 g_param_spec_boxed ("force-caps", _("force caps"),
215 _("force caps without doing a typefind"), gst_caps_get_type (),
216 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
217 /**
218 * GstTypeFindElement::have-type:
219 * @typefind: the typefind instance
220 * @probability: the probability of the type found
221 * @caps: the caps of the type found
222 *
223 * This signal gets emitted when the type and its probability has
224 * been found.
225 */
226 gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
227 G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
228 G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
229 gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
230 G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
232 typefind_class->have_type =
233 GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
235 gstelement_class->change_state =
236 GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
237 }
239 static void
240 gst_type_find_element_init (GstTypeFindElement * typefind,
241 GstTypeFindElementClass * g_class)
242 {
243 /* sinkpad */
244 typefind->sink =
245 gst_pad_new_from_static_template (&type_find_element_sink_template,
246 "sink");
248 gst_pad_set_activate_function (typefind->sink,
249 GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
250 gst_pad_set_setcaps_function (typefind->sink,
251 GST_DEBUG_FUNCPTR (gst_type_find_element_setcaps));
252 gst_pad_set_chain_function (typefind->sink,
253 GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
254 gst_pad_set_event_function (typefind->sink,
255 GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
256 gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
258 /* srcpad */
259 typefind->src =
260 gst_pad_new_from_static_template (&type_find_element_src_template, "src");
262 gst_pad_set_activatepull_function (typefind->src,
263 GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
264 gst_pad_set_checkgetrange_function (typefind->src,
265 GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
266 gst_pad_set_getrange_function (typefind->src,
267 GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
268 gst_pad_set_event_function (typefind->src,
269 GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
270 gst_pad_set_query_function (typefind->src,
271 GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
272 gst_pad_use_fixed_caps (typefind->src);
273 gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
275 typefind->mode = MODE_TYPEFIND;
276 typefind->caps = NULL;
277 typefind->min_probability = 1;
278 typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
280 typefind->store = NULL;
281 }
283 static void
284 gst_type_find_element_dispose (GObject * object)
285 {
286 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
288 if (typefind->store) {
289 gst_buffer_unref (typefind->store);
290 typefind->store = NULL;
291 }
292 if (typefind->force_caps) {
293 gst_caps_unref (typefind->force_caps);
294 typefind->force_caps = NULL;
295 }
297 G_OBJECT_CLASS (parent_class)->dispose (object);
298 }
300 static void
301 gst_type_find_element_set_property (GObject * object, guint prop_id,
302 const GValue * value, GParamSpec * pspec)
303 {
304 GstTypeFindElement *typefind;
306 typefind = GST_TYPE_FIND_ELEMENT (object);
308 switch (prop_id) {
309 case PROP_MINIMUM:
310 typefind->min_probability = g_value_get_uint (value);
311 break;
312 case PROP_MAXIMUM:
313 typefind->max_probability = g_value_get_uint (value);
314 break;
315 case PROP_FORCE_CAPS:
316 GST_OBJECT_LOCK (typefind);
317 if (typefind->force_caps)
318 gst_caps_unref (typefind->force_caps);
319 typefind->force_caps = g_value_dup_boxed (value);
320 GST_OBJECT_UNLOCK (typefind);
321 break;
322 default:
323 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
324 break;
325 }
326 }
328 static void
329 gst_type_find_element_get_property (GObject * object, guint prop_id,
330 GValue * value, GParamSpec * pspec)
331 {
332 GstTypeFindElement *typefind;
334 typefind = GST_TYPE_FIND_ELEMENT (object);
336 switch (prop_id) {
337 case PROP_CAPS:
338 g_value_set_boxed (value, typefind->caps);
339 break;
340 case PROP_MINIMUM:
341 g_value_set_uint (value, typefind->min_probability);
342 break;
343 case PROP_MAXIMUM:
344 g_value_set_uint (value, typefind->max_probability);
345 break;
346 case PROP_FORCE_CAPS:
347 GST_OBJECT_LOCK (typefind);
348 g_value_set_boxed (value, typefind->force_caps);
349 GST_OBJECT_UNLOCK (typefind);
350 break;
351 default:
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
353 break;
354 }
355 }
357 static gboolean
358 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
359 {
360 GstTypeFindElement *typefind;
361 gboolean res = FALSE;
362 GstPad *peer;
364 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
366 peer = gst_pad_get_peer (typefind->sink);
367 if (peer == NULL)
368 return FALSE;
370 res = gst_pad_query (peer, query);
371 if (!res)
372 goto out;
374 switch (GST_QUERY_TYPE (query)) {
375 case GST_QUERY_POSITION:
376 {
377 gint64 peer_pos;
378 GstFormat format;
380 if (typefind->store == NULL)
381 goto out;
383 gst_query_parse_position (query, &format, &peer_pos);
385 /* FIXME: this code assumes that there's no discont in the queue */
386 switch (format) {
387 case GST_FORMAT_BYTES:
388 peer_pos -= GST_BUFFER_SIZE (typefind->store);
389 break;
390 default:
391 /* FIXME */
392 break;
393 }
394 gst_query_set_position (query, format, peer_pos);
395 break;
396 }
397 default:
398 break;
399 }
401 out:
402 gst_object_unref (peer);
403 return res;
404 }
406 #if 0
407 static const GstEventMask *
408 gst_type_find_element_src_event_mask (GstPad * pad)
409 {
410 static const GstEventMask mask[] = {
411 {GST_EVENT_SEEK,
412 GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
413 GST_SEEK_FLAG_FLUSH},
414 /* add more if you want, event masks suck and need to die anyway */
415 {0,}
416 };
418 return mask;
419 }
420 #endif
422 static gboolean
423 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
424 {
425 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
427 if (typefind->mode != MODE_NORMAL) {
428 /* need to do more? */
429 gst_mini_object_unref (GST_MINI_OBJECT (event));
430 return FALSE;
431 }
432 return gst_pad_push_event (typefind->sink, event);
433 }
435 static void
436 start_typefinding (GstTypeFindElement * typefind)
437 {
438 GST_DEBUG_OBJECT (typefind, "starting typefinding");
439 gst_pad_set_caps (typefind->src, NULL);
440 if (typefind->caps) {
441 gst_caps_replace (&typefind->caps, NULL);
442 }
443 typefind->mode = MODE_TYPEFIND;
444 }
446 static void
447 stop_typefinding (GstTypeFindElement * typefind)
448 {
449 GstState state;
450 gboolean push_cached_buffers;
452 gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
454 push_cached_buffers = (state >= GST_STATE_PAUSED);
456 GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
457 push_cached_buffers ? " and pushing cached buffers" : "");
459 if (typefind->store) {
460 if (!push_cached_buffers) {
461 gst_buffer_unref (typefind->store);
462 } else {
463 GstPad *peer = gst_pad_get_peer (typefind->src);
465 typefind->mode = MODE_NORMAL;
466 gst_buffer_set_caps (typefind->store, typefind->caps);
468 /* make sure the user gets a meaningful error message in this case,
469 * which is not a core bug or bug of any kind (as the default error
470 * message emitted by gstpad.c otherwise would make you think) */
471 if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
472 GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
473 "downstream element only works in pull mode, erroring out");
474 GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
475 ("%s cannot work in push mode. The operation is not supported "
476 "with this source element or protocol.",
477 G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
478 ("Downstream pad %s:%s has no chainfunction, and the upstream "
479 "element does not support pull mode",
480 GST_DEBUG_PAD_NAME (peer)));
481 typefind->mode = MODE_ERROR; /* make the chain function error out */
482 } else {
483 gst_type_find_element_send_cached_events (typefind);
484 gst_pad_push (typefind->src, typefind->store);
485 }
487 if (peer)
488 gst_object_unref (peer);
489 }
490 typefind->store = NULL;
491 }
492 }
494 static gboolean
495 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
496 {
497 gboolean res = FALSE;
498 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
500 GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
501 GST_EVENT_TYPE_NAME (event), typefind->mode);
503 switch (typefind->mode) {
504 case MODE_TYPEFIND:
505 switch (GST_EVENT_TYPE (event)) {
506 case GST_EVENT_EOS:{
507 GstTypeFindProbability prob = 0;
508 GstCaps *caps = NULL;
510 GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
512 /* we might not have started typefinding yet because there was not
513 * enough data so far; just give it a shot now and see what we get */
514 if (typefind->store) {
515 caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
516 typefind->store, &prob);
518 if (caps && prob >= typefind->min_probability) {
519 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
520 0, prob, caps);
521 } else {
522 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
523 (NULL), (NULL));
524 }
525 gst_caps_replace (&caps, NULL);
526 } else {
527 /* keep message in sync with the one in the pad activate function */
528 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
529 (_("Stream contains no data.")),
530 ("Can't typefind empty stream"));
531 }
533 stop_typefinding (typefind);
534 res = gst_pad_push_event (typefind->src, event);
535 break;
536 }
537 case GST_EVENT_FLUSH_STOP:
538 g_list_foreach (typefind->cached_events,
539 (GFunc) gst_mini_object_unref, NULL);
540 g_list_free (typefind->cached_events);
541 typefind->cached_events = NULL;
542 gst_buffer_replace (&typefind->store, NULL);
543 /* fall through */
544 case GST_EVENT_FLUSH_START:
545 res = gst_pad_push_event (typefind->src, event);
546 break;
547 default:
548 GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
549 GST_EVENT_TYPE_NAME (event));
550 typefind->cached_events =
551 g_list_append (typefind->cached_events, event);
552 res = TRUE;
553 break;
554 }
555 break;
556 case MODE_NORMAL:
557 res = gst_pad_push_event (typefind->src, event);
558 break;
559 case MODE_ERROR:
560 break;
561 default:
562 g_assert_not_reached ();
563 }
564 return res;
565 }
567 static void
568 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
569 {
570 GList *l;
572 for (l = typefind->cached_events; l != NULL; l = l->next) {
573 GstEvent *event = GST_EVENT (l->data);
575 GST_DEBUG_OBJECT (typefind, "sending cached %s event",
576 GST_EVENT_TYPE_NAME (event));
577 gst_pad_push_event (typefind->src, event);
578 }
579 g_list_free (typefind->cached_events);
580 typefind->cached_events = NULL;
581 }
583 static gboolean
584 gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps)
585 {
586 GstTypeFindElement *typefind;
588 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
590 /* don't operate on ANY caps */
591 if (gst_caps_is_any (caps))
592 return TRUE;
594 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
595 GST_TYPE_FIND_MAXIMUM, caps);
597 /* Shortcircuit typefinding if we get caps */
598 if (typefind->mode == MODE_TYPEFIND) {
599 GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
600 "upstream buffer: %" GST_PTR_FORMAT, caps);
601 typefind->mode = MODE_NORMAL;
603 gst_type_find_element_send_cached_events (typefind);
604 if (typefind->store) {
605 GST_DEBUG_OBJECT (typefind, "Pushing store: %d",
606 GST_BUFFER_SIZE (typefind->store));
607 gst_buffer_set_caps (typefind->store, typefind->caps);
608 gst_pad_push (typefind->src, typefind->store);
609 typefind->store = NULL;
610 }
611 }
613 return TRUE;
614 }
616 static gchar *
617 gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
618 {
619 GstQuery *query;
620 gchar *uri, *result;
621 size_t len;
622 gint find;
624 query = gst_query_new_uri ();
626 /* try getting the caps with an uri query and from the extension */
627 if (!gst_pad_peer_query (pad, query))
628 goto peer_query_failed;
630 gst_query_parse_uri (query, &uri);
631 if (uri == NULL)
632 goto no_uri;
634 GST_DEBUG_OBJECT (typefind, "finding extension of %s", uri);
636 /* find the extension on the uri, this is everything after a '.' */
637 len = strlen (uri);
638 find = len - 1;
640 while (find >= 0) {
641 if (uri[find] == '.')
642 break;
643 find--;
644 }
645 if (find < 0)
646 goto no_extension;
648 result = g_strdup (&uri[find + 1]);
650 GST_DEBUG_OBJECT (typefind, "found extension %s", result);
651 gst_query_unref (query);
653 return result;
655 /* ERRORS */
656 peer_query_failed:
657 {
658 GST_WARNING_OBJECT (typefind, "failed to query peer uri");
659 gst_query_unref (query);
660 return NULL;
661 }
662 no_uri:
663 {
664 GST_WARNING_OBJECT (typefind, "could not parse the peer uri");
665 gst_query_unref (query);
666 return NULL;
667 }
668 no_extension:
669 {
670 GST_WARNING_OBJECT (typefind, "could not find uri extension in %s", uri);
671 gst_query_unref (query);
672 return NULL;
673 }
674 }
676 static GstCaps *
677 gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
678 GstTypeFindProbability * probability)
679 {
680 gchar *ext;
681 GstCaps *caps;
683 ext = gst_type_find_get_extension (typefind, pad);
684 if (!ext)
685 return NULL;
687 caps = gst_type_find_helper_for_extension (GST_OBJECT_CAST (typefind), ext);
688 if (caps)
689 *probability = GST_TYPE_FIND_MAXIMUM;
691 g_free (ext);
693 return caps;
694 }
696 static GstFlowReturn
697 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
698 {
699 GstTypeFindElement *typefind;
700 GstFlowReturn res = GST_FLOW_OK;
702 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
704 switch (typefind->mode) {
705 case MODE_ERROR:
706 /* we should already have called GST_ELEMENT_ERROR */
707 return GST_FLOW_ERROR;
708 case MODE_NORMAL:
709 gst_buffer_set_caps (buffer, typefind->caps);
710 return gst_pad_push (typefind->src, buffer);
711 case MODE_TYPEFIND:{
712 if (typefind->store)
713 typefind->store = gst_buffer_join (typefind->store, buffer);
714 else
715 typefind->store = buffer;
717 res = gst_type_find_element_chain_do_typefinding (typefind);
719 if (typefind->mode == MODE_ERROR)
720 res = GST_FLOW_ERROR;
722 break;
723 }
724 default:
725 g_assert_not_reached ();
726 return GST_FLOW_ERROR;
727 }
729 return res;
730 }
732 static GstFlowReturn
733 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
734 {
735 GstTypeFindProbability probability;
736 GstCaps *caps;
738 if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
739 GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
740 "(%u bytes)", GST_BUFFER_SIZE (typefind->store));
741 return GST_FLOW_OK;
742 }
744 caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
745 typefind->store, &probability);
747 if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
748 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
749 stop_typefinding (typefind);
750 return GST_FLOW_ERROR;
751 } else if (caps == NULL) {
752 GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, "
753 "waiting for more data", GST_BUFFER_SIZE (typefind->store));
754 return GST_FLOW_OK;
755 }
757 /* found a type */
758 if (probability < typefind->min_probability) {
759 GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
760 "probability is %u which is lower than the required minimum of %u",
761 caps, probability, typefind->min_probability);
763 gst_caps_replace (&caps, NULL);
765 if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) {
766 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
767 stop_typefinding (typefind);
768 return GST_FLOW_ERROR;
769 }
771 GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
772 return GST_FLOW_OK;
773 }
775 /* probability is good enough too, so let's make it known ... */
776 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
777 probability, caps);
779 /* .. and send out the accumulated data */
780 stop_typefinding (typefind);
781 gst_caps_unref (caps);
782 return GST_FLOW_OK;
783 }
785 static gboolean
786 gst_type_find_element_checkgetrange (GstPad * srcpad)
787 {
788 GstTypeFindElement *typefind;
790 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
792 return gst_pad_check_pull_range (typefind->sink);
793 }
795 static GstFlowReturn
796 gst_type_find_element_getrange (GstPad * srcpad,
797 guint64 offset, guint length, GstBuffer ** buffer)
798 {
799 GstTypeFindElement *typefind;
800 GstFlowReturn ret;
802 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
804 ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
806 if (ret == GST_FLOW_OK && buffer && *buffer)
807 gst_buffer_set_caps (*buffer, typefind->caps);
809 return ret;
810 }
812 static gboolean
813 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
814 {
815 GstTypeFindElement *typefind;
817 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
819 return gst_pad_activate_pull (typefind->sink, active);
820 }
822 static gboolean
823 gst_type_find_element_activate (GstPad * pad)
824 {
825 GstTypeFindProbability probability = 0;
826 GstCaps *found_caps = NULL;
827 GstTypeFindElement *typefind;
829 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
831 /* if we have force caps, use those */
832 if (typefind->force_caps) {
833 found_caps = gst_caps_ref (typefind->force_caps);
834 probability = GST_TYPE_FIND_MAXIMUM;
835 goto done;
836 }
838 /* 1. try to activate in pull mode. if not, switch to push and succeed.
839 2. try to pull type find.
840 3. deactivate pull mode.
841 4. src pad might have been activated push by the state change. deactivate.
842 5. if we didn't find any caps, try getting the uri extension by doing an uri
843 query.
844 6. if we didn't find any caps, fail.
845 7. emit have-type; maybe the app connected the source pad to something.
846 8. if the sink pad is activated, we are in pull mode. succeed.
847 otherwise activate both pads in push mode and succeed.
848 */
850 /* 1 */
851 if (!gst_pad_check_pull_range (pad) || !gst_pad_activate_pull (pad, TRUE)) {
852 start_typefinding (typefind);
853 return gst_pad_activate_push (pad, TRUE);
854 }
856 /* 2 */
857 {
858 GstPad *peer;
860 peer = gst_pad_get_peer (pad);
861 if (peer) {
862 gint64 size;
863 GstFormat format = GST_FORMAT_BYTES;
864 gchar *ext;
866 if (!gst_pad_query_duration (peer, &format, &size)) {
867 GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
868 gst_object_unref (peer);
869 return FALSE;
870 }
872 /* the size if 0, we cannot continue */
873 if (size == 0) {
874 /* keep message in sync with message in sink event handler */
875 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
876 (_("Stream contains no data.")), ("Can't typefind empty stream"));
877 gst_object_unref (peer);
878 return FALSE;
879 }
880 ext = gst_type_find_get_extension (typefind, pad);
882 found_caps = gst_type_find_helper_get_range_ext (GST_OBJECT_CAST (peer),
883 (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
884 (guint64) size, ext, &probability);
885 g_free (ext);
887 gst_object_unref (peer);
888 }
889 }
891 /* 3 */
892 gst_pad_activate_pull (pad, FALSE);
894 /* 4 */
895 gst_pad_activate_push (typefind->src, FALSE);
897 /* 5 */
898 if (!found_caps || probability < typefind->min_probability) {
899 found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability);
900 }
902 /* 6 */
903 if (!found_caps || probability < typefind->min_probability) {
904 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
905 gst_caps_replace (&found_caps, NULL);
906 return FALSE;
907 }
909 done:
910 /* 7 */
911 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
912 0, probability, found_caps);
913 gst_caps_unref (found_caps);
914 typefind->mode = MODE_NORMAL;
916 /* 8 */
917 if (gst_pad_is_active (pad))
918 return TRUE;
919 else {
920 gboolean ret;
922 ret = gst_pad_activate_push (typefind->src, TRUE);
923 ret &= gst_pad_activate_push (pad, TRUE);
924 return ret;
925 }
926 }
928 static GstStateChangeReturn
929 gst_type_find_element_change_state (GstElement * element,
930 GstStateChange transition)
931 {
932 GstStateChangeReturn ret;
933 GstTypeFindElement *typefind;
935 typefind = GST_TYPE_FIND_ELEMENT (element);
938 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
940 switch (transition) {
941 case GST_STATE_CHANGE_PAUSED_TO_READY:
942 case GST_STATE_CHANGE_READY_TO_NULL:
943 gst_caps_replace (&typefind->caps, NULL);
945 g_list_foreach (typefind->cached_events,
946 (GFunc) gst_mini_object_unref, NULL);
947 g_list_free (typefind->cached_events);
948 typefind->cached_events = NULL;
949 break;
950 default:
951 break;
952 }
954 return ret;
955 }