[FFmpeg-user] smarter scaling filter

Jim Worrall coniophora at gmail.com
Sat Dec 10 01:01:22 CET 2011


On Dec 9, 2011, at 7:19 AM, Jim Worrall wrote:

> 
> On Dec 8, 2011, at 10:16 AM, Jim Worrall wrote:
> 
>> 
>> 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 "
> 
> 
> I have finally determined that the problem seems to be a bug in the evaluation of expressions.
> I reduced the filter to the simplest form needed to show the bug:
> 
> -vf "scale = st(0\,1) * 640 + not(ld(0)) * 1080 : ld(0) * 480 + not(ld(0)) * 720"
> . . . .


I found out I could reduce this expression even further, and it still seems to produce the wrong result:

-vf "scale = st(0,1) * 640 : ld(0) * 480"

The first function, st(0,1), evaluates to 1, and the output file has a width of 640.
The second function, ld(0), apparently evaluates to 0, and the output retains its original height.

Isn't ld(0) supposed to reload var 0 with a value of 1?
Does a variable not survive a colon, or what? 
Is it possible I screwed up the compilation and made a bad ffmpeg?

I could really use some help here guys!

Jim

ffmpeg version 0.8.7.git-5b98ea1, Copyright (c) 2000-2011 the FFmpeg developers
  built on Dec  9 2011 16:52:59 with clang 3.0 (tags/Apple/clang-211.12)
  configuration: --prefix=/Volumes/Ramdisk/sw --cc=clang --enable-gpl --enable-version3 --enable-filters --arch=x86_64 --enable-hardcoded-tables --disable-indevs --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libvo-aacenc --enable-libvpx --disable-decoder=libvpx --enable-libmp3lame --enable-libx264 --enable-libvorbis --enable-libtheora --enable-libspeex
  libavutil    51. 31. 0 / 51. 31. 0
  libavcodec   53. 42. 0 / 53. 42. 0
  libavformat  53. 24. 0 / 53. 24. 0
  libavdevice  53.  4. 0 / 53.  4. 0
  libavfilter   2. 52. 0 /  2. 52. 0
  libswscale    2.  1. 0 /  2.  1. 0
  libpostproc  51.  2. 0 / 51.  2. 0




More information about the ffmpeg-user mailing list