mirror of https://github.com/FFmpeg/FFmpeg.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
7.1 KiB
278 lines
7.1 KiB
/* |
|
* LGPL |
|
*/ |
|
|
|
/* |
|
* typical parsed command line: |
|
* msmpeg4:bitrate=720000:qmax=16 |
|
* |
|
*/ |
|
|
|
#include "avcodec.h" |
|
#ifdef OPTS_MAIN |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#endif |
|
|
|
/* |
|
* todo - use for decoder options also |
|
*/ |
|
|
|
static int parse_bool(avc_config_t* c, char* s) |
|
{ |
|
int b = 1; /* by default -on- when present */ |
|
if (s) { |
|
if (!strcasecmp(s, "off") || !strcasecmp(s, "false") |
|
|| !strcmp(s, "0")) |
|
b = 0; |
|
else if (!strcasecmp(s, "on") || !strcasecmp(s, "true") |
|
|| !strcmp(s, "1")) |
|
b = 1; |
|
else |
|
return -1; |
|
} |
|
|
|
if (c && c->val) |
|
*(int*)(c->val) = b; |
|
return 0; |
|
} |
|
|
|
static int parse_double(avc_config_t* c, char* s) |
|
{ |
|
double d; |
|
if (!s) |
|
return -1; |
|
d = atof(s); |
|
if (c->min != c->max) { |
|
if (d < c->min || d > c->max) { |
|
fprintf(stderr, "Option: %s double value: %f out of range <%f, %f>\n", |
|
c->name, d, c->min, c->max); |
|
return -1; |
|
} |
|
} |
|
if (c && c->val) |
|
*(double*)(c->val) = d; |
|
return 0; |
|
} |
|
|
|
static int parse_int(avc_config_t* c, char* s) |
|
{ |
|
int i; |
|
if (!s) |
|
return -1; |
|
i = atoi(s); |
|
if (c->min != c->max) { |
|
if (i < (int)c->min || i > (int)c->max) { |
|
fprintf(stderr, "Option: %s integer value: %d out of range <%d, %d>\n", |
|
c->name, i, (int)c->min, (int)c->max); |
|
return -1; |
|
} |
|
} |
|
if (c && c->val) |
|
*(int*)(c->val) = i; |
|
return 0; |
|
} |
|
|
|
static int parse_string(AVCodecContext* avctx, avc_config_t* c, char* s) |
|
{ |
|
if (!s) |
|
return -1; |
|
|
|
if (c->type == FF_CONF_TYPE_RCOVERIDE) { |
|
int sf, ef, qs; |
|
float qf; |
|
if (sscanf(s, "%d,%d,%d,%f", &sf, &ef, &qs, &qf) == 4 && sf < ef) { |
|
RcOverride* o; |
|
*((RcOverride**)c->val) = |
|
realloc(*((RcOverride**)c->val), |
|
sizeof(RcOverride) * (avctx->rc_override_count + 1)); |
|
o = *((RcOverride**)c->val) + avctx->rc_override_count++; |
|
o->start_frame = sf; |
|
o->end_frame = ef; |
|
o->qscale = qs; |
|
o->quality_factor = qf; |
|
|
|
//printf("parsed Rc: %d,%d,%d,%f (%d)\n", sf,ef,qs,qf, avctx->rc_override_count); |
|
} else { |
|
printf("incorrect/unparsable Rc: \"%s\"\n", s); |
|
} |
|
} else |
|
(char*)(c->val) = strdup(s); |
|
return 0; |
|
} |
|
|
|
static int parse(AVCodecContext* avctx, avc_config_t* config, char* str) |
|
{ |
|
while (str && *str) { |
|
avc_config_t* c = config; |
|
char* e = strchr(str, ':'); |
|
char* p; |
|
if (e) |
|
*e++ = 0; |
|
|
|
p = strchr(str, '='); |
|
if (p) |
|
*p++ = 0; |
|
|
|
while (c->name) { |
|
if (!strcmp(c->name, str)) { |
|
switch (c->type & FF_CONF_TYPE_MASK) { |
|
case FF_CONF_TYPE_BOOL: |
|
parse_bool(c, p); |
|
break; |
|
case FF_CONF_TYPE_DOUBLE: |
|
parse_double(c, p); |
|
break; |
|
case FF_CONF_TYPE_INT: |
|
parse_int(c, p); |
|
break; |
|
case FF_CONF_TYPE_STRING: |
|
parse_string(avctx, c, p); |
|
break; |
|
default: |
|
abort(); |
|
break; |
|
} |
|
} |
|
c++; |
|
} |
|
str = e; |
|
} |
|
return 0; |
|
} |
|
|
|
/** |
|
* |
|
* \param avctx where to store parsed results |
|
* \param str string with options for parsing |
|
* or selectional string (pick only options appliable |
|
* for codec - use ,msmpeg4, (with commas to avoid mismatch) |
|
* \param config allocated avc_config_t for external parsing |
|
* i.e. external program might learn about all available |
|
* options for given codec |
|
**/ |
|
void avcodec_getopt(AVCodecContext* avctx, const char* str, avc_config_t** config) |
|
{ |
|
AVCodecContext avctx_tmp; |
|
AVCodecContext* ctx = (avctx) ? avctx : &avctx_tmp; |
|
static const char* class_h263 = ",msmpeg4,"; |
|
//"huffyuv,wmv1,msmpeg4v2,msmpeg4,mpeg4,mpeg1,mpeg1video,mjpeg,rv10,h263,h263p" |
|
|
|
avc_config_t cnf[] = |
|
{ |
|
// FIXME: sorted by importance!!! |
|
// expert option should follow more common ones |
|
{ |
|
"bitrate", "desired video bitrate", |
|
FF_CONF_TYPE_INT, &ctx->bit_rate, 4, 240000000, 800000, NULL, class_h263 |
|
}, { |
|
"vhq", "very high quality", |
|
FF_CONF_TYPE_FLAG, &ctx->flags, 0, CODEC_FLAG_HQ, 0, NULL, class_h263 |
|
}, { |
|
"ratetol", "number of bits the bitstream is allowed to diverge from the reference" |
|
"the reference can be CBR (for CBR pass1) or VBR (for pass2)", |
|
FF_CONF_TYPE_INT, &ctx->bit_rate_tolerance, 4, 240000000, 8000, NULL, class_h263 |
|
}, { |
|
"qmin", "minimum quantizer", FF_CONF_TYPE_INT, &ctx->qmin, 1, 31, 2, NULL, class_h263 |
|
}, { |
|
"qmax", "maximum qunatizer", FF_CONF_TYPE_INT, &ctx->qmax, 1, 31, 31, NULL, class_h263 |
|
}, { |
|
"rc_eq", "rate control equation", |
|
FF_CONF_TYPE_STRING, &ctx->rc_eq, 0, 0, 0, "tex^qComp" /* FILLME options */, class_h263 |
|
}, { |
|
"rc_minrate", "rate control minimum bitrate", |
|
FF_CONF_TYPE_INT, &ctx->rc_min_rate, 4, 24000000, 0, NULL, class_h263 |
|
}, { |
|
"rc_maxrate", "rate control maximum bitrate", |
|
FF_CONF_TYPE_INT, &ctx->rc_max_rate, 4, 24000000, 0, NULL, class_h263 |
|
}, { |
|
"psnr", "calculate PSNR of compressed frames", |
|
FF_CONF_TYPE_FLAG, &ctx->flags, 0, CODEC_FLAG_PSNR, 0, NULL, class_h263 |
|
}, { |
|
"rc_override", "ratecontrol override (=startframe,endframe,qscale,quality_factor)", |
|
FF_CONF_TYPE_RCOVERIDE, &ctx->rc_override, 0, 0, 0, "0,0,0,0", class_h263 |
|
}, |
|
|
|
{ NULL, NULL, 0, NULL, 0, 0, 0, NULL, NULL } |
|
}; |
|
|
|
if (config) { |
|
*config = malloc(sizeof(cnf)); |
|
if (*config) { |
|
avc_config_t* src = cnf; |
|
avc_config_t* dst = *config; |
|
while (src->name) { |
|
if (!str || !src->supported || strstr(src->supported, str)) |
|
memcpy(dst++, src, sizeof(avc_config_t)); |
|
src++; |
|
} |
|
memset(dst, 0, sizeof(avc_config_t)); |
|
} |
|
} else if (str) { |
|
char* s = strdup(str); |
|
if (s) { |
|
parse(avctx, cnf, s); |
|
free(s); |
|
} |
|
} |
|
} |
|
|
|
#ifdef OPTS_MAIN |
|
/* |
|
* API test - |
|
* arg1: options |
|
* arg2: codec type |
|
* |
|
* compile standalone: make CFLAGS="-DOPTS_MAIN" opts |
|
*/ |
|
int main(int argc, char* argv[]) |
|
{ |
|
AVCodecContext avctx; |
|
avc_config_t* config; |
|
char* def = malloc(5000); |
|
const char* col = ""; |
|
int i = 0; |
|
|
|
memset(&avctx, 0, sizeof(avctx)); |
|
*def = 0; |
|
avcodec_getopt(&avctx, argv[1], NULL); |
|
|
|
avcodec_getopt(NULL, (argc > 2) ? argv[2] : NULL, &config); |
|
if (config) |
|
while (config->name) { |
|
int t = config->type & FF_CONF_TYPE_MASK; |
|
printf("Config %s %s\n", config->name, |
|
t == FF_CONF_TYPE_BOOL ? "bool" : |
|
t == FF_CONF_TYPE_DOUBLE ? "double" : |
|
t == FF_CONF_TYPE_INT ? "integer" : |
|
t == FF_CONF_TYPE_STRING ? "string" : |
|
"unknown??"); |
|
switch (t) { |
|
case FF_CONF_TYPE_BOOL: |
|
i += sprintf(def + i, "%s%s=%s", |
|
col, config->name, |
|
config->defval != 0. ? "on" : "off"); |
|
break; |
|
case FF_CONF_TYPE_DOUBLE: |
|
i += sprintf(def + i, "%s%s=%f", |
|
col, config->name, config->defval); |
|
break; |
|
case FF_CONF_TYPE_INT: |
|
i += sprintf(def + i, "%s%s=%d", |
|
col, config->name, (int) config->defval); |
|
break; |
|
case FF_CONF_TYPE_STRING: |
|
i += sprintf(def + i, "%s%s=%s", |
|
col, config->name, config->defstr); |
|
break; |
|
} |
|
col = ":"; |
|
config++; |
|
} |
|
|
|
printf("Default Options: %s\n", def); |
|
|
|
return 0; |
|
} |
|
#endif
|
|
|