/* * LGPL */ /* * typical parsed command line: * msmpeg4:bitrate=720000:qmax=16 * */ #include "avcodec.h" #ifdef OPTS_MAIN #include #include #include #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