51 return strcmp (GST_PLUGIN_FEATURE_NAME (fac1), |
51 return strcmp (GST_PLUGIN_FEATURE_NAME (fac1), |
52 GST_PLUGIN_FEATURE_NAME (fac2)); |
52 GST_PLUGIN_FEATURE_NAME (fac2)); |
53 } |
53 } |
54 |
54 |
55 /* ********************** typefinding in pull mode ************************ */ |
55 /* ********************** typefinding in pull mode ************************ */ |
56 |
|
57 static void |
|
58 helper_find_suggest (gpointer data, guint probability, const GstCaps * caps); |
|
59 |
56 |
60 typedef struct |
57 typedef struct |
61 { |
58 { |
62 GSList *buffers; /* buffer cache */ |
59 GSList *buffers; /* buffer cache */ |
63 guint64 size; |
60 guint64 size; |
87 { |
84 { |
88 GstTypeFindHelper *helper; |
85 GstTypeFindHelper *helper; |
89 GstBuffer *buffer; |
86 GstBuffer *buffer; |
90 GstFlowReturn ret; |
87 GstFlowReturn ret; |
91 GSList *insert_pos = NULL; |
88 GSList *insert_pos = NULL; |
92 guint buf_size; |
|
93 guint64 buf_offset; |
|
94 GstCaps *caps; |
|
95 |
89 |
96 helper = (GstTypeFindHelper *) data; |
90 helper = (GstTypeFindHelper *) data; |
97 |
91 |
98 GST_LOG_OBJECT (helper->obj, "'%s' called peek (%" G_GINT64_FORMAT |
92 GST_LOG_OBJECT (helper->obj, "'%s' called peek (%" G_GINT64_FORMAT |
99 ", %u)", GST_PLUGIN_FEATURE_NAME (helper->factory), offset, size); |
93 ", %u)", GST_PLUGIN_FEATURE_NAME (helper->factory), offset, size); |
115 for (walk = helper->buffers; walk; walk = walk->next) { |
109 for (walk = helper->buffers; walk; walk = walk->next) { |
116 GstBuffer *buf = GST_BUFFER_CAST (walk->data); |
110 GstBuffer *buf = GST_BUFFER_CAST (walk->data); |
117 guint64 buf_offset = GST_BUFFER_OFFSET (buf); |
111 guint64 buf_offset = GST_BUFFER_OFFSET (buf); |
118 guint buf_size = GST_BUFFER_SIZE (buf); |
112 guint buf_size = GST_BUFFER_SIZE (buf); |
119 |
113 |
120 /* buffers are kept sorted by end offset (highest first) in the list, so |
|
121 * at this point we save the current position and stop searching if |
|
122 * we're after the searched end offset */ |
|
123 if (buf_offset <= offset) { |
114 if (buf_offset <= offset) { |
124 if ((offset + size) < (buf_offset + buf_size)) { |
115 if ((offset + size) < (buf_offset + buf_size)) { |
125 return GST_BUFFER_DATA (buf) + (offset - buf_offset); |
116 return GST_BUFFER_DATA (buf) + (offset - buf_offset); |
126 } |
117 } |
127 } else if (offset + size >= buf_offset + buf_size) { |
118 /* buffers are kept sorted by offset (highest first) in the list, so |
|
119 * at this point we know we don't need to check the remaining buffers |
|
120 * (is that correct or just a guess that we're unlikely to find a |
|
121 * match further down and it's most of the time not worth going through |
|
122 * the entire list? How do we know the next buffer isn't offset-N with |
|
123 * a big enough size to cover the requested offset+size?) */ |
128 insert_pos = walk; |
124 insert_pos = walk; |
129 break; |
125 break; |
130 } |
126 } |
131 } |
127 } |
132 } |
128 } |
136 * small buffers. It is really inefficient to pull each time, and pulling |
132 * small buffers. It is really inefficient to pull each time, and pulling |
137 * a larger chunk is almost free. Trying to pull a larger chunk at the end |
133 * a larger chunk is almost free. Trying to pull a larger chunk at the end |
138 * of the file is also not a problem here, we'll just get a truncated buffer |
134 * of the file is also not a problem here, we'll just get a truncated buffer |
139 * in that case (and we'll have to double-check the size we actually get |
135 * in that case (and we'll have to double-check the size we actually get |
140 * anyway, see below) */ |
136 * anyway, see below) */ |
141 ret = helper->func (helper->obj, offset, MAX (size, 4096), &buffer); |
137 ret = helper->func (helper->obj, offset, MAX (size, 512), &buffer); |
142 |
138 |
143 if (ret != GST_FLOW_OK) |
139 if (ret != GST_FLOW_OK) |
144 goto error; |
140 goto error; |
145 |
141 |
146 caps = GST_BUFFER_CAPS (buffer); |
|
147 |
|
148 if (caps && !gst_caps_is_empty (caps) && !gst_caps_is_any (caps)) { |
|
149 GST_DEBUG ("buffer has caps %" GST_PTR_FORMAT ", suggest max probability", |
|
150 caps); |
|
151 |
|
152 gst_caps_replace (&helper->caps, caps); |
|
153 helper->best_probability = GST_TYPE_FIND_MAXIMUM; |
|
154 |
|
155 gst_buffer_unref (buffer); |
|
156 return NULL; |
|
157 } |
|
158 |
|
159 /* getrange might silently return shortened buffers at the end of a file, |
142 /* 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 */ |
143 * we must, however, always return either the full requested data or NULL */ |
161 buf_offset = GST_BUFFER_OFFSET (buffer); |
144 if (GST_BUFFER_OFFSET (buffer) != offset || GST_BUFFER_SIZE (buffer) < size) { |
162 buf_size = GST_BUFFER_SIZE (buffer); |
|
163 |
|
164 if ((buf_offset != -1 && buf_offset != offset) || buf_size < size) { |
|
165 GST_DEBUG ("droping short buffer: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT |
145 GST_DEBUG ("droping short buffer: %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT |
166 " instead of %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, |
146 " instead of %" G_GUINT64_FORMAT "-%" G_GUINT64_FORMAT, |
167 buf_offset, buf_offset + buf_size - 1, offset, offset + size - 1); |
147 GST_BUFFER_OFFSET (buffer), GST_BUFFER_OFFSET (buffer) + |
|
148 GST_BUFFER_SIZE (buffer) - 1, offset, offset + size - 1); |
168 gst_buffer_unref (buffer); |
149 gst_buffer_unref (buffer); |
169 return NULL; |
150 return NULL; |
170 } |
151 } |
171 |
152 |
172 if (insert_pos) { |
153 if (insert_pos) { |
174 g_slist_insert_before (helper->buffers, insert_pos, buffer); |
155 g_slist_insert_before (helper->buffers, insert_pos, buffer); |
175 } else { |
156 } else { |
176 /* if insert_pos is not set, our offset is bigger than the largest offset |
157 /* 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 |
158 * we have so far; since we keep the list sorted with highest offsets |
178 * first, we need to prepend the buffer to the list */ |
159 * first, we need to prepend the buffer to the list */ |
179 helper->last_offset = GST_BUFFER_OFFSET (buffer) + GST_BUFFER_SIZE (buffer); |
160 /* FIXME: why not last_offset = buffer_offset + buffer_size here? */ |
|
161 helper->last_offset = GST_BUFFER_OFFSET (buffer); |
180 helper->buffers = g_slist_prepend (helper->buffers, buffer); |
162 helper->buffers = g_slist_prepend (helper->buffers, buffer); |
181 } |
163 } |
182 return GST_BUFFER_DATA (buffer); |
164 return GST_BUFFER_DATA (buffer); |
183 |
165 |
184 error: |
166 error: |
486 GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)", |
468 GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)", |
487 result, (guint) helper.best_probability); |
469 result, (guint) helper.best_probability); |
488 |
470 |
489 return result; |
471 return result; |
490 } |
472 } |
491 |
|
492 /** |
|
493 * gst_type_find_helper_for_extension: |
|
494 * @obj: object doing the typefinding, or NULL (used for logging) |
|
495 * @extension: an extension |
|
496 * |
|
497 * Tries to find the best #GstCaps associated with @extension. |
|
498 * |
|
499 * All available typefinders will be checked against the extension in order |
|
500 * of rank. The caps of the first typefinder that can handle @extension will be |
|
501 * returned. |
|
502 * |
|
503 * Returns: The #GstCaps corresponding to @extension, or #NULL if no type could |
|
504 * be found. The caller should free the caps returned with gst_caps_unref(). |
|
505 * |
|
506 * Since: 0.10.23 |
|
507 */ |
|
508 #ifdef __SYMBIAN32__ |
|
509 EXPORT_C |
|
510 #endif |
|
511 |
|
512 GstCaps * |
|
513 gst_type_find_helper_for_extension (GstObject * obj, const gchar * extension) |
|
514 { |
|
515 GList *l, *type_list; |
|
516 GstCaps *result = NULL; |
|
517 |
|
518 g_return_val_if_fail (extension != NULL, NULL); |
|
519 |
|
520 GST_LOG_OBJECT (obj, "finding caps for extension %s", extension); |
|
521 |
|
522 type_list = gst_type_find_factory_get_list (); |
|
523 type_list = g_list_sort (type_list, type_find_factory_rank_cmp); |
|
524 |
|
525 for (l = type_list; l; l = g_list_next (l)) { |
|
526 GstTypeFindFactory *factory; |
|
527 gchar **ext; |
|
528 gint i; |
|
529 |
|
530 factory = GST_TYPE_FIND_FACTORY (l->data); |
|
531 |
|
532 /* get the extension that this typefind factory can handle */ |
|
533 ext = gst_type_find_factory_get_extensions (factory); |
|
534 if (ext == NULL) |
|
535 continue; |
|
536 |
|
537 /* we only want to check those factories without a function */ |
|
538 if (factory->function != NULL) |
|
539 continue; |
|
540 |
|
541 /* there are extension, see if one of them matches the requested |
|
542 * extension */ |
|
543 for (i = 0; ext[i]; i++) { |
|
544 if (strcmp (ext[i], extension) == 0) { |
|
545 /* we found a matching extension, take the caps */ |
|
546 if ((result = gst_type_find_factory_get_caps (factory))) { |
|
547 gst_caps_ref (result); |
|
548 goto done; |
|
549 } |
|
550 } |
|
551 } |
|
552 } |
|
553 done: |
|
554 gst_plugin_feature_list_free (type_list); |
|
555 |
|
556 GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT, result); |
|
557 |
|
558 return result; |
|
559 } |
|