插件库:libgsttypefindfunctions.so
源码位置:gsttypefindfunctionsplugin.c/gsttypefindfunctions.c/gsttypefindfunctionsriff.c/gsttypefindfunctionsstartwith.c
(开源typefind主要在libgsttypefindfunctions.so以及libgstlibav.so)
typefind插件注册:
static gboolean
plugin_init (GstPlugin * plugin)
{
/* can't initialize this via a struct as caps can't be statically initialized */
GST_DEBUG_CATEGORY_INIT (type_find_functions_debug, "typefindfunctions",
GST_DEBUG_FG_GREEN | GST_DEBUG_BG_RED, "generic type find functions");
/* note: asx/wax/wmx are XML files, asf doesn't handle them */
/* must use strings, macros don't accept initializers */
/*Riff Type find register */
GST_TYPE_FIND_REGISTER (avi, plugin);
GST_TYPE_FIND_REGISTER (qcp, plugin);
GST_TYPE_FIND_REGISTER (cdxa, plugin);
GST_TYPE_FIND_REGISTER (riff_mid, plugin);
{省略}
GST_TYPE_FIND_REGISTER (aa, plugin);
GST_TYPE_FIND_REGISTER (tap, plugin);
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
typefindfunctions,
"default typefind functions",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
typefind函数实现:gsttypefindfunctions
/* Try and detect at least 4 packets in at most 10 packets worth of
* data. Need to try several possible packet sizes */
static void
mpeg_ts_type_find (GstTypeFind * tf, gpointer unused)
{
/* TS packet sizes to test: normal, DVHS packet size and
* FEC with 16 or 20 byte codes packet size. */
const gint pack_sizes[] = { 188, 192, 204, 208 };
const guint8 *data = NULL;
guint size = 0;
guint64 skipped = 0;
while (skipped < GST_MPEGTS_TYPEFIND_SCAN_LENGTH) {
if (size < MPEGTS_HDR_SIZE) {
data = gst_type_find_peek (tf, skipped, GST_MPEGTS_TYPEFIND_SYNC_SIZE);
if (!data)
break;
size = GST_MPEGTS_TYPEFIND_SYNC_SIZE;
}
/* Have at least MPEGTS_HDR_SIZE bytes at this point */
if (IS_MPEGTS_HEADER (data)) {
gsize p;
GST_LOG ("possible mpeg-ts sync at offset %" G_GUINT64_FORMAT, skipped);
for (p = 0; p < G_N_ELEMENTS (pack_sizes); p++) {
gint found;
/* Probe ahead at size pack_sizes[p] */
found = mpeg_ts_probe_headers (tf, skipped, pack_sizes[p]);
if (found >= GST_MPEGTS_TYPEFIND_MIN_HEADERS) {
gint probability;
/* found at least 4 headers. 10 headers = MAXIMUM probability.
* Arbitrarily, I assigned 10% probability for each header we
* found, 40% -> 100% */
probability = MIN (10 * found, GST_TYPE_FIND_MAXIMUM);
gst_type_find_suggest_simple (tf, probability, "video/mpegts",
"systemstream", G_TYPE_BOOLEAN, TRUE,
"packetsize", G_TYPE_INT, pack_sizes[p], NULL);
return;
}
}
}
data++;
skipped++;
size--;
}
}
GST_TYPE_FIND_REGISTER_DEFINE (mpeg_sys, "video/mpeg-sys", GST_RANK_PRIMARY,
mpeg_sys_type_find, "mpe,mpeg,mpg", MPEG_SYS_CAPS, NULL, NULL);
GST_TYPE_FIND_REGISTER_DEFINE (mpeg_ts, "video/mpegts", GST_RANK_PRIMARY,
mpeg_ts_type_find, "ts,mts", MPEGTS_CAPS, NULL, NULL);
typefind函数实现:gsttypefindfunctionsriff
static void
start_with_type_find (GstTypeFind * tf, gpointer private)
{
GstTypeFindData *start_with = (GstTypeFindData *) private;
const guint8 *data;
GST_LOG ("trying to find mime type %s with the first %u bytes of data",
gst_structure_get_name (gst_caps_get_structure (start_with->caps, 0)),
start_with->size);
data = gst_type_find_peek (tf, 0, start_with->size);
if (data && memcmp (data, start_with->data, start_with->size) == 0) {
gst_type_find_suggest (tf, start_with->probability, start_with->caps);
}
}
#define TYPE_FIND_REGISTER_START_WITH_DEFINE(typefind_name, name, rank, ext, _data, _size, _probability)\
G_BEGIN_DECLS \
static gboolean \
G_PASTE(_private_type_find_start_with_, typefind_name) (GstPlugin * plugin) \
{ \
GstTypeFindData *sw_data = g_slice_new (GstTypeFindData); \
sw_data->data = (const guint8 *)_data; \
sw_data->size = _size; \
sw_data->probability = _probability; \
sw_data->caps = gst_caps_new_empty_simple (name); \
if (!gst_type_find_register (plugin, name, rank, start_with_type_find,\
ext, sw_data->caps, sw_data, \
(GDestroyNotify) (sw_data_destroy))) { \
sw_data_destroy (sw_data); \
return FALSE; \
} \
return TRUE; \
}\
GST_TYPE_FIND_REGISTER_DEFINE_CUSTOM (typefind_name, G_PASTE(_private_type_find_start_with_, typefind_name)); \
G_END_DECLS
/*'Start with' type find definition */
TYPE_FIND_REGISTER_START_WITH_DEFINE (asf, "video/x-ms-asf",
GST_RANK_SECONDARY, "asf,wm,wma,wmv",
"\060\046\262\165\216\146\317\021\246\331\000\252\000\142\316\154", 16,
GST_TYPE_FIND_MAXIMUM);
typefind函数实现:gsttypefindfunctionsstartwith
static void
start_with_type_find (GstTypeFind * tf, gpointer private)
{
GstTypeFindData *start_with = (GstTypeFindData *) private;
const guint8 *data;
GST_LOG ("trying to find mime type %s with the first %u bytes of data",
gst_structure_get_name (gst_caps_get_structure (start_with->caps, 0)),
start_with->size);
data = gst_type_find_peek (tf, 0, start_with->size);
if (data && memcmp (data, start_with->data, start_with->size) == 0) {
gst_type_find_suggest (tf, start_with->probability, start_with->caps);
}
}
#define TYPE_FIND_REGISTER_START_WITH_DEFINE(typefind_name, name, rank, ext, _data, _size, _probability)\
G_BEGIN_DECLS \
static gboolean \
G_PASTE(_private_type_find_start_with_, typefind_name) (GstPlugin * plugin) \
{ \
GstTypeFindData *sw_data = g_slice_new (GstTypeFindData); \
sw_data->data = (const guint8 *)_data; \
sw_data->size = _size; \
sw_data->probability = _probability; \
sw_data->caps = gst_caps_new_empty_simple (name); \
if (!gst_type_find_register (plugin, name, rank, start_with_type_find,\
ext, sw_data->caps, sw_data, \
(GDestroyNotify) (sw_data_destroy))) { \
sw_data_destroy (sw_data); \
return FALSE; \
} \
return TRUE; \
}\
GST_TYPE_FIND_REGISTER_DEFINE_CUSTOM (typefind_name, G_PASTE(_private_type_find_start_with_, typefind_name)); \
G_END_DECLS
/*'Start with' type find definition */
TYPE_FIND_REGISTER_START_WITH_DEFINE (asf, "video/x-ms-asf",
GST_RANK_SECONDARY, "asf,wm,wma,wmv",
"\060\046\262\165\216\146\317\021\246\331\000\252\000\142\316\154", 16,
GST_TYPE_FIND_MAXIMUM);
TYPE_FIND_REGISTER_START_WITH_DEFINE (vcd, "video/x-vcd", GST_RANK_PRIMARY,
"dat", "\000\377\377\377\377\377\377\377\377\377\377\000", 12,
GST_TYPE_FIND_MAXIMUM);
三者没有本质区别,最终都是通过gst_type_find_register注册。
/**
* gst_type_find_register:
* @plugin: (nullable): A #GstPlugin, or %NULL for a static typefind function
* @name: The name for registering
* @rank: The rank (or importance) of this typefind function
* @func: The #GstTypeFindFunction to use
* @extensions: (nullable): Optional comma-separated list of extensions
* that could belong to this type
* @possible_caps: (nullable): Optionally the caps that could be returned when typefinding
* succeeds
* @data: Optional user data. This user data must be available until the plugin
* is unloaded.
* @data_notify: a #GDestroyNotify that will be called on @data when the plugin
* is unloaded.
*
* Registers a new typefind function to be used for typefinding. After
* registering this function will be available for typefinding.
* This function is typically called during an element's plugin initialization.
*
* Returns: %TRUE on success, %FALSE otherwise
*/
gboolean
gst_type_find_register (GstPlugin * plugin, const gchar * name, guint rank,
GstTypeFindFunction func, const gchar * extensions,
GstCaps * possible_caps, gpointer data, GDestroyNotify data_notify)
{
GstTypeFindFactory *factory;
g_return_val_if_fail (name != NULL, FALSE);
GST_INFO ("registering typefind function for %s", name);
factory = g_object_new (GST_TYPE_TYPE_FIND_FACTORY, NULL);
GST_DEBUG_OBJECT (factory, "using new typefind factory for %s", name);
gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name);
gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE_CAST (factory), rank);
if (extensions)
factory->extensions = g_strsplit (extensions, ",", -1);
gst_caps_replace (&factory->caps, possible_caps);
factory->function = func;
factory->user_data = data;
factory->user_data_notify = data_notify;
if (plugin && plugin->desc.name) {
GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = plugin->desc.name; /* interned string */
GST_PLUGIN_FEATURE_CAST (factory)->plugin = plugin;
g_object_add_weak_pointer ((GObject *) plugin,
(gpointer *) & GST_PLUGIN_FEATURE_CAST (factory)->plugin);
} else {
GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = "NULL";
GST_PLUGIN_FEATURE_CAST (factory)->plugin = NULL;
}
GST_PLUGIN_FEATURE_CAST (factory)->loaded = TRUE;
gst_registry_add_feature (gst_registry_get (),
GST_PLUGIN_FEATURE_CAST (factory));
return TRUE;
}
将对应插件保存到gst_registry_get ()注册表中,包括factory->function = func,也就是各种格式相应的GstTypeFindFunction。
那我们看下typefind是如何识别出媒体资源格式的。
playbin篇章我们讲过decodebin的gst_decode_bin_init中创建typefind,并监听"have-type"信号
decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
dbin->have_type_id = g_signal_connect (dbin->typefind, "have-type",G_CALLBACK (type_found), dbin);
gsttypefindelement.c
#define _do_init \
GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", \
GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
#define gst_type_find_element_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstTypeFindElement, gst_type_find_element,
GST_TYPE_ELEMENT, _do_init);
GST_ELEMENT_REGISTER_DEFINE (typefind, "typefind", GST_RANK_NONE,
GST_TYPE_TYPE_FIND_ELEMENT);
看下sinkpad的模式,如果支持GST_PAD_MODE_PULL则开启task :gst_type_find_element_loop,否则PUSH模式。gst_pad_activate_mode会调用
gst_type_find_element_activate_sink_mode。
static gboolean
gst_type_find_element_activate_sink (GstPad * pad, GstObject * parent)
{
GstQuery *query;
gboolean pull_mode;
query = gst_query_new_scheduling ();
if (!gst_pad_peer_query (pad, query)) {
gst_query_unref (query);
goto typefind_push;
}
pull_mode = gst_query_has_scheduling_mode_with_flags (query,
GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
gst_query_unref (query);
if (!pull_mode)
goto typefind_push;
if (!gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE))
goto typefind_push;
/* only start our task if we ourselves decide to start in pull mode */
return gst_pad_start_task (pad, (GstTaskFunction) gst_type_find_element_loop,
pad, NULL);
typefind_push:
{
return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
}
}
看下gst_type_find_element_init,设置了一些函数:
gst_pad_set_activatemode_function (typefind->src,
GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_mode));
gst_pad_set_getrange_function (typefind->src,
GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
gst_pad_set_chain_function (typefind->sink,
GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
typefind->mode = MODE_TYPEFIND;
PULL模式,如filesrc
static void
gst_type_find_element_loop (GstPad * pad)
{
GstTypeFindElement *typefind;
GstFlowReturn ret = GST_FLOW_OK;
typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
if (typefind->need_stream_start) {
gchar *stream_id;
GstEvent *event;
stream_id = gst_pad_create_stream_id (typefind->src,
GST_ELEMENT_CAST (typefind), NULL);
GST_DEBUG_OBJECT (typefind, "Pushing STREAM_START");
event = gst_event_new_stream_start (stream_id);
gst_event_set_group_id (event, gst_util_group_id_next ());
gst_pad_push_event (typefind->src, event);
typefind->need_stream_start = FALSE;
g_free (stream_id);
}
if (typefind->mode == MODE_TYPEFIND) {
GstPad *peer = NULL;
GstCaps *found_caps = NULL;
GstTypeFindProbability probability = GST_TYPE_FIND_NONE;
GST_DEBUG_OBJECT (typefind, "find type in pull mode");
GST_OBJECT_LOCK (typefind);
if (typefind->force_caps) {
found_caps = gst_caps_ref (typefind->force_caps);
probability = GST_TYPE_FIND_MAXIMUM;
}
GST_OBJECT_UNLOCK (typefind);
if (!found_caps) {
peer = gst_pad_get_peer (pad);
if (peer) {
gint64 size;
gchar *ext;
if (!gst_pad_query_duration (peer, GST_FORMAT_BYTES, &size)) {
GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
gst_object_unref (peer);
ret = GST_FLOW_ERROR;
goto pause;
}
/* the size if 0, we cannot continue */
if (size == 0) {
/* keep message in sync with message in sink event handler */
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
(_("Stream contains no data.")), ("Can't typefind empty stream"));
gst_object_unref (peer);
ret = GST_FLOW_ERROR;
goto pause;
}
ext = gst_type_find_get_extension (typefind, pad);
ret =
gst_type_find_helper_get_range_full (GST_OBJECT_CAST (peer),
GST_OBJECT_PARENT (peer),
(GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
(guint64) size, ext, &found_caps, &probability);
g_free (ext);
GST_DEBUG ("Found caps %" GST_PTR_FORMAT, found_caps);
gst_object_unref (peer);
if (ret != GST_FLOW_OK)
goto pause;
}
}
if (!found_caps || probability < typefind->min_probability) {
GST_DEBUG ("Trying to guess using extension");
gst_caps_replace (&found_caps, NULL);
found_caps =
gst_type_find_guess_by_extension (typefind, pad, &probability);
}
if (!found_caps || probability < typefind->min_probability) {
GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
gst_caps_replace (&found_caps, NULL);
ret = GST_FLOW_ERROR;
goto pause;
}
GST_DEBUG ("Emitting found caps %" GST_PTR_FORMAT, found_caps);
/* Set to MODE_NORMAL before emitting have-type, in case it triggers a seek */
typefind->mode = MODE_NORMAL;
gst_type_find_element_emit_have_type (typefind, probability, found_caps);
gst_caps_unref (found_caps);
} else if (typefind->mode == MODE_NORMAL) {
GstBuffer *outbuf = NULL;
if (typefind->need_segment) {
GstEvent *event;
typefind->need_segment = FALSE;
event = gst_event_new_segment (&typefind->segment);
if (typefind->seqnum != 0)
gst_event_set_seqnum (event, typefind->seqnum);
gst_pad_push_event (typefind->src, event);
}
/* Pull 4k blocks and send downstream */
ret = gst_pad_pull_range (typefind->sink, typefind->offset, 4096, &outbuf);
if (ret != GST_FLOW_OK)
goto pause;
typefind->offset += gst_buffer_get_size (outbuf);
ret = gst_pad_push (typefind->src, outbuf);
if (ret != GST_FLOW_OK)
goto pause;
} else {
/* Error out */
ret = GST_FLOW_ERROR;
goto pause;
}
return;
......
}
关键流程:
(1)gst_type_find_element_loop,其中need_stream_start=true,push STREAM_START 到下游插件.
(2)第一次typefind->mode == MODE_TYPEFIND,第一阶段这里是true,typefind有两个阶段,第一个阶段是识别数据格式,第二个阶段是透传数据到下游插件。
a)关键流程gst_type_find_get_extension,获取uri后缀结尾,如.mp3,然后调用gst_type_find_helper_get_range_full去识别数据格式found_caps。
b)如果流程a没成功识别,则继续gst_type_find_guess_by_extension识别
c)识别成功,则切换到第二阶段:typefind->mode = MODE_NORMAL,并且触发gst_type_find_element_emit_have_type信号
(3)typefind->mode = MODE_NORMAL阶段,就是通过gst_pad_pull_range不断读取数据然后push到下游了。
我们重点看下gst_type_find_helper_get_range_full:
/**
* gst_type_find_helper_get_range_full:
* @obj: A #GstObject that will be passed as first argument to @func
* @parent: (allow-none): the parent of @obj or %NULL
* @func: (scope call): A generic #GstTypeFindHelperGetRangeFunction that will
* be used to access data at random offsets when doing the typefinding
* @size: The length in bytes
* @extension: (allow-none): extension of the media, or %NULL
* @caps: (out) (transfer full): returned caps
* @prob: (out) (allow-none): location to store the probability of the found
* caps, or %NULL
*
* Utility function to do pull-based typefinding. Unlike gst_type_find_helper()
* however, this function will use the specified function @func to obtain the
* data needed by the typefind functions, rather than operating on a given
* source pad. This is useful mostly for elements like tag demuxers which
* strip off data at the beginning and/or end of a file and want to typefind
* the stripped data stream before adding their own source pad (the specified
* callback can then call the upstream peer pad with offsets adjusted for the
* tag size, for example).
*
* When @extension is not %NULL, this function will first try the typefind
* functions for the given extension, which might speed up the typefinding
* in many cases.
*
* Returns: the last %GstFlowReturn from pulling a buffer or %GST_FLOW_OK if
* typefinding was successful.
*
* Since: 1.14.3
*/
GstFlowReturn
gst_type_find_helper_get_range_full (GstObject * obj, GstObject * parent,
GstTypeFindHelperGetRangeFunction func, guint64 size,
const gchar * extension, GstCaps ** caps, GstTypeFindProbability * prob)
{
GstTypeFindHelper helper;
GstTypeFind find;
GSList *walk;
GList *l, *type_list;
GstCaps *result = NULL;
g_return_val_if_fail (GST_IS_OBJECT (obj), GST_FLOW_ERROR);
g_return_val_if_fail (func != NULL, GST_FLOW_ERROR);
g_return_val_if_fail (caps != NULL, GST_FLOW_ERROR);
*caps = NULL;
helper.buffers = NULL;
helper.size = size;
helper.last_offset = 0;
helper.func = func;
helper.best_probability = GST_TYPE_FIND_NONE;
helper.caps = NULL;
helper.obj = obj;
helper.parent = parent;
helper.flow_ret = GST_FLOW_OK;
find.data = &helper;
find.peek = helper_find_peek;
find.suggest = helper_find_suggest;
if (size == 0 || size == (guint64) - 1) {
find.get_length = NULL;
} else {
find.get_length = helper_find_get_length;
}
type_list = gst_type_find_factory_get_list ();
type_list = prioritize_extension (obj, type_list, extension);
for (l = type_list; l; l = l->next) {
helper.factory = GST_TYPE_FIND_FACTORY (l->data);
gst_type_find_factory_call_function (helper.factory, &find);
if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM) {
/* Any other flow return can be ignored here, we found
* something before any error with highest probability */
helper.flow_ret = GST_FLOW_OK;
break;
} else if (helper.flow_ret != GST_FLOW_OK
&& helper.flow_ret != GST_FLOW_EOS) {
/* We had less than maximum probability and an error, don't return
* any caps as they might be with a lower probability than what
* we would've gotten when continuing if there was no error */
gst_caps_replace (&helper.caps, NULL);
break;
}
}
gst_plugin_feature_list_free (type_list);
for (walk = helper.buffers; walk; walk = walk->next) {
GstMappedBuffer *bmap = (GstMappedBuffer *) walk->data;
gst_buffer_unmap (bmap->buffer, &bmap->map);
gst_buffer_unref (bmap->buffer);
g_slice_free (GstMappedBuffer, bmap);
}
g_slist_free (helper.buffers);
if (helper.best_probability > 0)
result = helper.caps;
if (prob)
*prob = helper.best_probability;
*caps = result;
if (helper.flow_ret == GST_FLOW_EOS) {
/* Some typefinder might've tried to read too much, if we
* didn't get any meaningful caps because of that this is
* just a normal error */
helper.flow_ret = GST_FLOW_ERROR;
}
GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)",
result, (guint) helper.best_probability);
return helper.flow_ret;
}
关键流程
(1)helper.func = func,也就是GST_PAD_GETRANGEFUNC (peer),filesrc中的getrange函数
(2)gst_type_find_factory_get_list,从注册表中获取factory到type_list
(3)prioritize_extension,对type_list进行sort,将uri后缀匹配的,调整到最前面。
(4)gst_type_find_factory_call_function,遍历type_list会调用factory的typefindfunction,也就是之前gst_typefind_register讲解的识别函数。
(5)返回识别的caps以及probability。
到这里我们就已经搞清楚了typefind的PULL模式的运转流程了。
PUSH模式,如souphttpsrc
当上游推送数据会调用gst_type_find_element_chain
static GstFlowReturn
gst_type_find_element_chain (GstPad * pad, GstObject * parent,
GstBuffer * buffer)
{
GstTypeFindElement *typefind;
GstFlowReturn res = GST_FLOW_OK;
typefind = GST_TYPE_FIND_ELEMENT (parent);
GST_LOG_OBJECT (typefind, "handling buffer in mode %d", typefind->mode);
switch (typefind->mode) {
case MODE_ERROR:
/* we should already have called GST_ELEMENT_ERROR */
return GST_FLOW_ERROR;
case MODE_NORMAL:
/* don't take object lock as typefind->caps should not change anymore */
return gst_pad_push (typefind->src, buffer);
case MODE_TYPEFIND:
{
GST_OBJECT_LOCK (typefind);
if (typefind->initial_offset == GST_BUFFER_OFFSET_NONE)
typefind->initial_offset = GST_BUFFER_OFFSET (buffer);
gst_adapter_push (typefind->adapter, buffer);
GST_OBJECT_UNLOCK (typefind);
res = gst_type_find_element_chain_do_typefinding (typefind, TRUE, FALSE);
if (typefind->mode == MODE_ERROR)
res = GST_FLOW_ERROR;
break;
}
default:
g_assert_not_reached ();
return GST_FLOW_ERROR;
}
return res;
}
一样是两个阶段:MODE_NORMAL和MODE_TYPEFIND
重点函数gst_type_find_element_chain_do_typefinding
static GstFlowReturn
gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind,
gboolean check_avail, gboolean at_eos)
{
GstTypeFindProbability probability;
GstCaps *caps = NULL;
gsize avail;
const guint8 *data;
gboolean have_min, have_max;
gchar *ext;
GST_OBJECT_LOCK (typefind);
if (typefind->force_caps) {
caps = gst_caps_ref (typefind->force_caps);
probability = GST_TYPE_FIND_MAXIMUM;
}
if (!caps) {
avail = gst_adapter_available (typefind->adapter);
if (check_avail) {
have_min = avail >= TYPE_FIND_MIN_SIZE;
have_max = avail >= TYPE_FIND_MAX_SIZE;
} else {
have_min = avail > 0;
have_max = TRUE;
}
if (!have_min)
goto not_enough_data;
ext = gst_type_find_get_extension (typefind, typefind->sink);
/* map all available data */
data = gst_adapter_map (typefind->adapter, avail);
caps = gst_type_find_helper_for_data_with_extension (GST_OBJECT (typefind),
data, avail, ext, &probability);
gst_adapter_unmap (typefind->adapter);
g_free (ext);
if (caps == NULL && have_max)
goto no_type_found;
else if (caps == NULL)
goto wait_for_data;
/* found a type */
if (probability < typefind->min_probability)
goto low_probability;
}
GST_OBJECT_UNLOCK (typefind);
/* probability is good enough too, so let's make it known ... emitting this
* signal calls our object handler which sets the caps. */
/* Set to MODE_NORMAL before emitting have-type, in case it triggers a seek */
typefind->mode = MODE_NORMAL;
gst_type_find_element_emit_have_type (typefind, probability, caps);
/* .. and send out the accumulated data */
stop_typefinding (typefind);
gst_caps_unref (caps);
return GST_FLOW_OK;
......
}
一样流程gst_type_find_get_extension->gst_type_find_helper_for_data_with_extension识别到caps,然后切换到MODE_NORMAL阶段。
到这里我们就已经搞清楚了typefind的PULL和PUSH模式的运转流程了。