当前位置: 首页 > 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_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);
    }

相关文章:

  • Windows文件资源管理器左侧导航窗格没有WSL的Linux图标的解决方法
  • eNSP中AR2220、AR201、AR1220、AR2240、AR3260、Router、NE40E、NE5000E、NE9000、CX路由器学习笔记
  • 算法-二叉树篇15-最大二叉树
  • 蓝桥杯 路径之谜
  • spineNET模型详解及代码复现
  • 六、索引优化实战案例
  • 自然语言处理NLP入门 -- 第五节词向量与嵌入
  • 2025计算机考研复试资料(附:网课+历年复试真题+140所高校真题+机试)
  • python量化交易——金融数据管理最佳实践——qteasy创建本地数据源
  • Spring 源码硬核解析系列专题(六):Spring MVC 的请求处理源码解析
  • Python 中,将十进制整数转换为二进制
  • 机器视觉线阵相机分时频闪选型/机器视觉线阵相机分时频闪选型
  • Apollo Cyber 学习笔记
  • 数据库服务器和普通服务器之间的区别
  • [IP] DDR_FIFO(DDR3 用户FIFO接口)
  • Redis---LRU原理与算法实现
  • TCP长连接与短连接
  • Java基础关键_013_日期处理
  • STM32之影子寄存器
  • Rust学习总结之-match
  • 梭子手做鱼网站/网站开发建站
  • 企业网站的作用/免费网站在线观看人数在哪直播
  • 宁波网站建设企业/湖南seo优化推荐
  • 做外贸业务去哪些网站/百度竞价点击价格
  • 百度做网站推广多少钱/怎么免费创建网站
  • 外贸企业网站策划/推广平台的方法