2

I am currently trying to have ffmpeg blur part of an input video, using boxes over 1/10 seconds frames from a previous part of the program.

The command is along these lines:

ffmpeg -y -i input.mp4 -pix_fmt yuv420p -filter_complex [0:v]crop='in_w*if(lt(t,0.1),0.23132270574569702,if(lt(t,0.2),0.21441733837127686,if(lt(t,0.30000000000000004),0.1499532163143158,if(lt(t,0.4),0.1259399652481079,if(lt(t,0.5),0.16647100448608398,if(lt(t,0.6),0.209006667137146,if(lt(t,0.7),0.19645869731903076,if(lt(t,0.7999999999999999),0.14811599254608154,if(lt(t,0.9),0.13625645637512207,if(lt(t,1.0),0.23812496662139893,if(lt(t,1.1),0.24143600463867188,if(lt(t,1.2000000000000002),0.21351194381713867,if(lt(t,1.3),0.15060842037200928,if(lt(t,1.4000000000000001),0.11908853054046631,if(lt(t,2.0),0.10922718048095703,0.5)))))))))))))))':'in_h*if(lt(t,0.1),0.7302078008651733,if(lt(t,0.2),0.72728231549263,if(lt(t,0.30000000000000004),0.7276445627212524,if(lt(t,0.4),0.7524535357952118,if(lt(t,0.5),0.7392034530639648,if(lt(t,0.6),0.7145015895366669,if(lt(t,0.7),0.6905231177806854,if(lt(t,0.7999999999999999),0.7224559783935547,if(lt(t,0.9),0.7534412145614624,if(lt(t,1.0),0.7607900202274323,if(lt(t,1.1),0.7299857437610626,if(lt(t,1.2000000000000002),0.7394903004169464,if(lt(t,1.3),0.7487046718597412,if(lt(t,1.4000000000000001),0.7166697978973389,if(lt(t,2.0),0.7316611707210541,0.5)))))))))))))))':'in_w*if(lt(t,0.1),0.3309709429740906,if(lt(t,0.2),0.357507586479187,if(lt(t,0.30000000000000004),0.44701889157295227,if(lt(t,0.4),0.5001536011695862,if(lt(t,0.5),0.5295754075050354,if(lt(t,0.6),0.5418452620506287,if(lt(t,0.7),0.5671597719192505,if(lt(t,0.7999999999999999),0.6490602493286133,if(lt(t,0.9),0.6897507905960083,if(lt(t,1.0),0.6941888928413391,if(lt(t,1.1),0.7210350036621094,if(lt(t,1.2000000000000002),0.7504343390464783,if(lt(t,1.3),0.8392617702484131,if(lt(t,1.4000000000000001),0.880531907081604,if(lt(t,2.0),0.890772819519043,0.5)))))))))))))))':'in_h*if(lt(t,0.1),0.24461424350738525,if(lt(t,0.2),0.255586713552475,if(lt(t,0.30000000000000004),0.2545440196990967,if(lt(t,0.4),0.2454611361026764,if(lt(t,0.5),0.25117623805999756,if(lt(t,0.6),0.2627399265766144,if(lt(t,0.7),0.275628000497818,if(lt(t,0.7999999999999999),0.25284475088119507,if(lt(t,0.9),0.2374727725982666,if(lt(t,1.0),0.23920997977256775,if(lt(t,1.1),0.25456926226615906,if(lt(t,1.2000000000000002),0.25374671816825867,if(lt(t,1.3),0.23654210567474365,if(lt(t,1.4000000000000001),0.25168418884277344,if(lt(t,2.0),0.2447432577610016,0.5)))))))))))))))',boxblur=12[fg];[0:v][fg]overlay='main_w*if(lt(t,0.1),0.3309709429740906,if(lt(t,0.2),0.357507586479187,if(lt(t,0.30000000000000004),0.44701889157295227,if(lt(t,0.4),0.5001536011695862,if(lt(t,0.5),0.5295754075050354,if(lt(t,0.6),0.5418452620506287,if(lt(t,0.7),0.5671597719192505,if(lt(t,0.7999999999999999),0.6490602493286133,if(lt(t,0.9),0.6897507905960083,if(lt(t,1.0),0.6941888928413391,if(lt(t,1.1),0.7210350036621094,if(lt(t,1.2000000000000002),0.7504343390464783,if(lt(t,1.3),0.8392617702484131,if(lt(t,1.4000000000000001),0.880531907081604,if(lt(t,2.0),0.890772819519043,0.5)))))))))))))))':'main_h*if(lt(t,0.1),0.24461424350738525,if(lt(t,0.2),0.255586713552475,if(lt(t,0.30000000000000004),0.2545440196990967,if(lt(t,0.4),0.2454611361026764,if(lt(t,0.5),0.25117623805999756,if(lt(t,0.6),0.2627399265766144,if(lt(t,0.7),0.275628000497818,if(lt(t,0.7999999999999999),0.25284475088119507,if(lt(t,0.9),0.2374727725982666,if(lt(t,1.0),0.23920997977256775,if(lt(t,1.1),0.25456926226615906,if(lt(t,1.2000000000000002),0.25374671816825867,if(lt(t,1.3),0.23654210567474365,if(lt(t,1.4000000000000001),0.25168418884277344,if(lt(t,2.0),0.2447432577610016,0.5)))))))))))))))':enable='between(t,-0.5,1.9)'[v] -map [v] -map 0:a? output.mp4 

The general idea being to build "brackets" for width,height,x,y for every tenth of a second, and use the box coordinates to fill in the values.

While this works fine for the "overlay" part, for the "crop" part the width and height of the cropped region is only evaluated once (as the documentation mentions: https://ffmpeg.org/ffmpeg-filters.html#crop).

Using 't' directly in a width expression outright results in a Invalid argument error.

Is there a way to force ffmpeg to recalculate crop dimensions every frame, or another approach to the issue?

0

The crop filter doesn't accept variable dimensions for output. But the end goal of blurring a variable region of the input and superimposing that on the original input can be achieved using a different route. Since your original list of conditions will be too long to make for a clear and short presentation, I've used fewer conditionals. But you should be able to easily expand it.

ffmpeg -i input.mp4 -filter_complex
  "[0]split=3[orig][blur][alpha];
   [blur]boxblur=12[blur];
   [alpha]format=gray,drawbox=color=black:t=fill,
   drawbox=w='iw*0.231':h='ih*0.730':x='iw*0.330':y='ih*0.244':t=fill:color=white:enable='between(t,0,0.1)',
   drawbox=w='iw*0.214':h='ih*0.727':x='iw*0.357':y='ih*0.255':t=fill:color=white:enable='between(t,0.1,0.2)',
   drawbox=w='iw*0.149':h='ih*0.727':x='iw*0.447':y='ih*0.254':t=fill:color=white:enable='between(t,0.2,0.3)'[alpha];
   [blur][alpha]alphamerge[blurred];
   [orig][blurred]overlay" -c:a copy output.mp4

The gist of the method is to

1)blur a copy of the full frame of the input.

2)Black out a 2nd copy of the input. Then draw a white box at the co-ordinates you wish to keep.

3)Merge this 3rd copy as an alpha plane with the blurred copy.

4)Overlay the blurred stream onto the original. When the overlay has an alpha plane, the filter blends the two inputs using the alpha as a key. The overlay region where the alpha is black becomes invisible, and where the alpha is white, remains opaque.

If you have an older version of ffmpeg, you will have to use max in place of fill in drawbox.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.