Branch data Line data Source code
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 : : * Whenever a type is found the #GstTypeFindElement::have-type signal is
29 : : * emitted, either from the streaming thread or the application thread
30 : : * (the latter may happen when typefinding is done pull-based from the
31 : : * state change function).
32 : : *
33 : : * Plugins can register custom typefinders by using #GstTypeFindFactory.
34 : : */
35 : :
36 : : /* FIXME: need a better solution for non-seekable streams */
37 : :
38 : : /* way of operation:
39 : : * 1) get a list of all typefind functions sorted best to worst
40 : : * 2) if all elements have been called with all requested data goto 8
41 : : * 3) call all functions once with all available data
42 : : * 4) if a function returns a value >= PROP_MAXIMUM goto 8
43 : : * 5) all functions with a result > PROP_MINIMUM or functions that did not get
44 : : * all requested data (where peek returned NULL) stay in list
45 : : * 6) seek to requested offset of best function that still has open data
46 : : * requests
47 : : * 7) goto 2
48 : : * 8) take best available result and use its caps
49 : : *
50 : : * The element has two scheduling modes:
51 : : *
52 : : * 1) chain based, it will collect buffers and run the typefind function on
53 : : * the buffer until something is found.
54 : : * 2) getrange based, it will proxy the getrange function to the sinkpad. It
55 : : * is assumed that the peer element is happy with whatever format we
56 : : * eventually read.
57 : : *
58 : : * By default it tries to do pull based typefinding (this avoids joining
59 : : * received buffers and holding them back in store.)
60 : : *
61 : : * When the element has no connected srcpad, and the sinkpad can operate in
62 : : * getrange based mode, the element starts its own task to figure out the
63 : : * type of the stream.
64 : : *
65 : : * Most of the actual implementation is in libs/gst/base/gsttypefindhelper.c.
66 : : */
67 : :
68 : : #ifdef HAVE_CONFIG_H
69 : : # include "config.h"
70 : : #endif
71 : :
72 : : #include "gst/gst_private.h"
73 : :
74 : : #include "gsttypefindelement.h"
75 : : #include "gst/gst-i18n-lib.h"
76 : : #include "gst/base/gsttypefindhelper.h"
77 : :
78 : : #include <gst/gsttypefind.h>
79 : : #include <gst/gstutils.h>
80 : : #include <gst/gsterror.h>
81 : :
82 : : GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
83 : : #define GST_CAT_DEFAULT gst_type_find_element_debug
84 : :
85 : : /* generic templates */
86 : : static GstStaticPadTemplate type_find_element_sink_template =
87 : : GST_STATIC_PAD_TEMPLATE ("sink",
88 : : GST_PAD_SINK,
89 : : GST_PAD_ALWAYS,
90 : : GST_STATIC_CAPS_ANY);
91 : :
92 : : static GstStaticPadTemplate type_find_element_src_template =
93 : : GST_STATIC_PAD_TEMPLATE ("src",
94 : : GST_PAD_SRC,
95 : : GST_PAD_ALWAYS,
96 : : GST_STATIC_CAPS_ANY);
97 : :
98 : : /* Require at least 2kB of data before we attempt typefinding in chain-mode.
99 : : * 128kB is massive overkill for the maximum, but doesn't do any harm */
100 : : #define TYPE_FIND_MIN_SIZE (2*1024)
101 : : #define TYPE_FIND_MAX_SIZE (128*1024)
102 : :
103 : : /* TypeFind signals and args */
104 : : enum
105 : : {
106 : : HAVE_TYPE,
107 : : LAST_SIGNAL
108 : : };
109 : : enum
110 : : {
111 : : PROP_0,
112 : : PROP_CAPS,
113 : : PROP_MINIMUM,
114 : : PROP_MAXIMUM,
115 : : PROP_FORCE_CAPS,
116 : : PROP_LAST
117 : : };
118 : : enum
119 : : {
120 : : MODE_NORMAL, /* act as identity */
121 : : MODE_TYPEFIND, /* do typefinding */
122 : : MODE_ERROR /* had fatal error */
123 : : };
124 : :
125 : :
126 : : #define _do_init(bla) \
127 : : GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", \
128 : : GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
129 : :
130 [ + + ][ + - ]: 205 : GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
131 : 205 : GST_TYPE_ELEMENT, _do_init);
132 : :
133 : : static void gst_type_find_element_dispose (GObject * object);
134 : : static void gst_type_find_element_set_property (GObject * object,
135 : : guint prop_id, const GValue * value, GParamSpec * pspec);
136 : : static void gst_type_find_element_get_property (GObject * object,
137 : : guint prop_id, GValue * value, GParamSpec * pspec);
138 : :
139 : : #if 0
140 : : static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
141 : : #endif
142 : :
143 : : static gboolean gst_type_find_element_src_event (GstPad * pad,
144 : : GstEvent * event);
145 : : static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
146 : :
147 : : static gboolean gst_type_find_element_handle_event (GstPad * pad,
148 : : GstEvent * event);
149 : : static gboolean gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps);
150 : : static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
151 : : GstBuffer * buffer);
152 : : static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
153 : : guint64 offset, guint length, GstBuffer ** buffer);
154 : : static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
155 : :
156 : : static GstStateChangeReturn
157 : : gst_type_find_element_change_state (GstElement * element,
158 : : GstStateChange transition);
159 : : static gboolean gst_type_find_element_activate (GstPad * pad);
160 : : static gboolean
161 : : gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
162 : : static GstFlowReturn
163 : : gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
164 : : static void
165 : : gst_type_find_element_send_cached_events (GstTypeFindElement * typefind);
166 : :
167 : : static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
168 : :
169 : : static void
170 : 0 : gst_type_find_element_have_type (GstTypeFindElement * typefind,
171 : : guint probability, const GstCaps * caps)
172 : : {
173 : : GstCaps *copy;
174 : :
175 [ # # ]: 0 : g_assert (caps != NULL);
176 : :
177 [ # # ]: 0 : GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
178 : : caps, probability);
179 : :
180 : 0 : GST_OBJECT_LOCK (typefind);
181 [ # # ]: 0 : if (typefind->caps)
182 : 0 : gst_caps_unref (typefind->caps);
183 : 0 : typefind->caps = gst_caps_copy (caps);
184 : 0 : copy = gst_caps_ref (typefind->caps);
185 : 0 : GST_OBJECT_UNLOCK (typefind);
186 : :
187 : 0 : gst_pad_set_caps (typefind->src, copy);
188 : 0 : gst_caps_unref (copy);
189 : 0 : }
190 : :
191 : : static void
192 : 8 : gst_type_find_element_base_init (gpointer g_class)
193 : : {
194 : 8 : GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
195 : :
196 : 8 : gst_element_class_set_details_simple (gstelement_class,
197 : : "TypeFind",
198 : : "Generic",
199 : : "Finds the media type of a stream",
200 : : "Benjamin Otte <in7y118@public.uni-hamburg.de>");
201 : 8 : gst_element_class_add_pad_template (gstelement_class,
202 : : gst_static_pad_template_get (&type_find_element_src_template));
203 : 8 : gst_element_class_add_pad_template (gstelement_class,
204 : : gst_static_pad_template_get (&type_find_element_sink_template));
205 : 8 : }
206 : :
207 : : static void
208 : 8 : gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
209 : : {
210 : 8 : GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
211 : 8 : GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
212 : :
213 : 8 : gobject_class->set_property = gst_type_find_element_set_property;
214 : 8 : gobject_class->get_property = gst_type_find_element_get_property;
215 : 8 : gobject_class->dispose = gst_type_find_element_dispose;
216 : :
217 : 8 : g_object_class_install_property (gobject_class, PROP_CAPS,
218 : 8 : g_param_spec_boxed ("caps", _("caps"),
219 : 8 : _("detected capabilities in stream"), gst_caps_get_type (),
220 : : G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
221 : 8 : g_object_class_install_property (gobject_class, PROP_MINIMUM,
222 : 8 : g_param_spec_uint ("minimum", _("minimum"),
223 : : "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
224 : : GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM,
225 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
226 : 8 : g_object_class_install_property (gobject_class, PROP_MAXIMUM,
227 : 8 : g_param_spec_uint ("maximum", _("maximum"),
228 : : "probability to stop typefinding (deprecated; non-functional)",
229 : : GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM,
230 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
231 : 8 : g_object_class_install_property (gobject_class, PROP_FORCE_CAPS,
232 : 8 : g_param_spec_boxed ("force-caps", _("force caps"),
233 : 8 : _("force caps without doing a typefind"), gst_caps_get_type (),
234 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
235 : : /**
236 : : * GstTypeFindElement::have-type:
237 : : * @typefind: the typefind instance
238 : : * @probability: the probability of the type found
239 : : * @caps: the caps of the type found
240 : : *
241 : : * This signal gets emitted when the type and its probability has
242 : : * been found.
243 : : */
244 : 8 : gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have-type",
245 : : G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
246 : : G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
247 : : gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
248 : 8 : G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
249 : :
250 : 8 : typefind_class->have_type =
251 : 8 : GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
252 : :
253 : 8 : gstelement_class->change_state =
254 : 8 : GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
255 : 8 : }
256 : :
257 : : static void
258 : 3 : gst_type_find_element_init (GstTypeFindElement * typefind,
259 : : GstTypeFindElementClass * g_class)
260 : : {
261 : : /* sinkpad */
262 : 3 : typefind->sink =
263 : 3 : gst_pad_new_from_static_template (&type_find_element_sink_template,
264 : : "sink");
265 : :
266 : 3 : gst_pad_set_activate_function (typefind->sink,
267 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
268 : 3 : gst_pad_set_setcaps_function (typefind->sink,
269 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_setcaps));
270 : 3 : gst_pad_set_chain_function (typefind->sink,
271 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
272 : 3 : gst_pad_set_event_function (typefind->sink,
273 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
274 : 3 : gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
275 : :
276 : : /* srcpad */
277 : 3 : typefind->src =
278 : 3 : gst_pad_new_from_static_template (&type_find_element_src_template, "src");
279 : :
280 : 3 : gst_pad_set_activatepull_function (typefind->src,
281 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
282 : 3 : gst_pad_set_checkgetrange_function (typefind->src,
283 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
284 : 3 : gst_pad_set_getrange_function (typefind->src,
285 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
286 : 3 : gst_pad_set_event_function (typefind->src,
287 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
288 : 3 : gst_pad_set_query_function (typefind->src,
289 : 3 : GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
290 : 3 : gst_pad_use_fixed_caps (typefind->src);
291 : 3 : gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
292 : :
293 : 3 : typefind->mode = MODE_TYPEFIND;
294 : 3 : typefind->caps = NULL;
295 : 3 : typefind->min_probability = 1;
296 : 3 : typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
297 : :
298 : 3 : typefind->store = NULL;
299 : 3 : }
300 : :
301 : : static void
302 : 3 : gst_type_find_element_dispose (GObject * object)
303 : : {
304 : 3 : GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
305 : :
306 [ - + ]: 3 : if (typefind->store) {
307 : 0 : gst_buffer_unref (typefind->store);
308 : 0 : typefind->store = NULL;
309 : : }
310 : :
311 [ - + ]: 3 : if (typefind->force_caps) {
312 : 0 : gst_caps_unref (typefind->force_caps);
313 : 0 : typefind->force_caps = NULL;
314 : : }
315 : :
316 : 3 : G_OBJECT_CLASS (parent_class)->dispose (object);
317 : 3 : }
318 : :
319 : : static void
320 : 0 : gst_type_find_element_set_property (GObject * object, guint prop_id,
321 : : const GValue * value, GParamSpec * pspec)
322 : : {
323 : : GstTypeFindElement *typefind;
324 : :
325 : 0 : typefind = GST_TYPE_FIND_ELEMENT (object);
326 : :
327 [ # # # # ]: 0 : switch (prop_id) {
328 : : case PROP_MINIMUM:
329 : 0 : typefind->min_probability = g_value_get_uint (value);
330 : 0 : break;
331 : : case PROP_MAXIMUM:
332 : 0 : typefind->max_probability = g_value_get_uint (value);
333 : 0 : break;
334 : : case PROP_FORCE_CAPS:
335 : 0 : GST_OBJECT_LOCK (typefind);
336 [ # # ]: 0 : if (typefind->force_caps)
337 : 0 : gst_caps_unref (typefind->force_caps);
338 : 0 : typefind->force_caps = g_value_dup_boxed (value);
339 : 0 : GST_OBJECT_UNLOCK (typefind);
340 : 0 : break;
341 : : default:
342 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343 : 0 : break;
344 : : }
345 : 0 : }
346 : :
347 : : static void
348 : 0 : gst_type_find_element_get_property (GObject * object, guint prop_id,
349 : : GValue * value, GParamSpec * pspec)
350 : : {
351 : : GstTypeFindElement *typefind;
352 : :
353 : 0 : typefind = GST_TYPE_FIND_ELEMENT (object);
354 : :
355 [ # # # # : 0 : switch (prop_id) {
# ]
356 : : case PROP_CAPS:
357 : 0 : GST_OBJECT_LOCK (typefind);
358 : 0 : g_value_set_boxed (value, typefind->caps);
359 : 0 : GST_OBJECT_UNLOCK (typefind);
360 : 0 : break;
361 : : case PROP_MINIMUM:
362 : 0 : g_value_set_uint (value, typefind->min_probability);
363 : 0 : break;
364 : : case PROP_MAXIMUM:
365 : 0 : g_value_set_uint (value, typefind->max_probability);
366 : 0 : break;
367 : : case PROP_FORCE_CAPS:
368 : 0 : GST_OBJECT_LOCK (typefind);
369 : 0 : g_value_set_boxed (value, typefind->force_caps);
370 : 0 : GST_OBJECT_UNLOCK (typefind);
371 : 0 : break;
372 : : default:
373 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
374 : 0 : break;
375 : : }
376 : 0 : }
377 : :
378 : : static gboolean
379 : 0 : gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
380 : : {
381 : : GstTypeFindElement *typefind;
382 : 0 : gboolean res = FALSE;
383 : : GstPad *peer;
384 : :
385 : 0 : typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
386 : :
387 : 0 : peer = gst_pad_get_peer (typefind->sink);
388 [ # # ]: 0 : if (peer == NULL)
389 : 0 : return FALSE;
390 : :
391 : 0 : res = gst_pad_query (peer, query);
392 [ # # ]: 0 : if (!res)
393 : 0 : goto out;
394 : :
395 [ # # ]: 0 : switch (GST_QUERY_TYPE (query)) {
396 : : case GST_QUERY_POSITION:
397 : : {
398 : : gint64 peer_pos;
399 : : GstFormat format;
400 : :
401 : 0 : GST_OBJECT_LOCK (typefind);
402 [ # # ]: 0 : if (typefind->store == NULL) {
403 : 0 : GST_OBJECT_UNLOCK (typefind);
404 : 0 : goto out;
405 : : }
406 : :
407 : 0 : gst_query_parse_position (query, &format, &peer_pos);
408 : :
409 : : /* FIXME: this code assumes that there's no discont in the queue */
410 [ # # ]: 0 : switch (format) {
411 : : case GST_FORMAT_BYTES:
412 : 0 : peer_pos -= GST_BUFFER_SIZE (typefind->store);
413 : 0 : break;
414 : : default:
415 : : /* FIXME */
416 : 0 : break;
417 : : }
418 : 0 : GST_OBJECT_UNLOCK (typefind);
419 : 0 : gst_query_set_position (query, format, peer_pos);
420 : 0 : break;
421 : : }
422 : : default:
423 : 0 : break;
424 : : }
425 : :
426 : : out:
427 : 0 : gst_object_unref (peer);
428 : 0 : return res;
429 : : }
430 : :
431 : : #if 0
432 : : static const GstEventMask *
433 : : gst_type_find_element_src_event_mask (GstPad * pad)
434 : : {
435 : : static const GstEventMask mask[] = {
436 : : {GST_EVENT_SEEK,
437 : : GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
438 : : GST_SEEK_FLAG_FLUSH},
439 : : /* add more if you want, event masks suck and need to die anyway */
440 : : {0,}
441 : : };
442 : :
443 : : return mask;
444 : : }
445 : : #endif
446 : :
447 : : static gboolean
448 : 0 : gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
449 : : {
450 : 0 : GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
451 : :
452 [ # # ]: 0 : if (typefind->mode != MODE_NORMAL) {
453 : : /* need to do more? */
454 : 0 : gst_mini_object_unref (GST_MINI_OBJECT (event));
455 : 0 : return FALSE;
456 : : }
457 : 0 : return gst_pad_push_event (typefind->sink, event);
458 : : }
459 : :
460 : : static void
461 : 7 : start_typefinding (GstTypeFindElement * typefind)
462 : : {
463 [ - + ]: 7 : GST_DEBUG_OBJECT (typefind, "starting typefinding");
464 : 7 : gst_pad_set_caps (typefind->src, NULL);
465 : :
466 : 7 : GST_OBJECT_LOCK (typefind);
467 [ - + ]: 7 : if (typefind->caps)
468 : 0 : gst_caps_replace (&typefind->caps, NULL);
469 : 7 : GST_OBJECT_UNLOCK (typefind);
470 : :
471 : 7 : typefind->mode = MODE_TYPEFIND;
472 : 7 : }
473 : :
474 : : static void
475 : 0 : stop_typefinding (GstTypeFindElement * typefind)
476 : : {
477 : : GstState state;
478 : : gboolean push_cached_buffers;
479 : :
480 : 0 : gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
481 : :
482 : 0 : push_cached_buffers = (state >= GST_STATE_PAUSED);
483 : :
484 [ # # ][ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
485 : : push_cached_buffers ? " and pushing cached buffers" : "");
486 : :
487 : 0 : GST_OBJECT_LOCK (typefind);
488 [ # # ]: 0 : if (typefind->store) {
489 : : GstBuffer *store;
490 : :
491 : 0 : store = gst_buffer_make_metadata_writable (typefind->store);
492 : 0 : typefind->store = NULL;
493 : 0 : gst_buffer_set_caps (store, typefind->caps);
494 : 0 : GST_OBJECT_UNLOCK (typefind);
495 : :
496 [ # # ]: 0 : if (!push_cached_buffers) {
497 : 0 : gst_buffer_unref (store);
498 : : } else {
499 : 0 : GstPad *peer = gst_pad_get_peer (typefind->src);
500 : :
501 : 0 : typefind->mode = MODE_NORMAL;
502 : :
503 : : /* make sure the user gets a meaningful error message in this case,
504 : : * which is not a core bug or bug of any kind (as the default error
505 : : * message emitted by gstpad.c otherwise would make you think) */
506 [ # # ][ # # ]: 0 : if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
507 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
508 : : "downstream element only works in pull mode, erroring out");
509 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
510 : : ("%s cannot work in push mode. The operation is not supported "
511 : : "with this source element or protocol.",
512 : : G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
513 : : ("Downstream pad %s:%s has no chainfunction, and the upstream "
514 : : "element does not support pull mode",
515 : : GST_DEBUG_PAD_NAME (peer)));
516 : 0 : typefind->mode = MODE_ERROR; /* make the chain function error out */
517 : 0 : gst_buffer_unref (store);
518 : : } else {
519 : 0 : gst_type_find_element_send_cached_events (typefind);
520 : 0 : gst_pad_push (typefind->src, store);
521 : : }
522 : :
523 [ # # ]: 0 : if (peer)
524 : 0 : gst_object_unref (peer);
525 : : }
526 : : } else {
527 : 0 : GST_OBJECT_UNLOCK (typefind);
528 : : }
529 : 0 : }
530 : :
531 : : static gboolean
532 : 0 : gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
533 : : {
534 : 0 : gboolean res = FALSE;
535 : 0 : GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
536 : :
537 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
538 : : GST_EVENT_TYPE_NAME (event), typefind->mode);
539 : :
540 [ # # # # ]: 0 : switch (typefind->mode) {
541 : : case MODE_TYPEFIND:
542 [ # # # # ]: 0 : switch (GST_EVENT_TYPE (event)) {
543 : : case GST_EVENT_EOS:{
544 : 0 : GstTypeFindProbability prob = 0;
545 : 0 : GstCaps *caps = NULL;
546 : :
547 [ # # ]: 0 : GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
548 : :
549 : : /* we might not have started typefinding yet because there was not
550 : : * enough data so far; just give it a shot now and see what we get */
551 : 0 : GST_OBJECT_LOCK (typefind);
552 [ # # ]: 0 : if (typefind->store) {
553 : 0 : caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
554 : : typefind->store, &prob);
555 : 0 : GST_OBJECT_UNLOCK (typefind);
556 : :
557 [ # # ][ # # ]: 0 : if (caps && prob >= typefind->min_probability) {
558 : 0 : g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
559 : : 0, prob, caps);
560 : : } else {
561 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
[ # # ][ # # ]
562 : : (NULL), (NULL));
563 : : }
564 : 0 : gst_caps_replace (&caps, NULL);
565 : : } else {
566 : 0 : GST_OBJECT_UNLOCK (typefind);
567 : : /* keep message in sync with the one in the pad activate function */
568 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
[ # # ][ # # ]
569 : : (_("Stream contains no data.")),
570 : : ("Can't typefind empty stream"));
571 : : }
572 : :
573 : 0 : stop_typefinding (typefind);
574 : 0 : res = gst_pad_push_event (typefind->src, event);
575 : 0 : break;
576 : : }
577 : : case GST_EVENT_FLUSH_STOP:
578 : 0 : GST_OBJECT_LOCK (typefind);
579 : 0 : g_list_foreach (typefind->cached_events,
580 : : (GFunc) gst_mini_object_unref, NULL);
581 : 0 : g_list_free (typefind->cached_events);
582 : 0 : typefind->cached_events = NULL;
583 : 0 : gst_buffer_replace (&typefind->store, NULL);
584 : 0 : GST_OBJECT_UNLOCK (typefind);
585 : : /* fall through */
586 : : case GST_EVENT_FLUSH_START:
587 : 0 : res = gst_pad_push_event (typefind->src, event);
588 : 0 : break;
589 : : default:
590 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
591 : : GST_EVENT_TYPE_NAME (event));
592 : 0 : GST_OBJECT_LOCK (typefind);
593 : 0 : typefind->cached_events =
594 : 0 : g_list_append (typefind->cached_events, event);
595 : 0 : GST_OBJECT_UNLOCK (typefind);
596 : 0 : res = TRUE;
597 : 0 : break;
598 : : }
599 : 0 : break;
600 : : case MODE_NORMAL:
601 : 0 : res = gst_pad_push_event (typefind->src, event);
602 : 0 : break;
603 : : case MODE_ERROR:
604 : 0 : break;
605 : : default:
606 : 0 : g_assert_not_reached ();
607 : : }
608 : 0 : return res;
609 : : }
610 : :
611 : : static void
612 : 0 : gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
613 : : {
614 : : GList *l, *cached_events;
615 : :
616 : 0 : GST_OBJECT_LOCK (typefind);
617 : 0 : cached_events = typefind->cached_events;
618 : 0 : typefind->cached_events = NULL;
619 : 0 : GST_OBJECT_UNLOCK (typefind);
620 : :
621 [ # # ]: 0 : for (l = cached_events; l != NULL; l = l->next) {
622 : 0 : GstEvent *event = GST_EVENT (l->data);
623 : :
624 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "sending cached %s event",
625 : : GST_EVENT_TYPE_NAME (event));
626 : 0 : gst_pad_push_event (typefind->src, event);
627 : : }
628 : 0 : g_list_free (cached_events);
629 : 0 : }
630 : :
631 : : static gboolean
632 : 0 : gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps)
633 : : {
634 : : GstTypeFindElement *typefind;
635 : :
636 : 0 : typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
637 : :
638 : : /* don't operate on ANY caps */
639 [ # # ]: 0 : if (gst_caps_is_any (caps))
640 : 0 : return TRUE;
641 : :
642 : 0 : g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
643 : : GST_TYPE_FIND_MAXIMUM, caps);
644 : :
645 : : /* Shortcircuit typefinding if we get caps */
646 [ # # ]: 0 : if (typefind->mode == MODE_TYPEFIND) {
647 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
648 : : "upstream buffer: %" GST_PTR_FORMAT, caps);
649 : 0 : typefind->mode = MODE_NORMAL;
650 : :
651 : 0 : gst_type_find_element_send_cached_events (typefind);
652 : 0 : GST_OBJECT_LOCK (typefind);
653 [ # # ]: 0 : if (typefind->store) {
654 : : GstBuffer *store;
655 : :
656 : 0 : store = gst_buffer_make_metadata_writable (typefind->store);
657 : 0 : typefind->store = NULL;
658 : 0 : gst_buffer_set_caps (store, typefind->caps);
659 : 0 : GST_OBJECT_UNLOCK (typefind);
660 : :
661 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "Pushing store: %d", GST_BUFFER_SIZE (store));
662 : 0 : gst_pad_push (typefind->src, store);
663 : : } else {
664 : 0 : GST_OBJECT_UNLOCK (typefind);
665 : : }
666 : : }
667 : :
668 : 0 : return TRUE;
669 : : }
670 : :
671 : : static gchar *
672 : 0 : gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
673 : : {
674 : : GstQuery *query;
675 : : gchar *uri, *result;
676 : : size_t len;
677 : : gint find;
678 : :
679 : 0 : query = gst_query_new_uri ();
680 : :
681 : : /* try getting the caps with an uri query and from the extension */
682 [ # # ]: 0 : if (!gst_pad_peer_query (pad, query))
683 : 0 : goto peer_query_failed;
684 : :
685 : 0 : gst_query_parse_uri (query, &uri);
686 [ # # ]: 0 : if (uri == NULL)
687 : 0 : goto no_uri;
688 : :
689 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "finding extension of %s", uri);
690 : :
691 : : /* find the extension on the uri, this is everything after a '.' */
692 : 0 : len = strlen (uri);
693 : 0 : find = len - 1;
694 : :
695 [ # # ]: 0 : while (find >= 0) {
696 [ # # ]: 0 : if (uri[find] == '.')
697 : 0 : break;
698 : 0 : find--;
699 : : }
700 [ # # ]: 0 : if (find < 0)
701 : 0 : goto no_extension;
702 : :
703 : 0 : result = g_strdup (&uri[find + 1]);
704 : :
705 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "found extension %s", result);
706 : 0 : gst_query_unref (query);
707 : 0 : g_free (uri);
708 : :
709 : 0 : return result;
710 : :
711 : : /* ERRORS */
712 : : peer_query_failed:
713 : : {
714 [ # # ]: 0 : GST_WARNING_OBJECT (typefind, "failed to query peer uri");
715 : 0 : gst_query_unref (query);
716 : 0 : return NULL;
717 : : }
718 : : no_uri:
719 : : {
720 [ # # ]: 0 : GST_WARNING_OBJECT (typefind, "could not parse the peer uri");
721 : 0 : gst_query_unref (query);
722 : 0 : return NULL;
723 : : }
724 : : no_extension:
725 : : {
726 [ # # ]: 0 : GST_WARNING_OBJECT (typefind, "could not find uri extension in %s", uri);
727 : 0 : gst_query_unref (query);
728 : 0 : g_free (uri);
729 : 0 : return NULL;
730 : : }
731 : : }
732 : :
733 : : static GstCaps *
734 : 0 : gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
735 : : GstTypeFindProbability * probability)
736 : : {
737 : : gchar *ext;
738 : : GstCaps *caps;
739 : :
740 : 0 : ext = gst_type_find_get_extension (typefind, pad);
741 [ # # ]: 0 : if (!ext)
742 : 0 : return NULL;
743 : :
744 : 0 : caps = gst_type_find_helper_for_extension (GST_OBJECT_CAST (typefind), ext);
745 [ # # ]: 0 : if (caps)
746 : 0 : *probability = GST_TYPE_FIND_MAXIMUM;
747 : :
748 : 0 : g_free (ext);
749 : :
750 : 0 : return caps;
751 : : }
752 : :
753 : : static GstFlowReturn
754 : 0 : gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
755 : : {
756 : : GstTypeFindElement *typefind;
757 : 0 : GstFlowReturn res = GST_FLOW_OK;
758 : :
759 : 0 : typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
760 : :
761 [ # # ]: 0 : GST_LOG_OBJECT (typefind, "handling buffer in mode %d", typefind->mode);
762 : :
763 [ # # # # ]: 0 : switch (typefind->mode) {
764 : : case MODE_ERROR:
765 : : /* we should already have called GST_ELEMENT_ERROR */
766 : 0 : return GST_FLOW_ERROR;
767 : : case MODE_NORMAL:
768 : : /* don't take object lock as typefind->caps should not change anymore */
769 : 0 : buffer = gst_buffer_make_metadata_writable (buffer);
770 : 0 : gst_buffer_set_caps (buffer, typefind->caps);
771 : 0 : return gst_pad_push (typefind->src, buffer);
772 : : case MODE_TYPEFIND:{
773 : 0 : GST_OBJECT_LOCK (typefind);
774 [ # # ]: 0 : if (typefind->store)
775 : 0 : typefind->store = gst_buffer_join (typefind->store, buffer);
776 : : else
777 : 0 : typefind->store = buffer;
778 : 0 : GST_OBJECT_UNLOCK (typefind);
779 : :
780 : 0 : res = gst_type_find_element_chain_do_typefinding (typefind);
781 : :
782 [ # # ]: 0 : if (typefind->mode == MODE_ERROR)
783 : 0 : res = GST_FLOW_ERROR;
784 : :
785 : 0 : break;
786 : : }
787 : : default:
788 : 0 : g_assert_not_reached ();
789 : : return GST_FLOW_ERROR;
790 : : }
791 : :
792 : 0 : return res;
793 : : }
794 : :
795 : : static GstFlowReturn
796 : 0 : gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
797 : : {
798 : : GstTypeFindProbability probability;
799 : : GstCaps *caps;
800 : :
801 : 0 : GST_OBJECT_LOCK (typefind);
802 [ # # ]: 0 : if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
803 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
804 : : "(%u bytes)", GST_BUFFER_SIZE (typefind->store));
805 : 0 : GST_OBJECT_UNLOCK (typefind);
806 : 0 : return GST_FLOW_OK;
807 : : }
808 : :
809 : 0 : caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
810 : : typefind->store, &probability);
811 [ # # ][ # # ]: 0 : if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
812 : 0 : GST_OBJECT_UNLOCK (typefind);
813 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
[ # # ][ # # ]
814 : 0 : stop_typefinding (typefind);
815 : 0 : return GST_FLOW_ERROR;
816 [ # # ]: 0 : } else if (caps == NULL) {
817 : 0 : GST_OBJECT_UNLOCK (typefind);
818 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, "
819 : : "waiting for more data", GST_BUFFER_SIZE (typefind->store));
820 : 0 : return GST_FLOW_OK;
821 : : }
822 : :
823 : : /* found a type */
824 [ # # ]: 0 : if (probability < typefind->min_probability) {
825 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
826 : : "probability is %u which is lower than the required minimum of %u",
827 : : caps, probability, typefind->min_probability);
828 : :
829 : 0 : gst_caps_replace (&caps, NULL);
830 : :
831 [ # # ]: 0 : if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) {
832 : 0 : GST_OBJECT_UNLOCK (typefind);
833 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
[ # # ][ # # ]
834 : 0 : stop_typefinding (typefind);
835 : 0 : return GST_FLOW_ERROR;
836 : : }
837 : :
838 : 0 : GST_OBJECT_UNLOCK (typefind);
839 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
840 : 0 : return GST_FLOW_OK;
841 : : }
842 : 0 : GST_OBJECT_UNLOCK (typefind);
843 : :
844 : : /* probability is good enough too, so let's make it known ... */
845 : 0 : g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
846 : : probability, caps);
847 : :
848 : : /* .. and send out the accumulated data */
849 : 0 : stop_typefinding (typefind);
850 : 0 : gst_caps_unref (caps);
851 : 0 : return GST_FLOW_OK;
852 : : }
853 : :
854 : : static gboolean
855 : 0 : gst_type_find_element_checkgetrange (GstPad * srcpad)
856 : : {
857 : : GstTypeFindElement *typefind;
858 : :
859 : 0 : typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
860 : :
861 : 0 : return gst_pad_check_pull_range (typefind->sink);
862 : : }
863 : :
864 : : static GstFlowReturn
865 : 0 : gst_type_find_element_getrange (GstPad * srcpad,
866 : : guint64 offset, guint length, GstBuffer ** buffer)
867 : : {
868 : : GstTypeFindElement *typefind;
869 : : GstFlowReturn ret;
870 : :
871 : 0 : typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
872 : :
873 : 0 : ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
874 : :
875 [ # # ][ # # ]: 0 : if (ret == GST_FLOW_OK && buffer && *buffer) {
[ # # ]
876 : : /* don't take object lock as typefind->caps should not change anymore */
877 : : /* we assume that pulled buffers are meta-data writable */
878 : 0 : gst_buffer_set_caps (*buffer, typefind->caps);
879 : : }
880 : :
881 : 0 : return ret;
882 : : }
883 : :
884 : : static gboolean
885 : 0 : gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
886 : : {
887 : : GstTypeFindElement *typefind;
888 : :
889 : 0 : typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
890 : :
891 : 0 : return gst_pad_activate_pull (typefind->sink, active);
892 : : }
893 : :
894 : : static gboolean
895 : 7 : gst_type_find_element_activate (GstPad * pad)
896 : : {
897 : 7 : GstTypeFindProbability probability = 0;
898 : 7 : GstCaps *found_caps = NULL;
899 : : GstTypeFindElement *typefind;
900 : :
901 : 7 : typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
902 : :
903 : : /* if we have force caps, use those */
904 : 7 : GST_OBJECT_LOCK (typefind);
905 [ - + ]: 7 : if (typefind->force_caps) {
906 : 0 : found_caps = gst_caps_ref (typefind->force_caps);
907 : 0 : probability = GST_TYPE_FIND_MAXIMUM;
908 : 0 : GST_OBJECT_UNLOCK (typefind);
909 : 0 : goto done;
910 : : }
911 : 7 : GST_OBJECT_UNLOCK (typefind);
912 : :
913 : : /* 1. try to activate in pull mode. if not, switch to push and succeed.
914 : : 2. try to pull type find.
915 : : 3. deactivate pull mode.
916 : : 4. src pad might have been activated push by the state change. deactivate.
917 : : 5. if we didn't find any caps, try getting the uri extension by doing an uri
918 : : query.
919 : : 6. if we didn't find any caps, fail.
920 : : 7. emit have-type; maybe the app connected the source pad to something.
921 : : 8. if the sink pad is activated, we are in pull mode. succeed.
922 : : otherwise activate both pads in push mode and succeed.
923 : : */
924 : :
925 : : /* 1 */
926 [ - + ][ # # ]: 7 : if (!gst_pad_check_pull_range (pad) || !gst_pad_activate_pull (pad, TRUE)) {
927 : 7 : start_typefinding (typefind);
928 : 7 : return gst_pad_activate_push (pad, TRUE);
929 : : }
930 : :
931 [ # # ]: 0 : GST_DEBUG_OBJECT (typefind, "find type in pull mode");
932 : :
933 : : /* 2 */
934 : : {
935 : : GstPad *peer;
936 : :
937 : 0 : peer = gst_pad_get_peer (pad);
938 [ # # ]: 0 : if (peer) {
939 : : gint64 size;
940 : 0 : GstFormat format = GST_FORMAT_BYTES;
941 : : gchar *ext;
942 : :
943 [ # # ]: 0 : if (!gst_pad_query_duration (peer, &format, &size)) {
944 [ # # ]: 0 : GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
945 : 0 : gst_object_unref (peer);
946 : 0 : gst_pad_activate_pull (pad, FALSE);
947 : 0 : return FALSE;
948 : : }
949 : :
950 : : /* the size if 0, we cannot continue */
951 [ # # ]: 0 : if (size == 0) {
952 : : /* keep message in sync with message in sink event handler */
953 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
[ # # ][ # # ]
954 : : (_("Stream contains no data.")), ("Can't typefind empty stream"));
955 : 0 : gst_object_unref (peer);
956 : 0 : gst_pad_activate_pull (pad, FALSE);
957 : 0 : return FALSE;
958 : : }
959 : 0 : ext = gst_type_find_get_extension (typefind, pad);
960 : :
961 : 0 : found_caps = gst_type_find_helper_get_range_ext (GST_OBJECT_CAST (peer),
962 : 0 : (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
963 : : (guint64) size, ext, &probability);
964 : 0 : g_free (ext);
965 : :
966 : 0 : gst_object_unref (peer);
967 : : }
968 : : }
969 : :
970 : : /* the type find helpers might have triggered setcaps here (due to upstream)
971 : : * setting caps on buffers, which emits typefound signal and an element
972 : : * could have been linked and have its pads activated
973 : : *
974 : : * If we deactivate the pads in the following steps we might mess up
975 : : * downstream element. We should prevent that.
976 : : */
977 [ # # ]: 0 : if (typefind->mode == MODE_NORMAL) {
978 : : /* this means we already emitted typefound */
979 [ # # ]: 0 : GST_DEBUG ("Already managed to typefind !");
980 : 0 : goto really_done;
981 : : }
982 : :
983 : : /* 3 */
984 : 0 : gst_pad_activate_pull (pad, FALSE);
985 : :
986 : : /* 4 */
987 : 0 : gst_pad_activate_push (typefind->src, FALSE);
988 : :
989 : : /* 5 */
990 [ # # ][ # # ]: 0 : if (!found_caps || probability < typefind->min_probability) {
991 : 0 : found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability);
992 : : }
993 : :
994 : : /* 6 */
995 [ # # ][ # # ]: 0 : if (!found_caps || probability < typefind->min_probability) {
996 [ # # ][ # # ]: 0 : GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
[ # # ][ # # ]
997 : 0 : gst_caps_replace (&found_caps, NULL);
998 : 0 : return FALSE;
999 : : }
1000 : :
1001 : : done:
1002 : : /* 7 */
1003 : 0 : g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
1004 : : 0, probability, found_caps);
1005 : 0 : typefind->mode = MODE_NORMAL;
1006 : : really_done:
1007 : 0 : gst_caps_unref (found_caps);
1008 : :
1009 : : /* 8 */
1010 [ # # ]: 0 : if (gst_pad_is_active (pad))
1011 : 0 : return TRUE;
1012 : : else {
1013 : : gboolean ret;
1014 : :
1015 : 0 : ret = gst_pad_activate_push (typefind->src, TRUE);
1016 : 0 : ret &= gst_pad_activate_push (pad, TRUE);
1017 : 7 : return ret;
1018 : : }
1019 : : }
1020 : :
1021 : : static GstStateChangeReturn
1022 : 34 : gst_type_find_element_change_state (GstElement * element,
1023 : : GstStateChange transition)
1024 : : {
1025 : : GstStateChangeReturn ret;
1026 : : GstTypeFindElement *typefind;
1027 : :
1028 : 34 : typefind = GST_TYPE_FIND_ELEMENT (element);
1029 : :
1030 : :
1031 : 34 : ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1032 : :
1033 [ + + ]: 34 : switch (transition) {
1034 : : case GST_STATE_CHANGE_PAUSED_TO_READY:
1035 : : case GST_STATE_CHANGE_READY_TO_NULL:
1036 : 11 : GST_OBJECT_LOCK (typefind);
1037 : 11 : gst_caps_replace (&typefind->caps, NULL);
1038 : :
1039 : 11 : g_list_foreach (typefind->cached_events,
1040 : : (GFunc) gst_mini_object_unref, NULL);
1041 : 11 : g_list_free (typefind->cached_events);
1042 : 11 : typefind->cached_events = NULL;
1043 : 11 : typefind->mode = MODE_TYPEFIND;
1044 : 11 : GST_OBJECT_UNLOCK (typefind);
1045 : 11 : break;
1046 : : default:
1047 : 23 : break;
1048 : : }
1049 : :
1050 : 34 : return ret;
1051 : : }
|