02.vlc 变量.md

一、变量结构variable_t

struct variable_t
{
    char *       psz_name; /**< The variable unique name (must be first) */
    /** The variable's exported value */
    vlc_value_t  val;//变量真正的值,可以是int、bool、float等
    /** The variable display name, mainly for use by the interfaces */
    char *       psz_text;//变量显示名称,主要用于界面
    const variable_ops_t *ops;//变量的操作函数,比较、拷贝、释放
    int          i_type;   /**< The type of the variable */
    unsigned     i_usage;  //引用计数值
    /** If the variable has min/max/step values */
    vlc_value_t  min, max, step;//范围值
    /** List of choices */
    vlc_list_t   choices;
    /** List of friendly names for the choices */
    vlc_list_t   choices_text;
    /** Set to TRUE if the variable is in a callback */
    bool   b_incallback;//变量在执行回调中
        /** Registered value callbacks */
        callback_table_t    value_callbacks;//注册的回调函数
        /** Registered list callbacks */
        callback_table_t    list_callbacks;
};

二、变量的创建

每个object对象创建的时候,都会创建一些变量属性,变量var与对象object的关联关系保存在vlc_object_internals结构中的二叉树var_root中。

int var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
{
    assert( p_this );
            //创建变量内存
    variable_t *p_var = calloc( 1, sizeof( *p_var ) );
    if( p_var == NULL )
        return VLC_ENOMEM;
            //对变量进行初始化
    p_var->psz_name = strdup( psz_name );
    p_var->psz_text = NULL;
    p_var->i_type = i_type & ~VLC_VAR_DOINHERIT;
    p_var->i_usage = 1;
   
    p_var->choices.i_count = 0;
    p_var->choices.p_values = NULL;
    p_var->choices_text.i_count = 0;
    p_var->choices_text.p_values = NULL;
    p_var->b_incallback = false;
    p_var->value_callbacks = (callback_table_t){ 0, NULL };
    /* Always initialize the variable, even if it is a list variable; this
     * will lead to errors if the variable is not initialized, but it will
     * not cause crashes in the variable handling. */
        //不同类型的变量的初始化
switch( i_type & VLC_VAR_CLASS )
    {
        case VLC_VAR_BOOL:
            p_var->ops = &bool_ops;
            p_var->val.b_bool = false;
            break;
        case VLC_VAR_INTEGER:
            p_var->ops = &int_ops;
            p_var->val.i_int = 0;
            p_var->min.i_int = INT64_MIN;
            p_var->max.i_int = INT64_MAX;
            break;
        case VLC_VAR_STRING:
            p_var->ops = &string_ops;
            p_var->val.psz_string = NULL;
            break;
        case VLC_VAR_FLOAT:
            p_var->ops = &float_ops;
            p_var->val.f_float = 0.f;
            p_var->min.f_float = -FLT_MAX;
            p_var->max.f_float = FLT_MAX;
            break;
        case VLC_VAR_COORDS:
            p_var->ops = &coords_ops;
            p_var->val.coords.x = p_var->val.coords.y = 0;
            break;
        case VLC_VAR_ADDRESS:
            p_var->ops = &addr_ops;
            p_var->val.p_address = NULL;
            break;
        case VLC_VAR_VOID:
            p_var->ops = &void_ops;
            break;
        default:
            vlc_assert_unreachable ();
    }
    if (i_type & VLC_VAR_DOINHERIT)
        var_Inherit(p_this, psz_name, i_type, &p_var->val);
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
    variable_t **pp_var, *p_oldvar;
    int ret = VLC_SUCCESS;
    vlc_mutex_lock( &p_priv->var_lock );
    pp_var = tsearch( p_var, &p_priv->var_root, varcmp );
    if( unlikely(pp_var == NULL) )
        ret = VLC_ENOMEM;
    else if( (p_oldvar = *pp_var) == p_var ) /* Variable create */
        p_var = NULL; /* Variable created */
    else /* Variable already exists */
    {
        assert (((i_type ^ p_oldvar->i_type) & VLC_VAR_CLASS) == 0);
        p_oldvar->i_usage++;
        p_oldvar->i_type |= i_type & VLC_VAR_ISCOMMAND;
    }
    vlc_mutex_unlock( &p_priv->var_lock );
    /* If we did not need to create a new variable, free everything... */
    if( p_var != NULL )
        Destroy( p_var );
    return ret;
}

三、变量的赋值和获取

变量的赋值都会调用var_SetChecked函数,只是不同类型的变量会在这个函数上面封装一层,如int类型:

static inline int var_SetInteger( vlc_object_t *p_obj, const char *psz_name,
                                  int64_t i )
{
    vlc_value_t val;
    val.i_int = i;
    return var_SetChecked( p_obj, psz_name, VLC_VAR_INTEGER, val );
}

var_SetChecked实际如下:

int var_SetChecked( vlc_object_t *p_this, const char *psz_name,
                    int expected_type, vlc_value_t val )
{
    int i_ret = VLC_SUCCESS;
    variable_t *p_var;
    vlc_value_t oldval;
    assert( p_this );
     //从对象中获取变量树,并中二叉树中找出变量指针
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
    vlc_mutex_lock( &p_priv->var_lock );
    p_var = Lookup( p_this, psz_name );
    if( p_var == NULL )
    {
        vlc_mutex_unlock( &p_priv->var_lock );
        return VLC_ENOVAR;
    }
    assert( expected_type == 0 ||
            (p_var->i_type & VLC_VAR_CLASS) == expected_type );
    assert ((p_var->i_type & VLC_VAR_CLASS) != VLC_VAR_VOID);
    //等待,直到变量不是在回调中
    WaitUnused( p_this, p_var );
    //将传入的值赋值给变量
    p_var->ops->pf_dup( &val );
    /* Backup needed stuff */
    oldval = p_var->val;
    //检测val值的范围是否越界,进行修正
    CheckValue( p_var, &val );
    //设置变量值
    p_var->val = val;
    /* Deal with callbacks */
    i_ret = TriggerCallback( p_this, p_var, psz_name, oldval );
    //释放老的变量值
    p_var->ops->pf_free( &oldval );
    vlc_mutex_unlock( &p_priv->var_lock );
    return i_ret;
}

执行变量已注册的回调函数

static int TriggerCallback( vlc_object_t *p_this, variable_t *p_var,
                            const char *psz_name, vlc_value_t oldval )
{
    assert( p_this );
    int i_entries = p_var->i_entries;
    if( i_entries == 0 )
        return VLC_SUCCESS;
    callback_entry_t *p_entries = p_var->p_entries;
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
    assert( !p_var->b_incallback );
    p_var->b_incallback = true;//这个值与上面对应,当两个线程同时需要使用该变量时,会通过b_incallback来等待回调执行完毕
    vlc_mutex_unlock( &p_priv->var_lock );
    /* The real calls */
    for( ; i_entries-- ; )
    {
        p_entries[i_entries].pf_callback( p_this, psz_name, oldval, p_var->val,
                                          p_entries[i_entries].p_data );
    }
    vlc_mutex_lock( &p_priv->var_lock );
    p_var->b_incallback = false;
    vlc_cond_broadcast( &p_priv->var_wait );//通知回调执行完成,变量可以使用了
    return VLC_SUCCESS;
}

变量值的获取使用同样的方式,在var_GetChecked上封装一层,var_GetChecked实现方式如下,

int var_GetChecked( vlc_object_t *p_this, const char *psz_name,
                    int expected_type, vlc_value_t *p_val )
{
    assert( p_this );
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
    variable_t *p_var;
    int err = VLC_SUCCESS;
    vlc_mutex_lock( &p_priv->var_lock );
    //从对象的二叉树中找到该变量
    p_var = Lookup( p_this, psz_name );
    if( p_var != NULL )
    {
        assert( expected_type == 0 ||
                (p_var->i_type & VLC_VAR_CLASS) == expected_type );
        assert ((p_var->i_type & VLC_VAR_CLASS) != VLC_VAR_VOID);
        /* Really get the variable */
        *p_val = p_var->val;
        /* Duplicate value if needed */
        p_var->ops->pf_dup( p_val );
    }
    else
        err = VLC_ENOVAR;
    vlc_mutex_unlock( &p_priv->var_lock );
    return err;
}

不过有一种特殊的查找变量值方式var_Inherit,它先在本对象中找是否有该变量,没有的话去它的父结点找,一直找到根结点,还没找到则从配置中查找该变量

int var_Inherit( vlc_object_t *p_this, const char *psz_name, int i_type,
                 vlc_value_t *p_val )
{
    i_type &= VLC_VAR_CLASS;
    //遍历对象树,找该变量
    for( vlc_object_t *obj = p_this; obj != NULL; obj = obj->p_parent )
    {
        if( var_GetChecked( obj, psz_name, i_type, p_val ) == VLC_SUCCESS )
            return VLC_SUCCESS;
    }
    //从配置文件中找该变量
    switch( i_type & VLC_VAR_CLASS )
    {
        case VLC_VAR_STRING:
            p_val->psz_string = config_GetPsz( p_this, psz_name );
            if( !p_val->psz_string ) p_val->psz_string = strdup("");
            break;
        case VLC_VAR_FLOAT:
            p_val->f_float = config_GetFloat( p_this, psz_name );
            break;
        case VLC_VAR_INTEGER:
            p_val->i_int = config_GetInt( p_this, psz_name );
            break;
        case VLC_VAR_BOOL:
            p_val->b_bool = config_GetInt( p_this, psz_name );
            break;
        default:
            assert(0);
        case VLC_VAR_ADDRESS:
            return VLC_ENOOBJ;
    }
    return VLC_SUCCESS;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值