[FFmpeg-user] smarter scaling filter

Jim Worrall coniophora at gmail.com
Thu Dec 8 18:16:42 CET 2011


On Wed, Dec 7, 2011 at 3:24 PM, Jim Worrall <coniophora at gmail.com> wrote:

> I've been trying to find or write a script/filtergraph that will take a
> target frame size and automatically scale down the input video (maintaining
> aspect ratio) if needed to fit the frame, and leave it the same if it is
> already the size or smaller than the frame.  I'm in a bit over my head and
> hoping for some pointers.
>
> I'm starting with a very clever set of calculations that Francesco Turco
> posted here 12 June 2011. One side of each plus sign will always evaluate
> to 0 (escapes removed for clarity; his target frame size was 720x576):
> -vf scale = '
> gte(iw/ih,720/576)*720 + lt(iw/ih,720/576)*((576*iw)/ih) :
> lte(iw/ih,720/576)*576 + gt(iw/ih,720/576)*((720*ih)/iw) '
>
> He thought it was too long, but still seems a great approach.  The problem
> for me is it will upscale too, which seems undesirable if the device
> doesn't require an exact size.  So I'm trying to add some logic to keep the
> input scale if both iw and ih are the size of or smaller than the frame.
> While I'm at it, I'm hoping to use some variables from the script for the
> frame size.
>
> The bash script asks for the target device (just iPhone 3 or iPhone4 now)
> and sets device-specific values for the maximum frame width ($FW) and
> height ($FH) and the corresponding aspect ratio ($FA).  The filter also
> seems to need some stored variables within ffmpeg, but I've only found one
> example of their real use on the web and couldn't make much sense out of
> it.  I can't figure how st(var,expr) is supposed to be incorporated into
> the filter, since it can't seem to go before it.  And there's a
> while(cond,expr) I don't know where to put either.
>
> Here's an idea what I'm trying to do, and I think it is a long way from
> working.  The st(0,expr) that I put in the beginning (not knowing where it
> goes) stores 0 if both dimensions fit in the target frame.  I'm not sure if
> I can use a script variable inside a filter, hope so.  Anyway, the while
> statement is supposed to convert var 0 to 1 if it is not 0.  The rest is
> just an add-on to Francesco's filter that should specify the input
> dimensions if var 0 is 0.
> -vf = "st(0,gt(iw,$FW)+gt(ih,$FH)) ;
>   while(ld(0),st(0,1) ;
>   scale= ld(0) * ( gte(a,$FA)*$FW + lt(a,$FA)*(($FH*iw)/ih) ) +
> eq(0,ld(0))*iw :
>              ld(0) * ( lte(a,$FA)*$FH + gt(a,$FA)*(($FW*ih)/iw) ) +
> eq(0,ld(0))*ih "
>
> In case it matters, I'm a user/hobbyist.  Any tips will be appreciated.
> Thanks,
> Jim
>

By trial and error I learned that the variable storage and manipulation
functions have
to go where the variables are first used in the actual filter expression.
Doing that I eventually got it to run without errors, so major progress.

It worked as expected for video
with smaller size than the target frame size, but not with a video that it
actually
needed to scale down.  One of the functions is apparently not doing what I
think it
does.  I would appreciate some help.

Here are the input values from the input file and the target values from
the script (which
are getting read correctly).  The filter should give a video of 640x360,
but it actually gives
640x720. Below is the scale filter expression and above each line, how I
think it should
evaluate for the current case.  I guess there is no way to see the value of
variables inside
ffmpeg (created with st(var,expr) )?

Jim

INPUT values:
iw    1280
ih    720
a    ~1.78
TARGET FRAME SIZE values:
$FW    640
$FH    480
$FA    ~1.33

        stored in var 0:    1                         *
                                   1  +     1
-vf="scale = st(0, min( 1 , gt(iw,$FW)+gt(ih,$FH) ) ) * \

                    640                                      :
(      1    *640 +    0     *    853.33    ) +         0     :
( gte(a,$FA)*$FW + lt(a,$FA)*(($FH*iw)/ih) ) + not(ld(0))*iw : \

                    360
  1   * (      0    *480 +    1     *   360        ) +    0
ld(0) * ( lte(a,$FA)*$FH + gt(a,$FA)*(($FW*ih)/iw) ) + not(ld(0))*ih "


More information about the ffmpeg-user mailing list