Extract frames and thumbnails¶
The frames op (spec 0021) writes still
images from a video without a full transcode. Drive it with a FrameJob and
Runtime.Frames; the encoders it uses (png, mjpeg, webp) are in every profile, and the
scene/thumbnail selectors need the intermediate profile's native filters.
A FrameJob names the input, a Path template with an optional integer token
("out/frame_%03d.png"), an image Codec, an optional Scale, and exactly one selector in
FrameSelect.
One frame at a timestamp¶
at := 12.5
job := afmpeg.FrameJob{
Input: "in.mp4",
Select: afmpeg.FrameSelect{Timestamp: &at}, // pointer: &0.0 is the first frame, not "unset"
Path: "poster.png", // no token: a single frame
Codec: "png",
}
res, err := rt.Frames(ctx, fs, job)
// res.Count, res.Frames[i].Path / .Index / .Timestamp
Timestamp is a *float64 so that 0 (the first frame) is distinct from an unset selector.
Several specific timestamps¶
job := afmpeg.FrameJob{
Input: "in.mp4",
Select: afmpeg.FrameSelect{Timestamps: []float64{0, 30, 60}},
Path: "out/shot_%02d.png",
}
A frame every N seconds¶
Scene changes or representative thumbnails¶
thresh := 0.4
Select: afmpeg.FrameSelect{SceneThreshold: &thresh} // frames whose scene score exceeds 0.4
// or
Select: afmpeg.FrameSelect{Thumbnail: true} // representative frames via the thumbnail filter
Scale and cap the output¶
Scale applies ffmpeg scale args to each frame, and Count caps how many are emitted:
job := afmpeg.FrameJob{
Input: "in.mp4",
Select: afmpeg.FrameSelect{Interval: 2},
Path: "out/thumb_%03d.webp",
Codec: "webp",
Scale: "320:-2", // 320px wide, height keeps the aspect ratio
Count: 20, // stop after 20 frames
}
Set exactly one selector — Timestamp, Timestamps, Interval, SceneThreshold, or
Thumbnail. Setting none or more than one is a validation error before the engine runs.
See also¶
- Obtain a module — the scene/thumbnail selectors need the intermediate profile.
- Read a raw or headerless input —
FrameJob.Format/Optionsforce the demuxer, same asInput.