当前位置:网站首页>Initialization process of gstlibav

Initialization process of gstlibav

2022-06-25 22:44:00 Hui's technical notes

gst-libav File directory structure

gstlibav The core code is gst-libav/ext/libav Under the table of contents , hold plugin Corresponding c There are so many documents listed as follows :

gst-libav/ext/libav
├── gstavauddec.c
├── gstavaudenc.c
├── gstav.c
├── gstavdemux.c
├── gstavmux.c
├── gstavprotocol.c
├── gstavutils.c
├── gstavviddec.c
├── gstavvidenc.c

gstav.c It defines plugin_init function ,plugin_init yes libav The entry function of , stay plugin_init Will call decoder, demux, mux Corresponding register function

  plugin_init
  - gst_ffmpeg_log_callback
  - gst_ffmpeg_init_pix_fmt_info
  - gst_ffmpeg_cfg_init
  - gst_ffmpegaudenc_register
  - gst_ffmpegvidenc_register
  - gst_ffmpegauddec_register
  - gst_ffmpegviddec_register
  - gst_ffmpegdemux_register
  - gst_ffmpegmux_register
  - gst_ffmpegdeinterlace_register

GST_PLUGIN_DEFINE Expansion of

gst/gstplugin.h

gstav.c Of GST_PLUGIN_DEFINE Initialize the plugin Basic information of , hold plugin_init As a parameter init Passed on to gst_plugin_register_static,gst_plugin_register_static In the following decomposition analysis, we can see .

#define GST_VERSION_MAJOR (1)
#define GST_VERSION_MINOR (14)
#define GST_VERSION_MICRO (5) 

GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
    GST_VERSION_MINOR,
    libav,
    "All libav codecs and formats (" LIBAV_SOURCE ")",
    plugin_init, PACKAGE_VERSION, LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

GST_PLUGIN_DEFINE Macro definition

#define GST_PLUGIN_DEFINE(major,minor,name,description,init,version,license,package,origin) \
G_BEGIN_DECLS \
GST_PLUGIN_EXPORT const GstPluginDesc * G_PASTE(gst_plugin_, G_PASTE(name, _get_desc)) (void); \
GST_PLUGIN_EXPORT void G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void); \
\
static const GstPluginDesc gst_plugin_desc = { \
  major, \
  minor, \
  G_STRINGIFY(name), \
  (gchar *) description, \
  init, \
  version, \
  license, \
  PACKAGE, \
  package, \
  origin, \
  __GST_PACKAGE_RELEASE_DATETIME, \
  GST_PADDING_INIT \
};                                       \
\
const GstPluginDesc * \c++
G_PASTE(gst_plugin_, G_PASTE(name, _get_desc)) (void) \
{ \
    return &gst_plugin_desc; \
} \
\
void \
G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void) \
{ \
  gst_plugin_register_static (major, minor, G_STRINGIFY(name), \
      description, init, version, license, \
      PACKAGE, package, origin); \
} \
G_END_DECLS

gst_plugin_register_static: gstreamer/gst/gstplugin.c

gst_plugin_register_func: gstreamer/gst/gstplugin.c

G_PASTE & G_PASTE_ARGS

#define G_PASTE_ARGS(identifier1,identifier2) identifier1 ## identifier2
#define G_PASTE(identifier1,identifier2) G_PASTE_ARGS (identifier1, identifier2)

According to the following GST_PLUGIN_DEFINE The definition of , front GST_PLUGIN_DEFINE Defined libav You can expand them one by one .

The first two function declarations expand :

const GstPluginDesc * G_PASTE(gst_plugin_, G_PASTE(name, _get_desc)) (void);
\
const GstPluginDesc *G_PASTE(gst_plugin_, libav_get_desc)) (void);
\
const GstPluginDesc gst_plugin_libav_get_desc (void);
void G_PASTE(gst_plugin_, G_PASTE(name, _register)) (void);
\
void G_PASTE(gst_plugin_, libav_register) (void);

void gst_plugin_libav_register(void);

After deployment , The first two lines declare two functions gst_plugin_libav_get_desc and gst_plugin_libav_register.

gst_plugin_desc

The middle part is right gst_plugin_desc Initialization of structure :

static const GstPluginDesc gst_plugin_desc = { \
  major, \
  minor, \
  G_STRINGIFY(name), \
  (gchar *) description, \
  init, \
  version, \
  license, \
  PACKAGE, \
  package, \
  origin, \
  __GST_PACKAGE_RELEASE_DATETIME, \
  GST_PADDING_INIT \
};    

_GstPluginDesc Prototype

struct _GstPluginDesc {
    
  gint major_version;
  gint minor_version;
  const gchar *name;
  const gchar *description;
  GstPluginInitFunc plugin_init;
  const gchar *version;
  const gchar *license;
  const gchar *source;
  const gchar *package;
  const gchar *origin;
  const gchar *release_datetime;
  /*< private >*/
  gpointer _gst_reserved[GST_PADDING];
};

gst_plugin_libav_register & gst_plugin_libav_get_desc

The macro expands as follows :

const GstPluginDesc gst_plugin_libav_get_desc (void) {
    
	return &gst_plugin_desc;
}

void gst_plugin_libav_register(void) {
    
  	gst_plugin_register_static (major, minor, G_STRINGIFY(name), 
      description, init, version, license, PACKAGE, package, origin);
}

gst_plugin_register_static

gst_plugin_register_func Created in GObject Type of plugin, Through the gst_plugin_desc initialization , And then call plugin_init function

gboolean
gst_plugin_register_static (gint major_version, gint minor_version,
    const gchar * name, const gchar * description, GstPluginInitFunc init_func,
    const gchar * version, const gchar * license, const gchar * source,
    const gchar * package, const gchar * origin)
{
    
  GstPluginDesc desc = {
     major_version, minor_version, name, description,
    init_func, version, license, source, package, origin, NULL,
  };
  GstPlugin *plugin;
  gboolean res = FALSE;

  g_return_val_if_fail (name != NULL, FALSE);
  g_return_val_if_fail (description != NULL, FALSE);
  g_return_val_if_fail (init_func != NULL, FALSE);
  g_return_val_if_fail (version != NULL, FALSE);
  g_return_val_if_fail (license != NULL, FALSE);
  g_return_val_if_fail (source != NULL, FALSE);
  g_return_val_if_fail (package != NULL, FALSE);
  g_return_val_if_fail (origin != NULL, FALSE);

  /* make sure gst_init() has been called */
  g_return_val_if_fail (_gst_plugin_inited != FALSE, FALSE);

  GST_LOG ("attempting to load static plugin \"%s\" now...", name);
  //  establish plugin
  plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
    
  //  call gst_plugin_register_func
  if (gst_plugin_register_func (plugin, &desc, NULL) != NULL) {
    
    GST_INFO ("registered static plugin \"%s\"", name);

    // gst_registry_get get registry,  It's actually a GstRegistry Type of static Global variable of 
    // gst_registry_add_plugin Put this plugin Add to registry Of list Inside 
    res = gst_registry_add_plugin (gst_registry_get (), plugin);
    GST_INFO ("added static plugin \"%s\", result: %d", name, res);
  }
  return res;
}

gst_plugin_register_func

gst_plugin_register_func() Function plugin Registration of , Information such as version will be checked , Then copy about plugin Description information of , Through the function pointer desc->plugin_init Real completion plugin Registration of .

static GstPlugin *
gst_plugin_register_func (GstPlugin * plugin, const GstPluginDesc * desc,
    gpointer user_data)
{
    
  if (!gst_plugin_check_version (desc->major_version, desc->minor_version)) {
    
    if (GST_CAT_DEFAULT)
      GST_WARNING ("plugin \"%s\" has incompatible version "
          "(plugin: %d.%d, gst: %d,%d), not loading",
          GST_STR_NULL (plugin->filename), desc->major_version,
          desc->minor_version, GST_VERSION_MAJOR, GST_VERSION_MINOR);
    return NULL;
  }

  if (!desc->license || !desc->description || !desc->source ||
      !desc->package || !desc->origin) {
    
    if (GST_CAT_DEFAULT)
      GST_WARNING ("plugin \"%s\" has missing detail in GstPluginDesc, not "
          "loading", GST_STR_NULL (plugin->filename));
    return NULL;
  }

  if (!gst_plugin_check_license (desc->license)) {
    
    if (GST_CAT_DEFAULT)
      GST_WARNING ("plugin \"%s\" has invalid license \"%s\", not loading",
          GST_STR_NULL (plugin->filename), desc->license);
    return NULL;
  }

  if (GST_CAT_DEFAULT)
    GST_LOG ("plugin \"%s\" looks good", GST_STR_NULL (plugin->filename));

  gst_plugin_desc_copy (&plugin->desc, desc);

  /* make resident so we're really sure it never gets unloaded again. * Theoretically this is not needed, but practically it doesn't hurt. * And we're rather safe than sorry. */
  if (plugin->module)
    g_module_make_resident (plugin->module);

  if (user_data) {
    
    // plugin_init call 
    if (!(((GstPluginInitFullFunc) (desc->plugin_init)) (plugin, user_data))) {
    
      if (GST_CAT_DEFAULT)
        GST_WARNING ("plugin \"%s\" failed to initialise",
            GST_STR_NULL (plugin->filename));
      return NULL;
    }
  } else {
    
    // plugin_init call 
    if (!((desc->plugin_init) (plugin))) {
    
      if (GST_CAT_DEFAULT)
        GST_WARNING ("plugin \"%s\" failed to initialise",
            GST_STR_NULL (plugin->filename));
      return NULL;
    }
  }

  if (GST_CAT_DEFAULT)
    GST_LOG ("plugin \"%s\" initialised", GST_STR_NULL (plugin->filename));

  return plugin;
}

gst_registry_add_plugin

gst_registry_add_plugin() Function and gst_registry_add_feature() Function similar to ,gst_registry_add_feature() Yes, it will feature Saved to the global variable _gst_registry_default Of ``priv->features member , and gst_registry_add_plugin Will create plugin Add to save to _gst_registry_default Of priv->plugins` member .

gboolean
gst_registry_add_plugin (GstRegistry * registry, GstPlugin * plugin)
{
    
  GstPlugin *existing_plugin;

  g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
  g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);

  GST_OBJECT_LOCK (registry);
  if (G_LIKELY (plugin->basename)) {
    
    /* we have a basename, see if we find the plugin */
    existing_plugin =
        gst_registry_lookup_bn_locked (registry, plugin->basename);
    if (existing_plugin) {
    
       // ... ...
    }
  }

  // pipeline When it's running grep ‘adding plugin‘ You can see plugin Registered log
  GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"",
      plugin, GST_STR_NULL (plugin->filename));

  //  add to plugin To registry Of list
  registry->priv->plugins = g_list_prepend (registry->priv->plugins, plugin);
  ++registry->priv->n_plugins;

  if (G_LIKELY (plugin->basename))
    g_hash_table_replace (registry->priv->basename_hash, plugin->basename,
        plugin);

  gst_object_ref_sink (plugin);
  GST_OBJECT_UNLOCK (registry);

  GST_LOG_OBJECT (registry, "emitting plugin-added for filename \"%s\"",
      GST_STR_NULL (plugin->filename));
  g_signal_emit (registry, gst_registry_signals[PLUGIN_ADDED], 0, plugin);

  return TRUE;
}

libav plugin Of log Output :

grep 'adding plugin' pipeline.log

adding plugin 0x55fdcb68d190 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstx265.so"
adding plugin 0x55fdcb68d2c0 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgsttimecode.so"
adding plugin 0x55fdcb68d3f0 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstinterlace.so"
adding plugin 0x55fdcb68d520 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstdc1394.so"
adding plugin 0x55fdcb68d650 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstde265.so"
adding plugin 0x55fdcb68d780 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstadpcmdec.so"
adding plugin 0x55fdcb68d8b0 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfaad.so"
adding plugin 0x55fdcb68d9e0 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstvcdsrc.so"
adding plugin 0x55fdcb68db10 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfrei0r.so"
adding plugin 0x55fdcb68dc40 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfieldanalysis.so"
adding plugin 0x55fdcb68dd70 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstasf.so"
adding plugin 0x55fdcb68dea0 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstopenglmixers.so"
adding plugin 0x55fdcb697060 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstwaylandsink.so"
adding plugin 0x55fdcb697190 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfbdevsink.so"
adding plugin 0x55fdcb6972c0 for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstuvch264.so"


grep 'plugin-added' pipeline.log
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstx265.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgsttimecode.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstinterlace.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstdc1394.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstde265.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstadpcmdec.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfaad.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstvcdsrc.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfrei0r.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstfieldanalysis.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstasf.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstopenglmixers.so"
emitting plugin-added for filename "/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstwaylandsink.so"

plugin_init

plugin The parameter is gst_plugin_register_static Call in plugin_init Function ,

static gboolean
plugin_init (GstPlugin * plugin)
{
    
  //  initialization debug Parameters 
  GST_DEBUG_CATEGORY_INIT (ffmpeg_debug, "libav", 0, "libav elements");

  /* Bail if not FFmpeg. We can no longer ensure operation with Libav */
  if (!gst_ffmpeg_avcodec_is_ffmpeg ()) {
    
    GST_ERROR_OBJECT (plugin,
        "Incompatible, non-FFmpeg libavcodec/format found");
    return FALSE;
  }
    
  //  Set up callback
#ifndef GST_DISABLE_GST_DEBUG
  av_log_set_callback (gst_ffmpeg_log_callback);
#endif

  //  initialization pix_fmt
  gst_ffmpeg_init_pix_fmt_info ();

  //  initialization  bitrate/gop/max-bframe/profile/level/color Equal parameter 
  /* build global ffmpeg param/property info */
  gst_ffmpeg_cfg_init ();

  //  Register separately audio enc/video enc/audio dec/video dec/demux/mux/interlace
  gst_ffmpegaudenc_register (plugin);
  gst_ffmpegvidenc_register (plugin);
  gst_ffmpegauddec_register (plugin);
  gst_ffmpegviddec_register (plugin);
  gst_ffmpegdemux_register (plugin);
  gst_ffmpegmux_register (plugin);
  gst_ffmpegdeinterlace_register (plugin);

  /* Now we can return the pointer to the newly created Plugin object. */
  return TRUE;
}

gst_ffmpeg_avcodec_is_ffmpeg

Judge ffmpeg Whether the version of is valid ,avcodec_version yes ffmpeg The function in , stay ffmpeg/libavcodec/avcodec.c in :

static inline gboolean
gst_ffmpeg_avcodec_is_ffmpeg (void)
{
    
  guint av_version = avcodec_version ();

  GST_DEBUG ("Using libavcodec version %d.%d.%d",
      av_version >> 16, (av_version & 0x00ff00) >> 8, av_version & 0xff);

  /* FFmpeg *_MICRO versions start at 100 and Libav's at 0 */
  if ((av_version & 0xff) < 100)
    return FALSE;

  return TRUE;
}

gst_ffmpegdemux_register Expansion of

Definition typeinfo

initialization typeinfo Several function pointers to :

  • base_init = gst_ffmpegdemux_base_init

  • class_init = gst_ffmpegdemux_class_init

  • instance_init = gst_ffmpegdemux_init

      GTypeInfo typeinfo = {
          
        sizeof (GstFFMpegDemuxClass),
        (GBaseInitFunc) gst_ffmpegdemux_base_init,
        NULL,
        (GClassInitFunc) gst_ffmpegdemux_class_init,
        NULL,
        NULL,
        sizeof (GstFFMpegDemux),
        0,
        (GInstanceInitFunc) gst_ffmpegdemux_init,
      };
    

register ffmpeg All in demuxer

The code is as follows ,av_demuxer_iterate It's defined in ffmpeg/libavformat/allformats.c in , iteration , Traverse in turn demuxer_list All in demux.

Whole while The loop will take all plugin Go through it , If register_typefind_func Set to false,gst_type_find_register Certainly not .

while ((in_plugin = av_demuxer_iterate (&i))) {
    
    /* Don't use the typefind functions of formats for which we already have * better typefind functions */
    if (!strcmp (in_plugin->name, "mov,mp4,m4a,3gp,3g2,mj2") ||
        !strcmp (in_plugin->name, "ass") ||
        // ...
        ) {
    
        // typefind Set to FALSE, no need libav
        register_typefind_func = FALSE;
    }
    
    /* Set the rank of demuxers known to work to MARGINAL. * Set demuxers for which we already have another implementation to NONE * Set All others to NONE*/
    if (!strcmp(in_plugin->name, "mov,mp4,m4a,3gp,3g2,mj2") ||
        !strcmp(in_plugin->name, "matroska,webm") ||
        !strcmp(in_plugin->name, "mpegts") ||
        !strcmp(in_plugin->name, "flv") ||
        // ...
        ) {
    
        //  The code of this department has been modified , hold avdemux The value of is set to the maximum rank value , And added mov etc. 
        rank = GST_RANK_PRIMARY + 1;
    }
    
    //  Generate type_name, Finally through  gst-inspect-1.0 | grep avdemux You can see things like avdemux_gif,avdemux_ape wait 
    /* construct the type */
    type_name = g_strdup_printf ("avdemux_%s", in_plugin->name);
    g_strdelimit (type_name, ".,|-<> ", '_');
    
    
    //  Generate typefind_name,dup 了 in_plugin->name
    typefind_name = g_strdup_printf ("avtype_%s", in_plugin->name);
    g_strdelimit (typefind_name, ".,|-<> ", '_');

    // g_type_register_static yes GObject A function of 
    // GST_TYPE_ELEMENT Is to return element type
    // typeinfo It was just the beginning typeinfo
    /* create the type now */
    type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
    g_type_set_qdata (type, GST_FFDEMUX_PARAMS_QDATA, (gpointer) in_plugin);
    
    // gst_element_register register plugin
    // register_typefind_func by true when , register type_find
    if (!gst_element_register (plugin, type_name, rank, type) ||
        (register_typefind_func == TRUE &&
            !gst_type_find_register (plugin, typefind_name, rank,
                gst_ffmpegdemux_type_find, extensions, NULL,
                (gpointer) in_plugin, NULL))) {
    
      g_warning ("Registration of type %s failed", type_name);
      g_free (type_name);
      g_free (typefind_name);
      g_free (extensions);
      return FALSE;
    }
}

g_type_register_static

gobject/gtype.c

GType
g_type_register_static (GType            parent_type,
			const gchar     *type_name,
			const GTypeInfo *info,
			GTypeFlags	 flags)
{
    
  TypeNode *pnode, *node;
  GType type = 0;
  
  g_assert_type_system_initialized ();
  g_return_val_if_fail (parent_type > 0, 0);
  g_return_val_if_fail (type_name != NULL, 0);
  g_return_val_if_fail (info != NULL, 0);
  
  if (!check_type_name_I (type_name) ||
      !check_derivation_I (parent_type, type_name))
    return 0;
  if (info->class_finalize)
    {
    
      g_warning ("class finalizer specified for static type '%s'",
		 type_name);
      return 0;
    }
  
  pnode = lookup_type_node_I (parent_type);
  G_WRITE_LOCK (&type_rw_lock);
  type_data_ref_Wm (pnode);
  if (check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (pnode), type_name, info))
    {
    
      node = type_node_new_W (pnode, type_name, NULL);
      type_add_flags_W (node, flags);
      type = NODE_TYPE (node);
      //  This will info and node Connect 
      type_data_make_W (node, info,
			check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);
    }
  G_WRITE_UNLOCK (&type_rw_lock);
  
  return type;
}

type_data_make_W

from type_data_make_W You can see in the implementation of class_init, front gst_ffmpegdemux_register Just beginning to define GTypeinfo The corresponding three functions in base_init = gst_ffmpegdemux_base_initclass_init = gst_ffmpegdemux_class_initinstance_init = gst_ffmpegdemux_init Is in this function and data Related to .

struct _GTypeInfo
{
    
  /* interface types, classed types, instantiated types */
  guint16                class_size;
  
  GBaseInitFunc          base_init;
  GBaseFinalizeFunc      base_finalize;
  
  /* interface types, classed types, instantiated types */
  GClassInitFunc         class_init;
  GClassFinalizeFunc     class_finalize;
  gconstpointer          class_data;
  
  /* instantiated types */
  guint16                instance_size;
  guint16                n_preallocs;
  GInstanceInitFunc      instance_init;
  
  /* value handling */
  const GTypeValueTable	*value_table;
};
union _TypeData
{
    
  CommonData         common;
  BoxedData          boxed;
  IFaceData          iface;
  ClassData          class;
  InstanceData       instance;
};
struct _InstanceData
{
    
  CommonData         common;
  guint16            class_size;
  guint16            class_private_size;
  int volatile       init_state; /* atomic - g_type_class_ref reads it unlocked */
  GBaseInitFunc      class_init_base;
  GBaseFinalizeFunc  class_finalize_base;
  GClassInitFunc     class_init;
  GClassFinalizeFunc class_finalize;
  gconstpointer      class_data;
  gpointer           class;
  guint16            instance_size;
  guint16            private_size;
  guint16            n_preallocs;
  GInstanceInitFunc  instance_init;
};
struct _ClassData
{
    
  CommonData         common;
  guint16            class_size;
  guint16            class_private_size;
  int volatile       init_state; /* atomic - g_type_class_ref reads it unlocked */
  GBaseInitFunc      class_init_base;
  GBaseFinalizeFunc  class_finalize_base;
  GClassInitFunc     class_init;
  GClassFinalizeFunc class_finalize;
  gconstpointer      class_data;
  gpointer           class;
};

TypeData It's a union type , It can be _ClassData, It can also be _InstanceData, stay type_data_make_W use _GTypeInfo Medium base_init、class_init、instance_init To assign a value to the corresponding item , that instance_init Where is it called ?

static void
type_data_make_W (TypeNode              *node,
		  const GTypeInfo       *info,
		  const GTypeValueTable *value_table)
{
    
  TypeData *data;
  GTypeValueTable *vtable = NULL;
  guint vtable_size = 0;
  
  g_assert (node->data == NULL && info != NULL);
  
  if (!value_table)
    {
    
      TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));
      
      if (pnode)
	vtable = pnode->data->common.value_table;
      else
	{
    
	  static const GTypeValueTable zero_vtable = {
     NULL, };
	  
	  value_table = &zero_vtable;
	}
    }
  if (value_table)
    {
    
      /* need to setup vtable_size since we have to allocate it with data in one chunk */
      vtable_size = sizeof (GTypeValueTable);
      if (value_table->collect_format)
	vtable_size += strlen (value_table->collect_format);
      if (value_table->lcopy_format)
	vtable_size += strlen (value_table->lcopy_format);
      vtable_size += 2;
    }
   
  if (node->is_instantiatable) /* careful, is_instantiatable is also is_classed */
    {
    
      TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));

      data = g_malloc0 (sizeof (InstanceData) + vtable_size);
      if (vtable_size)
	vtable = G_STRUCT_MEMBER_P (data, sizeof (InstanceData));
      data->instance.class_size = info->class_size;
      data->instance.class_init_base = info->base_init;
      data->instance.class_finalize_base = info->base_finalize;
      data->instance.class_init = info->class_init;
      data->instance.class_finalize = info->class_finalize;
      data->instance.class_data = info->class_data;
      data->instance.class = NULL;
      data->instance.init_state = UNINITIALIZED;
      data->instance.instance_size = info->instance_size;
      /* We'll set the final value for data->instance.private size * after the parent class has been initialized */
      data->instance.private_size = 0;
      data->instance.class_private_size = 0;
      if (pnode)
        data->instance.class_private_size = pnode->data->instance.class_private_size;
      data->instance.n_preallocs = MIN (info->n_preallocs, 1024);
      data->instance.instance_init = info->instance_init;
    }
  else if (node->is_classed) /* only classed */
    {
    
      TypeNode *pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));

      data = g_malloc0 (sizeof (ClassData) + vtable_size);
      if (vtable_size)
	vtable = G_STRUCT_MEMBER_P (data, sizeof (ClassData));
      data->class.class_size = info->class_size;
      data->class.class_init_base = info->base_init;
      data->class.class_finalize_base = info->base_finalize;
      data->class.class_init = info->class_init;
      data->class.class_finalize = info->class_finalize;
      data->class.class_data = info->class_data;
      data->class.class = NULL;
      data->class.class_private_size = 0;
      if (pnode)
        data->class.class_private_size = pnode->data->class.class_private_size;
      data->class.init_state = UNINITIALIZED;
    }
  else if (NODE_IS_IFACE (node))
    {
    
      data = g_malloc0 (sizeof (IFaceData) + vtable_size);
      if (vtable_size)
	vtable = G_STRUCT_MEMBER_P (data, sizeof (IFaceData));
      data->iface.vtable_size = info->class_size;
      data->iface.vtable_init_base = info->base_init;
      data->iface.vtable_finalize_base = info->base_finalize;
      data->iface.dflt_init = info->class_init;
      data->iface.dflt_finalize = info->class_finalize;
      data->iface.dflt_data = info->class_data;
      data->iface.dflt_vtable = NULL;
    }
  else if (NODE_IS_BOXED (node))
    {
    
      data = g_malloc0 (sizeof (BoxedData) + vtable_size);
      if (vtable_size)
	vtable = G_STRUCT_MEMBER_P (data, sizeof (BoxedData));
    }
  else
    {
    
      data = g_malloc0 (sizeof (CommonData) + vtable_size);
      if (vtable_size)
	vtable = G_STRUCT_MEMBER_P (data, sizeof (CommonData));
    }
  
  node->data = data;
  
  if (vtable_size)
    {
    
      gchar *p;
      
      /* we allocate the vtable and its strings together with the type data, so * children can take over their parent's vtable pointer, and we don't * need to worry freeing it or not when the child data is destroyed */
      *vtable = *value_table;
      p = G_STRUCT_MEMBER_P (vtable, sizeof (*vtable));
      p[0] = 0;
      vtable->collect_format = p;
      if (value_table->collect_format)
	{
    
	  strcat (p, value_table->collect_format);
	  p += strlen (value_table->collect_format);
	}
      p++;
      p[0] = 0;
      vtable->lcopy_format = p;
      if (value_table->lcopy_format)
	strcat  (p, value_table->lcopy_format);
    }
  node->data->common.value_table = vtable;
  node->mutatable_check_cache = (node->data->common.value_table->value_init != NULL &&
				 !((G_TYPE_FLAG_VALUE_ABSTRACT | G_TYPE_FLAG_ABSTRACT) &
				   GPOINTER_TO_UINT (type_get_qdata_L (node, static_quark_type_flags))));
  
  g_assert (node->data->common.value_table != NULL); /* paranoid */

  g_atomic_int_set ((int *) &node->ref_count, 1);
}

g_type_create_instance

gobject/gtype.c

call instance.instance_size Is in g_type_create_instance Medium , These belong to Glib The content of , In fact, by g_object_new To call indirectly g_type_create_instance, The call stack is roughly as follows , I have to look at the details Glib Code for :

g_object_new
	- g_object_new_internal
		- g_type_create_instance
GTypeInstance*
g_type_create_instance (GType type)
{
    
  TypeNode *node;
  GTypeInstance *instance;
  GTypeClass *class;
  gchar *allocated;
  gint private_size;
  gint ivar_size;
  guint i;

  node = lookup_type_node_I (type);
  if (!node || !node->is_instantiatable)
    {
    
      g_error ("cannot create new instance of invalid (non-instantiatable) type '%s'",
		 type_descriptive_name_I (type));
    }
  /* G_TYPE_IS_ABSTRACT() is an external call: _U */
  if (!node->mutatable_check_cache && G_TYPE_IS_ABSTRACT (type))
    {
    
      g_error ("cannot create instance of abstract (non-instantiatable) type '%s'",
		 type_descriptive_name_I (type));
    }
  
  class = g_type_class_ref (type);

  /* We allocate the 'private' areas before the normal instance data, in * reverse order. This allows the private area of a particular class * to always be at a constant relative address to the instance data. * If we stored the private data after the instance data this would * not be the case (since a subclass that added more instance * variables would push the private data further along). * * This presents problems for valgrindability, of course, so we do a * workaround for that case. We identify the start of the object to * valgrind as an allocated block (so that pointers to objects show up * as 'reachable' instead of 'possibly lost'). We then add an extra * pointer at the end of the object, after all instance data, back to * the start of the private area so that it is also recorded as * reachable. We also add extra private space at the start because * valgrind doesn't seem to like us claiming to have allocated an * address that it saw allocated by malloc(). */
  private_size = node->data->instance.private_size;
  ivar_size = node->data->instance.instance_size;

#ifdef ENABLE_VALGRIND
  if (private_size && RUNNING_ON_VALGRIND)
    {
    
      private_size += ALIGN_STRUCT (1);

      /* Allocate one extra pointer size... */
      allocated = g_slice_alloc0 (private_size + ivar_size + sizeof (gpointer));
      /* ... and point it back to the start of the private data. */
      *(gpointer *) (allocated + private_size + ivar_size) = allocated + ALIGN_STRUCT (1);

      /* Tell valgrind that it should treat the object itself as such */
      VALGRIND_MALLOCLIKE_BLOCK (allocated + private_size, ivar_size + sizeof (gpointer), 0, TRUE);
      VALGRIND_MALLOCLIKE_BLOCK (allocated + ALIGN_STRUCT (1), private_size - ALIGN_STRUCT (1), 0, TRUE);
    }
  else
#endif
    allocated = g_slice_alloc0 (private_size + ivar_size);

  instance = (GTypeInstance *) (allocated + private_size);

  for (i = node->n_supers; i > 0; i--)
    {
    
      TypeNode *pnode;
      
      pnode = lookup_type_node_I (node->supers[i]);
      if (pnode->data->instance.instance_init)
	{
    
	  instance->g_class = pnode->data->instance.class;
	  pnode->data->instance.instance_init (instance, class);
	}
    }

  instance->g_class = class;
  if (node->data->instance.instance_init)
    node->data->instance.instance_init (instance, class);

#ifdef G_ENABLE_DEBUG
  IF_DEBUG (INSTANCE_COUNT)
    {
    
      g_atomic_int_inc ((int *) &node->instance_count);
    }
#endif

  TRACE(GOBJECT_OBJECT_NEW(instance, type));

  return instance;
}

av_demuxer_iterate

Traverse in turn demuxer_list All in demux

miui12-q-cas-stable.xmlconst AVInputFormat *av_demuxer_iterate(void **opaque)
{
    
    static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1;
    uintptr_t i = (uintptr_t)*opaque;
    const AVInputFormat *f = NULL;

    if (i < size) {
    
        f = demuxer_list[i];
    } else if (indev_list) {
    
        f = indev_list[i - size];
    }

    // opaque It's a int* A pointer to a type is passed in ,*quaque The initial value is 0,
    //  Assign a value to i,i Point to demuxer_list The first of demuxer,i+1 Is the second corresponding address 
    if (f)
        *opaque = (void*)(i + 1);
    return f;
}

demuxer_list

demuxer_list Yes 300 Multiple lines , A variety of definitions are given demux, With ff_mov_demuxer For example , You can see movdemux The definition of includes mov,mp4,m4a,3gp,3g2,mj2

static const AVInputFormat * const demuxer_list[] = {
    
    &ff_aa_demuxer,
    &ff_aac_demuxer,
    &ff_aax_demuxer,
    &ff_ac3_demuxer,
    &ff_ace_demuxer,
    &ff_acm_demuxer,
    // ...
};

ff_mov_demuxer

AVInputFormat ff_mov_demuxer = {
    
    .name           = "mov,mp4,m4a,3gp,3g2,mj2",
    .long_name      = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
    .priv_class     = &mov_class,
    .priv_data_size = sizeof(MOVContext),
    .extensions     = "mov,mp4,m4a,3gp,3g2,mj2,psp,m4b,ism,ismv,isma,f4v",
    .read_probe     = mov_probe,
    .read_header    = mov_read_header,
    .read_packet    = mov_read_packet,
    .read_close     = mov_read_close,
    .read_seek      = mov_read_seek,
    .flags          = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS,
};

gst_element_register

adopt gst_element_register() Function will plugin The corresponding information of is registered to gstreamer in , Through this function , You can create one named name、 The priority for rank Of type type elementfactory, And will elementfactory Add to registry.

gboolean
gst_element_register (GstPlugin * plugin, const gchar * name, guint rank,
    GType type)
{
    
  GstPluginFeature *existing_feature;
  GstRegistry *registry;
  GstElementFactory *factory;
  GType *interfaces;
  guint n_interfaces, i;
  GstElementClass *klass;
  GList *item;

  g_return_val_if_fail (name != NULL, FALSE);
  g_return_val_if_fail (g_type_is_a (type, GST_TYPE_ELEMENT), FALSE);

  registry = gst_registry_get ();

  /* check if feature already exists, if it exists there is no need to update it * when the registry is getting updated, outdated plugins and all their * features are removed and readded. */
  existing_feature = gst_registry_lookup_feature (registry, name);
  if (existing_feature && existing_feature->plugin == plugin) {
    
    GST_DEBUG_OBJECT (registry, "update existing feature %p (%s)",
        existing_feature, name);
    factory = GST_ELEMENT_FACTORY_CAST (existing_feature);
    factory->type = type;
    existing_feature->loaded = TRUE;
    g_type_set_qdata (type, __gst_elementclass_factory, factory);
    gst_object_unref (existing_feature);
    return TRUE;
  } else if (existing_feature) {
    
    gst_object_unref (existing_feature);
  }

  factory = g_object_new (GST_TYPE_ELEMENT_FACTORY, NULL);
  gst_plugin_feature_set_name (GST_PLUGIN_FEATURE_CAST (factory), name);
  GST_LOG_OBJECT (factory, "Created new elementfactory for type %s",
      g_type_name (type));

  /* provide info needed during class structure setup */
  g_type_set_qdata (type, __gst_elementclass_factory, factory);
  klass = GST_ELEMENT_CLASS (g_type_class_ref (type));

  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_LONGNAME);
  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_KLASS);
  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_DESCRIPTION);
  CHECK_METADATA_FIELD (klass, name, GST_ELEMENT_METADATA_AUTHOR);

  factory->type = type;
  factory->metadata = gst_structure_copy ((GstStructure *) klass->metadata);

  for (item = klass->padtemplates; item; item = item->next) {
    
    GstPadTemplate *templ = item->data;
    GstStaticPadTemplate *newt;
    gchar *caps_string = gst_caps_to_string (templ->caps);

    newt = g_slice_new (GstStaticPadTemplate);
    newt->name_template = g_intern_string (templ->name_template);
    newt->direction = templ->direction;
    newt->presence = templ->presence;
    newt->static_caps.caps = NULL;
    newt->static_caps.string = g_intern_string (caps_string);
    factory->staticpadtemplates =
        g_list_append (factory->staticpadtemplates, newt);

    g_free (caps_string);
  }
  factory->numpadtemplates = klass->numpadtemplates;

  /* special stuff for URI handling */
  if (g_type_is_a (type, GST_TYPE_URI_HANDLER)) {
    
    GstURIHandlerInterface *iface = (GstURIHandlerInterface *)
        g_type_interface_peek (klass, GST_TYPE_URI_HANDLER);

    if (!iface || !iface->get_type || !iface->get_protocols)
      goto urierror;
    if (iface->get_type)
      factory->uri_type = iface->get_type (factory->type);
    if (!GST_URI_TYPE_IS_VALID (factory->uri_type))
      goto urierror;
    if (iface->get_protocols) {
    
      const gchar *const *protocols;

      protocols = iface->get_protocols (factory->type);
      factory->uri_protocols = g_strdupv ((gchar **) protocols);
    }
    if (!factory->uri_protocols)
      goto urierror;
  }

  interfaces = g_type_interfaces (type, &n_interfaces);
  for (i = 0; i < n_interfaces; i++) {
    
    __gst_element_factory_add_interface (factory, g_type_name (interfaces[i]));
  }
  g_free (interfaces);

  if (plugin && plugin->desc.name) {
    
    GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = plugin->desc.name;
    GST_PLUGIN_FEATURE_CAST (factory)->plugin = plugin;
    g_object_add_weak_pointer ((GObject *) plugin,
        (gpointer *) & GST_PLUGIN_FEATURE_CAST (factory)->plugin);
  } else {
    
    GST_PLUGIN_FEATURE_CAST (factory)->plugin_name = "NULL";
    GST_PLUGIN_FEATURE_CAST (factory)->plugin = NULL;
  }
  gst_plugin_feature_set_rank (GST_PLUGIN_FEATURE_CAST (factory), rank);
  GST_PLUGIN_FEATURE_CAST (factory)->loaded = TRUE;

  gst_registry_add_feature (registry, GST_PLUGIN_FEATURE_CAST (factory));

  return TRUE;

  /* ERRORS */
urierror:
  {
    
    GST_WARNING_OBJECT (factory, "error with uri handler!");
    gst_element_factory_cleanup (factory);
    return FALSE;
  }

detailserror:
  {
    
    gst_element_factory_cleanup (factory);
    return FALSE;
  }
}

原网站

版权声明
本文为[Hui's technical notes]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202180948019715.html