ffmpegmp4mask

How create a circular video (transparent area on top of video) effect without applying image mask to video


Basically i googled a lot and solutions suggests apply some PNG mask or do not provide needed solution.

What i've found.

ffmpeg -i main.mkv -i facecloseup.mkv
 -filter_complex "[1]trim=end_frame=1,
  geq='st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),pow(min(W/2,H/2),2)),255,0)':128:128,
  loop=-1:1,setpts=N/FRAME_RATE/TB[mask];
  [1][mask]alphamerge[cutout];
  [0][cutout]overlay=x=W-w:y=0[v];
  [0][1]amix=2[a]"
 -map "[v]" -map "[a]"  out.mp4
command = "-i " + this.video1Path.getPath() + " -i " + this.video2Path.getPath() + " -filter_complex [1]trim=end_frame=1,geq=lum_expr='st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3)," + (this.mZoomLayout.getZoomedWidth()/2) + "*" + (this.mZoomLayout.getZoomedWidth()/2) + "),255,0)':128:128,format=gray,loop=-1:1,setpts=N/FRAME_RATE/TB[mask];[1][mask]alphamerge,format=rgba,lutrgb=a=if(gte(val\\,16)\\,val)[cutout];[0][cutout]overlay=" + this.mZoomLayout.getCircleX() + ":" + this.mZoomLayout.getCircleY() + ":enable='between(t,0," + this.videoTwoDuration + ") -c:v libx264 -crf 24 -preset ultrafast " + videoPath.getPath(); 

So i tried to extract needed things from them, but i don't understand how exactly i need to do that, i did this:

ffmpeg -i video.mp4 -filter_complex "[0]geq='st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),pow(min(W/2,H/2),2)),255,0)':H:W; [0:v][mask]alphamerge" out.mp4
[mov,mp4,m4a,3gp,3g2,mj2 @ 000001f761dd8e40] Invalid stream specifier: mask.
    Last message repeated 1 times
Stream specifier 'mask' in filtergraph description [0]geq='st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),pow(min(W/2,H/2),2)),255,0)':H:W; [0:v][mask]alphamerge matches no streams.
ffmpeg -i video.mp4 -filter_complex "[0]geq=lum_expr='st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),pow(min(W/2,H/2),2)),255,0)':H:W; [0:v][mask]alphamerge" out.mp4
[mov,mp4,m4a,3gp,3g2,mj2 @ 000001bfd9218e80] Invalid stream specifier: mask.
    Last message repeated 1 times
Stream specifier 'mask' in filtergraph description [0]geq=lum_expr='st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),pow(min(W/2,H/2),2)),255,0)':H:W; [0:v][mask]alphamerge matches no streams.

And one more time, guys, if you are going to post some "prepared image mask" solution - just leave, the question is about creating mask on air.

So, let's say we have red square (yes, ratio is static, always 1:1), yes, i can't post it because i dont have 10 rep. (...).

https://i.sstatic.net/MsL71.png - red square.

https://i.sstatic.net/aIFEV.png - circle

https://i.sstatic.net/R8EAx.png - result

https://i.sstatic.net/WtqQg.png - final result

I actually want to get the answer from @Gyan or @llogan because i searched a lot and only these two guys do understand how to make things programmatically.

More tech details: Aspect ratio is constant - 1:1, width and height should be taken from the video in auto way, we need to create a white square with transparent circle inside it, the end result must contain "rounded" video with white background.


Solution

  • You can replicate your "final result" with this images:

    2 inputs

    red vignette over blue circle

    The value of the height variable should match the height of your source files. In this case it's 600px.

    red="red.png"
    blue="blue.png"
    
    height=600
    
    ffmpeg \
    -loop 1 -i "${red}" \
    -loop 1 -i "${blue}" \
    -filter_complex "\
    [1]format=yuva444p,geq=lum='p(X,Y)':a='st(1,pow(min(W/2,H/2),2))+st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),ld(1)),255,0)'[circular shaped video];\
    [circular shaped video]scale=w=-1:h=${height}[circular shaped video small];\
    [0][circular shaped video small]overlay" \
    -filter_complex_threads 1 \
    -c:v libx264 \
    -preset ultrafast \
    -t 5 \
    "final_result.mp4"
    

    You only need the -loop 1 options in front of the input when using images.

    If you are using video you might decide which audio to use.

    You can see everything in detail in my original post.

    1 input only

    red vignette over blue circle

    Here you only have to choose the color of the circular vignette.

    Color names are listet in the documentation.

    in="blue.png"
    
    vignette_color="red"
    
    ffmpeg \
    -loop 1 -i "${in}" \
    -filter_complex "\
    [0]setsar=1:1,format=yuva444p,drawbox=color=${vignette_color}@1:t=fill[vignette];\
    [0]format=yuva444p,geq=lum='p(X,Y)':a='st(1,pow(min(W/2,H/2),2))+st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),ld(1)),255,0)'[circular shaped video];\
    [vignette][circular shaped video]overlay" \
    -filter_complex_threads 1 \
    -c:v libx264 \
    -preset ultrafast \
    -t 5 \
    "result.mp4"
    

    1 video auto squared

    audio included. Anti-aliasing vignette edges.

    enter image description here

    in="snowboarder.mp4"
    
    vignette_color="black"
    
    # edge of vignette can be jagged. 
    # use value between 1 - 2 (e.g. 1.2). 1 doesn't do anything.
    anti_aliasing=2
    
    ffmpeg \
    -i "${in}" \
    -filter_complex "\
    [0:v]crop=ih:ih[video square];[video square]split=2[video square 1][video square 2];\
    [video square 1]setsar=1:1,drawbox=color=${vignette_color}@1:t=fill[vignette];\
    [video square 2]scale=w=iw*"${anti_aliasing}":h=iw*"${anti_aliasing}",format=yuva444p,geq=lum='p(X,Y)':a='st(1,pow(min(W/2,H/2),2))+st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),ld(1)),255,0)'[scaled up circular shaped video];\
    [scaled up circular shaped video]scale=w=iw/"${anti_aliasing}":h=iw/"${anti_aliasing}"[circular shaped video];\
    [vignette][circular shaped video]overlay" \
    -filter_complex_threads 1 \
    -c:v libx264 \
    -c:a aac \
    -preset ultrafast \
    "result_square.mp4"
    

    round video (square video with transparency)

    webm video with alpha channel in Firefox browser

    Chrome and Firefox support WebM videos with transparency (alpha channels).

    The checkerboard pattern is not part of the video. It is the background.

    input="snowboarder.mp4"
    
    # edge of vignette can be jagged. 
    # use value between 1 - 2 (e.g. 1.2). 1 doesn't do anything.
    anti_aliasing=2    
    
    ffmpeg \
    -i "${input}" \
    -filter_complex "\
    [0:v]crop=ih:ih[video square];\
    [video square]split=3[black canvas][white canvas][video square];\
    [black canvas]setsar=1:1,drawbox=color=black@1:t=fill[black background];\
    [white canvas]scale=w=iw*"${anti_aliasing}":h=iw*"${anti_aliasing}",format=yuva444p,geq=lum='p(X,Y)':a='st(1,pow(min(W/2,H/2),2))+st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),ld(1)),255,0)',drawbox=color=white@1:t=fill[scaled up white circle];\
    [scaled up white circle]scale=w=iw/"${anti_aliasing}":h=iw/"${anti_aliasing}"[white circle];\
    [black background][white circle]overlay[alpha mask];\
    [video square][alpha mask]alphamerge,format=yuva420p" \
    -filter_complex_threads 1 \
    -c:v libvpx -auto-alt-ref 0 \
    -c:a libvorbis \
    -preset ultrafast \
    "result_square.webm"