Reputation: 21
I'm trying to crop video to format 1080:1920, it works with most videos but sometimes it fails with an error like:
Invalid too big or non positive size for width '2304' or height '4096'
Here is the code I am using:
import ffmpy
ffmpy.FFmpeg(inputs={"input.mp4": None}, outputs={"output.mp4": ["-y", "-vf", "crop=ih*(9/16):ih,scale=1080:1920", "-preset", "ultrafast"]})`
Upvotes: 2
Views: 3497
Reputation: 32144
The reason for the error is that ih*(9/16) > frame_width
.
We can't crop a rectangle that exceeds the boundaries of the frame.
For example:
Assume the resolution of input.mp4 is 100x200 (100 is the width).
ih = 200
ih*(9/16)
= 112.5
We can't crop 112x200 pixels because the frame width is only 100 pixels...
For reproducing the issue, we may create synthetic video using FFmpeg (command line tool):
ffmpeg -y -f lavfi -i testsrc=size=100x200:rate=1:duration=5 input.mp4
(The synthetic video is used only for demonstration).
When executing ffmpy.FFmpeg(inputs={"input.mp4": None}, outputs={"output.mp4": ["-y", "-vf", "crop=ih*(9/16):ih,scale=1080:1920", "-preset", "ultrafast"]})
, we are getting an error message:
Invalid too big or non positive size for width '112' or height '200'
For fixing the issue, we may check if height*9/16 <= width
.
We may get the video resolution (width
and height
) using OpenCV (or any other package we find).
Now we can check if height*9/16 <= width
, and use other cropping parameters if the condition is false.
Code sample:
import ffmpy
import cv2
# Get video resolution using OpenCV
cap = cv2.VideoCapture('input.mp4')
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
cap.release()
crop_w = height*9/16
if crop_w <= width:
# We can do the cropping only when the cropped area is inside frame boundaries.
ff = ffmpy.FFmpeg(inputs={"input.mp4": None}, outputs={"output.mp4": ["-y", "-vf", "crop=ih*(9/16):ih,scale=1080:1920", "-preset", "ultrafast"]})
else:
ff = ffmpy.FFmpeg(inputs={"input.mp4": None}, outputs={"output.mp4": ["-y", "-vf", "crop=iw:iw*(16/9),scale=1080:1920", "-preset", "ultrafast"]})
ff.run()
Note: We don't really have to duplicate the part of the code (I used the duplication for demonstration).
Upvotes: 3