gst-libav的文件目录结构
gstlibav的核心代码在gst-libav/ext/libav目录下,把plugin对应的c文件列出来有以下这么多:
gst-libav/ext/libav
├── gstavauddec.c
├── gstavaudenc.c
├── gstav.c
├── gstavdemux.c
├── gstavmux.c
├── gstavprotocol.c
├── gstavutils.c
├── gstavviddec.c
├── gstavvidenc.c
gstav.c中定义了plugin_init函数,plugin_init是libav的入口函数,在plugin_init中会调用decoder, demux, mux对应的register函数
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的展开
gst/gstplugin.h
gstav.c的GST_PLUGIN_DEFINE初始化了plugin的基本信息,把plugin_init作为参数init传给了gst_plugin_register_static,gst_plugin_register_static在后面的分解分析中可以看到。
#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宏定义
#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)
按照下面GST_PLUGIN_DEFINE的定义,前面GST_PLUGIN_DEFINE定义的libav可以依次展开。
前两个函数声明展开:
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);
展开后,前面两行声明了两个函数gst_plugin_libav_get_desc和gst_plugin_libav_register。
gst_plugin_desc
中间部分是对gst_plugin_desc结构体的初始化:
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原型
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
宏展开后如下:
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中创建GObject类型的plugin,通过前面的gst_plugin_desc初始化,然后会调用plugin_init函数
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);
// 创建plugin
plugin = g_object_new (GST_TYPE_PLUGIN, NULL);
// 调用gst_plugin_register_func
if (gst_plugin_register_func (plugin, &desc, NULL) != NULL) {
GST_INFO ("registered static plugin \"%s\"", name);
// gst_registry_get获得registry, 实际上是一个GstRegistry类型的static的全局变量
// gst_registry_add_plugin将这个plugin添加到registry的list里面
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()函数进行plugin的注册,将会检查版本之类的信息,然后拷贝关于plugin的描述信息,在通过函数指针desc->plugin_init真正的完成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调用
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调用
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()函数与gst_registry_add_feature()函数类似,gst_registry_add_feature()是将feature保存到全局变量的_gst_registry_default
的``priv->features成员,而gst_registry_add_plugin会把创建的
plugin添加到保存到_gst_registry_default的
priv->plugins`成员。
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运行的时候grep ‘adding plugin‘可以看到plugin注册的log
GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"",
plugin, GST_STR_NULL (plugin->filename));
// 添加plugin到registry的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的log输出:
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参数是在gst_plugin_register_static中调用plugin_init函数的时候,
static gboolean
plugin_init (GstPlugin * plugin)
{
// 初始化debug参数
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;
}
// 设置callback
#ifndef GST_DISABLE_GST_DEBUG
av_log_set_callback (gst_ffmpeg_log_callback);
#endif
// 初始化pix_fmt
gst_ffmpeg_init_pix_fmt_info ();
// 初始化 bitrate/gop/max-bframe/profile/level/color等参数
/* build global ffmpeg param/property info */
gst_ffmpeg_cfg_init ();
// 分别注册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
判断ffmpeg的版本是否有效,avcodec_version是ffmpeg中的函数,在ffmpeg/libavcodec/avcodec.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_register的展开
定义typeinfo
初始化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, };
注册ffmpeg中的所有demuxer
代码如下,av_demuxer_iterate定义在ffmpeg/libavformat/allformats.c中,迭代,依次遍历demuxer_list中的所有demux。
整个while循环会把所有的plugin遍历一遍,如果register_typefind_func设置为false,gst_type_find_register肯定不会走到。
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设置为FALSE,不用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") ||
// ...
) {
// 这部门代码被修改过了,把avdemux的值设置为最大的rank值,并且加上了mov等
rank = GST_RANK_PRIMARY + 1;
}
// 生成type_name,最后通过 gst-inspect-1.0 | grep avdemux就能看到像avdemux_gif,avdemux_ape等等
/* construct the type */
type_name = g_strdup_printf ("avdemux_%s", in_plugin->name);
g_strdelimit (type_name, ".,|-<> ", '_');
// 生成typefind_name,dup了in_plugin->name
typefind_name = g_strdup_printf ("avtype_%s", in_plugin->name);
g_strdelimit (typefind_name, ".,|-<> ", '_');
// g_type_register_static是GObject的一个函数
// GST_TYPE_ELEMENT是返回element type
// typeinfo是刚开始的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注册plugin
// register_typefind_func为true时,注册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);
// 这个将info和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
从type_data_make_W的实现中可以看到class_init,前面gst_ffmpegdemux_register刚开始定义的GTypeinfo中对应的三个函数base_init = gst_ffmpegdemux_base_init
、class_init = gst_ffmpegdemux_class_init
、instance_init = gst_ffmpegdemux_init
是在这个函数里面和data关联起来的。
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是一个union类型,可以是_ClassData
,也可以是_InstanceData
,在type_data_make_W用_GTypeInfo
中的base_init、class_init、instance_init来赋值给对应的项,那么instance_init是在哪里被调用的?
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
调用instance.instance_size是在g_type_create_instance中的,这些都属于Glib的内容,实际上是通过g_object_new来间接调用g_type_create_instance,调用栈大致如下,细节还得看下Glib的代码:
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
依次遍历demuxer_list中的所有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是一个int*类型的指针传进来的,*quaque初始值是0,
// 赋值给i,i指向demuxer_list中的第一个demuxer,i+1就是第二个对应的地址
if (f)
*opaque = (void*)(i + 1);
return f;
}
demuxer_list
demuxer_list有300多行,定义了各种demux,以ff_mov_demuxer为例,可以看到movdemux的定义包含了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
通过gst_element_register()函数将plugin的相应信息注册到gstreamer中,通过该函数,可以创建一个名称为name、优先级为rank的type类型elementfactory,并将elementfactory添加到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;
}
}