一、vlc_object对象
1、vlc_object对象结构
vlc中所有对象都包含vlc_object,类似c++中的继承,都从vlc_object中继承过来,如stream_t、input_thread_t等,vlc播放环节必有的一些对象都是需要从vlc_object继承
struct vlc_object_t
{
VLC_COMMON_MEMBERS //此宏展开如下:
};
struct vlc_object_t
{
const char *psz_object_type;//对象类型
char *psz_header;
int i_flags;
bool b_force;
libvlc_int_t *p_libvlc;//指向libvlc,所有环境的根结点
vlc_object_t * p_parent;//类似qt中的父对象
};
2、vlc_object_internals_t结构
每个vlc_object_t对象创建时,都会在vlc_object_t对象的前面创建一个这样的对象,用来进行对象父子关系的管理,类似于qt中的对象树机制
struct vlc_object_internals
{
char *psz_name;// 对象名称
/* Object variables */
void *var_root;
vlc_mutex_t var_lock;
vlc_cond_t var_wait;
/* Objects thread synchronization */
int pipes[2];//管道,用来线程同步
atomic_bool alive;//管道是否激活
/* Objects management */
atomic_uint refs;//引用计数值
vlc_destructor_t pf_destructor;//释放内存回调函数
/* Objects tree structure */
vlc_object_internals_t *next; 下一个兄弟结点
vlc_object_internals_t *prev; 前一个兄弟结点
vlc_object_internals_t *first; 第一个子结点
};
3、vlc_object对象的创建
所有对象都是通过该函数创建,不同类型使用typename标识
void *vlc_custom_create (vlc_object_t *parent, size_t length,
const char *typename)
{
/* NOTE:
vlc_object_t对象创建分三步,
1紧挨着vlc_object_t对象,在它前面创建vlc_object_internals(结构体如上),
2 初始化vlc_object_t中VLC_COMMON_MEMBERS宏所包含的成员变量
3 对各个不同object对象所特有的数据进行初始化
*/
assert (length >= sizeof (vlc_object_t));
//length:object对象本身的大小,包含VLC_COMMON_MEMBERS的大小,但是不包含vlc_object_internals的大小,此时创建内存的时候,将vlc_object_internals的大小一起算进去
vlc_object_internals_t *priv = malloc (sizeof (*priv) + length);
if (unlikely(priv == NULL))
return NULL;
//对vlc_object_internals对象进行初始化
priv->psz_name = NULL;
priv->var_root = NULL;
vlc_mutex_init (&priv->var_lock);//创建互斥锁(window下是临界区),默认是递归的
vlc_cond_init (&priv->var_wait);//创建条件变量,条件变量的超时时钟使用MONOTONIC模式
priv->pipes[0] = priv->pipes[1] = -1;
atomic_init (&priv->alive, true);
atomic_init (&priv->refs, 1);
priv->pf_destructor = NULL;
priv->prev = NULL;
priv->first = NULL;
//obj为vlc_object_t 对象的首地址,开始初始化vlc_object_t 对象自己的成员变量
vlc_object_t *obj = (vlc_object_t *)(priv + 1);
obj->psz_object_type = typename;//对象名称,如"input",创建的是input_thread_t变量
obj->psz_header = NULL;
obj->b_force = false;
//obj + 1表示跳过vlc_object_t 对象,对vlc_object_t 对象后面的私有数据进行初始化为0
memset (obj + 1, 0, length - sizeof (*obj)); /* type-specific stuff */
if (likely(parent != NULL))
{
//vlc_internals这个宏是获取对象的vlc_object_internals首地址,这里是获取父对象的vlc_object_internals_t首地址
vlc_object_internals_t *papriv = vlc_internals (parent);
obj->i_flags = parent->i_flags;
obj->p_libvlc = parent->p_libvlc;
/* Attach the child to its parent (no lock needed) */
//vlc_object_hold 引用数值+1,类似c++中的智能指针share_ptr中的引用计数
obj->p_parent = vlc_object_hold (parent);
//开始建立父子兄弟关系
/* Attach the parent to its child (structure lock needed) */
libvlc_lock (obj->p_libvlc);
priv->next = papriv->first;
if (priv->next != NULL)
priv->next->prev = priv;
papriv->first = priv;
libvlc_unlock (obj->p_libvlc);
}
else
{
//如果没有父对象,则是libvlc_int_t对象
libvlc_int_t *self = (libvlc_int_t *)obj;
obj->i_flags = 0;
obj->p_libvlc = self;
obj->p_parent = NULL;
priv->next = NULL;
vlc_mutex_init (&(libvlc_priv (self)->structure_lock));
/* TODO: should be in src/libvlc.c */
int canc = vlc_savecancel ();
//创建对象树tree变量
var_Create (obj, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND);
var_AddCallback (obj, "tree", DumpCommand, obj);
//创建变量值vars
var_Create (obj, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND);
var_AddCallback (obj, "vars", DumpCommand, obj);
vlc_restorecancel (canc);
}
return obj;
}
4、vlc_object对象的释放
void vlc_object_release( vlc_object_t *p_this )
{
vlc_object_internals_t *internals = vlc_internals( p_this );
vlc_object_t *parent = NULL;
unsigned refs = atomic_load (&internals->refs);
/* Fast path */
//当refs大于1时,说明还有引用没释放,返回
while (refs > 1)
{
if (atomic_compare_exchange_weak (&internals->refs, &refs, refs - 1))
return; /* There are still other references to the object */
assert (refs > 0);
}
/* Slow path */
libvlc_lock (p_this->p_libvlc);
//引用计数-1,减成0,然后返回1
refs = atomic_fetch_sub (&internals->refs, 1);
assert (refs > 0);
if (likely(refs == 1))
{
/* Detach from parent to protect against vlc_object_find_name() */
parent = p_this->p_parent;
if (likely(parent))
{
/* Unlink */
//从对象树中将自己去掉
vlc_object_internals_t *prev = internals->prev;
vlc_object_internals_t *next = internals->next;
if (prev != NULL)
prev->next = next;
else
vlc_internals (parent)->first = next;
if (next != NULL)
next->prev = prev;
}
/* We have no children */
assert (internals->first == NULL);
}
libvlc_unlock (p_this->p_libvlc);
if (likely(refs == 1))
{
int canc = vlc_savecancel ();
//引用计数值为0了,开始释放内存
vlc_object_destroy( p_this );
vlc_restorecancel (canc);
//如过有父对象,就一直往上追寻释放,对象树内存的释放,就是先释放子结点,再释放父结点
if (parent)
vlc_object_release (parent);
}
}
5、实际内存释放函数vlc_object_destroy
static void vlc_object_destroy( vlc_object_t *p_this )
{
vlc_object_internals_t *p_priv = vlc_internals( p_this );
//通过注册的释放内存回调,释放内存
if( p_priv->pf_destructor )
p_priv->pf_destructor( p_this );
if (unlikely(p_this == VLC_OBJECT(p_this->p_libvlc)))
{
/* TODO: should be in src/libvlc.c */
var_DelCallback (p_this, "tree", DumpCommand, p_this);
var_DelCallback (p_this, "vars", DumpCommand, p_this);
}
//释放vlc_object_internals_t所对应的内存快,与vlc_custom_create创建的内存对应释放
var_DestroyAll( p_this );//释放object有关的变量
vlc_cond_destroy( &p_priv->var_wait );
vlc_mutex_destroy( &p_priv->var_lock );
free( p_this->psz_header );
free( p_priv->psz_name );
if( p_priv->pipes[1] != -1 && p_priv->pipes[1] != p_priv->pipes[0] )
close( p_priv->pipes[1] );
if( p_priv->pipes[0] != -1 )
close( p_priv->pipes[0] );
if( VLC_OBJECT(p_this->p_libvlc) == p_this )
vlc_mutex_destroy (&(libvlc_priv ((libvlc_int_t *)p_this)->structure_lock));
free( p_priv );
}
二、vlc 中的变量
vlc中变量的用处很大,到处都是变量的身影,主要用于事件的订阅与通知,每个变量可以注册多个回调函数,当变量值发生改变时,会调用注册过的回调函数,通知订阅的人有数据发生改变,这是典型的观察者模式。