Make the filter accept parametric expressions for the output video size.
Unified · Split
| @@ -772,13 +772,33 @@ can be used to test the monowhite pixel format descriptor definition. · 771 unmodified lines | |||
| 772 | 772 | ||
| 773 | Scale the input video to @var{width}:@var{height} and/or convert the image format. | 773 | Scale the input video to @var{width}:@var{height} and/or convert the image format. |
| 774 | 774 | ||
| 775 | For example the command: | 775 | The parameters @var{width} and @var{height} are expressions containing |
| 776 | the following constants: | ||
| 776 | 777 | ||
| 777 | @example | 778 | @table @option |
| 778 | ./ffmpeg -i in.avi -vf "scale=200:100" out.avi | 779 | @item E, PI, PHI |
| 779 | @end example | 780 | the corresponding mathematical approximated values for e |
| 781 | (euler number), pi (greek PI), phi (golden ratio) | ||
| 782 | |||
| 783 | @item in_w, in_h | ||
| 784 | the input width and heigth | ||
| 785 | |||
| 786 | @item iw, ih | ||
| 787 | same as @var{in_w} and @var{in_h} | ||
| 788 | |||
| 789 | @item out_w, out_h | ||
| 790 | the output (cropped) width and heigth | ||
| 791 | |||
| 792 | @item ow, oh | ||
| 793 | same as @var{out_w} and @var{out_h} | ||
| 780 | 794 | ||
| 781 | will scale the input video to a size of 200x100. | 795 | @item a |
| 796 | input display aspect ratio, same as @var{iw} / @var{ih} | ||
| 797 | |||
| 798 | @item hsub, vsub | ||
| 799 | horizontal and vertical chroma subsample values. For example for the | ||
| 800 | pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1. | ||
| 801 | @end table | ||
| 782 | 802 | ||
| 783 | If the input image format is different from the format requested by | 803 | If the input image format is different from the format requested by |
| 784 | the next filter, the scale filter will convert the input to the | 804 | the next filter, the scale filter will convert the input to the |
| @@ -793,6 +813,36 @@ ratio of the input image. · 8 unmodified lines | |||
| 793 | 813 | ||
| 794 | The default value of @var{width} and @var{height} is 0. | 814 | The default value of @var{width} and @var{height} is 0. |
| 795 | 815 | ||
| 816 | Some examples follow: | ||
| 817 | @example | ||
| 818 | # scale the input video to a size of 200x100. | ||
| 819 | scale=200:100 | ||
| 820 | |||
| 821 | # scale the input to 2x | ||
| 822 | scale=2*iw:2*ih | ||
| 823 | # the above is the same as | ||
| 824 | scale=2*in_w:2*in_h | ||
| 825 | |||
| 826 | # scale the input to half size | ||
| 827 | scale=iw/2:ih/2 | ||
| 828 | |||
| 829 | # increase the width, and set the height to the same size | ||
| 830 | scale=3/2*iw:ow | ||
| 831 | |||
| 832 | # seek for Greek harmony | ||
| 833 | scale=iw:1/PHI*iw | ||
| 834 | scale=ih*PHI:ih | ||
| 835 | |||
| 836 | # increase the height, and set the width to 3/2 of the height | ||
| 837 | scale=3/2*oh:3/5*ih | ||
| 838 | |||
| 839 | # increase the size, but make the size a multiple of the chroma | ||
| 840 | scale="trunc(3/2*iw/hsub)*hsub:trunc(3/2*ih/vsub)*vsub" | ||
| 841 | |||
| 842 | # increase the width to a maximum of 500 pixels, keep the same input aspect ratio | ||
| 843 | scale='min(500\, iw*3/2):-1' | ||
| 844 | @end example | ||
| 845 | |||
| 796 | @anchor{setdar} | 846 | @anchor{setdar} |
| 797 | @section setdar | 847 | @section setdar |
| 798 | 848 | ||
| @@ -24,9 +24,39 @@ · 23 unmodified lines | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include "avfilter.h" | 26 | #include "avfilter.h" |
| 27 | #include "libavutil/avstring.h" | ||
| 28 | #include "libavutil/eval.h" | ||
| 27 | #include "libavutil/pixdesc.h" | 29 | #include "libavutil/pixdesc.h" |
| 28 | #include "libswscale/swscale.h" | 30 | #include "libswscale/swscale.h" |
| 29 | 31 | ||
| 32 | static const char *var_names[] = { | ||
| 33 | "PI", | ||
| 34 | "PHI", | ||
| 35 | "E", | ||
| 36 | "in_w", "iw", | ||
| 37 | "in_h", "ih", | ||
| 38 | "out_w", "ow", | ||
| 39 | "out_h", "oh", | ||
| 40 | "a", | ||
| 41 | "hsub", | ||
| 42 | "vsub", | ||
| 43 | NULL | ||
| 44 | }; | ||
| 45 | |||
| 46 | enum var_name { | ||
| 47 | VAR_PI, | ||
| 48 | VAR_PHI, | ||
| 49 | VAR_E, | ||
| 50 | VAR_IN_W, VAR_IW, | ||
| 51 | VAR_IN_H, VAR_IH, | ||
| 52 | VAR_OUT_W, VAR_OW, | ||
| 53 | VAR_OUT_H, VAR_OH, | ||
| 54 | VAR_A, | ||
| 55 | VAR_HSUB, | ||
| 56 | VAR_VSUB, | ||
| 57 | VARS_NB | ||
| 58 | }; | ||
| 59 | |||
| 30 | typedef struct { | 60 | typedef struct { |
| 31 | struct SwsContext *sws; ///< software scaler context | 61 | struct SwsContext *sws; ///< software scaler context |
| 32 | 62 | ||
| @@ -41,6 +71,9 @@ typedef struct { · 8 unmodified lines | |||
| 41 | int hsub, vsub; ///< chroma subsampling | 71 | int hsub, vsub; ///< chroma subsampling |
| 42 | int slice_y; ///< top of current output slice | 72 | int slice_y; ///< top of current output slice |
| 43 | int input_is_pal; ///< set to 1 if the input format is paletted | 73 | int input_is_pal; ///< set to 1 if the input format is paletted |
| 74 | |||
| 75 | char w_expr[256]; ///< width expression string | ||
| 76 | char h_expr[256]; ///< height expression string | ||
| 44 | } ScaleContext; | 77 | } ScaleContext; |
| 45 | 78 | ||
| 46 | static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) | 79 | static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) |
| @@ -48,21 +81,16 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque) · 1 unmodified line | |||
| 48 | ScaleContext *scale = ctx->priv; | 81 | ScaleContext *scale = ctx->priv; |
| 49 | const char *p; | 82 | const char *p; |
| 50 | 83 | ||
| 84 | av_strlcpy(scale->w_expr, "iw", sizeof(scale->w_expr)); | ||
| 85 | av_strlcpy(scale->h_expr, "ih", sizeof(scale->h_expr)); | ||
| 86 | |||
| 51 | scale->flags = SWS_BILINEAR; | 87 | scale->flags = SWS_BILINEAR; |
| 52 | if (args) { | 88 | if (args) { |
| 53 | sscanf(args, "%d:%d", &scale->w, &scale->h); | 89 | sscanf(args, "%255[^:]:%255[^:]", scale->w_expr, scale->h_expr); |
| 54 | p = strstr(args,"flags="); | 90 | p = strstr(args,"flags="); |
| 55 | if (p) scale->flags = strtoul(p+6, NULL, 0); | 91 | if (p) scale->flags = strtoul(p+6, NULL, 0); |
| 56 | } | 92 | } |
| 57 | 93 | ||
| 58 | /* sanity check params */ | ||
| 59 | if (scale->w < -1 || scale->h < -1) { | ||
| 60 | av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n"); | ||
| 61 | return AVERROR(EINVAL); | ||
| 62 | } | ||
| 63 | if (scale->w == -1 && scale->h == -1) | ||
| 64 | scale->w = scale->h = 0; | ||
| 65 | |||
| 66 | return 0; | 94 | return 0; |
| 67 | } | 95 | } |
| 68 | 96 | ||
| @@ -109,6 +137,48 @@ static int config_props(AVFilterLink *outlink) · 40 unmodified lines | |||
| 109 | AVFilterLink *inlink = outlink->src->inputs[0]; | 137 | AVFilterLink *inlink = outlink->src->inputs[0]; |
| 110 | ScaleContext *scale = ctx->priv; | 138 | ScaleContext *scale = ctx->priv; |
| 111 | int64_t w, h; | 139 | int64_t w, h; |
| 140 | double var_values[VARS_NB], res; | ||
| 141 | char *expr; | ||
| 142 | int ret; | ||
| 143 | |||
| 144 | var_values[VAR_PI] = M_PI; | ||
| 145 | var_values[VAR_PHI] = M_PHI; | ||
| 146 | var_values[VAR_E] = M_E; | ||
| 147 | var_values[VAR_IN_W] = var_values[VAR_IW] = inlink->w; | ||
| 148 | var_values[VAR_IN_H] = var_values[VAR_IH] = inlink->h; | ||
| 149 | var_values[VAR_OUT_W] = var_values[VAR_OW] = NAN; | ||
| 150 | var_values[VAR_OUT_H] = var_values[VAR_OH] = NAN; | ||
| 151 | var_values[VAR_A] = (float) inlink->w / inlink->h; | ||
| 152 | var_values[VAR_HSUB] = 1<<av_pix_fmt_descriptors[inlink->format].log2_chroma_w; | ||
| 153 | var_values[VAR_VSUB] = 1<<av_pix_fmt_descriptors[inlink->format].log2_chroma_h; | ||
| 154 | |||
| 155 | /* evaluate width and height */ | ||
| 156 | av_expr_parse_and_eval(&res, (expr = scale->w_expr), | ||
| 157 | var_names, var_values, | ||
| 158 | NULL, NULL, NULL, NULL, NULL, 0, ctx); | ||
| 159 | scale->w = var_values[VAR_OUT_W] = var_values[VAR_OW] = res; | ||
| 160 | if ((ret = av_expr_parse_and_eval(&res, (expr = scale->h_expr), | ||
| 161 | var_names, var_values, | ||
| 162 | NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) | ||
| 163 | goto fail; | ||
| 164 | scale->h = var_values[VAR_OUT_H] = var_values[VAR_OH] = res; | ||
| 165 | /* evaluate again the width, as it may depend on the output height */ | ||
| 166 | if ((ret = av_expr_parse_and_eval(&res, (expr = scale->w_expr), | ||
| 167 | var_names, var_values, | ||
| 168 | NULL, NULL, NULL, NULL, NULL, 0, ctx)) < 0) | ||
| 169 | goto fail; | ||
| 170 | scale->w = res; | ||
| 171 | |||
| 172 | w = scale->w; | ||
| 173 | h = scale->h; | ||
| 174 | |||
| 175 | /* sanity check params */ | ||
| 176 | if (w < -1 || h < -1) { | ||
| 177 | av_log(ctx, AV_LOG_ERROR, "Size values less than -1 are not acceptable.\n"); | ||
| 178 | return AVERROR(EINVAL); | ||
| 179 | } | ||
| 180 | if (w == -1 && h == -1) | ||
| 181 | scale->w = scale->h = 0; | ||
| 112 | 182 | ||
| 113 | if (!(w = scale->w)) | 183 | if (!(w = scale->w)) |
| 114 | w = inlink->w; | 184 | w = inlink->w; |
| @@ -142,6 +212,11 @@ static int config_props(AVFilterLink *outlink) · 27 unmodified lines | |||
| 142 | return AVERROR(EINVAL); | 212 | return AVERROR(EINVAL); |
| 143 | 213 | ||
| 144 | return 0; | 214 | return 0; |
| 215 | |||
| 216 | fail: | ||
| 217 | av_log(NULL, AV_LOG_ERROR, | ||
| 218 | "Error when evaluating the expression '%s'\n", expr); | ||
| 219 | return ret; | ||
| 145 | } | 220 | } |
| 146 | 221 | ||
| 147 | static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) | 222 | static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref) |