Skip to content
Back to skills

Ffmpeg Production

ASecurity

FFmpeg video/audio processing — conversion, scaling, compression, trimming, concatenation, AI post-processing. Not for audio ducking/voice mixing (tts-production) or Remotion rendering.

  • 23 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added October 6, 2026
ai-agentsgobash

Works with

  • cli

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 6, 2026

npx -y skills add Galbaz1/video-research-mcp --skill ffmpeg-production --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ffmpeg Production?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ffmpeg Production
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/galbaz1-ffmpeg-production/badge)](https://www.skillsdirectory.com/skills/galbaz1-ffmpeg-production)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ffmpeg-production
description: FFmpeg video/audio processing — conversion, scaling, compression, trimming, concatenation, AI post-processing. Not for audio ducking/voice mixing (tts-production) or Remotion rendering.
---

# FFmpeg Production

FFmpeg recipes for video post-production. Covers the operations you reach for daily: format conversion, scaling, trimming, concatenation, compression, and AI video post-processing.

For platform-specific export presets (YouTube, TikTok, Instagram, Twitter), see [references/platform-presets.md](references/platform-presets.md).

## Post-Processing Filter Order

Use this order when these filters are needed. Compare against the original; unnecessary processing can remove detail or introduce artifacts.

```
[1] Temporal denoise  — remove inter-frame shimmer before any processing
[2] Scale             — scale before sharpening avoids halos
[3] Sharpen           — recover edge detail lost in generation/upscale
[4] Color grade (LUT) — normalize over-saturated AI palette
[5] Curves/EQ         — fine-tune contrast and shadow lift
[6] Film grain        — LAST before encode; grain before denoising destroys it
[7] Encode            — libx265 -tune grain or AV1 FGS
```

Denoising can remove added grain, and interpolation can distort it. Add grain after those operations.

Full chain as a single filtergraph:

```bash
ffmpeg -i input.mp4 \
  -vf "hqdn3d=2:2:3:3,\
       scale=1920:1080:flags=lanczos,\
       unsharp=5:5:0.8:5:5:0.4,\
       lut3d=grade.cube,\
       curves=r='0/0 0.5/0.52 1/1':b='0/0.03 1/0.97',\
       noise=alls=6:allf=t+u" \
  -c:v libx265 -crf 18 -preset slow -tune grain \
  -c:a copy output.mp4
```

### Hald CLUT Color Grading

For iterative grading, export a Hald CLUT, edit it in Photoshop/GIMP, and re-import. LUT edits leave the source untouched; rendering the graded video still encodes it.

```bash
ffmpeg -i input.mp4 -i hald_clut_graded.png \
  -filter_complex "[0:v][1:v] haldclut" \
  -c:v libx265 -crf 18 output.mp4
```

## Format Conversion

### Codec Selection

| Target | Codec | When to use |
|--------|-------|-------------|
| Web/streaming | libx264 | Universal compatibility |
| Compact retained copy | libx265 | Compare quality/size for the actual material; CRF encoding is lossy |
| Modern distribution | libsvtav1 | Compare compression, encode time, and target-player support |
| Browser embed | libvpx-vp9 | WebM container, good compression |

### Essential Flags

| Flag | Purpose |
|------|---------|
| `-movflags +faststart` | Moves moov atom to front for web streaming |
| `-pix_fmt yuv420p` | Ensures player compatibility |
| `-preset slow/medium/fast` | Encode speed vs compression tradeoff |
| `-crf 18-28` | Quality control (lower = better, 23 is default) |
| `-profile:v high` | H.264 feature set (high for quality, baseline for compat) |

### CRF Quality Guide

| Use case | CRF | Preset | Notes |
|----------|-----|--------|-------|
| Archive/master | 18 | slow | Best quality, large files |
| Production | 20-22 | medium | Good balance |
| Web/preview | 23-25 | fast | Smaller files |
| Draft/quick | 28+ | veryfast | Fast encoding |

### GIF to MP4

```bash
ffmpeg -i input.gif -movflags faststart -pix_fmt yuv420p \
  -vf "scale=trunc(iw/2)*2:trunc(ih/2)*2" output.mp4
```

### Compress Video

```bash
# Good quality, smaller file
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4

# Target file size (e.g., ~10MB for 60s = ~1.3Mbps)
ffmpeg -i input.mp4 -c:v libx264 -b:v 1300k -c:a aac -b:a 128k output.mp4
```

## Video Scaling and Cropping

```bash
# Scale to 1080p (letterbox — maintain aspect ratio, add black bars)
ffmpeg -i input.mp4 \
  -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2" \
  output.mp4

# Scale to 1080p (crop to fill)
ffmpeg -i input.mp4 \
  -vf "scale=1920:1080:force_original_aspect_ratio=increase,crop=1920:1080" \
  output.mp4

# Scale to width, auto height (even dimensions)
ffmpeg -i input.mp4 -vf "scale=1280:-2" output.mp4
```

## Audio Extraction and Conversion

```bash
# Extract to MP3
ffmpeg -i input.mp4 -vn -acodec libmp3lame -q:a 2 output.mp3

# Extract to AAC
ffmpeg -i input.mp4 -vn -acodec aac -b:a 192k output.m4a

# Extract to WAV (uncompressed)
ffmpeg -i input.mp4 -vn output.wav

# M4A to MP3
ffmpeg -i input.m4a -codec:a libmp3lame -qscale:a 2 output.mp3

# Adjust volume
ffmpeg -i input.mp3 -filter:a "volume=1.5" output.mp3
```

## Trimming and Cutting

```bash
# Cut from timestamp for duration (recommended — re-encode for accuracy)
ffmpeg -i input.mp4 -ss 00:00:30 -t 00:00:15 -c:v libx264 -c:a aac output.mp4

# Cut between timestamps
ffmpeg -i input.mp4 -ss 00:00:30 -to 00:00:45 -c:v libx264 -c:a aac output.mp4

# Stream copy (faster but may lose frames at non-keyframe cut points)
ffmpeg -i input.mp4 -ss 00:00:30 -t 00:00:15 -c copy output.mp4
```

Re-encoding is recommended for trimming. Stream copy (`-c copy`) can silently drop video if the seek point misses a keyframe.

## Concatenation

```bash
# Create file list
printf "file '%s'\n" clip1.mp4 clip2.mp4 clip3.mp4 > list.txt

# Concatenate (same codec/resolution — stream copy)
ffmpeg -f concat -safe 0 -i list.txt -c copy output.mp4

# Concatenate (mixed sources — re-encode)
ffmpeg -f concat -safe 0 -i list.txt -c:v libx264 -c:a aac output.mp4
```

## Speed Change

```bash
# 2x speed (video + audio)
ffmpeg -i input.mp4 \
  -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" \
  -map "[v]" -map "[a]" output.mp4

# 0.5x slow motion
ffmpeg -i input.mp4 \
  -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" \
  -map "[v]" -map "[a]" output.mp4

# Video only (drop audio)
ffmpeg -i input.mp4 -filter:v "setpts=0.5*PTS" -an output.mp4
```

**Speed math:** To fit X seconds into Y seconds: `speed = X / Y`, `setpts = 1/speed * PTS`, `atempo = speed`.

**Extreme speeds (>2x audio):** `atempo` accepts 0.5–100, but values above 2 skip samples. Chain factors at or below 2 to avoid that behavior ([filter contract](https://ffmpeg.org/ffmpeg-filters.html#atempo)):

```bash
# 4x audio: atempo=2.0,atempo=2.0
# 8x audio: atempo=2.0,atempo=2.0,atempo=2.0
```

## Fade and Transitions

```bash
# Video fade in/out (1s each, 10s video)
ffmpeg -i input.mp4 \
  -vf "fade=t=in:st=0:d=1,fade=t=out:st=9:d=1" -c:a copy output.mp4

# Audio fade in/out
ffmpeg -i input.mp4 \
  -af "afade=t=in:st=0:d=1,afade=t=out:st=9:d=1" -c:v copy output.mp4
```

## Two-Pass Loudnorm (EBU R128)

Use two passes when targeting linear normalization. Supply all measured values; the filter falls back to dynamic mode if the target LRA or true-peak constraints prevent linear gain. Inspect its reported mode ([loudnorm contract](https://ffmpeg.org/ffmpeg-filters.html#loudnorm)).

```bash
# Pass 1: measure
ffmpeg -i input.mp4 \
  -af "loudnorm=I=-16:LRA=11:TP=-1.5:print_format=json" \
  -f null - 2>loudnorm_stats.json

# Pass 2: apply (substitute measured values from stats)
ffmpeg -i input.mp4 \
  -af "loudnorm=I=-16:LRA=11:TP=-1.5:measured_I=-18.2:measured_LRA=9.1:measured_TP=-3.2:measured_thresh=-28.5:linear=true" \
  output_normalized.mp4
```

Target levels: YouTube `-14 LUFS` TP `-1 dBFS` | Streaming `-14 LUFS` TP `-2 dBFS` | Broadcast EBU R128 `-23 LUFS` TP `-1 dBFS`.

## Probe and Validate

```bash
# Get duration
ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4

# Full info as JSON
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4

# Inspect the reported video codec; verify decode/playback separately
ffprobe -v error -select_streams v:0 -show_entries stream=codec_name -of csv=p=0 output.mp4
```

## Common Errors

| Error | Fix |
|-------|-----|
| "height not divisible by 2" | Add `-vf "scale=trunc(iw/2)*2:trunc(ih/2)*2"` |
| Video won't play in browser | Use `-movflags faststart -pix_fmt yuv420p -c:v libx264` |
| Audio out of sync after speed change | Use `filter_complex` with matched `setpts` + `atempo` |
| Output 0 bytes | Check full ffmpeg output — silent failures hide in stderr |
| "encoder not found" | Install FFmpeg with full codecs (`brew install ffmpeg`) |

Files in this skill

  • SKILL.md8 KB
  • references/platform-presets.md7.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.