#include "libavutil/internal.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
+#include "libavutil/parseutils.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/avassert.h"
};
typedef struct {
+ const AVClass *class;
struct SwsContext *sws; ///< software scaler context
struct SwsContext *isws[2]; ///< software scaler context for interlaced material
* -1 = keep original aspect
*/
int w, h;
+ char *flags_str; ///sws flags string
+ char *size_str;
unsigned int flags; ///sws flags
int hsub, vsub; ///< chroma subsampling
int output_is_pal; ///< set to 1 if the output format is paletted
int interlaced;
- char w_expr[256]; ///< width expression string
- char h_expr[256]; ///< height expression string
+ char *w_expr; ///< width expression string
+ char *h_expr; ///< height expression string
} ScaleContext;
+#define OFFSET(x) offsetof(ScaleContext, x)
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
+
+static const AVOption scale_options[] = {
+ { "w", "set width expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "width", "set width expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "h", "set height expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "height", "set height expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
+ { "flags", "set libswscale flags", OFFSET(flags_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, INT_MAX, FLAGS },
+ { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, 1, FLAGS },
+ { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS },
+ { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS },
+ { NULL },
+};
+
+AVFILTER_DEFINE_CLASS(scale);
+
static av_cold int init(AVFilterContext *ctx, const char *args)
{
ScaleContext *scale = ctx->priv;
- const char *p;
+ static const char *shorthand[] = { "w", "h", NULL };
+ int ret;
+ const char *args0 = args;
- av_strlcpy(scale->w_expr, "iw", sizeof(scale->w_expr));
- av_strlcpy(scale->h_expr, "ih", sizeof(scale->h_expr));
+ scale->class = &scale_class;
+ av_opt_set_defaults(scale);
- scale->flags = SWS_BILINEAR;
- if (args) {
- sscanf(args, "%255[^:]:%255[^:]", scale->w_expr, scale->h_expr);
- p = strstr(args,"flags=");
- if (p) {
- const AVClass *class = sws_get_class();
- const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0,
- AV_OPT_SEARCH_FAKE_OBJ);
- int ret = av_opt_eval_flags(&class, o, p + 6, &scale->flags);
-
- if (ret < 0)
- return ret;
+ if (args && (scale->size_str = av_get_token(&args, ":"))) {
+ if (av_parse_video_size(&scale->w, &scale->h, scale->size_str) < 0) {
+ av_freep(&scale->size_str);
+ args = args0;
+ } else if (*args)
+ args++;
+ }
+
+ if ((ret = av_opt_set_from_string(scale, args, shorthand, "=", ":")) < 0)
+ return ret;
+
+ if (scale->size_str && (scale->w_expr || scale->h_expr)) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Size and width/height expressions cannot be set at the same time.\n");
+ return AVERROR(EINVAL);
+ }
+
+ if (scale->size_str) {
+ char buf[32];
+ if ((ret = av_parse_video_size(&scale->w, &scale->h, scale->size_str)) < 0) {
+ av_log(ctx, AV_LOG_ERROR,
+ "Invalid size '%s'\n", scale->size_str);
+ return ret;
}
- if(strstr(args,"interl=1")){
- scale->interlaced=1;
- }else if(strstr(args,"interl=-1"))
- scale->interlaced=-1;
+ snprintf(buf, sizeof(buf)-1, "%d", scale->w);
+ av_opt_set(scale, "w", buf, 0);
+ snprintf(buf, sizeof(buf)-1, "%d", scale->h);
+ av_opt_set(scale, "h", buf, 0);
+ }
+ if (!scale->w_expr)
+ av_opt_set(scale, "w", "iw", 0);
+ if (!scale->h_expr)
+ av_opt_set(scale, "h", "ih", 0);
+
+ av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",
+ scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);
+
+ scale->flags = SWS_BILINEAR;
+ if (scale->flags_str) {
+ const AVClass *class = sws_get_class();
+ const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0,
+ AV_OPT_SEARCH_FAKE_OBJ);
+ int ret = av_opt_eval_flags(&class, o, scale->flags_str, &scale->flags);
+ if (ret < 0)
+ return ret;
}
return 0;
sws_freeContext(scale->isws[0]);
sws_freeContext(scale->isws[1]);
scale->sws = NULL;
+ av_opt_free(scale);
}
static int query_formats(AVFilterContext *ctx)
AVFilterLink *outlink = link->dst->outputs[0];
AVFilterBufferRef *outpicref, *for_next_filter;
const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
+ char buf[32];
int ret = 0;
if( picref->video->w != link->w
|| picref->video->h != link->h
|| picref->format != link->format) {
int ret;
- snprintf(scale->w_expr, sizeof(scale->w_expr)-1, "%d", outlink->w);
- snprintf(scale->h_expr, sizeof(scale->h_expr)-1, "%d", outlink->h);
+ snprintf(buf, sizeof(buf)-1, "%d", outlink->w);
+ av_opt_set(scale, "w", buf, 0);
+ snprintf(buf, sizeof(buf)-1, "%d", outlink->h);
+ av_opt_set(scale, "h", buf, 0);
link->dst->inputs[0]->format = picref->format;
link->dst->inputs[0]->w = picref->video->w;
link->dst->inputs[0]->h = picref->video->h;
if ((ret = config_props(outlink)) < 0)
- av_assert0(0); //what to do here ?
+ return ret;
}
-
if (!scale->sws) {
outpicref = avfilter_ref_buffer(picref, ~0);
if (!outpicref)
.inputs = avfilter_vf_scale_inputs,
.outputs = avfilter_vf_scale_outputs,
+ .priv_class = &scale_class,
};