Skip to main content

g6-adapt-ffmpeg

Use when you need to convert, cut, join, resize, retime, filter, subtitle or level a video or sound file with ffmpeg, or pull out its sound or a frame, and you want every file ffmpeg writes measured against what you asked for before you use it.

Source facts

Repository
basicisabc1994/g6solver
Last source activity
October 26, 2026 at 01:52
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
g6-adapt-ffmpeg
description
Use when you need to convert, cut, join, resize, retime, filter, subtitle or level a video or sound file with ffmpeg, or pull out its sound or a frame, and you want every file ffmpeg writes measured against what you asked for before you use it.
# G6 adapt_ffmpeg `g6.media.adapt_ffmpeg` drives the ffmpeg and ffprobe you installed, over their command line. A source is a file name in G6's media folder (`$G6_HOME/media`); ffmpeg writes a fresh file there, which is probed from disk against what the request and the sources say it must be (its streams, a full decode, its length, frame size and rate, sample rate and channels, not silent, not blank), and only then given the name you asked for. ffmpeg's exit code is not a check. Its best state is `qualified-draft`. ## When to use it - You (a coding agent) cut a clip, change its format, frame size or frame rate, join clips, speed one up, lay a logo on it, burn in subtitles, take a frame or a GIF from it, or bring its loudness to a target, and you cannot watch or hear the result yourself. - You need ffprobe's account of a file, and whether ffmpeg can decode every frame of it. ## When not to use it - Editing sound sample by sample (equalising, compressing, de-noising, measuring pitch or tempo): use `adapt_audio`. - Making sound or speech: `adapt_synth`, `adapt_voice`. - A file outside the media folder or at an address: there is no path or URL input, and a link in the folder to a file kept elsewhere is refused. Put the file itself in the media folder. - Judging what a video shows or how it sounds: nothing here does. ## Ops - `probe`: ffprobe's format and streams for `source`, and whether ffmpeg decodes every frame, its sound is silent and its pictures blank, each measured whatever the others found (`null` when there is no sound or picture to measure). Nothing is written. - `convert`: `source` in another `format` (mp4, mov, mkv, webm, avi, mp3, wav, flac, ogg, opus, m4a); `video_codec`, `audio_codec` (plain names), `crf`, `audio_bitrate` (such as `128k`). - `trim`: from `start` to `end` seconds. By default (`accurate: true`) it re-encodes for an exact cut; `accurate: false` is a fast stream copy, whose cut lands on key frames, so it often measures longer and is then refused. - `concat`: `sources`, two to twenty files, one after another, at the first one's frame size and rate. - `extract_audio`: the sound alone (`format` wav by default). - `add_audio`: `source`'s video with the sound of `audio`, as long as the shorter of the two. - `resize`: `width`, `height` or both; one side alone keeps the shape (an even size for a video format). - `framerate`: `fps`. - `filter`: `filter_expr`, a chain of allowed video filters (`eq`, `crop`, `scale`, `pad`, `hflip`, `vflip`, `transpose`, `rotate`, `hue`, `unsharp`, `gblur`, `fade` and a few more). Nothing that opens a file, a device or an address, runs a command or splits into several chains is accepted, so `curves` is not (it writes its plot to a file and reads a preset file). - `thumbnail`: one frame at `time` (the middle by default) as `png` or `jpg`, at `width` or `height` if given. - `gif`: an animated GIF with its own palette, at `fps` (10) and `width` (at most 480 by default), from `start` to `end`. - `overlay`: the picture or video `overlay` laid on `source` at `x`, `y`. - `speed`: `factor` from 0.25 to 4 (above 1 is faster); the sound keeps its pitch. - `normalize_audio`: EBU R128 loudness in two passes to `target_lufs` (-16), `true_peak` (-1.5 dBTP) and `lra` (11), the sample rate kept; the result is measured again. - `subtitles`: SRT, ASS or WebVTT `subtitles` (a file in the media folder) drawn onto the video. Every op that writes takes `name` (G6 chooses the folder; a different file of that name is never replaced unless `overwrite`), `format`, `tolerance` (seconds a length may differ by) and `timeout` (1 to 600 seconds). ## Alone and composed Alone over MCP: `g6_invoke("adapt_ffmpeg", "trim", '{"source": "talk.mp4", "start": 5, "end": 15}')`, then read `result.artifact.measured` and open `result.artifact.path`. Every op runs ffmpeg or ffprobe on the person's machine, so every one is sensitive: over MCP it runs only when the person who runs the server lists it (`adapt_ffmpeg.trim`) or the whole component (`adapt_ffmpeg`) in `G6_MCP_SENSITIVE`. Ask them; never set it yourself. Composed: - A picture from `adapt_image` or `adapt_generative_art` is an `overlay`; a sound from `adapt_synth` or `adapt_voice` is an `audio` for `add_audio`, by file name. - A slideshow: make the pictures, `concat` short clips of them, `add_audio` a narration, `normalize_audio` the result, then `probe` it. - `adapt_audio` edits a WAV this op extracted, and `convert` turns its WAV back into the format you need. ## Failure modes it catches - `visual_check_failed` (an image, video or 3D output that is blank, corrupt or wrong, reported as done): every frame is decoded, its frame size and rate compared with the request, and twelve frames sampled across it; a result whose every sampled frame is nearly one grey (a filter that turned it black) is refused with `G6_E_MEDIA_BLANK`, one that does not decode with `G6_E_MEDIA_UNDECODABLE`, the wrong size with `G6_E_MEDIA_SIZE_MISMATCH`. - `audio_check_failed` (sound output that is silent, clipped or wrong, reported as done): its sound is decoded and measured; a silent one is refused with `G6_E_MEDIA_SILENT`; a result shorter or longer than asked (a stream-copy cut that landed on key frames, a speed change gone wrong) with `G6_E_MEDIA_DURATION_MISMATCH`; the wrong sample rate, channels or streams with `G6_E_MEDIA_STREAM_MISMATCH`; a normalised file off its target with `G6_E_MEDIA_LOUDNESS_MISSED`. ffmpeg exiting 0 with nothing written, an empty file or a broken one is refused (`G6_E_MEDIA_NO_OUTPUT`, `_UNDECODABLE`), and the file is removed. ## Reading the result - A result is `qualified-draft` with `G6_E_MEDIA_PROBED`: its `artifact` holds the path, the MIME type, what was asked for (`requested`), what was measured (`measured`: format, length, video and audio streams, levels), the checks, and the provenance (ffmpeg's version, the argument list, the sources' SHA-256). `probe` answers `G6_E_MEDIA_MEASURED`. - A refusal is `blocked-escalated` with its code: the inspection codes above, `G6_E_OUTSIDE_PROGRAM_MISSING` (ffmpeg or ffprobe is not installed; the reason says how to install it), `G6_E_MEDIA_BACKEND_FAILED` (ffmpeg failed; its message is in the reason), `G6_E_MEDIA_TIME_LIMIT`, `G6_E_MEDIA_EXISTS` or `G6_E_MEDIA_INPUT_INVALID`. ## Blind spots - The probe measures; it does not watch or listen. A cut at the wrong moment, a wrong subtitle or a muddy encode passes. - Blank means every sampled frame (scaled to 160 x 90 in grey) is nearly one grey; a picture that is mostly black with a little in it passes, and so does a frozen picture. - Silent means under 0.1 % of the samples are louder than -60 dBFS; a very quiet recording is called silent, and hum or noise is not. - `subtitles` checks the video it writes, not that the words were drawn (the fonts are the system's). - ffmpeg runs as you; this is a resource bound (a deadline, an output cap, a clean environment), not a sandbox. Its decoders read files a caller gave, which is why every op is sensitive. ## What it needs - ffmpeg and ffprobe, installed by the person (ffmpeg.org; `winget install Gyan.FFmpeg`, `brew install ffmpeg` or `apt install ffmpeg`), on PATH or named by `G6_FFMPEG` and `G6_FFPROBE`. G6 never installs or bundles them; a missing one is refused with these steps. Their builds may be GPL, so G6 runs them over their command line only. - No Python extra. ## Examples A clip of the talk from 5 to 15 seconds, cut exactly (sensitive). ```g6-example op=trim {"source": "talk.mp4", "start": 5, "end": 15, "name": "talk-cut"} ``` Its loudness brought to -16 LUFS and measured again (sensitive). ```g6-example op=normalize_audio {"source": "talk-cut.mp4", "target_lufs": -16, "true_peak": -1.5, "name": "talk-level"} ``` From Python: a filter that would open a file is refused before ffmpeg is asked anything. ```python from g6.media._types import MediaError from g6.media.adapt_ffmpeg.commands import check_filter assert check_filter("hflip,eq=contrast=1.2") == "hflip,eq=contrast=1.2" try: check_filter("movie=../secret.mp4") except MediaError as exc: assert exc.code == "G6_E_MEDIA_INPUT_INVALID" else: raise AssertionError("an unsafe filter was accepted") ``` ## The four open problems - **Learning signals**: each refusal carries its code, the failed check and ffmpeg's argument list. Not yet: nothing counts them per op or per ffmpeg build. - **Evaluators the model cannot influence**: ffprobe and ffmpeg's own decoder read the written file, and what it must measure is computed from the request and the sources' probes, never read from the result. - **Transfer by failure mode**: "silent", "blank", "wrong length" and "does not decode" carry the same codes here as in `adapt_audio`, `adapt_synth` and `adapt_voice`. - **Enough held-out cases**: Not yet: the tests make their media with ffmpeg's own test sources; there is no stored set of reference files with known lengths and loudness.
View on GitHub