playbin之autoplug_factories源码剖析
一、autoplug_factories_cb
/* Called when we must provide a list of factories to plug to @pad with @caps.
* We first check if we have a sink that can handle the format and if we do, we
* return NULL, to expose the pad. If we have no sink (or the sink does not
* work), we return the list of elements that can connect. */
static GValueArray *
autoplug_factories_cb (GstElement * decodebin, GstPad * pad,
GstCaps * caps, GstSourceGroup * group)
{
GstPlayBin *playbin;
GList *factory_list, *tmp;
GValueArray *result;
gboolean unref_caps = FALSE;
gboolean isaudiodeclist = FALSE;
gboolean isvideodeclist = FALSE;
if (!caps) {
caps = gst_caps_new_any ();
unref_caps = TRUE;
}
playbin = group->playbin;
GST_DEBUG_OBJECT (playbin, "factories group %p for %s:%s, %" GST_PTR_FORMAT,
group, GST_DEBUG_PAD_NAME (pad), caps);
/* filter out the elements based on the caps. */
g_mutex_lock (&playbin->elements_lock);
gst_play_bin_update_elements_list (playbin);
//caps匹配的factory_list
factory_list =
gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
gst_caps_is_fixed (caps));
g_mutex_unlock (&playbin->elements_lock);
GST_DEBUG_OBJECT (playbin, "found factories %p", factory_list);
GST_PLUGIN_FEATURE_LIST_DEBUG (factory_list);
/* check whether the caps are asking for a list of audio/video decoders */
tmp = factory_list;
if (!gst_caps_is_any (caps)) {
for (; tmp; tmp = tmp->next) {
GstElementFactory *factory = (GstElementFactory *) tmp->data;
isvideodeclist = gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_DECODER |
GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
isaudiodeclist = gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_DECODER |
GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
if (isaudiodeclist || isvideodeclist)
break;
}
}
if (isaudiodeclist || isvideodeclist) {
GSequence **ave_list;
GstPlayFlags flags;
if (isaudiodeclist)
ave_list = &playbin->aelements;
else
ave_list = &playbin->velements;
flags = gst_play_bin_get_flags (playbin);
g_mutex_lock (&playbin->elements_lock);
/* sort factory_list based on the GstAVElement list priority */
factory_list = create_decoders_list (factory_list, *ave_list, flags);
g_mutex_unlock (&playbin->elements_lock);
}
/* 2 additional elements for the already set audio/video sinks */
result = g_value_array_new (g_list_length (factory_list) + 2);
/* Check if we already have an audio/video sink and if this is the case
* put it as the first element of the array */
if (group->audio_sink) {
GstElementFactory *factory = gst_element_get_factory (group->audio_sink);
if (factory && _factory_can_sink_caps (factory, caps)) {
GValue val = { 0, };
g_value_init (&val, G_TYPE_OBJECT);
g_value_set_object (&val, factory);
result = g_value_array_append (result, &val);
g_value_unset (&val);
}
}
if (group->video_sink) {
GstElementFactory *factory = gst_element_get_factory (group->video_sink);
if (factory && _factory_can_sink_caps (factory, caps)) {
GValue val = { 0, };
g_value_init (&val, G_TYPE_OBJECT);
g_value_set_object (&val, factory);
result = g_value_array_append (result, &val);
g_value_unset (&val);
}
}
for (tmp = factory_list; tmp; tmp = tmp->next) {
GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
GValue val = { 0, };
if (group->audio_sink && gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_SINK |
GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)) {
continue;
}
if (group->video_sink && gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO
| GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)) {
continue;
}
g_value_init (&val, G_TYPE_OBJECT);
g_value_set_object (&val, factory);
g_value_array_append (result, &val);
g_value_unset (&val);
}
gst_plugin_feature_list_free (factory_list);
if (unref_caps)
gst_caps_unref (caps);
return result;
}
1.gst_play_bin_update_elements_list函数,创建可用的factories列表playbin->elements( GList *elements; /* factories we can use for selecting elements */)
/* Must be called with elements lock! */
static void
gst_play_bin_update_elements_list (GstPlayBin * playbin)
{
GList *res, *tmp;
guint cookie;
cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
if (!playbin->elements || playbin->elements_cookie != cookie) {
if (playbin->elements)
gst_plugin_feature_list_free (playbin->elements);
res =
gst_element_factory_list_get_elements
(GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
tmp =
gst_element_factory_list_get_elements
(GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS, GST_RANK_MARGINAL);
playbin->elements = g_list_concat (res, tmp);
playbin->elements = g_list_sort (playbin->elements, compare_factories_func);
}
if (!playbin->aelements || playbin->elements_cookie != cookie) {
if (playbin->aelements)
g_sequence_free (playbin->aelements);
playbin->aelements = avelements_create (playbin, TRUE);
}
if (!playbin->velements || playbin->elements_cookie != cookie) {
if (playbin->velements)
g_sequence_free (playbin->velements);
playbin->velements = avelements_create (playbin, FALSE);
}
playbin->elements_cookie = cookie;
}
也就是同过gst_element_factory_list_get_elements从registry中获取type是GST_ELEMENT_FACTORY_TYPE_DECODABLE,GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS,优先级高于GST_RANK_MARGINAL的factory。
#define GST_ELEMENT_FACTORY_TYPE_DECODABLE \
((GstElementFactoryListType)(GST_ELEMENT_FACTORY_TYPE_DECODER | GST_ELEMENT_FACTORY_TYPE_DEMUXER | GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER | GST_ELEMENT_FACTORY_TYPE_PARSER | GST_ELEMENT_FACTORY_TYPE_DECRYPTOR))
#define GST_ELEMENT_FACTORY_TYPE_AUDIOVIDEO_SINKS ((GstElementFactoryListType)(GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO | GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE))
还有(GSequence *)playbin->aelements和playbin->velements用来保存audioelement和videoelement。
(1)先看下gst_element_factory_list_get_elements
GList *
gst_element_factory_list_get_elements (GstElementFactoryListType type,
GstRank minrank)
{
GList *result;
FilterData data;
/* prepare type */
data.type = type;
data.minrank = minrank;
/* get the feature list using the filter */
result = gst_registry_feature_filter (gst_registry_get (),
(GstPluginFeatureFilter) element_filter, FALSE, &data);
/* sort on rank and name */
result = g_list_sort (result, gst_plugin_feature_rank_compare_func);
return result;
}
//根据rank和type选择
static gboolean
element_filter (GstPluginFeature * feature, FilterData * data)
{
gboolean res;
/* we only care about element factories */
if (G_UNLIKELY (!GST_IS_ELEMENT_FACTORY (feature)))
return FALSE;
res = (gst_plugin_feature_get_rank (feature) >= data->minrank) &&
gst_element_factory_list_is_type (GST_ELEMENT_FACTORY_CAST (feature),
data->type);
return res;
}
//factory_type的判断逻辑
gboolean
gst_element_factory_list_is_type (GstElementFactory * factory,
GstElementFactoryListType type)
{
gboolean res = FALSE;
const gchar *klass;
klass =
gst_element_factory_get_metadata (factory, GST_ELEMENT_METADATA_KLASS);
if (klass == NULL) {
GST_ERROR_OBJECT (factory, "element factory is missing klass identifiers");
return res;
}
/* Filter by element type first, as soon as it matches
* one type, we skip all other tests */
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_SINK))
res = (strstr (klass, "Sink") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_SRC))
res = (strstr (klass, "Source") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_DECODER))
res = (strstr (klass, "Decoder") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_ENCODER))
res = (strstr (klass, "Encoder") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_MUXER))
res = (strstr (klass, "Muxer") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_DEMUXER))
res = (strstr (klass, "Demux") != NULL);
/* FIXME : We're actually parsing two Classes here... */
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_PARSER))
res = ((strstr (klass, "Parser") != NULL)
&& (strstr (klass, "Codec") != NULL));
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_DEPAYLOADER))
res = (strstr (klass, "Depayloader") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_PAYLOADER))
res = (strstr (klass, "Payloader") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_FORMATTER))
res = (strstr (klass, "Formatter") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_DECRYPTOR))
res = (strstr (klass, "Decryptor") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_ENCRYPTOR))
res = (strstr (klass, "Encryptor") != NULL);
if (!res && (type & GST_ELEMENT_FACTORY_TYPE_HARDWARE))
res = (strstr (klass, "Hardware") != NULL);
/* Filter by media type now, we only test if it
* matched any of the types above or only checking the media
* type was requested. */
if ((res || !(type & (GST_ELEMENT_FACTORY_TYPE_MAX_ELEMENTS - 1)))
&& (type & (GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO |
GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE |
GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE |
GST_ELEMENT_FACTORY_TYPE_MEDIA_METADATA)))
res = ((type & GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO)
&& (strstr (klass, "Audio") != NULL))
|| ((type & GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO)
&& (strstr (klass, "Video") != NULL))
|| ((type & GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE)
&& (strstr (klass, "Image") != NULL)) ||
((type & GST_ELEMENT_FACTORY_TYPE_MEDIA_SUBTITLE)
&& (strstr (klass, "Subtitle") != NULL)) ||
((type & GST_ELEMENT_FACTORY_TYPE_MEDIA_METADATA)
&& (strstr (klass, "Metadata") != NULL));
return res;
}
//根据rank排序
gint
gst_plugin_feature_rank_compare_func (gconstpointer p1, gconstpointer p2)
{
GstPluginFeature *f1, *f2;
gint diff;
f1 = (GstPluginFeature *) p1;
f2 = (GstPluginFeature *) p2;
diff = f2->rank - f1->rank;
if (diff != 0)
return diff;
diff = strcmp (GST_OBJECT_NAME (f1), GST_OBJECT_NAME (f2));
return diff;
}
(2)avelements_create,创建一个保存GstAudioVideoElement的GSequence
/* The GstAudioVideoElement structure holding the audio/video decoder
* and the audio/video sink factories together with field indicating
* the number of common caps features */
static GSequence *
avelements_create (GstPlayBin * playbin, gboolean isaudioelement)
{
GstElementFactory *d_factory, *s_factory;
GList *dec_list, *sink_list, *dl, *sl;
GSequence *ave_seq = NULL;
GstAVElement *ave;
guint n_common_cf = 0;
//选择符合要求的音视频添加到对应的sink_list和dec_list
if (isaudioelement) {
sink_list = gst_element_factory_list_get_elements
(GST_ELEMENT_FACTORY_TYPE_SINK |
GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_MARGINAL);
dec_list =
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECODER
| GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO, GST_RANK_MARGINAL);
} else {
sink_list = gst_element_factory_list_get_elements
(GST_ELEMENT_FACTORY_TYPE_SINK |
GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE, GST_RANK_MARGINAL);
dec_list =
gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_DECODER
| GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE, GST_RANK_MARGINAL);
}
/* create a list of audio/video elements. Each element in the list
* is holding an audio/video decoder and an audio/video sink in which
* the decoders srcpad template caps and sink element's sinkpad template
* caps are compatible */
dl = dec_list;
sl = sink_list;
ave_seq = g_sequence_new ((GDestroyNotify) avelements_free);
//查找可以匹配的dec和sink,组合形式的ave,并保存到ave_seq,函数最后会返回
/****
* typedef struct
*{
* GstElementFactory *dec; /* audio:video decoder */
* GstElementFactory *sink; /* audio:video sink */
* guint n_comm_cf; /* number of common caps features */
*} GstAVElement;
*****/
for (; dl; dl = dl->next) {
d_factory = (GstElementFactory *) dl->data;
for (; sl; sl = sl->next) {
s_factory = (GstElementFactory *) sl->data;
n_common_cf =
gst_playback_utils_get_n_common_capsfeatures (d_factory, s_factory,
gst_play_bin_get_flags (playbin), isaudioelement);
if (n_common_cf < 1)
continue;
ave = g_slice_new (GstAVElement);
ave->dec = gst_object_ref (d_factory);
ave->sink = gst_object_ref (s_factory);
ave->n_comm_cf = n_common_cf;
g_sequence_append (ave_seq, ave);
}
sl = sink_list;
}
g_sequence_sort (ave_seq, (GCompareDataFunc) avelement_compare_decoder, NULL);
gst_plugin_feature_list_free (dec_list);
gst_plugin_feature_list_free (sink_list);
return ave_seq;
}
主要看下gst_playback_utils_get_n_common_capsfeatures如何计算common caps features
for (i = 0; i < fact1_caps_size; i++) {
fact1_features =
gst_caps_get_features ((const GstCaps *) fact1_tmpl_caps, i);
if (gst_caps_features_is_any (fact1_features))
continue;
fact1_struct =
gst_caps_get_structure ((const GstCaps *) fact1_tmpl_caps, i);
for (j = 0; j < fact2_caps_size; j++) {
fact2_features =
gst_caps_get_features ((const GstCaps *) fact2_tmpl_caps, j);
if (gst_caps_features_is_any (fact2_features))
continue;
fact2_struct =
gst_caps_get_structure ((const GstCaps *) fact2_tmpl_caps, j);
/* A common caps feature is given if the caps features are equal
* and the structures can intersect. If the NATIVE_AUDIO/NATIVE_VIDEO
* flags are not set we also allow if both structures are raw caps with
* system memory caps features, because in that case we have converters in
* place.
*/
if (gst_caps_features_is_equal (fact1_features, fact2_features) &&
(gst_structure_can_intersect (fact1_struct, fact2_struct) ||
(!native_raw
&& gst_caps_features_is_equal (fact1_features,
GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
&& gst_structure_can_intersect (raw_struct, fact1_struct)
&& gst_structure_can_intersect (raw_struct, fact2_struct)))
&& !is_included (cf_list, fact2_features)) {
cf_list = g_list_prepend (cf_list, fact2_features);
n_common_cf++;
}
}
}
2 .获取factory_list :查找包含sink_pad类型是caps匹配的elements
factory_list =
gst_element_factory_list_filter (playbin->elements, caps, GST_PAD_SINK,
gst_caps_is_fixed (caps));
GList *
gst_element_factory_list_filter (GList * list,
const GstCaps * caps, GstPadDirection direction, gboolean subsetonly)
{
GQueue results = G_QUEUE_INIT;
GST_DEBUG ("finding factories");
/* loop over all the factories */
for (; list; list = list->next) {
GstElementFactory *factory;
const GList *templates;
GList *walk;
factory = (GstElementFactory *) list->data;
GST_DEBUG ("Trying %s",
gst_plugin_feature_get_name ((GstPluginFeature *) factory));
/* get the templates from the element factory */
templates = gst_element_factory_get_static_pad_templates (factory);
for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
GstStaticPadTemplate *templ = walk->data;
/* we only care about the sink templates */
if (templ->direction == direction) {
GstCaps *tmpl_caps;
/* try to intersect the caps with the caps of the template */
tmpl_caps = gst_static_caps_get (&templ->static_caps);
/* FIXME, intersect is not the right method, we ideally want to check
* for a subset here */
/* check if the intersection is empty */
if ((subsetonly && gst_caps_is_subset (caps, tmpl_caps)) ||
(!subsetonly && gst_caps_can_intersect (caps, tmpl_caps))) {
/* non empty intersection, we can use this element */
g_queue_push_tail (&results, gst_object_ref (factory));
gst_caps_unref (tmpl_caps);
break;
}
gst_caps_unref (tmpl_caps);
}
}
}
return results.head;
}
3.然后继续后续处理,判断找到factory_list中第一个audio/video decoder的位置
/* check whether the caps are asking for a list of audio/video decoders */
tmp = factory_list;
if (!gst_caps_is_any (caps)) {
for (; tmp; tmp = tmp->next) {
GstElementFactory *factory = (GstElementFactory *) tmp->data;
isvideodeclist = gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_DECODER |
GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO |
GST_ELEMENT_FACTORY_TYPE_MEDIA_IMAGE);
isaudiodeclist = gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_DECODER |
GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO);
if (isaudiodeclist || isvideodeclist)
break;
}
}
if (isaudiodeclist || isvideodeclist) {
GSequence **ave_list;
GstPlayFlags flags;
if (isaudiodeclist)
ave_list = &playbin->aelements;
else
ave_list = &playbin->velements;
flags = gst_play_bin_get_flags (playbin);
//创建decoder_list
g_mutex_lock (&playbin->elements_lock);
/* sort factory_list based on the GstAVElement list priority */
factory_list = create_decoders_list (factory_list, *ave_list, flags);
g_mutex_unlock (&playbin->elements_lock);
}
static GList *
create_decoders_list (GList * factory_list, GSequence * avelements,
GstPlayFlags flags)
{
GList *dec_list = NULL, *tmp;
GList *ave_list = NULL;
GList *ave_free_list = NULL;
GstAVElement *ave, *best_ave;
g_return_val_if_fail (factory_list != NULL, NULL);
g_return_val_if_fail (avelements != NULL, NULL);
for (tmp = factory_list; tmp; tmp = tmp->next) {
GstElementFactory *factory = (GstElementFactory *) tmp->data;
/* if there are parsers or sink elements, add them first */ //parsers or sink elements直接dec_list,如果不是走下面流程添加到ave_list
if (gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_PARSER) ||
gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_SINK)) {
dec_list = g_list_prepend (dec_list, gst_object_ref (factory));
} else if (!(((flags & GST_PLAY_FLAG_FORCE_SW_DECODERS) != 0) //如果没有同时满足以下两个条件则为TRUE:强制软件解码且factory 是硬件解码器类型
&& gst_element_factory_list_is_type (factory,
GST_ELEMENT_FACTORY_TYPE_HARDWARE))) {
GSequenceIter *seq_iter;
seq_iter =
g_sequence_lookup (avelementszh, factory,
(GCompareDataFunc) avelement_lookup_decoder, NULL);//avelements中查找,匹配条件avelement_lookup_decoder
if (!seq_iter) {
GstAVElement *ave = g_slice_new0 (GstAVElement);
ave->dec = factory;
ave->sink = NULL;
/* There's at least raw */
ave->n_comm_cf = 1;
ave_list = g_list_prepend (ave_list, ave);
/* We need to free these later */
ave_free_list = g_list_prepend (ave_free_list, ave);
continue;
}
/* Go to first iter with that decoder */
do {
GSequenceIter *tmp_seq_iter;
tmp_seq_iter = g_sequence_iter_prev (seq_iter);
if (!avelement_iter_is_equal (tmp_seq_iter, factory))
break;
seq_iter = tmp_seq_iter;
} while (!g_sequence_iter_is_begin (seq_iter));
/* Get the best ranked GstAVElement for that factory */
best_ave = NULL;
while (!g_sequence_iter_is_end (seq_iter)
&& avelement_iter_is_equal (seq_iter, factory)) {
ave = g_sequence_get (seq_iter);
if (!best_ave || avelement_compare (ave, best_ave) < 0) //最佳匹配,匹配条件avelement_compare
best_ave = ave;
seq_iter = g_sequence_iter_next (seq_iter);
}
ave_list = g_list_prepend (ave_list, best_ave);
}
}
/* Sort all GstAVElements by their relative ranks and insert
* into the decoders list */
ave_list = g_list_sort (ave_list, (GCompareFunc) avelement_compare);
for (tmp = ave_list; tmp; tmp = tmp->next) {
ave = (GstAVElement *) tmp->data;
dec_list = g_list_prepend (dec_list, gst_object_ref (ave->dec));//prepend是添加到list的头部,所以需要后面的翻转
}
g_list_free (ave_list);
gst_plugin_feature_list_free (factory_list);
for (tmp = ave_free_list; tmp; tmp = tmp->next)
g_slice_free (GstAVElement, tmp->data);
g_list_free (ave_free_list);
//所以parse和sink都被添加到了前面,其他的根据rank等排序
dec_list = g_list_reverse (dec_list);
return dec_list;
}
static gint
avelement_compare (gconstpointer p1, gconstpointer p2)
{
GstAVElement *v1, *v2;
GstPluginFeature *fd1, *fd2, *fs1, *fs2;
gint64 diff, v1_rank, v2_rank;
v1 = (GstAVElement *) p1;
v2 = (GstAVElement *) p2;
fd1 = (GstPluginFeature *) v1->dec;
fd2 = (GstPluginFeature *) v2->dec;
//优先比较sink的rank,没有在比较dec的rank
/* If both have a sink, we also compare their ranks */
if (v1->sink && v2->sink) {
fs1 = (GstPluginFeature *) v1->sink;
fs2 = (GstPluginFeature *) v2->sink;
v1_rank = (gint64) gst_plugin_feature_get_rank (fd1) *
gst_plugin_feature_get_rank (fs1);
v2_rank = (gint64) gst_plugin_feature_get_rank (fd2) *
gst_plugin_feature_get_rank (fs2);
} else {
v1_rank = gst_plugin_feature_get_rank (fd1);
v2_rank = gst_plugin_feature_get_rank (fd2);
fs1 = fs2 = NULL;
}
/* comparison based on the rank */
diff = v2_rank - v1_rank;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
//比较number of common caps feature,多的优先
/* comparison based on number of common caps features */
diff = v2->n_comm_cf - v1->n_comm_cf;
if (diff != 0)
return diff;
if (fs1 && fs2) {
/* comparison based on the name of sink elements */
diff = strcmp (GST_OBJECT_NAME (fs1), GST_OBJECT_NAME (fs2));
if (diff != 0)
return diff;
}
/* comparison based on the name of decoder elements */
return strcmp (GST_OBJECT_NAME (fd1), GST_OBJECT_NAME (fd2));
}
这里注意下list中的排序吧:parse和sink最前,其他会按照优先级(rank
)、共有 caps 特性数量、接收器名称和解码器名称的顺序排列 。
后续如果应有sink则将sink插入到list中,基本也就完成了autoplug_factories_cb流程了。
二、autoplug_select_cb
GstPlayBin *playbin;
GstElement *element;
const gchar *klass;
GstPlaySinkType type;
GstElement **sinkp;
GList *ave_list = NULL, *l;
GstAVElement *ave = NULL;
GSequence *ave_seq = NULL;
GSequenceIter *seq_iter;
gboolean created_sink = FALSE;
{省略}
if (isaudiodec) {
ave_seq = playbin->aelements;
sinkp = &group->audio_sink;
} else {
ave_seq = playbin->velements;
sinkp = &group->video_sink;
}
seq_iter =
g_sequence_lookup (ave_seq, factory,
(GCompareDataFunc) avelement_lookup_decoder, NULL);
if (seq_iter) {
/* Go to first iter with that decoder */
do {
GSequenceIter *tmp_seq_iter;
tmp_seq_iter = g_sequence_iter_prev (seq_iter);
if (!avelement_iter_is_equal (tmp_seq_iter, factory))
break;
seq_iter = tmp_seq_iter;
} while (!g_sequence_iter_is_begin (seq_iter));
while (!g_sequence_iter_is_end (seq_iter)
&& avelement_iter_is_equal (seq_iter, factory)) {
ave = g_sequence_get (seq_iter);
ave_list = g_list_prepend (ave_list, ave);
seq_iter = g_sequence_iter_next (seq_iter);
}
/* Sort all GstAVElements by their relative ranks and insert
* into the decoders list */
ave_list = g_list_sort (ave_list, (GCompareFunc) avelement_compare);
} else {
ave_list = g_list_prepend (ave_list, NULL);
}