Straighten a tilted video by API: rotate, then crop by angle
Level a crooked horizon with Sume video filter: rotate in radians, crop out the corners with a factor per angle (0.97 at 1 degree), scale back. $0.02.

To straighten a clip whose horizon slopes, send Sume's video filter a rotate by the opposite angle, then crop away the black corners the rotation exposes and scale back: rotate=a=-2*PI/180:fillcolor=black,crop=w=floor(iw*0.94/2)*2:h=floor(ih*0.94/2)*2,scale=w=floor(iw/0.94/2)*2:h=floor(ih/0.94/2)*2. For a 2 degree tilt the crop factor is 0.94; the table below gives the factor for other angles.
This is a different problem from perspective correction or a clip that plays sideways because of its rotation flag. Here the camera was simply held a few degrees off level, which is common with handheld phone footage. Video inspect tells you about the flag; your eyes tell you about the tilt.
Which way do I rotate, and how big is the angle?
Positive a turns the picture clockwise. A horizon that dips to the right is tilted clockwise, so you rotate counter-clockwise with a negative value. a=-2*PI/180 converts 2 degrees to radians inside the expression, and the filter accepts PI.
To measure the tilt, pull a still with video frames and read the angle off a straight edge, or use the thirds grid review described in another post. Start from a small angle; rotating further than 5 degrees costs a lot of frame.
How much must I crop?
Rotation leaves empty corners. The largest same-shaped rectangle that fits inside a rotated frame has a scale of min(w / (w cos t + h sin t), h / (w sin t + h cos t)). I computed it for three common shapes and rounded down to two decimals so the corners are always gone. I also ran the 2 degree, 0.94 case on a white 1080x1920 test frame with a local ffmpeg build and all four corner pixels stayed white.
- The crop and scale use
floor(.../2)*2so both sides stay even, which a yuv420p encode requires. - The last scale returns to within a couple of pixels of the source size: 1080x1920 comes back as 1078x1918 with a 0.94 factor.
- Zoom costs sharpness. If the clip is short on pixels, run the Sume video upscale afterwards rather than shipping a soft frame.
| Tilt | 9:16 or 16:9 | 1:1 |
|---|---|---|
| 0.5 degrees | 0.98 | 0.99 |
| 1 degree | 0.97 | 0.98 |
| 2 degrees | 0.94 | 0.96 |
| 3 degrees | 0.91 | 0.95 |
| 5 degrees | 0.86 | 0.92 |
How do I run it?
Run the check route, read the compiled filter names (rotate, crop, scale), then submit the encode with an idempotency key. The graph contains no commas outside parentheses and no forbidden characters, so it passes the contract check.
The source must be a Sume-hosted clip of 300 seconds or less, and an HDR or non-YUV clip fails closed.
curl -X POST https://api.sume.com/v1/video-filter/check \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"video_url": "https://media.sume.com/artifacts/artf_demo/clip.mp4",
"filtergraph": "rotate=a=-2*PI/180:fillcolor=black,crop=w=floor(iw*0.94/2)*2:h=floor(ih*0.94/2)*2,scale=w=floor(iw/0.94/2)*2:h=floor(ih/0.94/2)*2"
}'What can't this fix?
A single fixed angle assumes the tilt is constant. If the camera rolls during the shot, a fixed rotation will correct one moment and worsen another; Sume has no stabiliser on the allowlist, so split the clip into ranges with video trim and give each its own angle.
Sources
Related posts
More in Media tools
- Sume media import failed: source_not_found vs source_not_video
A Sume media import fails with source_not_found for private, deleted or region-locked posts and source_not_video for photos and carousels. Don't retry either.
- Timeline failed with source_not_found: read source_slot to find it
A failed Sume Timeline job names the dead input by slot, like video[3] or soundtrack, plus host and 404 or 410. Replace it with a media.sume.com asset URL.
- Which Sume media routes need a flag, and which are on prod?
Remix media, reference ingest and the trending-videos rebuild are flag-gated; video inspect, frames, trim, detach, filter and timeline are on dest and prod.
- Whistle word timestamps to burned captions with Sume's words field
Turn Whistle's on-device word timings into burned-in captions: map them to words with text, start and end, then call Sume video captions with no STT run.
Written by Sume