📄 variables.c
字号:
/* Free data if needed */ p_var->pf_free( &oldval ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS;}/** * Get a variable's value * * \param p_this The object that holds the variable * \param psz_name The name of the variable * \param p_val Pointer to a vlc_value_t that will hold the variable's value * after the function is finished */int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val ){ int i_var; variable_t *p_var; vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_refcheck( p_this ); vlc_mutex_lock( &p_priv->var_lock ); i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } p_var = &p_priv->p_vars[i_var]; /* Really get the variable */ *p_val = p_var->val; /* Duplicate value if needed */ p_var->pf_dup( p_val ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS;}/** * Finds a process-wide mutex, creates it if needed, and locks it. * Unlock with vlc_mutex_unlock(). */vlc_mutex_t *var_AcquireMutex( const char *name ){ libvlc_global_data_t *p_global = vlc_global(); vlc_value_t val; if( var_Create( p_global, name, VLC_VAR_MUTEX ) ) return NULL; var_Get( p_global, name, &val ); vlc_mutex_lock( val.p_address ); return val.p_address;}/** * Register a callback in a variable * * We store a function pointer that will be called upon variable * modification. * * \param p_this The object that holds the variable * \param psz_name The name of the variable * \param pf_callback The function pointer * \param p_data A generic pointer that will be passed as the last * argument to the callback function. * * \warning The callback function is run in the thread that calls var_Set on * the variable. Use proper locking. This thread may not have much * time to spare, so keep callback functions short. */int __var_AddCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ){ int i_var; variable_t *p_var; callback_entry_t entry; vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_refcheck( p_this ); entry.pf_callback = pf_callback; entry.p_data = p_data; vlc_mutex_lock( &p_priv->var_lock ); i_var = GetUnused( p_this, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_priv->var_lock ); return i_var; } p_var = &p_priv->p_vars[i_var]; INSERT_ELEM( p_var->p_entries, p_var->i_entries, p_var->i_entries, entry ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS;}/** * Remove a callback from a variable * * pf_callback and p_data have to be given again, because different objects * might have registered the same callback function. */int __var_DelCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ){ int i_entry, i_var; variable_t *p_var; vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_refcheck( p_this ); vlc_mutex_lock( &p_priv->var_lock ); i_var = GetUnused( p_this, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_priv->var_lock ); return i_var; } p_var = &p_priv->p_vars[i_var]; for( i_entry = p_var->i_entries ; i_entry-- ; ) { if( p_var->p_entries[i_entry].pf_callback == pf_callback && p_var->p_entries[i_entry].p_data == p_data ) { break; } } if( i_entry < 0 ) { vlc_mutex_unlock( &p_priv->var_lock ); return VLC_EGENERIC; } REMOVE_ELEM( p_var->p_entries, p_var->i_entries, i_entry ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS;}/** * Trigger callback on a variable * * \param p_this The object that hold the variable * \param psz_name The name of the variable */int __var_TriggerCallback( vlc_object_t *p_this, const char *psz_name ){ int i_var; variable_t *p_var; vlc_value_t oldval; vlc_object_internals_t *p_priv = vlc_internals( p_this ); vlc_mutex_lock( &p_priv->var_lock ); i_var = GetUnused( p_this, psz_name ); if( i_var < 0 ) { vlc_mutex_unlock( &p_priv->var_lock ); return i_var; } p_var = &p_priv->p_vars[i_var]; /* Backup needed stuff */ oldval = p_var->val; /* Deal with callbacks. Tell we're in a callback, release the lock, * call stored functions, retake the lock. */ if( p_var->i_entries ) { int i_var; int i_entries = p_var->i_entries; callback_entry_t *p_entries = p_var->p_entries; p_var->b_incallback = true; vlc_mutex_unlock( &p_priv->var_lock ); /* The real calls */ for( ; i_entries-- ; ) { p_entries[i_entries].pf_callback( p_this, psz_name, oldval, oldval, p_entries[i_entries].p_data ); } vlc_mutex_lock( &p_priv->var_lock ); i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name ); if( i_var < 0 ) { msg_Err( p_this, "variable %s has disappeared", psz_name ); vlc_mutex_unlock( &p_priv->var_lock ); return VLC_ENOVAR; } p_var = &p_priv->p_vars[i_var]; p_var->b_incallback = false; } vlc_mutex_unlock( &p_priv->var_lock ); return VLC_SUCCESS;}/** Parse a stringified option * This function parse a string option and create the associated object * variable * The option must be of the form "[no[-]]foo[=bar]" where foo is the * option name and bar is the value of the option. * \param p_obj the object in which the variable must be created * \param psz_option the option to parse * \param trusted whether the option is set by a trusted input or not * \return nothing */void var_OptionParse( vlc_object_t *p_obj, const char *psz_option, bool trusted ){ char *psz_name, *psz_value; int i_type; bool b_isno = false; vlc_value_t val; val.psz_string = NULL; /* It's too much of a hassle to remove the ':' when we parse * the cmd line :) */ if( psz_option[0] == ':' ) psz_option++; if( !psz_option[0] ) return; psz_name = strdup( psz_option ); if( psz_name == NULL ) return; psz_value = strchr( psz_name, '=' ); if( psz_value != NULL ) *psz_value++ = '\0'; /* FIXME: :programs should be handled generically */ if( !strcmp( psz_name, "programs" ) ) i_type = VLC_VAR_LIST; else i_type = config_GetType( p_obj, psz_name ); if( !i_type && !psz_value ) { /* check for "no-foo" or "nofoo" */ if( !strncmp( psz_name, "no-", 3 ) ) { memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 ); } else if( !strncmp( psz_name, "no", 2 ) ) { memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 ); } else goto cleanup; /* Option doesn't exist */ b_isno = true; i_type = config_GetType( p_obj, psz_name ); } if( !i_type ) goto cleanup; /* Option doesn't exist */ if( ( i_type != VLC_VAR_BOOL ) && ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */ /* check if option is unsafe */ if( !trusted ) { module_config_t *p_config = config_FindConfig( p_obj, psz_name ); if( !p_config->b_safe ) { msg_Err( p_obj, "unsafe option \"%s\" has been ignored for " "security reasons", psz_name ); return; } } /* Create the variable in the input object. * Children of the input object will be able to retreive this value * thanks to the inheritance property of the object variables. */ var_Create( p_obj, psz_name, i_type ); switch( i_type ) { case VLC_VAR_BOOL: val.b_bool = !b_isno; break; case VLC_VAR_INTEGER: val.i_int = strtol( psz_value, NULL, 0 ); break; case VLC_VAR_FLOAT: val.f_float = atof( psz_value ); break; case VLC_VAR_STRING: case VLC_VAR_MODULE: case VLC_VAR_FILE: case VLC_VAR_DIRECTORY: val.psz_string = psz_value; break; case VLC_VAR_LIST: { char *psz_orig, *psz_var; vlc_list_t *p_list = malloc(sizeof(vlc_list_t)); val.p_list = p_list; p_list->i_count = 0; psz_var = psz_orig = strdup(psz_value); while( psz_var && *psz_var ) { char *psz_item = psz_var; vlc_value_t val2; while( *psz_var && *psz_var != ',' ) psz_var++; if( *psz_var == ',' ) { *psz_var = '\0'; psz_var++; } val2.i_int = strtol( psz_item, NULL, 0 ); INSERT_ELEM( p_list->p_values, p_list->i_count, p_list->i_count, val2 ); /* p_list->i_count is incremented twice by INSERT_ELEM */ p_list->i_count--; INSERT_ELEM( p_list->pi_types, p_list->i_count, p_list->i_count, VLC_VAR_INTEGER ); } free( psz_orig ); break; } default: goto cleanup; } var_Set( p_obj, psz_name, val );cleanup: free( psz_name );}/* Following functions are local *//***************************************************************************** * GetUnused: find an unused variable from its name ***************************************************************************** * We do i_tries tries before giving up, just in case the variable is being * modified and called from a callback. *****************************************************************************/static int GetUnused( vlc_object_t *p_this, const char *psz_name ){ int i_var, i_tries = 0; vlc_object_internals_t *p_priv = vlc_internals( p_this ); while( true ) { i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name ); if( i_var < 0 ) { return VLC_ENOVAR; } if( ! p_priv->p_vars[i_var].b_incallback ) { return i_var; } if( i_tries++ > 100 ) { msg_Err( p_this, "caught in a callback deadlock? ('%s')", psz_name ); return VLC_ETIMEOUT; } vlc_mutex_unlock( &p_priv->var_lock ); msleep( THREAD_SLEEP ); vlc_mutex_lock( &p_priv->var_lock ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -