@ -18,6 +18,7 @@
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# include <float.h>
# include "libavutil/opt.h"
# include "libavutil/parseutils.h"
# include "libavutil/avstring.h"
@ -238,9 +239,8 @@ static void add_codec(FFServerStream *stream, AVCodecContext *av)
st = av_mallocz ( sizeof ( AVStream ) ) ;
if ( ! st )
return ;
st - > codec = avcodec_alloc_context3 ( NULL ) ;
st - > codec = av ;
stream - > streams [ stream - > nb_streams + + ] = st ;
memcpy ( st - > codec , av , sizeof ( AVCodecContext ) ) ;
}
static enum AVCodecID opt_codec ( const char * name , enum AVMediaType type )
@ -269,12 +269,15 @@ static int ffserver_opt_preset(const char *arg,
FILE * f = NULL ;
char filename [ 1000 ] , tmp [ 1000 ] , tmp2 [ 1000 ] , line [ 1000 ] ;
int ret = 0 ;
AVCodec * codec = avcodec_find_encoder ( avctx - > codec_id ) ;
AVCodec * codec = NULL ;
if ( avctx )
codec = avcodec_find_encoder ( avctx - > codec_id ) ;
if ( ! ( f = get_preset_file ( filename , sizeof ( filename ) , arg , 0 ,
codec ? codec - > name : NULL ) ) ) {
fprintf ( stderr , " File for preset '%s' not found \n " , arg ) ;
return 1 ;
return AVERROR ( EINVAL ) ;
}
while ( ! feof ( f ) ) {
@ -284,18 +287,17 @@ static int ffserver_opt_preset(const char *arg,
e | = sscanf ( line , " %999[^=]=%999[^ \n ] \n " , tmp , tmp2 ) - 2 ;
if ( e ) {
fprintf ( stderr , " %s: Invalid syntax: '%s' \n " , filename , line ) ;
ret = 1 ;
ret = AVERROR ( EINVAL ) ;
break ;
}
if ( ! strcmp ( tmp , " acodec " ) ) {
if ( audio_id & & ! strcmp ( tmp , " acodec " ) ) {
* audio_id = opt_codec ( tmp2 , AVMEDIA_TYPE_AUDIO ) ;
} else if ( ! strcmp ( tmp , " vcodec " ) ) {
} else if ( video_id & & ! strcmp ( tmp , " vcodec " ) ) {
* video_id = opt_codec ( tmp2 , AVMEDIA_TYPE_VIDEO ) ;
} else if ( ! strcmp ( tmp , " scodec " ) ) {
} else if ( ! strcmp ( tmp , " scodec " ) ) {
/* opt_subtitle_codec(tmp2); */
} else if ( ffserver_opt_default ( tmp , tmp2 , avctx , type ) < 0 ) {
} else if ( avctx & & ( ret = ffserver_opt_default ( tmp , tmp2 , avctx , type ) ) < 0 ) {
fprintf ( stderr , " %s: Invalid option or argument: '%s', parsed as '%s' = '%s' \n " , filename , line , tmp , tmp2 ) ;
ret = 1 ;
break ;
}
}
@ -323,15 +325,78 @@ static AVOutputFormat *ffserver_guess_format(const char *short_name, const char
return fmt ;
}
static void vreport_config_error ( const char * filename , int line_num , int log_level , int * errors , const char * fmt , va_list vl )
{
av_log ( NULL , log_level , " %s:%d: " , filename , line_num ) ;
av_vlog ( NULL , log_level , fmt , vl ) ;
( * errors ) + + ;
}
static void report_config_error ( const char * filename , int line_num , int log_level , int * errors , const char * fmt , . . . )
{
va_list vl ;
va_start ( vl , fmt ) ;
av_log ( NULL , log_level , " %s:%d: " , filename , line_num ) ;
av_vlog ( NULL , log_level , fmt , vl ) ;
vreport_config_error ( filename , line_num , log_level , errors , fmt , vl ) ;
va_end ( vl ) ;
}
( * errors ) + + ;
static int ffserver_set_int_param ( int * dest , const char * value , int factor , int min , int max ,
FFServerConfig * config , int line_num , const char * error_msg , . . . )
{
int tmp ;
char * tailp ;
if ( ! value | | ! value [ 0 ] )
goto error ;
errno = 0 ;
tmp = strtol ( value , & tailp , 0 ) ;
if ( tmp < min | | tmp > max )
goto error ;
if ( factor ) {
if ( FFABS ( tmp ) > INT_MAX / FFABS ( factor ) )
goto error ;
tmp * = factor ;
}
if ( tailp [ 0 ] | | errno )
goto error ;
if ( dest )
* dest = tmp ;
return 0 ;
error :
if ( config ) {
va_list vl ;
va_start ( vl , error_msg ) ;
vreport_config_error ( config - > filename , line_num , AV_LOG_ERROR , & config - > errors , error_msg , vl ) ;
va_end ( vl ) ;
}
return AVERROR ( EINVAL ) ;
}
static int ffserver_set_float_param ( float * dest , const char * value , float factor , float min , float max ,
FFServerConfig * config , int line_num , const char * error_msg , . . . )
{
double tmp ;
char * tailp ;
if ( ! value | | ! value [ 0 ] )
goto error ;
errno = 0 ;
tmp = strtod ( value , & tailp ) ;
if ( tmp < min | | tmp > max )
goto error ;
if ( factor )
tmp * = factor ;
if ( tailp [ 0 ] | | errno )
goto error ;
if ( dest )
* dest = tmp ;
return 0 ;
error :
if ( config ) {
va_list vl ;
va_start ( vl , error_msg ) ;
vreport_config_error ( config - > filename , line_num , AV_LOG_ERROR , & config - > errors , error_msg , vl ) ;
va_end ( vl ) ;
}
return AVERROR ( EINVAL ) ;
}
# define ERROR(...) report_config_error(config->filename, line_num, AV_LOG_ERROR, &config->errors, __VA_ARGS__)
@ -502,6 +567,87 @@ static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, c
return 0 ;
}
static int ffserver_apply_stream_config ( AVCodecContext * enc , const AVDictionary * conf , AVDictionary * * opts )
{
AVDictionaryEntry * e ;
int ret = 0 ;
/* Return values from ffserver_set_*_param are ignored.
Values are initially parsed and checked before inserting to AVDictionary . */
//video params
if ( ( e = av_dict_get ( conf , " VideoBitRateRangeMin " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > rc_min_rate , e - > value , 1000 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoBitRateRangeMax " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > rc_max_rate , e - > value , 1000 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " Debug " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > debug , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " Strict " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > strict_std_compliance , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoBufferSize " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > rc_buffer_size , e - > value , 8 * 1024 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoBitRateTolerance " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > bit_rate_tolerance , e - > value , 1000 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoBitRate " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > bit_rate , e - > value , 1000 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoSizeWidth " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > width , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoSizeHeight " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > height , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " PixelFormat " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > pix_fmt , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoGopSize " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > gop_size , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoFrameRateNum " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > time_base . num , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoFrameRateDen " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > time_base . den , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoQDiff " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > max_qdiff , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoQMax " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > qmax , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " VideoQMin " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > qmin , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " LumiMask " , NULL , 0 ) ) )
ffserver_set_float_param ( & enc - > lumi_masking , e - > value , 0 , - FLT_MAX , FLT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " DarkMask " , NULL , 0 ) ) )
ffserver_set_float_param ( & enc - > dark_masking , e - > value , 0 , - FLT_MAX , FLT_MAX , NULL , 0 , NULL ) ;
if ( av_dict_get ( conf , " BitExact " , NULL , 0 ) )
enc - > flags | = CODEC_FLAG_BITEXACT ;
if ( av_dict_get ( conf , " DctFastint " , NULL , 0 ) )
enc - > dct_algo = FF_DCT_FASTINT ;
if ( av_dict_get ( conf , " IdctSimple " , NULL , 0 ) )
enc - > idct_algo = FF_IDCT_SIMPLE ;
if ( av_dict_get ( conf , " VideoHighQuality " , NULL , 0 ) )
enc - > mb_decision = FF_MB_DECISION_BITS ;
if ( ( e = av_dict_get ( conf , " VideoTag " , NULL , 0 ) ) )
enc - > codec_tag = MKTAG ( e - > value [ 0 ] , e - > value [ 1 ] , e - > value [ 2 ] , e - > value [ 3 ] ) ;
if ( av_dict_get ( conf , " Qscale " , NULL , 0 ) ) {
enc - > flags | = CODEC_FLAG_QSCALE ;
ffserver_set_int_param ( & enc - > global_quality , e - > value , FF_QP2LAMBDA , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
}
if ( av_dict_get ( conf , " Video4MotionVector " , NULL , 0 ) ) {
enc - > mb_decision = FF_MB_DECISION_BITS ; //FIXME remove
enc - > flags | = CODEC_FLAG_4MV ;
}
//audio params
if ( ( e = av_dict_get ( conf , " AudioChannels " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > channels , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " AudioSampleRate " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > sample_rate , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
if ( ( e = av_dict_get ( conf , " AudioBitRate " , NULL , 0 ) ) )
ffserver_set_int_param ( & enc - > bit_rate , e - > value , 0 , INT_MIN , INT_MAX , NULL , 0 , NULL ) ;
av_opt_set_dict2 ( enc , opts , AV_OPT_SEARCH_CHILDREN ) ;
e = NULL ;
while ( e = av_dict_get ( * opts , " " , e , AV_DICT_IGNORE_SUFFIX ) ) {
av_log ( NULL , AV_LOG_ERROR , " Provided AVOption '%s' doesn't match any existing option. \n " , e - > key ) ;
ret = AVERROR ( EINVAL ) ;
}
return ret ;
}
static int ffserver_parse_config_stream ( FFServerConfig * config , const char * cmd , const char * * p ,
int line_num , FFServerStream * * pstream )
{
@ -528,14 +674,12 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
}
stream - > fmt = ffserver_guess_format ( NULL , stream - > filename , NULL ) ;
avcodec_get_context_defaults3 ( & config - > video_enc , NULL ) ;
avcodec_get_context_defaults3 ( & config - > audio_enc , NULL ) ;
config - > audio_id = AV_CODEC_ID_NONE ;
config - > video_id = AV_CODEC_ID_NONE ;
if ( stream - > fmt ) {
config - > audio_id = stream - > fmt - > audio_codec ;
config - > video_id = stream - > fmt - > video_codec ;
} else {
config - > audio_id = AV_CODEC_ID_NONE ;
config - > video_id = AV_CODEC_ID_NONE ;
}
* pstream = stream ;
return 0 ;
@ -587,23 +731,20 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
! av_strcasecmp ( cmd , " Copyright " ) | |
! av_strcasecmp ( cmd , " Title " ) ) {
char key [ 32 ] ;
int i , ret ;
int i ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
for ( i = 0 ; i < strlen ( cmd ) ; i + + )
key [ i ] = av_tolower ( cmd [ i ] ) ;
key [ i ] = 0 ;
WARNING ( " '%s' option in configuration file is deprecated, "
" use 'Metadata %s VALUE' instead \n " , cmd , key ) ;
if ( ( ret = av_dict_set ( & stream - > metadata , key , arg , 0 ) ) < 0 )
ERROR ( " Could not set metadata '%s' to value '%s': %s \n " , key , arg , av_err2str ( ret ) ) ;
if ( av_dict_set ( & stream - > metadata , key , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " Metadata " ) ) {
int ret ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
ffserver_get_arg ( arg2 , sizeof ( arg2 ) , p ) ;
if ( ( ret = av_dict_set ( & stream - > metadata , arg , arg2 , 0 ) ) < 0 ) {
ERROR ( " Could not set metadata '%s' to value '%s': %s \n " ,
arg , arg2 , av_err2str ( ret ) ) ;
}
if ( av_dict_set ( & stream - > metadata , arg , arg2 , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " Preroll " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
stream - > prebuffer = atof ( arg ) * 1000 ;
@ -624,136 +765,166 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
stream - > max_time = atof ( arg ) * 1000 ;
} else if ( ! av_strcasecmp ( cmd , " AudioBitRate " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > audio_enc . bit_rate = lrintf ( atof ( arg ) * 1000 ) ;
float f ;
ffserver_set_float_param ( & f , arg , 1000 , 0 , FLT_MAX , config , line_num , " Invalid %s: %s \n " , cmd , arg ) ;
if ( av_dict_set_int ( & config - > audio_conf , cmd , lrintf ( f ) , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " AudioChannels " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > audio_enc . channels = atoi ( arg ) ;
ffserver_set_int_param ( NULL , arg , 0 , 1 , 8 , config , line_num , " Invalid %s: %s, valid range is 1-8. " , cmd , arg ) ;
if ( av_dict_set ( & config - > audio_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " AudioSampleRate " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > audio_enc . sample_rate = atoi ( arg ) ;
ffserver_set_int_param ( NULL , arg , 0 , 0 , INT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > audio_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoBitRateRange " ) ) {
int minrate , maxrate ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
if ( sscanf ( arg , " %d-%d " , & minrate , & maxrate ) = = 2 ) {
config - > video_enc . rc_min_rate = minrate * 1000 ;
config - > video_enc . rc_max_rate = maxrate * 1000 ;
if ( av_dict_set_int ( & config - > video_conf , " VideoBitRateRangeMin " , minrate , 0 ) < 0 | |
av_dict_set_int ( & config - > video_conf , " VideoBitRateRangeMax " , maxrate , 0 ) < 0 )
goto nomem ;
} else
ERROR ( " Incorrect format for VideoBitRateRange -- should be <min>-<max>: %s \n " , arg ) ;
} else if ( ! av_strcasecmp ( cmd , " Debug " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . debug = strtol ( arg , 0 , 0 ) ;
ffserver_set_int_param ( NULL , arg , 0 , INT_MIN , INT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " Strict " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . strict_std_compliance = atoi ( arg ) ;
ffserver_set_int_param ( NULL , arg , 0 , INT_MIN , INT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoBufferSize " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . rc_buffer_size = atoi ( arg ) * 8 * 1024 ;
ffserver_set_int_param ( NULL , arg , 8 * 1024 , 0 , INT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoBitRateTolerance " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . bit_rate_tolerance = atoi ( arg ) * 1000 ;
ffserver_set_int_param ( NULL , arg , 1000 , INT_MIN , INT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoBitRate " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . bit_rate = atoi ( arg ) * 1000 ;
ffserver_set_int_param ( NULL , arg , 1000 , 0 , INT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoSize " ) ) {
int ret ;
int ret , w , h ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
ret = av_parse_video_size ( & config - > video_enc . width , & config - > video_enc . height , arg ) ;
ret = av_parse_video_size ( & w , & h , arg ) ;
if ( ret < 0 )
ERROR ( " Invalid video size '%s' \n " , arg ) ;
else if ( ( config - > video_enc . width % 16 ) ! = 0 | | ( config - > video_enc . height % 16 ) ! = 0 )
else if ( ( w % 16 ) | | ( h % 16 ) )
ERROR ( " Image size must be a multiple of 16 \n " ) ;
if ( av_dict_set_int ( & config - > video_conf , " VideoSizeWidth " , w , 0 ) < 0 | |
av_dict_set_int ( & config - > video_conf , " VideoSizeHeight " , h , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoFrameRate " ) ) {
AVRational frame_rate ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
if ( av_parse_video_rate ( & frame_rate , arg ) < 0 ) {
ERROR ( " Incorrect frame rate: %s \n " , arg ) ;
} else {
config - > video_enc . time_base . num = frame_rate . den ;
config - > video_enc . time_base . den = frame_rate . num ;
if ( av_dict_set_int ( & config - > video_conf , " VideoFrameRateNum " , frame_rate . num , 0 ) < 0 | |
av_dict_set_int ( & config - > video_conf , " VideoFrameRateDen " , frame_rate . den , 0 ) < 0 )
goto nomem ;
}
} else if ( ! av_strcasecmp ( cmd , " PixelFormat " ) ) {
enum AVPixelFormat pix_fmt ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . pix_fmt = av_get_pix_fmt ( arg ) ;
if ( config - > video_enc . pix_fmt = = AV_PIX_FMT_NONE )
pix_fmt = av_get_pix_fmt ( arg ) ;
if ( pix_fmt = = AV_PIX_FMT_NONE )
ERROR ( " Unknown pixel format: %s \n " , arg ) ;
if ( av_dict_set_int ( & config - > video_conf , cmd , pix_fmt , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoGopSize " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . gop_size = atoi ( arg ) ;
ffserver_set_int_param ( NULL , arg , 0 , INT_MIN , INT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoIntraOnly " ) ) {
config - > video_enc . gop_size = 1 ;
if ( av_dict_set ( & config - > video_conf , cmd , " 1 " , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoHighQuality " ) ) {
config - > video_enc . mb_decision = FF_MB_DECISION_BITS ;
if ( av_dict_set ( & config - > video_conf , cmd , " " , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " Video4MotionVector " ) ) {
config - > video_enc . mb_decision = FF_MB_DECISION_BITS ; //FIXME remove
config - > video_enc . flags | = CODEC_FLAG_4MV ;
if ( av_dict_set ( & config - > video_conf , cmd , " " , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " AVOptionVideo " ) | |
! av_strcasecmp ( cmd , " AVOptionAudio " ) ) {
AVCodecContext * avctx ;
int type ;
AVDictionary * * dict ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
ffserver_get_arg ( arg2 , sizeof ( arg2 ) , p ) ;
if ( ! av_strcasecmp ( cmd , " AVOptionVideo " ) ) {
avctx = & config - > video_enc ;
type = AV_OPT_FLAG_VIDEO_PARAM ;
} else {
avctx = & config - > audio_enc ;
type = AV_OPT_FLAG_AUDIO_PARAM ;
}
if ( ffserver_opt_default ( arg , arg2 , avctx , type | AV_OPT_FLAG_ENCODING_PARAM ) ) {
ERROR ( " Error setting %s option to %s %s \n " , cmd , arg , arg2 ) ;
}
if ( ! av_strcasecmp ( cmd , " AVOptionVideo " ) )
dict = & config - > video_opts ;
else
dict = & config - > audio_opts ;
if ( av_dict_set ( dict , arg , arg2 , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " AVPresetVideo " ) | |
! av_strcasecmp ( cmd , " AVPresetAudio " ) ) {
AVCodecContext * avctx ;
int type ;
char * * preset = NULL ;
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
if ( ! av_strcasecmp ( cmd , " AVPresetVideo " ) ) {
avctx = & config - > video_enc ;
config - > video_enc . codec_id = config - > video_id ;
type = AV_OPT_FLAG_VIDEO_PARAM ;
preset = & config - > video_preset ;
ffserver_opt_preset ( arg , NULL , 0 , NULL , & config - > video_id ) ;
} else {
avctx = & config - > audio_enc ;
config - > audio_enc . codec_id = config - > audio_id ;
type = AV_OPT_FLAG_AUDIO_PARAM ;
}
if ( ffserver_opt_preset ( arg , avctx , type | AV_OPT_FLAG_ENCODING_PARAM , & config - > audio_id , & config - > video_id ) ) {
ERROR ( " AVPreset error: %s \n " , arg ) ;
preset = & config - > audio_preset ;
ffserver_opt_preset ( arg , NULL , 0 , & config - > audio_id , NULL ) ;
}
* preset = av_strdup ( arg ) ;
if ( ! preset )
return AVERROR ( ENOMEM ) ;
} else if ( ! av_strcasecmp ( cmd , " VideoTag " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
if ( strlen ( arg ) = = 4 )
config - > video_enc . codec_tag = MKTAG ( arg [ 0 ] , arg [ 1 ] , arg [ 2 ] , arg [ 3 ] ) ;
if ( strlen ( arg ) = = 4 ) {
if ( av_dict_set ( & config - > video_conf , " VideoTag " , " arg " , 0 ) < 0 )
goto nomem ;
}
} else if ( ! av_strcasecmp ( cmd , " BitExact " ) ) {
config - > video_enc . flags | = CODEC_FLAG_BITEXACT ;
if ( av_dict_set ( & config - > video_conf , cmd , " " , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " DctFastint " ) ) {
config - > video_enc . dct_algo = FF_DCT_FASTINT ;
if ( av_dict_set ( & config - > video_conf , cmd , " " , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " IdctSimple " ) ) {
config - > video_enc . idct_algo = FF_IDCT_SIMPLE ;
if ( av_dict_set ( & config - > video_conf , cmd , " " , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " Qscale " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . flags | = CODEC_FLAG_QSCALE ;
config - > video_enc . global_quality = FF_QP2LAMBDA * atoi ( arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoQDiff " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . max_qdiff = atoi ( arg ) ;
if ( config - > video_enc . max_qdiff < 1 | | config - > video_enc . max_qdiff > 31 )
ERROR ( " VideoQDiff out of range \n " ) ;
ffserver_set_int_param ( NULL , arg , 0 , 1 , 31 , config , line_num , " %s out of range \n " , cmd ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoQMax " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . qmax = atoi ( arg ) ;
if ( config - > video_enc . qmax < 1 | | config - > video_enc . qmax > 31 )
ERROR ( " VideoQMax out of range \n " ) ;
ffserver_set_int_param ( NULL , arg , 0 , 1 , 31 , config , line_num , " %s out of range \n " , cmd ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " VideoQMin " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . qmin = atoi ( arg ) ;
if ( config - > video_enc . qmin < 1 | | config - > video_enc . qmin > 31 )
ERROR ( " VideoQMin out of range \n " ) ;
ffserver_set_int_param ( NULL , arg , 0 , 1 , 31 , config , line_num , " %s out of range \n " , cmd ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " LumiMask " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . lumi_masking = atof ( arg ) ;
ffserver_set_float_param ( NULL , arg , 0 , - FLT_MAX , FLT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " DarkMask " ) ) {
ffserver_get_arg ( arg , sizeof ( arg ) , p ) ;
config - > video_enc . dark_masking = atof ( arg ) ;
ffserver_set_float_param ( NULL , arg , 0 , - FLT_MAX , FLT_MAX , config , line_num , " Invalid %s: %s " , cmd , arg ) ;
if ( av_dict_set ( & config - > video_conf , cmd , arg , 0 ) < 0 )
goto nomem ;
} else if ( ! av_strcasecmp ( cmd , " NoVideo " ) ) {
config - > video_id = AV_CODEC_ID_NONE ;
} else if ( ! av_strcasecmp ( cmd , " NoAudio " ) ) {
@ -783,16 +954,32 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
} else if ( ! av_strcasecmp ( cmd , " </Stream> " ) ) {
if ( stream - > feed & & stream - > fmt & & strcmp ( stream - > fmt - > name , " ffm " ) ! = 0 ) {
if ( config - > audio_id ! = AV_CODEC_ID_NONE ) {
config - > audio_enc . codec_type = AVMEDIA_TYPE_AUDIO ;
config - > audio_enc . codec_id = config - > audio_id ;
add_codec ( stream , & config - > audio_enc ) ;
AVCodecContext * audio_enc = avcodec_alloc_context3 ( avcodec_find_encoder ( config - > audio_id ) ) ;
if ( config - > audio_preset & &
ffserver_opt_preset ( arg , audio_enc , AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ,
NULL , NULL ) < 0 )
ERROR ( " Could not apply preset '%s' \n " , arg ) ;
if ( ffserver_apply_stream_config ( audio_enc , config - > audio_conf , & config - > audio_opts ) < 0 )
config - > errors + + ;
add_codec ( stream , audio_enc ) ;
}
if ( config - > video_id ! = AV_CODEC_ID_NONE ) {
config - > video_enc . codec_type = AVMEDIA_TYPE_VIDEO ;
config - > video_enc . codec_id = config - > video_id ;
add_codec ( stream , & config - > video_enc ) ;
AVCodecContext * video_enc = avcodec_alloc_context3 ( avcodec_find_encoder ( config - > video_id ) ) ;
if ( config - > video_preset & &
ffserver_opt_preset ( arg , video_enc , AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM ,
NULL , NULL ) < 0 )
ERROR ( " Could not apply preset '%s' \n " , arg ) ;
if ( ffserver_apply_stream_config ( video_enc , config - > video_conf , & config - > video_opts ) < 0 )
config - > errors + + ;
add_codec ( stream , video_enc ) ;
}
}
av_dict_free ( & config - > video_opts ) ;
av_dict_free ( & config - > video_conf ) ;
av_dict_free ( & config - > audio_opts ) ;
av_dict_free ( & config - > audio_conf ) ;
av_freep ( & config - > video_preset ) ;
av_freep ( & config - > audio_preset ) ;
* pstream = NULL ;
} else if ( ! av_strcasecmp ( cmd , " File " ) | | ! av_strcasecmp ( cmd , " ReadOnlyFile " ) ) {
ffserver_get_arg ( stream - > feed_filename , sizeof ( stream - > feed_filename ) , p ) ;
@ -800,6 +987,15 @@ static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd,
ERROR ( " Invalid entry '%s' inside <Stream></Stream> \n " , cmd ) ;
}
return 0 ;
nomem :
av_log ( NULL , AV_LOG_ERROR , " Out of memory. Aborting. \n " ) ;
av_dict_free ( & config - > video_opts ) ;
av_dict_free ( & config - > video_conf ) ;
av_dict_free ( & config - > audio_opts ) ;
av_dict_free ( & config - > audio_conf ) ;
av_freep ( & config - > video_preset ) ;
av_freep ( & config - > audio_preset ) ;
return AVERROR ( ENOMEM ) ;
}
static int ffserver_parse_config_redirect ( FFServerConfig * config , const char * cmd , const char * * p ,