@ -340,6 +340,29 @@ void parse_options(void *optctx, int argc, char **argv, const OptionDef *options
}
}
}
}
int parse_optgroup ( void * optctx , OptionGroup * g )
{
int i , ret ;
av_log ( NULL , AV_LOG_DEBUG , " Parsing a group of options: %s %s. \n " ,
g - > group_def - > name , g - > arg ) ;
for ( i = 0 ; i < g - > nb_opts ; i + + ) {
Option * o = & g - > opts [ i ] ;
av_log ( NULL , AV_LOG_DEBUG , " Applying option %s (%s) with argument %s. \n " ,
o - > key , o - > opt - > help , o - > val ) ;
ret = write_option ( optctx , o - > opt , o - > key , o - > val ) ;
if ( ret < 0 )
return ret ;
}
av_log ( NULL , AV_LOG_DEBUG , " Successfully parsed a group of options. \n " ) ;
return 0 ;
}
int locate_option ( int argc , char * * argv , const OptionDef * options ,
int locate_option ( int argc , char * * argv , const OptionDef * options ,
const char * optname )
const char * optname )
{
{
@ -416,6 +439,224 @@ int opt_default(void *optctx, const char *opt, const char *arg)
return AVERROR_OPTION_NOT_FOUND ;
return AVERROR_OPTION_NOT_FOUND ;
}
}
/*
* Check whether given option is a group separator .
*
* @ return index of the group definition that matched or - 1 if none
*/
static int match_group_separator ( const OptionGroupDef * groups , const char * opt )
{
const OptionGroupDef * p = groups ;
while ( p - > name ) {
if ( p - > sep & & ! strcmp ( p - > sep , opt ) )
return p - groups ;
p + + ;
}
return - 1 ;
}
/*
* Finish parsing an option group .
*
* @ param group_idx which group definition should this group belong to
* @ param arg argument of the group delimiting option
*/
static void finish_group ( OptionParseContext * octx , int group_idx ,
const char * arg )
{
OptionGroupList * l = & octx - > groups [ group_idx ] ;
OptionGroup * g ;
GROW_ARRAY ( l - > groups , l - > nb_groups ) ;
g = & l - > groups [ l - > nb_groups - 1 ] ;
* g = octx - > cur_group ;
g - > arg = arg ;
g - > group_def = l - > group_def ;
# if CONFIG_SWSCALE
g - > sws_opts = sws_opts ;
# endif
g - > codec_opts = codec_opts ;
g - > format_opts = format_opts ;
codec_opts = NULL ;
format_opts = NULL ;
# if CONFIG_SWSCALE
sws_opts = NULL ;
# endif
init_opts ( ) ;
memset ( & octx - > cur_group , 0 , sizeof ( octx - > cur_group ) ) ;
}
/*
* Add an option instance to currently parsed group .
*/
static void add_opt ( OptionParseContext * octx , const OptionDef * opt ,
const char * key , const char * val )
{
int global = ! ( opt - > flags & ( OPT_PERFILE | OPT_SPEC | OPT_OFFSET ) ) ;
OptionGroup * g = global ? & octx - > global_opts : & octx - > cur_group ;
GROW_ARRAY ( g - > opts , g - > nb_opts ) ;
g - > opts [ g - > nb_opts - 1 ] . opt = opt ;
g - > opts [ g - > nb_opts - 1 ] . key = key ;
g - > opts [ g - > nb_opts - 1 ] . val = val ;
}
static void init_parse_context ( OptionParseContext * octx ,
const OptionGroupDef * groups )
{
static const OptionGroupDef global_group = { " global " } ;
const OptionGroupDef * g = groups ;
int i ;
memset ( octx , 0 , sizeof ( * octx ) ) ;
while ( g - > name )
g + + ;
octx - > nb_groups = g - groups ;
octx - > groups = av_mallocz ( sizeof ( * octx - > groups ) * octx - > nb_groups ) ;
if ( ! octx - > groups )
exit ( 1 ) ;
for ( i = 0 ; i < octx - > nb_groups ; i + + )
octx - > groups [ i ] . group_def = & groups [ i ] ;
octx - > global_opts . group_def = & global_group ;
octx - > global_opts . arg = " " ;
init_opts ( ) ;
}
void uninit_parse_context ( OptionParseContext * octx )
{
int i , j ;
for ( i = 0 ; i < octx - > nb_groups ; i + + ) {
OptionGroupList * l = & octx - > groups [ i ] ;
for ( j = 0 ; j < l - > nb_groups ; j + + ) {
av_freep ( & l - > groups [ j ] . opts ) ;
av_dict_free ( & l - > groups [ j ] . codec_opts ) ;
av_dict_free ( & l - > groups [ j ] . format_opts ) ;
# if CONFIG_SWSCALE
sws_freeContext ( l - > groups [ j ] . sws_opts ) ;
# endif
}
av_freep ( & l - > groups ) ;
}
av_freep ( & octx - > groups ) ;
av_freep ( & octx - > cur_group . opts ) ;
av_freep ( & octx - > global_opts . opts ) ;
uninit_opts ( ) ;
}
int split_commandline ( OptionParseContext * octx , int argc , char * argv [ ] ,
const OptionDef * options ,
const OptionGroupDef * groups )
{
int optindex = 1 ;
/* perform system-dependent conversions for arguments list */
prepare_app_arguments ( & argc , & argv ) ;
init_parse_context ( octx , groups ) ;
av_log ( NULL , AV_LOG_DEBUG , " Splitting the commandline. \n " ) ;
while ( optindex < argc ) {
const char * opt = argv [ optindex + + ] , * arg ;
const OptionDef * po ;
int ret ;
av_log ( NULL , AV_LOG_DEBUG , " Reading option '%s' ... " , opt ) ;
/* unnamed group separators, e.g. output filename */
if ( opt [ 0 ] ! = ' - ' | | ! opt [ 1 ] ) {
finish_group ( octx , 0 , opt ) ;
av_log ( NULL , AV_LOG_DEBUG , " matched as %s. \n " , groups [ 0 ] . name ) ;
continue ;
}
opt + + ;
# define GET_ARG(arg) \
do { \
arg = argv [ optindex + + ] ; \
if ( ! arg ) { \
av_log ( NULL , AV_LOG_ERROR , " Missing argument for option '%s'. \n " , opt ) ; \
return AVERROR ( EINVAL ) ; \
} \
} while ( 0 )
/* named group separators, e.g. -i */
if ( ( ret = match_group_separator ( groups , opt ) ) > = 0 ) {
GET_ARG ( arg ) ;
finish_group ( octx , ret , arg ) ;
av_log ( NULL , AV_LOG_DEBUG , " matched as %s with argument '%s'. \n " ,
groups [ ret ] . name , arg ) ;
continue ;
}
/* normal options */
po = find_option ( options , opt ) ;
if ( po - > name ) {
if ( po - > flags & OPT_EXIT ) {
/* optional argument, e.g. -h */
arg = argv [ optindex + + ] ;
} else if ( po - > flags & HAS_ARG ) {
GET_ARG ( arg ) ;
} else {
arg = " 1 " ;
}
add_opt ( octx , po , opt , arg ) ;
av_log ( NULL , AV_LOG_DEBUG , " matched as option '%s' (%s) with "
" argument '%s'. \n " , po - > name , po - > help , arg ) ;
continue ;
}
/* AVOptions */
if ( argv [ optindex ] ) {
ret = opt_default ( NULL , opt , argv [ optindex ] ) ;
if ( ret > = 0 ) {
av_log ( NULL , AV_LOG_DEBUG , " matched as AVOption '%s' with "
" argument '%s'. \n " , opt , argv [ optindex ] ) ;
optindex + + ;
continue ;
} else if ( ret ! = AVERROR_OPTION_NOT_FOUND ) {
av_log ( NULL , AV_LOG_ERROR , " Error parsing option '%s' "
" with argument '%s'. \n " , opt , argv [ optindex ] ) ;
return ret ;
}
}
/* boolean -nofoo options */
if ( opt [ 0 ] = = ' n ' & & opt [ 1 ] = = ' o ' & &
( po = find_option ( options , opt + 2 ) ) & &
po - > name & & po - > flags & OPT_BOOL ) {
add_opt ( octx , po , opt , " 0 " ) ;
av_log ( NULL , AV_LOG_DEBUG , " matched as option '%s' (%s) with "
" argument 0. \n " , po - > name , po - > help ) ;
continue ;
}
av_log ( NULL , AV_LOG_ERROR , " Unrecognized option '%s'. \n " , opt ) ;
return AVERROR_OPTION_NOT_FOUND ;
}
if ( octx - > cur_group . nb_opts | | codec_opts | | format_opts )
av_log ( NULL , AV_LOG_WARNING , " Trailing options were found on the "
" commandline. \n " ) ;
av_log ( NULL , AV_LOG_DEBUG , " Finished splitting the commandline. \n " ) ;
return 0 ;
}
int opt_loglevel ( void * optctx , const char * opt , const char * arg )
int opt_loglevel ( void * optctx , const char * opt , const char * arg )
{
{
const struct { const char * name ; int level ; } log_levels [ ] = {
const struct { const char * name ; int level ; } log_levels [ ] = {