00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include <stdio.h>
00027 #include <string.h>
00028
00029 #include "avfilter.h"
00030 #include "formats.h"
00031 #include "internal.h"
00032 #include "video.h"
00033 #include "libavutil/avstring.h"
00034 #include "libavutil/eval.h"
00035 #include "libavutil/internal.h"
00036 #include "libavutil/mathematics.h"
00037 #include "libavutil/opt.h"
00038 #include "libavutil/parseutils.h"
00039 #include "libavutil/pixdesc.h"
00040 #include "libavutil/imgutils.h"
00041 #include "libavutil/avassert.h"
00042 #include "libswscale/swscale.h"
00043
00044 static const char *const var_names[] = {
00045 "in_w", "iw",
00046 "in_h", "ih",
00047 "out_w", "ow",
00048 "out_h", "oh",
00049 "a",
00050 "sar",
00051 "dar",
00052 "hsub",
00053 "vsub",
00054 NULL
00055 };
00056
00057 enum var_name {
00058 VAR_IN_W, VAR_IW,
00059 VAR_IN_H, VAR_IH,
00060 VAR_OUT_W, VAR_OW,
00061 VAR_OUT_H, VAR_OH,
00062 VAR_A,
00063 VAR_SAR,
00064 VAR_DAR,
00065 VAR_HSUB,
00066 VAR_VSUB,
00067 VARS_NB
00068 };
00069
00070 typedef struct {
00071 const AVClass *class;
00072 struct SwsContext *sws;
00073 struct SwsContext *isws[2];
00074
00080 int w, h;
00081 char *flags_str;
00082 char *size_str;
00083 unsigned int flags;
00084
00085 int hsub, vsub;
00086 int slice_y;
00087 int input_is_pal;
00088 int output_is_pal;
00089 int interlaced;
00090
00091 char *w_expr;
00092 char *h_expr;
00093 } ScaleContext;
00094
00095 #define OFFSET(x) offsetof(ScaleContext, x)
00096 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
00097
00098 static const AVOption scale_options[] = {
00099 { "w", "set width expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
00100 { "width", "set width expression", OFFSET(w_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
00101 { "h", "set height expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
00102 { "height", "set height expression", OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
00103 { "flags", "set libswscale flags", OFFSET(flags_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, INT_MAX, FLAGS },
00104 { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, 1, FLAGS },
00105 { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS },
00106 { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS },
00107 { NULL },
00108 };
00109
00110 AVFILTER_DEFINE_CLASS(scale);
00111
00112 static av_cold int init(AVFilterContext *ctx, const char *args)
00113 {
00114 ScaleContext *scale = ctx->priv;
00115 static const char *shorthand[] = { "w", "h", NULL };
00116 int ret;
00117 const char *args0 = args;
00118
00119 scale->class = &scale_class;
00120 av_opt_set_defaults(scale);
00121
00122 if (args && (scale->size_str = av_get_token(&args, ":"))) {
00123 if (av_parse_video_size(&scale->w, &scale->h, scale->size_str) < 0) {
00124 av_freep(&scale->size_str);
00125 args = args0;
00126 } else if (*args)
00127 args++;
00128 }
00129
00130 if ((ret = av_opt_set_from_string(scale, args, shorthand, "=", ":")) < 0)
00131 return ret;
00132
00133 if (scale->size_str && (scale->w_expr || scale->h_expr)) {
00134 av_log(ctx, AV_LOG_ERROR,
00135 "Size and width/height expressions cannot be set at the same time.\n");
00136 return AVERROR(EINVAL);
00137 }
00138
00139 if (scale->size_str) {
00140 char buf[32];
00141 if ((ret = av_parse_video_size(&scale->w, &scale->h, scale->size_str)) < 0) {
00142 av_log(ctx, AV_LOG_ERROR,
00143 "Invalid size '%s'\n", scale->size_str);
00144 return ret;
00145 }
00146 snprintf(buf, sizeof(buf)-1, "%d", scale->w);
00147 av_opt_set(scale, "w", buf, 0);
00148 snprintf(buf, sizeof(buf)-1, "%d", scale->h);
00149 av_opt_set(scale, "h", buf, 0);
00150 }
00151 if (!scale->w_expr)
00152 av_opt_set(scale, "w", "iw", 0);
00153 if (!scale->h_expr)
00154 av_opt_set(scale, "h", "ih", 0);
00155
00156 av_log(ctx, AV_LOG_VERBOSE, "w:%s h:%s flags:'%s' interl:%d\n",
00157 scale->w_expr, scale->h_expr, (char *)av_x_if_null(scale->flags_str, ""), scale->interlaced);
00158
00159 scale->flags = SWS_BILINEAR;
00160 if (scale->flags_str) {
00161 const AVClass *class = sws_get_class();
00162 const AVOption *o = av_opt_find(&class, "sws_flags", NULL, 0,
00163 AV_OPT_SEARCH_FAKE_OBJ);
00164 int ret = av_opt_eval_flags(&class, o, scale->flags_str, &scale->flags);
00165 if (ret < 0)
00166 return ret;
00167 }
00168
00169 return 0;
00170 }
00171
00172 static av_cold void uninit(AVFilterContext *ctx)
00173 {
00174 ScaleContext *scale = ctx->priv;
00175 sws_freeContext(scale->sws);
00176 sws_freeContext(scale->isws[0]);
00177 sws_freeContext(scale->isws[1]);
00178 scale->sws = NULL;
00179 av_opt_free(scale);
00180 }
00181
00182 static int query_formats(AVFilterContext *ctx)
00183 {
00184 AVFilterFormats *formats;
00185 enum AVPixelFormat pix_fmt;
00186 int ret;
00187
00188 if (ctx->inputs[0]) {
00189 formats = NULL;
00190 for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++)
00191 if ( sws_isSupportedInput(pix_fmt)
00192 && (ret = ff_add_format(&formats, pix_fmt)) < 0) {
00193 ff_formats_unref(&formats);
00194 return ret;
00195 }
00196 ff_formats_ref(formats, &ctx->inputs[0]->out_formats);
00197 }
00198 if (ctx->outputs[0]) {
00199 formats = NULL;
00200 for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++)
00201 if ( (sws_isSupportedOutput(pix_fmt) || pix_fmt == AV_PIX_FMT_PAL8)
00202 && (ret = ff_add_format(&formats, pix_fmt)) < 0) {
00203 ff_formats_unref(&formats);
00204 return ret;
00205 }
00206 ff_formats_ref(formats, &ctx->outputs[0]->in_formats);
00207 }
00208
00209 return 0;
00210 }
00211
00212 static int config_props(AVFilterLink *outlink)
00213 {
00214 AVFilterContext *ctx = outlink->src;
00215 AVFilterLink *inlink = outlink->src->inputs[0];
00216 enum AVPixelFormat outfmt = outlink->format;
00217 ScaleContext *scale = ctx->priv;
00218 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
00219 int64_t w, h;
00220 double var_values[VARS_NB], res;
00221 char *expr;
00222 int ret;
00223
00224 var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w;
00225 var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h;
00226 var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN;
00227 var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN;
00228 var_values[VAR_A] = (double) inlink->w / inlink->h;
00229 var_values[VAR_SAR] = inlink->sample_aspect_ratio.num ?
00230 (double) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
00231 var_values[VAR_DAR] = var_values[VAR_A] * var_values[VAR_SAR];
00232 var_values[VAR_HSUB] = 1 << desc->log2_chroma_w;
00233 var_values[VAR_VSUB] = 1 << desc->log2_chroma_h;
00234
00235
00236 av_expr_parse_and_eval(&res, (expr = scale->w_expr),
00237 var_names, var_values,
00238 NULL, NULL, NULL, NULL, NULL, 0, ctx);
00239 scale->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res;
00240 if ((ret = av_expr_parse_and_eval(&res, (expr = scale->h_expr),
00241 var_names, var_values,
00242 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
00243 goto fail;
00244 scale->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res;
00245
00246 if ((ret = av_expr_parse_and_eval(&res, (expr = scale->w_expr),
00247 var_names, var_values,
00248 NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
00249 goto fail;
00250 scale->w = res;
00251
00252 w = scale->w;
00253 h = scale->h;
00254
00255
00256 if (w < -1 || h < -1) {
00257 av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n");
00258 return AVERROR(EINVAL);
00259 }
00260 if (w == -1 && h == -1)
00261 scale->w = scale->h = 0;
00262
00263 if (!(w = scale->w))
00264 w = inlink->w;
00265 if (!(h = scale->h))
00266 h = inlink->h;
00267 if (w == -1)
00268 w = av_rescale(h, inlink->w, inlink->h);
00269 if (h == -1)
00270 h = av_rescale(w, inlink->h, inlink->w);
00271
00272 if (w > INT_MAX || h > INT_MAX ||
00273 (h * inlink->w) > INT_MAX ||
00274 (w * inlink->h) > INT_MAX)
00275 av_log(ctx, AV_LOG_ERROR, "Rescaled value for width or height is too big.\n");
00276
00277 outlink->w = w;
00278 outlink->h = h;
00279
00280
00281
00282 scale->input_is_pal = desc->flags & PIX_FMT_PAL ||
00283 desc->flags & PIX_FMT_PSEUDOPAL;
00284 if (outfmt == AV_PIX_FMT_PAL8) outfmt = AV_PIX_FMT_BGR8;
00285 scale->output_is_pal = av_pix_fmt_desc_get(outfmt)->flags & PIX_FMT_PAL ||
00286 av_pix_fmt_desc_get(outfmt)->flags & PIX_FMT_PSEUDOPAL;
00287
00288 if (scale->sws)
00289 sws_freeContext(scale->sws);
00290 if (inlink->w == outlink->w && inlink->h == outlink->h &&
00291 inlink->format == outlink->format)
00292 scale->sws = NULL;
00293 else {
00294 scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
00295 outlink->w, outlink->h, outfmt,
00296 scale->flags, NULL, NULL, NULL);
00297 if (scale->isws[0])
00298 sws_freeContext(scale->isws[0]);
00299 scale->isws[0] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
00300 outlink->w, outlink->h/2, outfmt,
00301 scale->flags, NULL, NULL, NULL);
00302 if (scale->isws[1])
00303 sws_freeContext(scale->isws[1]);
00304 scale->isws[1] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
00305 outlink->w, outlink->h/2, outfmt,
00306 scale->flags, NULL, NULL, NULL);
00307 if (!scale->sws || !scale->isws[0] || !scale->isws[1])
00308 return AVERROR(EINVAL);
00309 }
00310
00311 if (inlink->sample_aspect_ratio.num){
00312 outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio);
00313 } else
00314 outlink->sample_aspect_ratio = inlink->sample_aspect_ratio;
00315
00316 av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d fmt:%s sar:%d/%d -> w:%d h:%d fmt:%s sar:%d/%d flags:0x%0x\n",
00317 inlink ->w, inlink ->h, av_get_pix_fmt_name( inlink->format),
00318 inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den,
00319 outlink->w, outlink->h, av_get_pix_fmt_name(outlink->format),
00320 outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den,
00321 scale->flags);
00322 return 0;
00323
00324 fail:
00325 av_log(NULL, AV_LOG_ERROR,
00326 "Error when evaluating the expression '%s'.\n"
00327 "Maybe the expression for out_w:'%s' or for out_h:'%s' is self-referencing.\n",
00328 expr, scale->w_expr, scale->h_expr);
00329 return ret;
00330 }
00331
00332 static int scale_slice(AVFilterLink *link, AVFilterBufferRef *out_buf, AVFilterBufferRef *cur_pic, struct SwsContext *sws, int y, int h, int mul, int field)
00333 {
00334 ScaleContext *scale = link->dst->priv;
00335 const uint8_t *in[4];
00336 uint8_t *out[4];
00337 int in_stride[4],out_stride[4];
00338 int i;
00339
00340 for(i=0; i<4; i++){
00341 int vsub= ((i+1)&2) ? scale->vsub : 0;
00342 in_stride[i] = cur_pic->linesize[i] * mul;
00343 out_stride[i] = out_buf->linesize[i] * mul;
00344 in[i] = cur_pic->data[i] + ((y>>vsub)+field) * cur_pic->linesize[i];
00345 out[i] = out_buf->data[i] + field * out_buf->linesize[i];
00346 }
00347 if(scale->input_is_pal)
00348 in[1] = cur_pic->data[1];
00349 if(scale->output_is_pal)
00350 out[1] = out_buf->data[1];
00351
00352 return sws_scale(sws, in, in_stride, y/mul, h,
00353 out,out_stride);
00354 }
00355
00356 static int filter_frame(AVFilterLink *link, AVFilterBufferRef *in)
00357 {
00358 ScaleContext *scale = link->dst->priv;
00359 AVFilterLink *outlink = link->dst->outputs[0];
00360 AVFilterBufferRef *out;
00361 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format);
00362 char buf[32];
00363
00364 if( in->video->w != link->w
00365 || in->video->h != link->h
00366 || in->format != link->format) {
00367 int ret;
00368 snprintf(buf, sizeof(buf)-1, "%d", outlink->w);
00369 av_opt_set(scale, "w", buf, 0);
00370 snprintf(buf, sizeof(buf)-1, "%d", outlink->h);
00371 av_opt_set(scale, "h", buf, 0);
00372
00373 link->dst->inputs[0]->format = in->format;
00374 link->dst->inputs[0]->w = in->video->w;
00375 link->dst->inputs[0]->h = in->video->h;
00376
00377 if ((ret = config_props(outlink)) < 0)
00378 return ret;
00379 }
00380
00381 if (!scale->sws)
00382 return ff_filter_frame(outlink, in);
00383
00384 scale->hsub = desc->log2_chroma_w;
00385 scale->vsub = desc->log2_chroma_h;
00386
00387 out = ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_ALIGN, outlink->w, outlink->h);
00388 if (!out) {
00389 avfilter_unref_bufferp(&in);
00390 return AVERROR(ENOMEM);
00391 }
00392
00393 avfilter_copy_buffer_ref_props(out, in);
00394 out->video->w = outlink->w;
00395 out->video->h = outlink->h;
00396
00397 if(scale->output_is_pal)
00398 avpriv_set_systematic_pal2((uint32_t*)out->data[1], outlink->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : outlink->format);
00399
00400 av_reduce(&out->video->sample_aspect_ratio.num, &out->video->sample_aspect_ratio.den,
00401 (int64_t)in->video->sample_aspect_ratio.num * outlink->h * link->w,
00402 (int64_t)in->video->sample_aspect_ratio.den * outlink->w * link->h,
00403 INT_MAX);
00404
00405 if(scale->interlaced>0 || (scale->interlaced<0 && link->cur_buf->video->interlaced)){
00406 scale_slice(link, out, in, scale->isws[0], 0, (link->h+1)/2, 2, 0);
00407 scale_slice(link, out, in, scale->isws[1], 0, link->h /2, 2, 1);
00408 }else{
00409 scale_slice(link, out, in, scale->sws, 0, link->h, 1, 0);
00410 }
00411
00412 avfilter_unref_bufferp(&in);
00413 return ff_filter_frame(outlink, out);
00414 }
00415
00416 static const AVFilterPad avfilter_vf_scale_inputs[] = {
00417 {
00418 .name = "default",
00419 .type = AVMEDIA_TYPE_VIDEO,
00420 .filter_frame = filter_frame,
00421 .min_perms = AV_PERM_READ,
00422 },
00423 { NULL }
00424 };
00425
00426 static const AVFilterPad avfilter_vf_scale_outputs[] = {
00427 {
00428 .name = "default",
00429 .type = AVMEDIA_TYPE_VIDEO,
00430 .config_props = config_props,
00431 },
00432 { NULL }
00433 };
00434
00435 AVFilter avfilter_vf_scale = {
00436 .name = "scale",
00437 .description = NULL_IF_CONFIG_SMALL("Scale the input video to width:height size and/or convert the image format."),
00438
00439 .init = init,
00440 .uninit = uninit,
00441
00442 .query_formats = query_formats,
00443
00444 .priv_size = sizeof(ScaleContext),
00445
00446 .inputs = avfilter_vf_scale_inputs,
00447 .outputs = avfilter_vf_scale_outputs,
00448 .priv_class = &scale_class,
00449 };