ffmpeg 7.1: each recording's audio as 16 kHz mono WAV
95
ffmpeg 7.1 over every recording of an input tree, as a ChRIS plugin.
pl-ffmpeg is a ChRIS <https://chrisproject.org/>_ DS plugin that runs ffmpeg once per recording, video or audio, found in its input tree, the first positional argument, /incoming below. By default it writes each recording's audio as a 16 kHz mono WAV, the form speech recognisers read, into the output tree, the second positional argument, /outgoing, in the directory matching the recording's own and under the recording's name: /incoming/weekly.mp4 gives /outgoing/weekly.wav. The common case needs no flags:
.. code-block:: bash
pl-ffmpeg /incoming /outgoing
Any other ffmpeg command line runs the same way through --exec. In the Transcribe pipeline pl-ffmpeg is the first step and pl-whisper <https://github.com/FNNDSC/pl-whisper>_ the second, so the decoding runs on any node and only the transcription asks for a GPU.
pl-ffmpeg has no engine of its own. It is pl-shexec <https://github.com/FNNDSC/pl-shexec>_, the plugin that runs a command template once per file of a tree, built into an image that also holds ffmpeg and given an ffmpeg command line as its default. Walking the tree, choosing the files, running the command and recording each run are pl-shexec's code; pl-ffmpeg supplies the image, the default arguments and its manual.
The default command is a template that pl-shexec resolves once per recording:
.. code-block:: text
ffmpeg -nostdin -hide_banner -y -i %{inputWorkingDir}/%{inputWorkingFile}
-vn -ac 1 -ar 16000 -c:a pcm_s16le %{outputWorkingDir}/%{inputWorkingFile|rmext}.wav
%{inputWorkingDir} is the recording's directory in the input tree, %{inputWorkingFile} the recording, %{outputWorkingDir} the matching directory in the output tree, and %{inputWorkingFile|rmext} the recording's name less its extension. The command drops any video, mixes to one channel and resamples to 16000 samples a second as 16-bit PCM, about 115 MB an hour of audio.
To write something else, pass another template:
.. code-block:: bash
pl-ffmpeg --exec "ffmpeg -nostdin -y -i %{inputWorkingDir}/%{inputWorkingFile}
-vn -ac 1 -b:a 64k %{outputWorkingDir}/%{inputWorkingFile|rmext}.mp3" \
/incoming /outgoing
pl-ffmpeg --man lists every tag and function.
Every file, at any depth, that passes --fileFilter. The default is one regular expression, blind to case, for the usual video and audio extensions: .mp4, .m4a, .m4v, .mov, .mkv, .webm, .avi, .mp3, .wav, .flac, .ogg, .oga, .opus, .aac and .wma. Notes, slides and sidecars beside the recordings are passed over. --analyzeFileIndex v, the default, runs every recording, each on its own.
.. code-block:: text
/incoming/weekly.mp4 -> /outgoing/weekly.wav
/incoming/2026-11/standup.m4a -> /outgoing/2026-11/standup.wav
/incoming/2026-11/review.MOV -> /outgoing/2026-11/review.wav
/incoming/2026-11/slides.pdf passed over
Two recordings of one directory that differ only in extension, weekly.mp4 and weekly.m4a, write the same WAV, the later over the earlier.
Beside the WAVs of each directory, jobs.jsonl holds one line per recording: the command, its output, its exit status, the host and the timing. pflog read /outgoing/**/jobs.jsonl prints them as a table. The plugin's own run is one line of JSON on standard error, which CUBE keeps with the plugin instance. A recording that fails is recorded and the run goes on; the plugin exits 0 when every recording of at least one directory completed, 1 otherwise, 2 on a usage error.
From ChRIS, attach it to a node holding recordings, or run the Transcribe pipeline, which starts with it. From the command line, with the image:
.. code-block:: bash
docker run --rm -v $PWD/in:/incoming:ro -v $PWD/out:/outgoing:rw fnndsc/pl-ffmpeg \
pl-ffmpeg /incoming /outgoing
docker run --rm fnndsc/pl-ffmpeg pl-ffmpeg --man
One instance runs the recordings of a directory one after another; --threads N runs up to N directories at once.
This plugin is pl-shexec's plugin_build called with a spec: the name, the version, the title and resource limits ChRIS sees, the default template, and the manual's words. The filters, the tags, the records and the exit status are pl-shexec's and are documented there. The plugin's version is independent of ffmpeg's: pl-ffmpeg --version prints both, and docs/history.adoc records which ffmpeg each plugin version carried.
.. code-block:: bash
uv venv --python /usr/bin/python3.14 .venv
uv pip install --python .venv/bin/python -e ".[dev]"
.venv/bin/ruff check . && .venv/bin/ruff format --check . && .venv/bin/python style_check.py pl_ffmpeg tests
.venv/bin/pytest -q
The tests run the plugin in-process with a stand-in ffmpeg on PATH, and once with the real ffmpeg when one is installed. ruff.toml and style_check.py are the lint configuration of the style guide <https://github.com/rudolphpienaar/style-guides>_. The CI workflow lints and tests on Python 3.11 to 3.14, builds the image on every push to main, pushes it to Docker Hub and ghcr.io, and keeps the plugin's description as a build artifact for registering it on a CUBE. The tag must match __version__ in pl_ffmpeg/__init__.py.
docs/purpose.adoc says why the plugin exists, docs/architecture.adoc how it is built, docs/history.adoc where it came from.
Content type
Image
Digest
sha256:45195d7c2…
Size
208.2 MB
Last updated
about 20 hours ago
docker pull fnndsc/pl-ffmpeg