Подробные статьи о технологиях, определяющих будущее.

FFmpeg без магии: ментальная модель, которой не хватает

Хватит слепо копировать команды FFmpeg. Разберитесь в контейнерах, кодеках, потоках и фильтрах и освойте рецепты, которые реально пригодятся.

Машина разделяет поток фильма, аудио и текста через воронки в один светящийся контейнер.

Все мы через это проходили. Нужно конвертировать видео, вы гуглите и находите ответ на Stack Overflow с командой, которая выглядит так, будто кто-то со всей силы ударил по клавиатуре: ffmpeg -i input.mov -c:v libx264 -preset slow -crf 22 -c:a aac -b:a 128k -movflags +faststart output.mp4. Запускаете. Работает. Понятия не имеете почему, и в следующий раз, когда понадобится что-то чуть-чуть другое, вы снова на Stack Overflow. Я так делал годами, пока наконец не сел и не разобрался, чего же FFmpeg от меня хочет.

Если честно, FFmpeg не так уж сложен. У него есть последовательная ментальная модель, и как только вы её поймёте, почти любая команда становится понятной. Проблема в том, что модель никто не объясняет, все просто подсовывают команды. Так что давайте это исправим.

Контейнеры и кодеки: что нужно понять в первую очередь

Самый большой источник путаницы с видеофайлами — разница между контейнерами и кодеками. Контейнер — это формат файла: .mp4, .mkv, .webm, .mov. Это коробка, которая что-то хранит. Кодек — это способ сжатия самих видео- и аудиоданных внутри этой коробки: H.264, H.265, VP9, AV1, AAC, Opus.

В файле MP4 может лежать видео H.264 с аудио AAC, либо видео H.265 с аудио Opus, либо десятки других комбинаций. Файл MKV может содержать практически что угодно. Когда кто-то говорит «конвертировать в MP4», обычно имеется в виду «упаковать видео H.264 и аудио AAC в контейнер MP4», но это три отдельных решения.

# See what's actually inside a file
$ ffprobe -hide_banner video.mkv
Input #0, matroska:
Stream #0:0: Video: hevc (Main), 1920x1080, 23.98 fps
Stream #0:1: Audio: opus, 48000 Hz, stereo
Stream #0:2: Subtitle: subrip
# This file is:
# Container: MKV (Matroska)
# Video codec: HEVC (H.265)
# Audio codec: Opus
# Plus a subtitle stream

Прежде чем что-либо делать, используйте ffprobe. Он покажет, с чем именно вы работаете. Примерно в половине случаев нужная вам «конвертация» — это просто ремуксинг, то есть перенос тех же потоков в другой контейнер без перекодирования. Это занимает считаные секунды.

Структура команды FFmpeg

Каждая команда FFmpeg следует одному и тому же шаблону, и как только вы его увидите, уже не сможете не замечать:

ffmpeg [global options] [input options] -i input [output options] output
# The KEY insight: options apply to the NEXT file.
# Options before -i apply to the input.
# Options after -i (before the output filename) apply to the output.
# This matters! These two commands are different:
ffmpeg -ss 00:01:00 -i video.mp4 output.mp4   # Seeks BEFORE decoding (fast)
ffmpeg -i video.mp4 -ss 00:01:00 output.mp4   # Seeks AFTER decoding (slow, precise)

Порядок имеет значение. Именно на этом спотыкаются все. Значение опции может меняться в зависимости от того, стоит она до или после -i. Пример с -ss выше — самый распространённый случай: если поставить её перед -i, FFmpeg перейдёт к нужному месту во входном файле напрямую (быстро, но возможна неточность), а если после — FFmpeg декодирует всё до этой точки и только потом начнёт вывод (медленно, зато точно по кадрам).

Выбор потоков: как сообщить FFmpeg, что вам нужно

Видеофайлы часто содержат несколько потоков: видео, аудио, субтитры, иногда несколько аудиодорожек на разных языках. Чтобы выбрать конкретные потоки, FFmpeg использует синтаксис спецификаторов потоков:

  • -c:v — кодек для видеопотоков (v = video)
  • -c:a — кодек для аудиопотоков (a = audio)
  • -c:s — кодек для потоков субтитров (s = subtitle)
  • -c copy — копировать ВСЕ потоки без перекодирования
  • -c:v copy -c:a aac — копировать видео как есть, перекодировать аудио в AAC
  • -map 0:a:1 — выбрать второй аудиопоток из первого входного файла

Флаг -c copy — самый важный из всех. Он говорит FFmpeg копировать данные потока напрямую, без перекодирования. Это практически мгновенно и без потерь: вы просто переносите данные из одного контейнера в другой. Если не нужно менять кодек, всегда используйте -c copy.

# Remux MKV to MP4 without re-encoding (instant)
ffmpeg -i input.mkv -c copy output.mp4
# Copy video but re-encode audio (fast — only audio is processed)
ffmpeg -i input.mkv -c:v copy -c:a aac -b:a 192k output.mp4
# Extract just the audio stream
ffmpeg -i video.mp4 -vn -c:a copy audio.aac
# -vn means "no video" — drop the video stream entirely

Практические рецепты, которые вы реально будете использовать

Вот команды, которыми я пользуюсь постоянно. Каждая из них объяснена, чтобы вы могли адаптировать её под свои задачи.

Сжатие видео для веба

ffmpeg -i raw_video.mov \
-c:v libx264 \
-preset slow \
-crf 23 \
-c:a aac -b:a 128k \
-movflags +faststart \
web_video.mp4
# -c:v libx264     → encode video with H.264
# -preset slow     → slower encoding = smaller file (options: ultrafast to veryslow)
# -crf 23          → quality level (18=near lossless, 23=default, 28=low quality)
# -c:a aac         → encode audio as AAC
# -b:a 128k        → audio bitrate 128 kbps
# -movflags +faststart → move metadata to start of file for streaming

Значение CRF (Constant Rate Factor) — самый важный регулятор качества. Чем меньше число, тем выше качество и больше файл. Для большинства веб-видео оптимальный диапазон — CRF 20–25. Я обычно ставлю 22 для всего, что должно хорошо выглядеть, и 26 для фонового или вспомогательного видео, где качество важно меньше.

Обрезка видео без перекодирования

# Extract from 1:30 to 3:45 — no re-encoding, nearly instant
ffmpeg -ss 00:01:30 -to 00:03:45 -i input.mp4 -c copy trimmed.mp4
# If you need frame-accurate cuts (slower):
ffmpeg -i input.mp4 -ss 00:01:30 -to 00:03:45 \
-c:v libx264 -crf 18 -c:a copy trimmed.mp4

Генерация миниатюр

# Single thumbnail at the 10-second mark
ffmpeg -ss 00:00:10 -i video.mp4 -frames:v 1 thumb.jpg
# One thumbnail every 30 seconds
ffmpeg -i video.mp4 -vf "fps=1/30" thumbs/thumb_%04d.jpg
# Resize to 320px wide, maintain aspect ratio
ffmpeg -ss 00:00:10 -i video.mp4 -frames:v 1 \
-vf "scale=320:-1" thumb_small.jpg

Создание GIF из видеоклипа

# Good quality GIF with palette generation (two-pass)
ffmpeg -ss 00:00:05 -t 3 -i video.mp4 \
-vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1]; \
[s0]palettegen[p];[s1][p]paletteuse" \
output.gif
# -t 3              → duration: 3 seconds
# fps=15            → 15 frames per second (keep GIFs small)
# scale=480:-1      → resize to 480px wide
# palettegen/use    → generate optimal color palette (much better quality)

Фильтры: главная сила FFmpeg

Именно фильтры превращают FFmpeg из «полезного инструмента» в «невероятно мощный». Флаг -vf (видеофильтр) и флаг -af (аудиофильтр) позволяют объединять цепочки операций обработки. Фильтры разделяются запятыми для последовательной обработки или точками с запятой для сложных графов фильтров.

# Chain multiple filters: resize, then add padding for exact dimensions
ffmpeg -i input.mp4 -vf "scale=1280:720:force_original_aspect_ratio=decrease,\
pad=1280:720:(ow-iw)/2:(oh-ih)/2:black" output.mp4
# Normalize audio volume
ffmpeg -i input.mp4 -af "loudnorm" -c:v copy output.mp4
# Speed up a video 2x (with audio pitch correction)
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -af "atempo=2.0" fast.mp4
# Add text overlay
ffmpeg -i input.mp4 \
-vf "drawtext=text='DRAFT':fontsize=72:fontcolor=red:x=10:y=10" \
watermarked.mp4

Система фильтров достаточно глубока, чтобы заполнить отдельную статью, но ключевая мысль такая: фильтры работают с декодированными кадрами. Значит, -c copy с фильтрами не использовать: видео нужно декодировать, отфильтровать и перекодировать заново. Если в команде есть -vf, заложите время на полное перекодирование.

Аппаратное ускорение: используйте GPU

Если вы регулярно кодируете видео, аппаратное ускорение может ускорить процесс в 5–10 раз. Современные GPU содержат выделенные блоки кодирования, которые FFmpeg умеет использовать.

# NVIDIA GPU (NVENC)
ffmpeg -i input.mp4 -c:v h264_nvenc -preset p4 -crf 23 output.mp4
# Apple Silicon (VideoToolbox)
ffmpeg -i input.mp4 -c:v h264_videotoolbox -b:v 5M output.mp4
# Intel Quick Sync (QSV)
ffmpeg -i input.mp4 -c:v h264_qsv -preset medium output.mp4
# Check what's available on your system:
ffmpeg -encoders 2>/dev/null | grep -E '(nvenc|videotoolbox|qsv|vaapi)'

Небольшое предостережение: аппаратные кодировщики быстрее, но при той же визуальной картинке обычно дают немного большие файлы, чем программное кодирование (libx264). Для разовых перекодирований, где важно качество, программное кодирование по-прежнему лучше. Для пакетной обработки или стриминга в реальном времени аппаратное ускорение явно выигрывает. Я использую libx264 для финальных продакшн-кодирований, а NVENC — для всего остального.

Частые ошибки и как их избежать

  • Перекодирование без необходимости. Если вы просто обрезаете, извлекаете аудио или меняете контейнер, используйте -c copy. Нет смысла тратить 20 минут на перекодирование видео, от которого вы отрезаете 30 секунд.
  • Слишком низкое значение CRF. CRF 18 даёт огромные файлы с улучшением качества, которое большинство людей не заметит. Начните с 23 и опускайтесь ниже, только если видите артефакты. Для большинства веб-контента 23–25 более чем достаточно.
  • Забытый -movflags +faststart. Без этого метаданные MP4 лежат в конце файла, и браузер не может начать воспроизведение, пока не загрузится весь файл. Всегда добавляйте этот флаг для веб-видео.
  • Непроверенный входной файл. Запустите ffprobe перед написанием команды. Знание входных кодеков, разрешения и структуры потоков делает всё проще.
  • Ожидание в никуда. Если FFmpeg кажется зависшим, возможно, он ждёт ответа на вопрос (например, перезаписывать ли существующий файл). Добавьте -y, чтобы перезаписывать автоматически, или -n, чтобы никогда не перезаписывать.

Шпаргалка

Вот что я храню в текстовом файле на рабочем столе. Этого хватает примерно на 90% моих ежедневных задач:

# Probe a file
ffprobe -hide_banner input.mp4
# Remux (change container, no re-encode)
ffmpeg -i input.mkv -c copy output.mp4
# Compress for web
ffmpeg -i input.mov -c:v libx264 -crf 23 -preset medium \
-c:a aac -b:a 128k -movflags +faststart output.mp4
# Extract audio only
ffmpeg -i video.mp4 -vn -c:a copy audio.m4a
# Trim without re-encoding
ffmpeg -ss 00:01:00 -to 00:02:30 -i input.mp4 -c copy clip.mp4
# Resize to 720p
ffmpeg -i input.mp4 -vf "scale=-1:720" -c:a copy output.mp4
# Convert to GIF
ffmpeg -ss 5 -t 3 -i input.mp4 \
-vf "fps=12,scale=400:-1" output.gif
# Concatenate files (same codec)
echo "file 'part1.mp4'" > list.txt
echo "file 'part2.mp4'" >> list.txt
ffmpeg -f concat -safe 0 -i list.txt -c copy combined.mp4

FFmpeg — не инструмент, который осваивается за день. Но как только вы поймёте ментальную модель — контейнеры содержат потоки, у потоков есть кодеки, опции применяются к следующему файлу, фильтры требуют перекодирования — документация начинает складываться в понятную картину. Вы перестаёте слепо копировать команды и начинаете составлять их осознанно. И, честно говоря, переход от «это магия» к «ага, вот что он делает» — один из самых приятных моментов, которые могут случиться с разработчиком.