一、变量结构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;
}