docs/examples/file-processing/ffmpeg.mdx
<Tooltip tip="This workflow prepares and restores a local disk snapshot, which is not available on microsandbox cloud."><span className="msb-badge-local">Local-only <Icon icon="circle-info" size={11} /></span></Tooltip>
Media parsers are a natural fit for disposable microVMs. This example snapshots a prepared FFmpeg toolchain, copies one input file into a networkless worker, and exports only the transcoded result.
Create one script to prepare the reusable toolchain:
#!/bin/sh
set -eu
apt-get update
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ffmpeg
rm -rf /var/lib/apt/lists/*
useradd --system --create-home --shell /usr/sbin/nologin media
mkdir -p /input /out
chown media:media /out
chmod 0555 /input
chmod 0700 /out
ffmpeg -version | head -1
Create the workload script that each worker will run:
#!/bin/sh
set -eu
test "$(id -u)" -ne 0
if (printf x >> /input/input.mov) 2>/dev/null; then
echo "input unexpectedly writable" >&2
exit 1
fi
if getent ahosts example.com >/dev/null 2>&1; then
echo "network unexpectedly reachable" >&2
exit 1
fi
echo "input read-only; network blocked"
ffmpeg -nostdin -hide_banner -y \
-i /input/input.mov \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 128k \
/out/output.mp4
ffprobe -v error \
-show_entries format=duration,size \
-of default=noprint_wrappers=1 \
/out/output.mp4
Install both scripts in the guest, then run the preparation script as the entrypoint:
<CodeGroup> ```sh macOS & Linux msb run --name ffmpeg-base --replace \ --cpus 2 --memory 2G --root-disk 4G \ --script-path prepare-ffmpeg:./prepare-ffmpeg.sh \ --script-path transcode-video:./transcode-video.sh \ --entrypoint prepare-ffmpeg \ debian:bookworm-slim ```msb run --name ffmpeg-base --replace `
--cpus 2 --memory 2G --root-disk 4G `
--script-path prepare-ffmpeg:./prepare-ffmpeg.sh `
--script-path transcode-video:./transcode-video.sh `
--entrypoint prepare-ffmpeg `
debian:bookworm-slim
Capture the prepared toolchain:
msb snapshot create ffmpeg-tools --from ffmpeg-base --integrity --force
Verify the snapshot before using it:
msb snapshot verify ffmpeg-tools
msb run -d --name ffmpeg-worker --replace `
--from-snapshot ffmpeg-tools `
--cpus 2 --memory 2G `
--user media --security restricted `
--no-net --max-duration 10m `
-- sh -lc 'exec sleep 10m'
Copy the input into the running worker:
msb cp ./input.mov ffmpeg-worker:/input/input.mov
Make the copied input read-only:
msb exec --user root ffmpeg-worker -- chmod 0444 /input/input.mov
Run the bounded transcode as the unprivileged media user:
msb exec --user media --timeout 9m `
--rlimit nproc=64 --rlimit nofile=256 --rlimit fsize=1073741824 `
ffmpeg-worker -- transcode-video
The worker boots before the input is copied because rootfs patches cannot be combined with --from-snapshot. The root-owned input directory prevents the unprivileged media process from replacing the copied file, while /out is the only workload-owned data directory. The untrusted transcode command sets its own process, file-descriptor, and per-file limits.
Prepare a fresh artifact directory on the host:
<CodeGroup> ```sh macOS & Linux export FFMPEG_ARTIFACT_DIR="${FFMPEG_ARTIFACT_DIR:-$PWD/.ffmpeg-artifacts}"if [ -e "$FFMPEG_ARTIFACT_DIR" ] || [ -L "$FFMPEG_ARTIFACT_DIR" ]; then echo "artifact path already exists: $FFMPEG_ARTIFACT_DIR" >&2 exit 1 fi
mkdir -m 700 "$FFMPEG_ARTIFACT_DIR"
```powershell Windows
if (-not $env:FFMPEG_ARTIFACT_DIR) {
$env:FFMPEG_ARTIFACT_DIR = Join-Path $PWD '.ffmpeg-artifacts'
}
if (Test-Path -LiteralPath $env:FFMPEG_ARTIFACT_DIR) {
throw "artifact path already exists: $env:FFMPEG_ARTIFACT_DIR"
}
New-Item -ItemType Directory -Path $env:FFMPEG_ARTIFACT_DIR | Out-Null
Stop the worker before exporting its output:
msb stop ffmpeg-worker
Copy the result to the host:
<CodeGroup> ```sh macOS & Linux msb cp ffmpeg-worker:/out/output.mp4 "$FFMPEG_ARTIFACT_DIR/output.mp4" ```$outputPath = Join-Path $env:FFMPEG_ARTIFACT_DIR 'output.mp4'
msb cp ffmpeg-worker:/out/output.mp4 $outputPath
Validate the exported file:
<CodeGroup> ```sh macOS & Linux test ! -L "$FFMPEG_ARTIFACT_DIR/output.mp4" && test -f "$FFMPEG_ARTIFACT_DIR/output.mp4" && test -s "$FFMPEG_ARTIFACT_DIR/output.mp4" && test "$(wc -c < "$FFMPEG_ARTIFACT_DIR/output.mp4")" -le 1073741824 ```$output = Get-Item -LiteralPath $outputPath
$isLink = ($output.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0
if ($output.PSIsContainer -or $isLink -or $output.Length -eq 0 -or $output.Length -gt 1GB) {
throw 'output.mp4 failed artifact validation'
}
Stopping the worker before export removes any process that could race the artifact path. The fresh private directory, regular-file check, and 1 GiB host-side size check keep the exported file within the transcode command's per-file limit.
The laboratory smoke test generated a two-second H.264 video and ffprobe verified its duration and size.
Remove the prepared sandbox and worker:
<CodeGroup> ```sh macOS & Linux msb rm -f ffmpeg-base ffmpeg-worker rm -f prepare-ffmpeg.sh transcode-video.sh ```msb rm -f ffmpeg-base ffmpeg-worker
Remove-Item prepare-ffmpeg.sh, transcode-video.sh
Remove the reusable toolchain snapshot:
msb snapshot rm ffmpeg-tools
The checked output remains in the artifact directory configured above until you remove it.
</Step> </Steps>--max-duration according to the longest media you accept.--no-net unless the worker must retrieve remote media; copy or stream validated input through a controlled host service instead.