How to freeze frame a video: hold the last or any frame

Freeze a video's last frame with one tpad filter call, or hold any frame mid-clip as a still between two parts of the clip in a Timeline render.

5 min readSume
All posts

To freeze frame a video, hold one frame on screen for a few seconds while the picture stops. For the last frame, FFmpeg's tpad filter does it: tpad=stop_mode=clone:stop_duration=3 adds three seconds of copies of the final frame. On a clip already hosted on Sume, that is one video filter call. For a freeze in the middle, pull that frame as a still with video frames and place it as its own slot between two parts of the clip in a Timeline 1.0 render.

The facts come from Sume's Video filter, Video frames, Audio detach, and Timeline 1.0 docs, the Sume API reference, and FFmpeg's ffmpeg tool, filters, and utilities documentation, read on 2026-09-27. Anything described as current behavior is read from Sume's code.

How do I freeze the last frame of a video?

Use FFmpeg's tpad filter. stop_mode=clone pads the end with clones of the last frame (the default, add, pads with solid-color frames), and stop_duration sets the length of the pad; a plain number is seconds. On your own computer, FFmpeg applies it with -vf while it re-encodes the file: ffmpeg -i clip.mp4 -vf tpad=stop_mode=clone:stop_duration=3 frozen.mp4.

On Sume, send the same filter as the filtergraph of POST /v1/video-filter; tpad is on Sume's filter allowlist today.

  • The clip must already be your workspace's media.sume.com artifact or asset, such as an earlier Sume job's output, and at most 300 seconds long. Sume has no public upload route for a file on your computer (which URLs each endpoint accepts). POST /v1/video-filter/check validates the same body for free.
  • The server wraps your graph around the video stream, and the docs say the output inherits the source's audio. So the sound still ends where the clip's did, and the held seconds are silent.
  • start_mode=clone with start_duration holds the first frame instead. That delays the picture but not the audio, so keep it for clips whose sound you will replace.
curl -X POST https://api.sume.com/v1/video-filter \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: freeze-end-001" \
  -d '{
    "video_url": "https://media.sume.com/artifacts/artf_demo/clip.mp4",
    "filtergraph": "tpad=stop_mode=clone:stop_duration=3"
  }'

How do I freeze a frame in the middle of a video?

Split the clip at the frame and hold a still of it between the two parts. That takes three calls:

  • POST /v1/video-frames with at: [8] and format: "png" returns a durable image of the instant at 8 seconds, at the source's size when max_edge is omitted; read its frames[].url from GET /v1/video-frames/:id once resource_status is ready. It is unbilled, takes sources up to 300 seconds, and every at value must be under the clip's duration.
  • POST /v1/audio-detach returns the clip's audio as a wav, the file a Timeline audio.url wants. In the current compiler a render's sound comes only from its spine and an optional soundtrack, never from the clips, so detaching is how the clip keeps its sound.
  • POST /v1/timeline-1.0/render takes the wav as the spine and three slots: the clip up to the frame, the still (stills are static holds), and the clip again from a later source_in. The default output is 1080×1920, so set output to the clip's size.
curl -X POST https://api.sume.com/v1/timeline-1.0/render \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: freeze-mid-001" \
  -d '{
    "audio": { "url": "https://media.sume.com/artifacts/artf_demo/clip.wav", "duration_seconds": 20 },
    "output": { "width": 1920, "height": 1080 },
    "video": [
      { "source_url": "https://media.sume.com/artifacts/artf_demo/clip.mp4", "start": 0, "duration": 8 },
      { "source_url": "https://media.sume.com/artifacts/artf_demo/frame-8s.png", "start": 8, "duration": 3 },
      { "source_url": "https://media.sume.com/artifacts/artf_demo/clip.mp4", "start": 11, "duration": 9, "source_in": 11 }
    ]
  }'

What happens to the sound during the freeze?

It keeps playing. The spine runs straight through, and even audio.parts[] slices join without silence at the seams, so the sound carries on under the still. That is why the last slot resumes at source_in: 11, not 8. The freeze covers three seconds of the clip, and picture and sound meet again in sync.

If the clip's sound doesn't matter, render with audio.mode: "silence" instead, which gives the output a silent track of duration_seconds. Then the freeze can add time: resume at source_in: 8 and set duration_seconds to 23. A soundtrack can lay music under the whole edit, as in add background music.

How do I hold the last frame inside a longer edit?

Make the clip's Timeline slot longer than the clip. Per the Sume API reference, render.pad_mode decides how a slot longer than its source is filled: freeze holds the last frame and loop replays the source. The default, auto, loops short sources instead of holding a long freeze, so send "render": { "pad_mode": "freeze" } when a slot should end on a held frame. The docs treat padded or looped short sources as soft warnings, not failures. Looping on purpose is covered in increase video length by looping.

What does each step cost, and what are the limits?

Video frames is unbilled. Every other step bills on its own, plus a 5.5% agent fee by default.

From Video filter, Video frames, Audio detach, Timeline 1.0, and API pricing, read 2026-09-27.
StepCallBillingLimits
Last-frame freezePOST /v1/video-filterPer encode job, rate in GET /v1/catalog; the check is freeSource ≤ 300 s
Frame stillPOST /v1/video-framesUnbilledSource ≤ 300 s; each at in [0, duration)
Clip audioPOST /v1/audio-detachPer job, rate in GET /v1/catalogSource ≤ 1,800 s; output ≤ 900 s
RenderPOST /v1/timeline-1.0/renderReserves $0.10 per output minute and never charges moreOutput 1–1,800 s; 1–200 slots, each ≥ 0.2 s

Sources

Related posts

More in Media tools

All Media tools posts

Written by Sume