lavfi/tests/filtfmts: fix the build warning.
[ffmpeg.git] / libavfilter / vf_pad.c
index 45b32e6..ed15557 100644 (file)
@@ -24,6 +24,8 @@
  * video padding filter
  */
 
+#include <float.h>  /* DBL_MAX */
+
 #include "avfilter.h"
 #include "formats.h"
 #include "internal.h"
@@ -33,9 +35,7 @@
 #include "libavutil/eval.h"
 #include "libavutil/pixdesc.h"
 #include "libavutil/colorspace.h"
-#include "libavutil/avassert.h"
 #include "libavutil/imgutils.h"
-#include "libavutil/opt.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/mathematics.h"
 #include "libavutil/opt.h"
@@ -74,15 +74,22 @@ enum var_name {
 
 static int query_formats(AVFilterContext *ctx)
 {
-    ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
-    return 0;
+    return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0));
 }
 
-typedef struct {
+enum EvalMode {
+    EVAL_MODE_INIT,
+    EVAL_MODE_FRAME,
+    EVAL_MODE_NB
+};
+
+typedef struct PadContext {
     const AVClass *class;
     int w, h;               ///< output dimensions, a value of 0 will result in the input size
     int x, y;               ///< offsets of the input area with respect to the padded area
     int in_w, in_h;         ///< width and height for the padded input video, which has to be aligned to the chroma values in order to avoid chroma issues
+    int inlink_w, inlink_h;
+    AVRational aspect;
 
     char *w_expr;           ///< width  expression string
     char *h_expr;           ///< height expression string
@@ -91,12 +98,15 @@ typedef struct {
     uint8_t rgba_color[4];  ///< color for the padding area
     FFDrawContext draw;
     FFDrawColor color;
+
+    int eval_mode;          ///< expression evaluation mode
 } PadContext;
 
 static int config_input(AVFilterLink *inlink)
 {
     AVFilterContext *ctx = inlink->dst;
     PadContext *s = ctx->priv;
+    AVRational adjusted_aspect = s->aspect;
     int ret;
     double var_values[VARS_NB], res;
     char *expr;
@@ -125,12 +135,26 @@ static int config_input(AVFilterLink *inlink)
                                       NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
         goto eval_fail;
     s->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res;
+    if (!s->h)
+        var_values[VAR_OUT_H] = var_values[VAR_OH] = s->h = inlink->h;
+
     /* evaluate the width again, as it may depend on the evaluated output height */
     if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr),
                                       var_names, var_values,
                                       NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0)
         goto eval_fail;
     s->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res;
+    if (!s->w)
+        var_values[VAR_OUT_W] = var_values[VAR_OW] = s->w = inlink->w;
+
+    if (adjusted_aspect.num && adjusted_aspect.den) {
+        adjusted_aspect = av_div_q(adjusted_aspect, inlink->sample_aspect_ratio);
+        if (s->h < av_rescale(s->w, adjusted_aspect.den, adjusted_aspect.num)) {
+            s->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = av_rescale(s->w, adjusted_aspect.den, adjusted_aspect.num);
+        } else {
+            s->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = av_rescale(s->h, adjusted_aspect.num, adjusted_aspect.den);
+        }
+    }
 
     /* evaluate x and y */
     av_expr_parse_and_eval(&res, (expr = s->x_expr),
@@ -149,23 +173,25 @@ static int config_input(AVFilterLink *inlink)
         goto eval_fail;
     s->x = var_values[VAR_X] = res;
 
+    if (s->x < 0 || s->x + inlink->w > s->w)
+        s->x = var_values[VAR_X] = (s->w - inlink->w) / 2;
+    if (s->y < 0 || s->y + inlink->h > s->h)
+        s->y = var_values[VAR_Y] = (s->h - inlink->h) / 2;
+
     /* sanity check params */
-    if (s->w < 0 || s->h < 0 || s->x < 0 || s->y < 0) {
+    if (s->w < 0 || s->h < 0) {
         av_log(ctx, AV_LOG_ERROR, "Negative values are not acceptable.\n");
         return AVERROR(EINVAL);
     }
 
-    if (!s->w)
-        s->w = inlink->w;
-    if (!s->h)
-        s->h = inlink->h;
-
     s->w    = ff_draw_round_to_sub(&s->draw, 0, -1, s->w);
     s->h    = ff_draw_round_to_sub(&s->draw, 1, -1, s->h);
     s->x    = ff_draw_round_to_sub(&s->draw, 0, -1, s->x);
     s->y    = ff_draw_round_to_sub(&s->draw, 1, -1, s->y);
     s->in_w = ff_draw_round_to_sub(&s->draw, 0, -1, inlink->w);
     s->in_h = ff_draw_round_to_sub(&s->draw, 1, -1, inlink->h);
+    s->inlink_w = inlink->w;
+    s->inlink_h = inlink->h;
 
     av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d x:%d y:%d color:0x%02X%02X%02X%02X\n",
            inlink->w, inlink->h, s->w, s->h, s->x, s->y,
@@ -202,12 +228,16 @@ static int config_output(AVFilterLink *outlink)
 static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h)
 {
     PadContext *s = inlink->dst->priv;
-
-    AVFrame *frame = ff_get_video_buffer(inlink->dst->outputs[0],
-                                         w + (s->w - s->in_w),
-                                         h + (s->h - s->in_h));
+    AVFrame *frame;
     int plane;
 
+    if (s->inlink_w <= 0)
+        return NULL;
+
+    frame = ff_get_video_buffer(inlink->dst->outputs[0],
+                                w + (s->w - s->in_w),
+                                h + (s->h - s->in_h) + (s->x > 0));
+
     if (!frame)
         return NULL;
 
@@ -252,7 +282,7 @@ static int buffer_needs_copy(PadContext *s, AVFrame *frame, AVBufferRef *buf)
                               (s->y >> vsub) * frame->linesize[planes[i]];
         ptrdiff_t req_end   = ((s->w - s->x - frame->width) >> hsub) *
                               s->draw.pixelstep[planes[i]] +
-                              (s->y >> vsub) * frame->linesize[planes[i]];
+                              ((s->h - s->y - frame->height) >> vsub) * frame->linesize[planes[i]];
 
         if (frame->linesize[planes[i]] < (s->w >> hsub) * s->draw.pixelstep[planes[i]])
             return 1;
@@ -293,8 +323,35 @@ static int frame_needs_copy(PadContext *s, AVFrame *frame)
 static int filter_frame(AVFilterLink *inlink, AVFrame *in)
 {
     PadContext *s = inlink->dst->priv;
+    AVFilterLink *outlink = inlink->dst->outputs[0];
     AVFrame *out;
-    int needs_copy = frame_needs_copy(s, in);
+    int needs_copy;
+    if(s->eval_mode == EVAL_MODE_FRAME && (
+           in->width  != s->inlink_w
+        || in->height != s->inlink_h
+        || in->format != outlink->format
+        || in->sample_aspect_ratio.den != outlink->sample_aspect_ratio.den || in->sample_aspect_ratio.num != outlink->sample_aspect_ratio.num)) {
+        int ret;
+
+        inlink->dst->inputs[0]->format = in->format;
+        inlink->dst->inputs[0]->w      = in->width;
+        inlink->dst->inputs[0]->h      = in->height;
+
+        inlink->dst->inputs[0]->sample_aspect_ratio.den = in->sample_aspect_ratio.den;
+        inlink->dst->inputs[0]->sample_aspect_ratio.num = in->sample_aspect_ratio.num;
+
+
+        if ((ret = config_input(inlink)) < 0) {
+            s->inlink_w = -1;
+            return ret;
+        }
+        if ((ret = config_output(outlink)) < 0) {
+            s->inlink_w = -1;
+            return ret;
+        }
+    }
+
+    needs_copy = frame_needs_copy(s, in);
 
     if (needs_copy) {
         av_log(inlink->dst, AV_LOG_DEBUG, "Direct padding impossible allocating new frame\n");
@@ -367,6 +424,10 @@ static const AVOption pad_options[] = {
     { "x",      "set the x offset expression for the input image position", OFFSET(x_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
     { "y",      "set the y offset expression for the input image position", OFFSET(y_expr), AV_OPT_TYPE_STRING, {.str = "0"}, CHAR_MIN, CHAR_MAX, FLAGS },
     { "color",  "set the color of the padded area border", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS },
+    { "eval",   "specify when to evaluate expressions",    OFFSET(eval_mode), AV_OPT_TYPE_INT, {.i64 = EVAL_MODE_INIT}, 0, EVAL_MODE_NB-1, FLAGS, "eval" },
+         { "init",  "eval expressions once during initialization", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_INIT},  .flags = FLAGS, .unit = "eval" },
+         { "frame", "eval expressions during initialization and per-frame", 0, AV_OPT_TYPE_CONST, {.i64=EVAL_MODE_FRAME}, .flags = FLAGS, .unit = "eval" },
+    { "aspect",  "pad to fit an aspect instead of a resolution", OFFSET(aspect), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, DBL_MAX, FLAGS },
     { NULL }
 };
 
@@ -392,9 +453,9 @@ static const AVFilterPad avfilter_vf_pad_outputs[] = {
     { NULL }
 };
 
-AVFilter avfilter_vf_pad = {
+AVFilter ff_vf_pad = {
     .name          = "pad",
-    .description   = NULL_IF_CONFIG_SMALL("Pad input image to width:height[:x:y[:color]] (default x and y: 0, default color: black)."),
+    .description   = NULL_IF_CONFIG_SMALL("Pad the input video."),
     .priv_size     = sizeof(PadContext),
     .priv_class    = &pad_class,
     .query_formats = query_formats,