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