Branch data Line data Source code
1 : : /* GStreamer
2 : : * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 : : * Copyright (C) 2000,2005 Wim Taymans <wim@fluendo.com>
4 : : * Copyright (C) 2006 Tim-Philipp Müller <tim centricular net>
5 : : *
6 : : * gsttypefindhelper.c:
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Library General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Library General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Library General Public
19 : : * License along with this library; if not, write to the
20 : : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 : : * Boston, MA 02111-1307, USA.
22 : : */
23 : :
24 : : /**
25 : : * SECTION:gsttypefindhelper
26 : : * @short_description: Utility functions for typefinding
27 : : *
28 : : * Utility functions for elements doing typefinding:
29 : : * gst_type_find_helper() does typefinding in pull mode, while
30 : : * gst_type_find_helper_for_buffer() is useful for elements needing to do
31 : : * typefinding in push mode from a chain function.
32 : : */
33 : :
34 : : #ifdef HAVE_CONFIG_H
35 : : # include "config.h"
36 : : #endif
37 : :
38 : : #include <stdlib.h>
39 : : #include <string.h>
40 : :
41 : : #include "gsttypefindhelper.h"
42 : :
43 : : /* ********************** typefinding in pull mode ************************ */
44 : :
45 : : static void
46 : : helper_find_suggest (gpointer data, guint probability, const GstCaps * caps);
47 : :
48 : : typedef struct
49 : : {
50 : : GSList *buffers; /* buffer cache */
51 : : guint64 size;
52 : : guint64 last_offset;
53 : : GstTypeFindHelperGetRangeFunction func;
54 : : guint best_probability;
55 : : GstCaps *caps;
56 : : GstTypeFindFactory *factory; /* for logging */
57 : : GstObject *obj; /* for logging */
58 : : } GstTypeFindHelper;
59 : :
60 : : /*
61 : : * helper_find_peek:
62 : : * @data: helper data struct
63 : : * @off: stream offset
64 : : * @size: block size
65 : : *
66 : : * Get data pointer within a stream. Keeps a cache of read buffers (partly
67 : : * for performance reasons, but mostly because pointers returned by us need
68 : : * to stay valid until typefinding has finished)
69 : : *
70 : : * Returns: address of the data or %NULL if buffer does not cover the
71 : : * requested range.
72 : : */
73 : : static guint8 *
74 : 0 : helper_find_peek (gpointer data, gint64 offset, guint size)
75 : : {
76 : : GstTypeFindHelper *helper;
77 : : GstBuffer *buffer;
78 : : GstFlowReturn ret;
79 : 0 : GSList *insert_pos = NULL;
80 : : guint buf_size;
81 : : guint64 buf_offset;
82 : : GstCaps *caps;
83 : :
84 : 0 : helper = (GstTypeFindHelper *) data;
85 : :
86 [ # # ]: 0 : GST_LOG_OBJECT (helper->obj, "'%s' called peek (%" G_GINT64_FORMAT
87 : : ", %u)", GST_PLUGIN_FEATURE_NAME (helper->factory), offset, size);
88 : :
89 [ # # ]: 0 : if (size == 0)
90 : 0 : return NULL;
91 : :
92 [ # # ]: 0 : if (offset < 0) {
93 [ # # ][ # # ]: 0 : if (helper->size == -1 || helper->size < -offset)
94 : 0 : return NULL;
95 : :
96 : 0 : offset += helper->size;
97 : : }
98 : :
99 : : /* see if we have a matching buffer already in our list */
100 [ # # ][ # # ]: 0 : if (size > 0 && offset <= helper->last_offset) {
101 : : GSList *walk;
102 : :
103 [ # # ]: 0 : for (walk = helper->buffers; walk; walk = walk->next) {
104 : 0 : GstBuffer *buf = GST_BUFFER_CAST (walk->data);
105 : 0 : guint64 buf_offset = GST_BUFFER_OFFSET (buf);
106 : 0 : guint buf_size = GST_BUFFER_SIZE (buf);
107 : :
108 : : /* buffers are kept sorted by end offset (highest first) in the list, so
109 : : * at this point we save the current position and stop searching if
110 : : * we're after the searched end offset */
111 [ # # ]: 0 : if (buf_offset <= offset) {
112 [ # # ]: 0 : if ((offset + size) < (buf_offset + buf_size)) {
113 : 0 : return GST_BUFFER_DATA (buf) + (offset - buf_offset);
114 : : }
115 [ # # ]: 0 : } else if (offset + size >= buf_offset + buf_size) {
116 : 0 : insert_pos = walk;
117 : 0 : break;
118 : : }
119 : : }
120 : : }
121 : :
122 : 0 : buffer = NULL;
123 : : /* some typefinders go in 1 byte steps over 1k of data and request
124 : : * small buffers. It is really inefficient to pull each time, and pulling
125 : : * a larger chunk is almost free. Trying to pull a larger chunk at the end
126 : : * of the file is also not a problem here, we'll just get a truncated buffer
127 : : * in that case (and we'll have to double-check the size we actually get
128 : : * anyway, see below) */
129 : 0 : ret = helper->func (helper->obj, offset, MAX (size, 4096), &buffer);
130 : :
131 [ # # ]: 0 : if (ret != GST_FLOW_OK)
132 : 0 : goto error;
133 : :
134 : 0 : caps = GST_BUFFER_CAPS (buffer);
135 : :
136 [ # # ][ # # ]: 0 : if (caps && !gst_caps_is_empty (caps) && !gst_caps_is_any (caps)) {
[ # # ]
137 [ # # ]: 0 : GST_DEBUG ("buffer has caps %" GST_PTR_FORMAT ", suggest max probability",
138 : : caps);
139 : :
140 : 0 : gst_caps_replace (&helper->caps, caps);
141 : 0 : helper->best_probability = GST_TYPE_FIND_MAXIMUM;
142 : :
143 : 0 : gst_buffer_unref (buffer);
144 : 0 : return NULL;
145 : : }
146 : :
147 : : /* getrange might silently return shortened buffers at the end of a file,
148 : : * we must, however, always return either the full requested data or NULL */
149 : 0 : buf_offset = GST_BUFFER_OFFSET (buffer);
150 : 0 : buf_size = GST_BUFFER_SIZE (buffer);
151 : :
152 [ # # ][ # # ]: 0 : if ((buf_offset != -1 && buf_offset != offset) || buf_size < size) {
[ # # ]
153 [ # # ]: 0 : GST_DEBUG ("droping short buffer: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT
154 : : " instead of %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT,
155 : : buf_offset, buf_offset + buf_size - 1, offset, offset + size - 1);
156 : 0 : gst_buffer_unref (buffer);
157 : 0 : return NULL;
158 : : }
159 : :
160 [ # # ]: 0 : if (insert_pos) {
161 : 0 : helper->buffers =
162 : 0 : g_slist_insert_before (helper->buffers, insert_pos, buffer);
163 : : } else {
164 : : /* if insert_pos is not set, our offset is bigger than the largest offset
165 : : * we have so far; since we keep the list sorted with highest offsets
166 : : * first, we need to prepend the buffer to the list */
167 : 0 : helper->last_offset = GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer);
168 : 0 : helper->buffers = g_slist_prepend (helper->buffers, buffer);
169 : : }
170 : 0 : return GST_BUFFER_DATA (buffer);
171 : :
172 : : error:
173 : : {
174 [ # # ]: 0 : GST_INFO ("typefind function returned: %s", gst_flow_get_name (ret));
175 : 0 : return NULL;
176 : : }
177 : : }
178 : :
179 : : /*
180 : : * helper_find_suggest:
181 : : * @data: helper data struct
182 : : * @probability: probability of the match
183 : : * @caps: caps of the type
184 : : *
185 : : * If given @probability is higher, replace previously store caps.
186 : : */
187 : : static void
188 : 0 : helper_find_suggest (gpointer data, guint probability, const GstCaps * caps)
189 : : {
190 : 0 : GstTypeFindHelper *helper = (GstTypeFindHelper *) data;
191 : :
192 [ # # ]: 0 : GST_LOG_OBJECT (helper->obj,
193 : : "'%s' called called suggest (%u, %" GST_PTR_FORMAT ")",
194 : : GST_PLUGIN_FEATURE_NAME (helper->factory), probability, caps);
195 : :
196 [ # # ]: 0 : if (probability > helper->best_probability) {
197 : 0 : GstCaps *copy = gst_caps_copy (caps);
198 : :
199 : 0 : gst_caps_replace (&helper->caps, copy);
200 : 0 : gst_caps_unref (copy);
201 : 0 : helper->best_probability = probability;
202 : : }
203 : 0 : }
204 : :
205 : : static guint64
206 : 0 : helper_find_get_length (gpointer data)
207 : : {
208 : 0 : GstTypeFindHelper *helper = (GstTypeFindHelper *) data;
209 : :
210 [ # # ]: 0 : GST_LOG_OBJECT (helper->obj, "'%s' called called get_length, returning %"
211 : : G_GUINT64_FORMAT, GST_PLUGIN_FEATURE_NAME (helper->factory),
212 : : helper->size);
213 : :
214 : 0 : return helper->size;
215 : : }
216 : :
217 : : /**
218 : : * gst_type_find_helper_get_range_ext:
219 : : * @obj: A #GstObject that will be passed as first argument to @func
220 : : * @func: (scope call): A generic #GstTypeFindHelperGetRangeFunction that will
221 : : * be used to access data at random offsets when doing the typefinding
222 : : * @size: The length in bytes
223 : : * @extension: extension of the media
224 : : * @prob: (out) (allow-none): location to store the probability of the found
225 : : * caps, or #NULL
226 : : *
227 : : * Utility function to do pull-based typefinding. Unlike gst_type_find_helper()
228 : : * however, this function will use the specified function @func to obtain the
229 : : * data needed by the typefind functions, rather than operating on a given
230 : : * source pad. This is useful mostly for elements like tag demuxers which
231 : : * strip off data at the beginning and/or end of a file and want to typefind
232 : : * the stripped data stream before adding their own source pad (the specified
233 : : * callback can then call the upstream peer pad with offsets adjusted for the
234 : : * tag size, for example).
235 : : *
236 : : * When @extension is not NULL, this function will first try the typefind
237 : : * functions for the given extension, which might speed up the typefinding
238 : : * in many cases.
239 : : *
240 : : * Free-function: gst_caps_unref
241 : : *
242 : : * Returns: (transfer full): the #GstCaps corresponding to the data stream.
243 : : * Returns #NULL if no #GstCaps matches the data stream.
244 : : *
245 : : * Since: 0.10.26
246 : : */
247 : : GstCaps *
248 : 0 : gst_type_find_helper_get_range_ext (GstObject * obj,
249 : : GstTypeFindHelperGetRangeFunction func, guint64 size,
250 : : const gchar * extension, GstTypeFindProbability * prob)
251 : : {
252 : : GstTypeFindHelper helper;
253 : : GstTypeFind find;
254 : : GSList *walk;
255 : : GList *l, *type_list;
256 : 0 : GstCaps *result = NULL;
257 : 0 : gint pos = 0;
258 : :
259 [ # # ][ # # ]: 0 : g_return_val_if_fail (GST_IS_OBJECT (obj), NULL);
[ # # ][ # # ]
260 [ # # ]: 0 : g_return_val_if_fail (func != NULL, NULL);
261 : :
262 : 0 : helper.buffers = NULL;
263 : 0 : helper.size = size;
264 : 0 : helper.last_offset = 0;
265 : 0 : helper.func = func;
266 : 0 : helper.best_probability = 0;
267 : 0 : helper.caps = NULL;
268 : 0 : helper.obj = obj;
269 : :
270 : 0 : find.data = &helper;
271 : 0 : find.peek = helper_find_peek;
272 : 0 : find.suggest = helper_find_suggest;
273 : :
274 [ # # ][ # # ]: 0 : if (size == 0 || size == (guint64) - 1) {
275 : 0 : find.get_length = NULL;
276 : : } else {
277 : 0 : find.get_length = helper_find_get_length;
278 : : }
279 : :
280 : 0 : type_list = gst_type_find_factory_get_list ();
281 : :
282 : : /* move the typefinders for the extension first in the list. The idea is that
283 : : * when one of them returns MAX we don't need to search further as there is a
284 : : * very high chance we got the right type. */
285 [ # # ]: 0 : if (extension) {
286 : : GList *next;
287 : :
288 [ # # ]: 0 : GST_LOG_OBJECT (obj, "sorting typefind for extension %s to head",
289 : : extension);
290 : :
291 [ # # ]: 0 : for (l = type_list; l; l = next) {
292 : : GstTypeFindFactory *factory;
293 : : gint i;
294 : : gchar **ext;
295 : :
296 : 0 : next = l->next;
297 : :
298 : 0 : factory = GST_TYPE_FIND_FACTORY (l->data);
299 : :
300 : 0 : ext = gst_type_find_factory_get_extensions (factory);
301 [ # # ]: 0 : if (ext == NULL)
302 : 0 : continue;
303 : :
304 [ # # ]: 0 : GST_LOG_OBJECT (obj, "testing factory %s for extension %s",
305 : : GST_PLUGIN_FEATURE_NAME (factory), extension);
306 : :
307 [ # # ]: 0 : for (i = 0; ext[i]; i++) {
308 [ # # ]: 0 : if (strcmp (ext[i], extension) == 0) {
309 : : /* found extension, move in front */
310 [ # # ]: 0 : GST_LOG_OBJECT (obj, "moving typefind for extension %s to head",
311 : : extension);
312 : : /* remove entry from list */
313 : 0 : type_list = g_list_delete_link (type_list, l);
314 : : /* insert at the position */
315 : 0 : type_list = g_list_insert (type_list, factory, pos);
316 : : /* next element will be inserted after this one */
317 : 0 : pos++;
318 : 0 : break;
319 : : }
320 : : }
321 : : }
322 : : }
323 : :
324 [ # # ]: 0 : for (l = type_list; l; l = l->next) {
325 : 0 : helper.factory = GST_TYPE_FIND_FACTORY (l->data);
326 : 0 : gst_type_find_factory_call_function (helper.factory, &find);
327 [ # # ]: 0 : if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM)
328 : 0 : break;
329 : : }
330 : 0 : gst_plugin_feature_list_free (type_list);
331 : :
332 [ # # ]: 0 : for (walk = helper.buffers; walk; walk = walk->next)
333 : 0 : gst_buffer_unref (GST_BUFFER_CAST (walk->data));
334 : 0 : g_slist_free (helper.buffers);
335 : :
336 [ # # ]: 0 : if (helper.best_probability > 0)
337 : 0 : result = helper.caps;
338 : :
339 [ # # ]: 0 : if (prob)
340 : 0 : *prob = helper.best_probability;
341 : :
342 [ # # ]: 0 : GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)",
343 : : result, (guint) helper.best_probability);
344 : :
345 : 0 : return result;
346 : : }
347 : :
348 : : /**
349 : : * gst_type_find_helper_get_range:
350 : : * @obj: A #GstObject that will be passed as first argument to @func
351 : : * @func: (scope call): A generic #GstTypeFindHelperGetRangeFunction that will
352 : : * be used to access data at random offsets when doing the typefinding
353 : : * @size: The length in bytes
354 : : * @prob: (out) (allow-none): location to store the probability of the found
355 : : * caps, or #NULL
356 : : *
357 : : * Utility function to do pull-based typefinding. Unlike gst_type_find_helper()
358 : : * however, this function will use the specified function @func to obtain the
359 : : * data needed by the typefind functions, rather than operating on a given
360 : : * source pad. This is useful mostly for elements like tag demuxers which
361 : : * strip off data at the beginning and/or end of a file and want to typefind
362 : : * the stripped data stream before adding their own source pad (the specified
363 : : * callback can then call the upstream peer pad with offsets adjusted for the
364 : : * tag size, for example).
365 : : *
366 : : * Free-function: gst_caps_unref
367 : : *
368 : : * Returns: (transfer full): the #GstCaps corresponding to the data stream.
369 : : * Returns #NULL if no #GstCaps matches the data stream.
370 : : */
371 : : GstCaps *
372 : 0 : gst_type_find_helper_get_range (GstObject * obj,
373 : : GstTypeFindHelperGetRangeFunction func, guint64 size,
374 : : GstTypeFindProbability * prob)
375 : : {
376 : 0 : return gst_type_find_helper_get_range_ext (obj, func, size, NULL, prob);
377 : : }
378 : :
379 : : /**
380 : : * gst_type_find_helper:
381 : : * @src: A source #GstPad
382 : : * @size: The length in bytes
383 : : *
384 : : * Tries to find what type of data is flowing from the given source #GstPad.
385 : : *
386 : : * Free-function: gst_caps_unref
387 : : *
388 : : * Returns: (transfer full): the #GstCaps corresponding to the data stream.
389 : : * Returns #NULL if no #GstCaps matches the data stream.
390 : : */
391 : :
392 : : GstCaps *
393 : 0 : gst_type_find_helper (GstPad * src, guint64 size)
394 : : {
395 : : GstTypeFindHelperGetRangeFunction func;
396 : :
397 [ # # ][ # # ]: 0 : g_return_val_if_fail (GST_IS_OBJECT (src), NULL);
[ # # ][ # # ]
398 [ # # ]: 0 : g_return_val_if_fail (GST_PAD_GETRANGEFUNC (src) != NULL, NULL);
399 : :
400 : 0 : func = (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (src));
401 : :
402 : 0 : return gst_type_find_helper_get_range (GST_OBJECT (src), func, size, NULL);
403 : : }
404 : :
405 : : /* ********************** typefinding for buffers ************************* */
406 : :
407 : : typedef struct
408 : : {
409 : : guint8 *data; /* buffer data */
410 : : guint size;
411 : : guint best_probability;
412 : : GstCaps *caps;
413 : : GstTypeFindFactory *factory; /* for logging */
414 : : GstObject *obj; /* for logging */
415 : : } GstTypeFindBufHelper;
416 : :
417 : : /*
418 : : * buf_helper_find_peek:
419 : : * @data: helper data struct
420 : : * @off: stream offset
421 : : * @size: block size
422 : : *
423 : : * Get data pointer within a buffer.
424 : : *
425 : : * Returns: address inside the buffer or %NULL if buffer does not cover the
426 : : * requested range.
427 : : */
428 : : static guint8 *
429 : 11 : buf_helper_find_peek (gpointer data, gint64 off, guint size)
430 : : {
431 : : GstTypeFindBufHelper *helper;
432 : :
433 : 11 : helper = (GstTypeFindBufHelper *) data;
434 [ - + ]: 11 : GST_LOG_OBJECT (helper->obj, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
435 : : GST_PLUGIN_FEATURE_NAME (helper->factory), off, size);
436 : :
437 [ + + ]: 11 : if (size == 0)
438 : 1 : return NULL;
439 : :
440 [ + + ]: 10 : if (off < 0) {
441 [ - + ]: 2 : GST_LOG_OBJECT (helper->obj, "'%s' wanted to peek at end; not supported",
442 : : GST_PLUGIN_FEATURE_NAME (helper->factory));
443 : 2 : return NULL;
444 : : }
445 : :
446 [ + + ]: 8 : if ((off + size) <= helper->size)
447 : 5 : return helper->data + off;
448 : :
449 : 11 : return NULL;
450 : : }
451 : :
452 : : /*
453 : : * buf_helper_find_suggest:
454 : : * @data: helper data struct
455 : : * @probability: probability of the match
456 : : * @caps: caps of the type
457 : : *
458 : : * If given @probability is higher, replace previously store caps.
459 : : */
460 : : static void
461 : 1 : buf_helper_find_suggest (gpointer data, guint probability, const GstCaps * caps)
462 : : {
463 : 1 : GstTypeFindBufHelper *helper = (GstTypeFindBufHelper *) data;
464 : :
465 [ - + ]: 1 : GST_LOG_OBJECT (helper->obj,
466 : : "'%s' called called suggest (%u, %" GST_PTR_FORMAT ")",
467 : : GST_PLUGIN_FEATURE_NAME (helper->factory), probability, caps);
468 : :
469 : : /* Note: not >= as we call typefinders in order of rank, highest first */
470 [ + - ]: 1 : if (probability > helper->best_probability) {
471 : 1 : GstCaps *copy = gst_caps_copy (caps);
472 : :
473 : 1 : gst_caps_replace (&helper->caps, copy);
474 : 1 : gst_caps_unref (copy);
475 : 1 : helper->best_probability = probability;
476 : : }
477 : 1 : }
478 : :
479 : : /**
480 : : * gst_type_find_helper_for_buffer:
481 : : * @obj: object doing the typefinding, or NULL (used for logging)
482 : : * @buf: (in) (transfer none): a #GstBuffer with data to typefind
483 : : * @prob: (out) (allow-none): location to store the probability of the found
484 : : * caps, or #NULL
485 : : *
486 : : * Tries to find what type of data is contained in the given #GstBuffer, the
487 : : * assumption being that the buffer represents the beginning of the stream or
488 : : * file.
489 : : *
490 : : * All available typefinders will be called on the data in order of rank. If
491 : : * a typefinding function returns a probability of #GST_TYPE_FIND_MAXIMUM,
492 : : * typefinding is stopped immediately and the found caps will be returned
493 : : * right away. Otherwise, all available typefind functions will the tried,
494 : : * and the caps with the highest probability will be returned, or #NULL if
495 : : * the content of the buffer could not be identified.
496 : : *
497 : : * Free-function: gst_caps_unref
498 : : *
499 : : * Returns: (transfer full): the #GstCaps corresponding to the data, or #NULL
500 : : * if no type could be found. The caller should free the caps returned
501 : : * with gst_caps_unref().
502 : : */
503 : : GstCaps *
504 : 1 : gst_type_find_helper_for_buffer (GstObject * obj, GstBuffer * buf,
505 : : GstTypeFindProbability * prob)
506 : : {
507 : : GstTypeFindBufHelper helper;
508 : : GstTypeFind find;
509 : : GList *l, *type_list;
510 : 1 : GstCaps *result = NULL;
511 : :
512 [ - + ]: 1 : g_return_val_if_fail (buf != NULL, NULL);
513 [ - + ][ + - ]: 1 : g_return_val_if_fail (GST_IS_BUFFER (buf), NULL);
[ + - ][ - + ]
514 [ + - ][ - + ]: 1 : g_return_val_if_fail (GST_BUFFER_OFFSET (buf) == 0 ||
515 : : GST_BUFFER_OFFSET (buf) == GST_BUFFER_OFFSET_NONE, NULL);
516 : :
517 : 1 : helper.data = GST_BUFFER_DATA (buf);
518 : 1 : helper.size = GST_BUFFER_SIZE (buf);
519 : 1 : helper.best_probability = 0;
520 : 1 : helper.caps = NULL;
521 : 1 : helper.obj = obj;
522 : :
523 [ + - ][ - + ]: 1 : if (helper.data == NULL || helper.size == 0)
524 : 0 : return NULL;
525 : :
526 : 1 : find.data = &helper;
527 : 1 : find.peek = buf_helper_find_peek;
528 : 1 : find.suggest = buf_helper_find_suggest;
529 : 1 : find.get_length = NULL;
530 : :
531 : 1 : type_list = gst_type_find_factory_get_list ();
532 : :
533 [ + - ]: 1 : for (l = type_list; l; l = l->next) {
534 : 1 : helper.factory = GST_TYPE_FIND_FACTORY (l->data);
535 : 1 : gst_type_find_factory_call_function (helper.factory, &find);
536 [ + - ]: 1 : if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM)
537 : 1 : break;
538 : : }
539 : 1 : gst_plugin_feature_list_free (type_list);
540 : :
541 [ + - ]: 1 : if (helper.best_probability > 0)
542 : 1 : result = helper.caps;
543 : :
544 [ - + ]: 1 : if (prob)
545 : 0 : *prob = helper.best_probability;
546 : :
547 [ - + ]: 1 : GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)",
548 : : result, (guint) helper.best_probability);
549 : :
550 : 1 : return result;
551 : : }
552 : :
553 : : /**
554 : : * gst_type_find_helper_for_extension:
555 : : * @obj: (allow-none): object doing the typefinding, or NULL (used for logging)
556 : : * @extension: an extension
557 : : *
558 : : * Tries to find the best #GstCaps associated with @extension.
559 : : *
560 : : * All available typefinders will be checked against the extension in order
561 : : * of rank. The caps of the first typefinder that can handle @extension will be
562 : : * returned.
563 : : *
564 : : * Free-function: gst_caps_unref
565 : : *
566 : : * Returns: (transfer full): the #GstCaps corresponding to @extension, or
567 : : * #NULL if no type could be found. The caller should free the caps
568 : : * returned with gst_caps_unref().
569 : : *
570 : : * Since: 0.10.23
571 : : */
572 : : GstCaps *
573 : 0 : gst_type_find_helper_for_extension (GstObject * obj, const gchar * extension)
574 : : {
575 : : GList *l, *type_list;
576 : 0 : GstCaps *result = NULL;
577 : :
578 [ # # ]: 0 : g_return_val_if_fail (extension != NULL, NULL);
579 : :
580 [ # # ]: 0 : GST_LOG_OBJECT (obj, "finding caps for extension %s", extension);
581 : :
582 : 0 : type_list = gst_type_find_factory_get_list ();
583 : :
584 [ # # ][ # # ]: 0 : for (l = type_list; l; l = g_list_next (l)) {
585 : : GstTypeFindFactory *factory;
586 : : gchar **ext;
587 : : gint i;
588 : :
589 : 0 : factory = GST_TYPE_FIND_FACTORY (l->data);
590 : :
591 : : /* we only want to check those factories without a function */
592 [ # # ]: 0 : if (factory->function != NULL)
593 : 0 : continue;
594 : :
595 : : /* get the extension that this typefind factory can handle */
596 : 0 : ext = gst_type_find_factory_get_extensions (factory);
597 [ # # ]: 0 : if (ext == NULL)
598 : 0 : continue;
599 : :
600 : : /* there are extension, see if one of them matches the requested
601 : : * extension */
602 [ # # ]: 0 : for (i = 0; ext[i]; i++) {
603 [ # # ]: 0 : if (strcmp (ext[i], extension) == 0) {
604 : : /* we found a matching extension, take the caps */
605 [ # # ]: 0 : if ((result = gst_type_find_factory_get_caps (factory))) {
606 : 0 : gst_caps_ref (result);
607 : 0 : goto done;
608 : : }
609 : : }
610 : : }
611 : : }
612 : : done:
613 : 0 : gst_plugin_feature_list_free (type_list);
614 : :
615 [ # # ]: 0 : GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT, result);
616 : :
617 : 0 : return result;
618 : : }
|