diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 72d6d32efb..fee760c56c 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -1152,7 +1152,7 @@ typedef struct { const char* supported; } avc_config_t; -void avcodec_getopt(AVCodecContext* avctx, char* str, avc_config_t** config); +void avcodec_getopt(AVCodecContext* avctx, const char* str, avc_config_t** config); /** * Interface for 0.5.0 version diff --git a/libavcodec/opts.c b/libavcodec/opts.c index bcefc40a3b..01fddd7c8f 100644 --- a/libavcodec/opts.c +++ b/libavcodec/opts.c @@ -9,21 +9,150 @@ */ #include "avcodec.h" +#ifdef OPTS_MAIN +#include +#include +#include +#endif /* - * possible extension - use for decoder options - * - for given codec names filter only correct - * options given (could be passed with 'str') + * 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, char* str, avc_config_t** config) +void avcodec_getopt(AVCodecContext* avctx, const char* str, avc_config_t** config) { AVCodecContext avctx_tmp; AVCodecContext* ctx = (avctx) ? avctx : &avctx_tmp; @@ -62,16 +191,88 @@ void avcodec_getopt(AVCodecContext* avctx, char* str, avc_config_t** config) 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, NULL, class_h263 + 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) - { + if (config) { *config = malloc(sizeof(cnf)); - if (*config) - memcpy(*config, cnf, 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