01-vlc-object对象

一、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中变量的用处很大,到处都是变量的身影,主要用于事件的订阅与通知,每个变量可以注册多个回调函数,当变量值发生改变时,会调用注册过的回调函数,通知订阅的人有数据发生改变,这是典型的观察者模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值