[FFmpeg-user] smarter scaling filter
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.
By trial and error I learned that the variable storage and manipulation
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
needed to scale down. One of the functions is apparently not doing what I
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
ffmpeg (created with st(var,expr) )?
TARGET FRAME SIZE values:
stored in var 0: 1 *
1 + 1
-vf="scale = st(0, min( 1 , gt(iw,$FW)+gt(ih,$FH) ) ) * \
( 1 *640 + 0 * 853.33 ) + 0 :
( gte(a,$FA)*$FW + lt(a,$FA)*(($FH*iw)/ih) ) + not(ld(0))*iw : \
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