File directory structure of GST libav
The core code of gstlibav is in the GST libav / ext / libav directory. The c files corresponding to the plugin are 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. Plugin is defined in C_ Init function, plugin_init is the entry function of libav, which is in the plugin_init will call the register function corresponding to decoder, demux and MUX
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_ Expansion of define
gst/gstplugin.h
gstav. GST of C_ PLUGIN_ Define initializes the basic information of the plugin_init is passed to GST as a parameter init_ plugin_ register_ static,gst_plugin_register_static can be seen in the following decomposition analysis.
#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)
Follow GST below_ PLUGIN_ Definition of define, before GST_ PLUGIN_ libav defined by define can be expanded in turn.
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 expansion, the first two lines declare two functions gst_plugin_libav_get_desc and gst_plugin_libav_register.
gst_plugin_desc
The middle part is about GST_ plugin_ Initialization of desc 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 is expanded 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_ Create a GObject type plugin in func through the previous gst_plugin_desc initializes and then calls 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); // Create 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 gets registry, which is actually a static global variable of type GstRegistry // gst_registry_add_plugin add this plugin to the list of registry 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_ The func() function registers the plugin, checks the version and other information, and then copies the description information about the plugin through the function pointer desc - > plugin_ Init really completes the registration of the plugin.
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_ The feature () function is similar to gst_registry_add_feature() is a method of saving a feature to a global variable_ gst_ registry_ The ` ` priv - > features member of default, while gst_registry_add_plugin will add the created plugin to and save it to_ gst_ registry_ Priv - > plugins ` member of default.
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) { // ... ... } } // When pipeline is running, grep 'adding plugin' can see the log registered by the plugin GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"", plugin, GST_STR_NULL (plugin->filename)); // Add plugin to the list of registry 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; }
log output of libav plugin:
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
The plugin parameter is in GST_ plugin_ register_ Calling plugin_ in static When using the init function,
static gboolean plugin_init (GstPlugin * plugin) { // Initialize 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 callback #ifndef GST_DISABLE_GST_DEBUG av_log_set_callback (gst_ffmpeg_log_callback); #endif // Initialize pix_fmt gst_ffmpeg_init_pix_fmt_info (); // Initialize parameters such as bitrate / GOP / max bframe / profile / level / color /* build global ffmpeg param/property info */ gst_ffmpeg_cfg_init (); // Register audio enc/video enc/audio dec/video dec/demux/mux/interlace respectively 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 whether the version of ffmpeg is valid, avcodec_version is a function in ffmpeg, which is in ffmpeg / libavcodec / avcodec In C:
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_ Expansion of register
Define typeinfo
Several function pointers for initializing typeinfo:
-
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 all demuxer s in ffmpeg
The code is as follows, av_demuxer_iterate is defined in ffmpeg / libavformat / allformats C, iterate and traverse demuxer in turn_ All demux in the list.
The whole while loop will traverse all plugin s, if register_typefind_func set to false, gst_type_find_register certainly won't come.
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 is set to FALSE without 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 to set the value of avdemux to the maximum rank value and add mov, etc rank = GST_RANK_PRIMARY + 1; } // Generate type_name. Finally, you can see avdemux through gst-inspect-1.0 | grep 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 is a function of GObject // GST_TYPE_ELEMENT is the element type returned // typeinfo is the initial 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_ When func is true, 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 associates info with node 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_ Class can be seen in the implementation of W_ Init, GST in front_ ffmpegdemux_ The three corresponding base functions in GTypeinfo defined by register at the beginning_ init = gst_ ffmpegdemux_ base_ init,class_init = gst_ffmpegdemux_class_init,instance_init = gst_ffmpegdemux_init is associated with data in this function.
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 is a union type, which can be_ ClassData, or_ InstanceData, in type_data_make_W use_ Base in GTypeInfo_ init,class_init,instance_init to assign to the corresponding item, then instance_ Where is init 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_ In instance, these belong to Glib, which is actually through g_object_new to indirectly call g_type_create_instance, the call stack is roughly as follows. See Glib's code for details:
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 demuxer in turn_ All demux in list
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 is passed in by an int * pointer, and the initial value of * quaque is 0, // Assigned to i,i points to demuxer_ The first demuxer in the list, i+1, is the second corresponding address if (f) *opaque = (void*)(i + 1); return f; }
demuxer_list
demuxer_list has more than 300 lines and defines various demux to FF_ mov_ Taking demuxer as an example, we can see that the definition of movdemux includes MOV, MP4, m4a, 3gp, 3g2 and 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
Through gst_element_register() function registers the corresponding information of the plugin into gstreamer. Through this function, you can create a type elementfactory with name and priority rank, and add elementfactory to the 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; } }