To get a 200x100 thumbnail from a video, I do ffmpeg -ss 100 -i /tmp/video.mp4 -frames:v 1 -s 200x100 image.jpg. But if the source video isn't in the same aspect ratio as 200x100, the thumbnail gets distorted (either stretched or squished, horizontally or vertically) and it looks bad.
Is there a way that ffmpeg can figure out for example that a 500x200 video is 100px too wide, and remove 50px from the right and 50px from the left, making the video 400x200? And because 400x200 is the same aspect ratio as 200x100, the thumbnail would have no distortion.
I know there are other tools that can do this to the thumbnails generated by ffmpeg, but I'd prefer doing it within ffmpeg and not having to process the thumbnails again.
You can use the force_original_aspect_ratio option in the scale filter.
ffmpeg -ss 100 -i /tmp/video.mp4 -frames:v 1 -q:v 2 -vf "scale=200:100:force_original_aspect_ratio=increase,crop=200:100" image.jpg
If your thumbnail size is 200x100 fixed, then run
ffmpeg -ss 100 -i /tmp/video.mp4 -vf "scale='if(gt(dar,200/100),100*dar,200)':'if(gt(dar,200/100),100,200/dar)',setsar=1,crop=200:100" -frames:v 1 image.jpg
The scale filter checks the aspect ratio of the source and scale so that one dimension fits the 200x100 canvas and the other overshoots, unless it's a perfect match. Then the crop filter crops it to 200x100 from the center thus taking care of the out of bounds region.
Related
I want use a still image to make a transparent webm video, this video needs to have the following style:
The image height auto increase from 0 to 100% in specific time.
I don't want scroll effect , what i want is just like the image spread from top to bottom
Below is my demo image:
This is the effect I want:
Black color part represent transparency.
1 second transition example
ffmpeg command for 5 second transition:
ffmpeg -loop 1 -t 5 -i input.png -filter_complex "drawbox=thickness=fill:color=black[black];[black][0]xfade=transition=wipedown:duration=5" output.webm
-loop 1 loops image.
-t 5 sets image duration to 5 seconds.
drawbox=thickness=fill:color=black drawbox filter to make black video from input.
xfade=transition=wipedown:duration=5 xfade filter using wipedown transition with a duration of 5 seconds.
Also see:
FFmpeg Wiki: xfade transitions gallery
FFmpeg Wiki: VP9 WebM Encoding
I have a generic process whose purpose is to take a video at any aspect ratio and generate a PNG from one of its frames. This frame should:
Be as large as possible, but no larger than 720x405 (16:9)
Maintain the aspect ratio of the video
Have no letterboxing
ffmpeg -y -nostats -ss 10 -i ./video.mp4 -max_muxing_queue_size 6400 -an -frames:v 1 -r 24/1 -vf "scale=w=720:h=405:force_original_aspect_ratio=decrease" -f image2 ./frame.png
When I give this command a video with a sample_aspect_ratio (SAR) of 4:3 and a display_aspect_ratio (DAR) of 16:9, I end up with a 540x405 (4:3) PNG where the image is horizontally compressed. Presumably force_original_aspect_ratio is looking at sample_aspect_ratio rather than display_aspect_ratio.
How do I ensure that the generated image maintains the same aspect ratio as the video (as displayed to the user)?
Insert a scale filter to convert frames to square pixels.
-vf "scale=iw*sar:ih,setsar=1,scale=w=720:h=405:force_original_aspect_ratio=decrease"
I found some posts explaining how to turn any video horizontal by adding blurred borders using FFMpeg, but I want to convert videos to vertical 1080x1920. I don't want it to enlarge the video, nor crop if a dimension is bigger than either 1080 or 1920 dimension. Instead, I want it to shrink the video until it fits fully inside 1080x1920, and then I want it to add blurred borders to the empty areas.
This is the snippet I found, but when I tried reversing the numbers, it actually cropped the video.
ffmpeg -I input.mp4 -lavfi "[0:v]scale=1920*2:1080*2,boxblur=luma_radius=min(h\,w)/20:luma_power=1:chroma_radius=min(cw\,ch)/20:chroma_power=1[bg];[0:v]scale=-1:1080[ov];[bg][ov]overlay=(W-w)/2:(H-h)/2,crop=w=1920:h=1080" output.mp4
Simple method:
ffmpeg -i input.mp4 -filter_complex "[0:v]boxblur=40,scale=1080x1920,setsar=1[bg];[0:v]scale=1080:1920:force_original_aspect_ratio=decrease[fg];[bg][fg]overlay=y=(H-h)/2" -c:a copy output.mp4
"Simple" because it forces the background to 1080x1920 and ignores aspect ratio. So the background it will looked stretched, but it is blurred so much nobody will care or notice.
I'm trying to create video from image but it's fit to video size (hd). How to keep aspect ratio of my image BUT get 1280 x 720 video?
Here is current result (image is 3264 x 2448 px, video 1280 x 720 px):
Here is my current command:
ffmpeg -loop 1 -i IMAGE_PATH -t 3 -s hd720 -c:v mpeg4 -pix_fmt yuv420p -preset ultrafast RESULT_PATH
Should I divide my task to two operations (generate image with black stripes then generate video)? Could you help to modify command to get desired result?
It is better to use aspect though you specify the s in the command.
-aspect 3264/2448
And also try pad to get the black bars around the output video without stretching the video to fit the screen size. This question is about that.
Hope this will help you!
I already have found out how to scale the thumbnail to stay within specified bounding dimensions while maintaining aspect ratio. For example, to get the frame shown at 6 seconds into the input.mp4 video file, and scale it to fit into 96x60 (16:10 aspect ratio):
ffmpeg -y -i input.mp4 -ss 6 -vframes 1 -vf scale="'if(gt(a,16/10),96,-1)':'if(gt(a,16/10),-1,60)'" output.png
This is fine, it works.
Next, I would like to do the same, but if the video's aspect ratio is not exactly 16:10, then I would like to force the output image to have an aspect ratio of 16:10 by taking the above transformation, and filling or padding the space with white. That is, I want the output to be as if I took, say, a 96x48 image, and laid it over a 96x60 white background, resulting in white bars above and below the 96x48 image.
Ideally, I do not want to resort to using another tool or library, such as ImageMagick. It would be best if ffmpeg could do this on its own.
Here's what I went with. For the -vf argument:
-vf "scale='if(gt(a,16/10),96,-1)':'if(gt(a,16/10),-1,60)', pad=w=96:h=60:x=(ow-iw)/2:y=(oh-ih)/2:color=white"
This applies two filters in sequence, separated by a comma.
target_H = 2436
target_W = 1124
ffmpeg -i 1.mp4 -ss 1 -vframes 1 -vf "scale=min(iw*2436/ih\,1124):min(2436\,ih*1124/iw),pad=1124:2436:(1124-iw)/2:(2436-ih)/2:green" output.png