video_trim_output_requires_exact: keyframe cuts can't resize

FFmpeg stream copy cannot filter, and Sume's keyframe trim cannot take an output size or fps. Why it is refused, and the one-line fix.

4 min readSume
All posts

POST /v1/video-trim returns video_trim_output_requires_exact when you send an output object (width, height or fps) together with precision: "keyframe". Keyframe mode is a stream copy, and a copy cannot change the picture. Switch to precision: "exact", which is the default, or drop output and conform the size later.

Why can't a stream copy resize?

The ffmpeg documentation describes streamcopy as copying packets with no decoding or encoding, fast and lossless, and states that applying filters is impossible because filters work on decoded frames. Scaling and frame-rate conversion are filters, so ffmpeg -c copy -vf scale=... cannot do what it says.

The same page explains the cut point: with -ss before the input, ffmpeg seeks to the closest seek point before the position, and in stream copy that extra segment is preserved. Sume's trim page describes the same effect: a keyframe cut may start a GOP early, so re-base against actual_start_seconds in the result.

video-trim precision modes, read 2026-10-03 from the Video trim page
precisionHow it cutsoutput allowedStart
exact (default)Frame-accurate re-encode, libx264 and yuv420pYes: width and height 256 to 2160, fps 24, 25, 30 or 60At the requested start
keyframeStream copyNo: video_trim_output_requires_exactMay be a GOP early; read actual_start_seconds

What are the two fixes?

Keep exact and send the output you wanted. The cut and the conform happen in one $0.02 job, since the Video trim page lists a flat public rate of $0.02 per job and says to confirm it in GET /v1/catalog. The other route is a keyframe cut with no output, then a Timeline render, whose output.width, output.height and output.fps set the final size.

Whichever you pick, the server compiles the ffmpeg arguments. Sending vf, codec, crf or similar fields gets ffmpeg_fields_rejected, so size changes only go through output.

How do I guard this in a client?

Build the body in one function and refuse the combination before the request leaves your code. The helper below runs as written and prints the accepted body, then the refusal it would have caused.

Remember the other trim limits when you test: a source up to 1,800 s, an output of 0.2 to 900 s, and exactly one of end or duration. Default mode is async, so poll GET /v1/jobs/:id/status and read GET /v1/jobs/:id/result for video_url.

import json

def trim_body(url, start, duration, precision="exact", size=None, fps=None):
    body = {"video_url": url, "start": start, "duration": duration,
            "precision": precision}
    if size or fps:
        if precision != "exact":
            raise ValueError("video_trim_output_requires_exact")
        body["output"] = {"width": size[0], "height": size[1], "fps": fps}
    return body

url = "https://media.sume.com/artifacts/artf_demo/talk.mp4"
print(json.dumps(trim_body(url, 2, 8, "exact", (1280, 720), 30)))
try:
    trim_body(url, 2, 8, "keyframe", (1280, 720), 30)
except ValueError as e:
    print("refused:", e)

When is keyframe mode still the right choice?

Use keyframe when you only need a fast, lossless cut and can accept a start that lands a little early, for example to pull a rough clip before review. The result tells you where the cut really began through actual_start_seconds, so a downstream step can re-base its own timings. For anything that must start on the exact frame, such as a transition point or a caption anchor, stay on exact.

A good habit is to pick the mode by the next step. If the next step is a Timeline render, the Timeline will conform size and rate anyway, so a keyframe trim followed by a render is often the cheaper pair. If the next step is delivery of the trimmed file itself, send exact with the output you need and skip the second job.

What do the cost and limits look like?

The Video trim page lists a flat $0.02 per job for both modes, with a source of up to 1,800 s and an output between 0.2 and 900 s. Because the price does not change with the mode, the choice is about accuracy and whether you need a new size or frame rate, not about cost.

Remember to send exactly one of end or duration, and an Idempotency-Key header on every submit, so a retry after a network error returns the original job and does not queue a second one.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume