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_listfactory_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;elseave_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_listif (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;elseave_list = &playbin->velements;flags = gst_play_bin_get_flags (playbin);//創建decoder_listg_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_listif (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_decoderif (!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_comparebest_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);}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/72140.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/72140.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/72140.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

58區間和+44開發商購買土地(前綴和)

58. 區間和&#xff08;第九期模擬筆試&#xff09; 題目描述 給定一個整數數組 Array&#xff0c;請計算該數組在每個指定區間內元素的總和。 輸入描述 第一行輸入為整數數組 Array 的長度 n&#xff0c;接下來 n 行&#xff0c;每行一個整數&#xff0c;表示數組的元素。…

laravel11設置中文語言包

安裝中文語言包 Laravel 11 默認沒有內置完整中文語言包&#xff0c;推薦使用第三方維護的完整翻譯&#xff1a; # 通過 Composer 安裝語言包 composer require laravel-lang/common --dev# 發布中文語言文件到項目 php artisan lang:add zh_CN這會自動將中文語言文件生成到 l…

智能文檔解析與語義分割:LlamaIndex 節點解析器模塊全解

節點解析器模塊 - LlamaIndex 文件內容的節點解析器 有幾種基于文件的節點解析器,它們會根據解析的內容類型(JSON、Markdown 等)創建節點。 最簡單的流程是將 FlatFileReader 與 SimpleFileNodeParser 結合使用,自動為每種內容類型選擇最佳節點解析器。然后,可以將基于…

實現遍歷Windows所有字體的基本屬性

參考podofo #include <windows.h> #include <string> #include <memory> #include <set> #include <unordered_map> #include <vector> #include <algorithm> #include <iostream> #include <iomanip> #include <fst…

postman--接口測試工具安裝和使用教程

postman–接口測試工具 postman是一款支持http協議的接口調試與測試工具&#xff0c;其主要特點就是功能強大&#xff0c;使用簡單且易用性好 。 無論是開發人員進行接口調試&#xff0c;還是測試人員做接口測試&#xff0c;postman都是我們的首選工具之一 。 下面先通過一張…

綜合練習 —— 遞歸、搜索與回溯算法

目錄 一、1863. 找出所有子集的異或總和再求和 - 力扣&#xff08;LeetCode&#xff09; 算法代碼&#xff1a; 代碼思路 問題分析 核心思想 實現細節 代碼解析 初始化 DFS 函數 時間復雜度 空間復雜度 示例運行 輸入 運行過程 總結 二、 47. 全排列 II - 力扣&a…

代碼隨想錄算法訓練day64---圖論系列8《拓撲排序dijkstra(樸素版)》

代碼隨想錄算法訓練 —day64 文章目錄 代碼隨想錄算法訓練前言一、53. 117. 軟件構建—拓撲排序二、47. 參加科學大會---dijkstra&#xff08;樸素版&#xff09;總結 前言 今天是算法營的第64天&#xff0c;希望自己能夠堅持下來&#xff01; 今天繼續圖論part&#xff01;今…

學術小助手智能體

學術小助手&#xff1a;開學季的學術領航員 文心智能體平臺AgentBuilder | 想象即現實 文心智能體平臺AgentBuilder&#xff0c;是百度推出的基于文心大模型的智能體平臺&#xff0c;支持廣大開發者根據自身行業領域、應用場景&#xff0c;選取不同類型的開發方式&#xff0c;…

JavaScript 簡單類型與復雜類型-復雜類型傳參

在JavaScript中&#xff0c;變量根據其存儲的數據類型可分為簡單類型&#xff08;基本數據類型&#xff09;和復雜類型&#xff08;引用數據類型&#xff09;。理解這兩者在函數調用時的行為差異對于編寫高效且無誤的代碼至關重要。本文將專注于探討復雜類型的參數傳遞機制&…

L2-043 龍龍送外賣(dfs)

龍龍是“飽了呀”外賣軟件的注冊騎手&#xff0c;負責送帕特小區的外賣。帕特小區的構造非常特別&#xff0c;都是雙向道路且沒有構成環 —— 你可以簡單地認為小區的路構成了一棵樹&#xff0c;根結點是外賣站&#xff0c;樹上的結點就是要送餐的地址。 每到中午 12 點&#…

如何基于PyTorch做二次開發

基于PyTorch進行二次開發以實現可視化工程&#xff0c;可以從以下幾個方面入手&#xff1a;模型結構可視化、訓練過程監控、特征可視化等。以下是一些推薦的GitHub項目&#xff0c;這些項目可以幫助你快速搭建一個可視化的工程環境&#xff1a; ### 1. **PyTorch CNN Visualiz…

本地大模型編程實戰(26)用langgraph實現基于SQL數據構建的問答系統(5)

本文將將擴展上一篇文章完成的 langgraph 鏈&#xff0c;繼續使用基于 langgraph 鏈 &#xff0c;對結構化數據庫 SQlite 進行查詢的方法。該系統建立以后&#xff0c;我們不需要掌握專業的 SQL 技能&#xff0c;可以用自然語言詢問有關數據庫中數據的問題并返回答案。主要完善…

【Kubernetes】污點和容忍

一、概述 在 Kubernetes&#xff08;k8s&#xff09;中&#xff0c;污點&#xff08;Taints&#xff09; 是定義在節點上的一種機制&#xff0c;用于拒絕某些 Pod 調度到該節點&#xff0c;除非這些 Pod 具有對應的容忍度&#xff08;Tolerations&#xff09;。污點可以用來控…

【大模型?知識圖譜】大模型結合醫療知識圖譜:解鎖智能輔助診療系統新范式

【大模型?知識圖譜】大模型結合醫療知識圖譜:解鎖智能輔助診療系統新范式 大模型結合醫療知識圖譜:解鎖智能輔助診療系統新范式引言一、系統架構1.1 系統架構圖1.2 架構模塊說明1.2.1 用戶輸入1.2.2 大模型(語義理解與意圖識別)1.2.3 Agent(問題解析與任務分配)1.2.4 問…

FASIONAD:自適應反饋的類人自動駕駛中快速和慢速思維融合系統

24年11月來自清華、早稻田大學、明尼蘇達大學、多倫多大學、廈門大學馬來西亞分校、電子科大&#xff08;成都&#xff09;、智平方科技和河南潤泰數字科技的論文“FASIONAD : FAst and Slow FusION Thinking Systems for Human-Like Autonomous Driving with Adaptive Feedbac…

【免費】YOLO[笑容]目標檢測全過程(yolo環境配置+labelimg數據集標注+目標檢測訓練測試)

一、yolo環境配置 這篇帖子是我試過的&#xff0c;非常全&#xff0c;很詳細【cudaanacondapytorchyolo(ultralytics)】 yolo環境配置 二、labelimg數據集標注 可以參考下面的帖子&#xff0c;不過可能會出現閃退的問題&#xff0c;安裝我的流程來吧 2.1 labelimg安裝 label…

Linux系統軟件管理

systemctl 控制軟件啟動和關閉 Linux系統很多軟件支持使用systemctl命令控制&#xff1a;啟動&#xff0c;停止&#xff0c;開啟自啟。 能被systemctl管理的軟件&#xff0c;一般被稱為&#xff1a;服務。 語法&#xff1a;systemctl start|stop|status|enable|disable 服務名…

CAN總線通信協議學習1——物理層

首先來看看CAN是怎么產生的&#xff1a;簡單理解&#xff0c;CAN就是一種“擁有特別連接方式”的數據傳輸的總線&#xff0c;其有特定的一些規則。 &#xff08;注&#xff1a;資料及圖片來源于知乎博主TOMOCAT。&#xff09; CAN總線的結構 查閱參考文獻&#xff0c;OSI標準…

偏移量是什么

在將二維網格映射到一維數組時&#xff0c;偏移量是指在一維數組中 某一行的第一個元素相對于數組起始位置的位置差。對于一個 3 行 4 列的網格&#xff0c;我們使用公式 cur_pos x * n y 來計算二維位置 (x, y) 在一維數組中的索引。 當 x 0 &#xff08;第一行&#xff…

【Mac電腦本地部署Deepseek-r1:詳細教程與Openwebui配置指南】

文章目錄 前言電腦配置&#xff1a;安裝的Deepseek版本&#xff1a;使用的UI框架&#xff1a;體驗效果展示&#xff1a;本地部署體驗總結 部署過程Ollama部署拉取模型運行模型Openwebui部署運行Ollama服務在Openwebui中配置ollama的服務 后話 前言 deepseek最近火的一塌糊涂&a…