当前位置: 首页 > news >正文

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);}

相关文章:

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…...

正浩创新内推:校招、社招EcoFlow社招内推码: FRQU1CY

EcoFlow社招内推码: FRQU1CY 投递链接: https://ecoflow.jobs.feishu.cn/s/Vo75bmlNr6c...

一文了解:部署 Deepseek 各版本的硬件要求

很多朋友在咨询关于 DeepSeek 模型部署所需硬件资源的需求&#xff0c;最近自己实践了一部分&#xff0c;部分信息是通过各渠道收集整理&#xff0c;so 仅供参考。 言归正转&#xff0c;大家都知道&#xff0c;DeepSeek 模型的性能在很大程度上取决于它运行的硬件。我们先看一下…...

有没有什么免费的AI工具可以帮忙做简单的ppt?

互联网各领域资料分享专区(不定期更新): Sheet 正文 1. 博思AIPPT 特点:专为中文用户设计,支持文本/文件导入生成PPT,内置海量模板和智能排版功能,涵盖商务、教育等多种场景。可一键优化布局、配色,并集成AI绘图功能(文生图/图生图)。适用场景:职场汇报、教育培训、商…...

python绘图之灰度图

灰度图&#xff08;Gray Scale Image&#xff09;是一种将图像中的像素值映射到灰度范围&#xff08;通常是0到255&#xff09;的图像表示方式。它在图像处理和计算机视觉中具有重要作用.本节学习使用python绘制灰度图 # 导入必要的库 import numpy as np import matplotlib.py…...

华为 VRP 系统简介配置SSH,TELNET远程登录

华为 VRP 系统简介&配置SSH/TELNET远程登录 1.华为 VRP 系统概述 1.1 什么是 VRP VRP&#xff08;Versatile Routing Platform 华为数通设备操作系统&#xff09;是华为公司数据通信产品的通用操作系统平台&#xff0c;从低端到核心的全系列路由器、以太网交换机、业务网…...

1.14 重叠因子:TRIMA三角移动平均线(Triangular Moving Average, TRIMA)概念与Python实战

目录 0. 本栏目因子汇总表1. 因子简述2. 因子计算逻辑3. 因子应用场景4. 因子优缺点5. 因子代码实现6. 因子取值范围及其含义7. 因子函数参数建议 0. 本栏目因子汇总表 【量海航行】 1. 因子简述 三角移动平均线(Triangular Moving Average, TRIMA)是一种特殊的加权移动平均…...

【tplink】校园网接路由器如何单独登录自己的账号,wan-lan和lan-lan区别

老式路由器TPLINK&#xff0c;接入校园网后一人登录&#xff0c;所有人都能通过连接此路由器上网&#xff0c;无法解决遂上网搜索&#xff0c;无果&#xff0c;幸而偶然看到一个帖子说要把信号源网线接入路由器lan口&#xff0c;开启新世界。 一、wan-lan&#xff0c;lan-lan区…...

PC 端连接安卓手机恢复各类数据:安装、操作步骤与实用指南

软件介绍 这款用于恢复安卓手机数据的软件&#xff0c;虽运行在 PC 端&#xff0c;却专为安卓手机数据恢复打造&#xff0c;使用时得用数据线把手机和电脑连接起来。它的功能相当强大&#xff0c;能帮你找回安卓手机里已删除的短信、联系人、通话记录、文档&#xff0c;还有照…...

【折线图 Line】——1

🌟 解锁数据可视化的魔法钥匙 —— pyecharts实战指南 🌟 在这个数据为王的时代,每一次点击、每一次交易、每一份报告背后都隐藏着无尽的故事与洞察。但你是否曾苦恼于如何将这些冰冷的数据转化为直观、吸引人的视觉盛宴? 🔥 欢迎来到《pyecharts图形绘制大师班》 �…...

SpringBoot 整合mongoDB并自定义连接池,实现多数据源配置

要想在同一个springboot项目中使用多个数据源&#xff0c;最主要是每个数据源都有自己的mongoTemplate和MongoDbFactory。mongoTemplate和MongoDbFactory是负责对数据源进行交互的并管理链接的。 spring提供了一个注解EnableMongoRepositories 用来注释在某些路径下的MongoRepo…...

TCP/IP的分层结构、各层的典型协议,以及与ISO七层模型的差别

1. TCP/IP的分层结构 TCP/IP模型是一个四层模型&#xff0c;主要用于网络通信的设计和实现。它的分层结构如下&#xff1a; (1) 应用层&#xff08;Application Layer&#xff09; 功能&#xff1a;提供应用程序之间的通信服务&#xff0c;处理特定的应用细节。 典型协议&am…...

FreeRTOS-中断管理

实验目的 创建一个队列及一个任务&#xff0c;按下按键 KEY1 触发中断&#xff0c;在中断服务函数里向队列里发送数据&#xff0c;任务则阻塞接 收队列数据。 实验代码 实验结果 这样就实现了&#xff0c;使用中断往队列的发送信息&#xff0c;用任务阻塞接收信息...

ShenNiusModularity项目源码学习(15:ShenNius.Admin.API项目分析)

ShenNius.Admin.Mvc项目是MVC模式的入口&#xff0c;ShenNius.Admin.Hosting项目是前后端分离模式的后台服务入口&#xff0c;这两个项目都依赖ShenNius.Admin.API项目&#xff0c;前者使用ShenniusAdminApiModule类注册服务及配置管道&#xff0c;而后者的webapi实现都在ShenN…...

Express + MongoDB 实现文件上传

使用 multer 中间件来处理文件上传&#xff0c;同时将文件的元数据存储到 MongoDB 中。 一、安装依赖 npm install multer 二、核心代码 // 定义文件模型const fileSchema new mongoose.Schema({originalname: String,mimetype: String,size: Number,path: String,});cons…...

计算机毕业设计SpringBoot+Vue.js作业管理系统(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

Odoo免费开源CRM技术实战:从商机线索关联转化为售后工单的应用

文 / 开源智造 Odoo金牌服务 Odoo&#xff1a;功能强大且免费开源的CRM Odoo 引入了一种高效的客户支持管理方式&#xff0c;即将 CRM 线索转换为服务台工单。此功能确保销售和支持团队能够无缝协作&#xff0c;从而提升客户满意度并缩短问题解决时间。通过整合 CRM 模块与服…...

2025年如何实现安卓、iOS、鸿蒙跨平台开发

2025年如何实现安卓、iOS、鸿蒙跨平台开发 文章目录 2025年如何实现安卓、iOS、鸿蒙跨平台开发1. 使用统一开发框架2. 华为官方工具链支持3. 代码适配策略4. 生态兼容性处理5. 性能与体验优化总结&#xff1a;方案选择建议 本文首发地址 https://h89.cn/archives/324.html 最新…...

萌新学 Python 之 os 模块

os 模块&#xff1a;主要提供程序与操作系统进行交互的接口 先导入模块&#xff1a;import os 1. os.listdir()&#xff0c;获取当前目录的文件&#xff0c;返回到列表中 2. os.mkdir(文件目录, mode 0o777)&#xff0c;创建目录&#xff0c;777 表示读写程序 在当前目录下…...

IPoIB源码深度解析:如何基于TCP/IP协议栈实现高性能InfiniBand通信

一、IPoIB的核心设计理念 IPoIB(IP over InfiniBand)是一种在InfiniBand网络上承载IP流量的技术,其核心目标是在不修改上层应用的前提下,利用InfiniBand的高带宽和低延迟特性。与自定义协议栈不同,IPoIB通过深度集成到Linux内核TCP/IP协议栈中,将InfiniBand设备抽象为标…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

YSYX学习记录(八)

C语言&#xff0c;练习0&#xff1a; 先创建一个文件夹&#xff0c;我用的是物理机&#xff1a; 安装build-essential 练习1&#xff1a; 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件&#xff0c;随机修改或删除一部分&#xff0c;之后…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现

摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序&#xff0c;以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务&#xff0c;提供稳定高效的数据处理与业务逻辑支持&#xff1b;利用 uniapp 实现跨平台前…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

aardio 自动识别验证码输入

技术尝试 上周在发学习日志时有网友提议“在网页上识别验证码”&#xff0c;于是尝试整合图像识别与网页自动化技术&#xff0c;完成了这套模拟登录流程。核心思路是&#xff1a;截图验证码→OCR识别→自动填充表单→提交并验证结果。 代码在这里 import soImage; import we…...

JS红宝书笔记 - 3.3 变量

要定义变量&#xff0c;可以使用var操作符&#xff0c;后跟变量名 ES实现变量初始化&#xff0c;因此可以同时定义变量并设置它的值 使用var操作符定义的变量会成为包含它的函数的局部变量。 在函数内定义变量时省略var操作符&#xff0c;可以创建一个全局变量 如果需要定义…...