FFmpeg — швейцарский нож для мультимедиа. Совершенно незаменимая программа, которую использует в повседневной жизни почти каждый, даже не зная об этом. Например, вы сняли видео и заливаете на видеохостинг — оно перекодируется и публикуется уже в другом разрешении/формате/размере. Как вы думаете, какая программа выполнила транскодирование? Вполне возможно, что под капотом на сервере работает FFmpeg.

FFmpeg объединяет более 300 видео/аудио/графических кодеков, декордеров, муксеров, демуксеров и фильтров. Благодаря ему вы можете написать собственный видеоплеер в тысячу строчек кода, не разбираясь с кишочками видеообработки.

Это «движок» почти всех современных инструментов для обработки/сжатия/редактирования видео. Они просто предлагают графический интерфейс с кнопками, а ffmpeg делает реальную работу.

Другими словами, существует основной движок FFmpeg, а весь остальной софт — это прокладки/GUI/плееры/редакторы, которые дают к нему доступ. Но можно обойтись без посредников и использовать FFmpeg напрямую. Только в консоли. Последняя версия программы лежит здесь (вместе с сопровождающими инструментами FFplay и FFprobe).

Для примера, вот несколько практических задач, с которыми приходится сталкиваться в повседневной рутине. Все они решаются однострочниками за несколько секунд.

▍ Вырезать кусочек видео, сохранить его в GIF


Стандартная ситуация, когда хочется вырезать из фильма или видеотрансляции какой-то жест или эмоцию и отправить в мессенджер как анимацию. Например, в Телеграме анимации можно отправлять в форматах GIF и MP4.

FFmpeg вырезает видеофрагмент и конвертирует его в GIF следующей командой:

ffmpeg -i input.mp4 -r 10 -an -ss '00:11:02.5' -to '00:11:05' output.gif

В команде указан фреймрейт gif (10), время начала и конца видео. Как вариант, можно указать время начала и продолжительность фрагмента.

Примечание. Для генерации простых команд ffmpeg в первое время можно пользоваться «помощником» ffmpeg buddy.


▍ Пережать другим кодеком


Например, мы оцифровали старую VHS-кассету в программе HandBrake (подключили с видеомагнитофона по USB), не применяли никаких фильтров и сохранили MPEG2 разрешением 720×576. С трёхчасовой кассеты получился файл размером 6,4 ГБ.

Понятно, что кассете 30 лет, качество сигнала плохое, тем более это вторая или третья копия, которая была ужасна в момент своего появления. Но выбирать не приходится.


Глядя на исходный MPEG2, возникают вопросы:

  1. Как сжать это видео (с потерями качества), чтобы быстро закинуть одноклассникам в Телеграм? Качество такое, что снижение разрешения не играет особой роли.
  2. Как сохранить это видео для длительного хранения? Существуют ли видеокодеки для сжатия без потерь, как в случае с фотографиями?

С первым вопросом всё довольно просто. Указываем в FFmpeg масштабирование 50% по горизонтали и вертикали, кодируем стандартным кодеком:

ffmpeg -i input.mpg -vf 'scale=iw*0.5:ih*0.5' output.mp4

Здесь масштабирование указано относительно оригинала.

Или так:

ffmpeg -i input.mpg -vf 'scale=360:288' output.mp4

Здесь масштабирование указано в пикселях (половина от оригинального 720×576). Результат будет идентичный:

Результат
ffmpeg -i input.mpg -vf 'scale=360:288' output.mp4
ffmpeg version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 11.2.0 (Rev7, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
Input #0, mpeg, from 'input.mpg':
  Duration: 02:26:12.00, start: 0.193178, bitrate: 6296 kb/s
  Stream #0:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bt470bg, top first), 720x576 [SAR 16:15 DAR 4:3], 25 fps, 25 tbr, 90k tbn
    Side data:
      cpb: bitrate max/min/avg: 8500000/0/0 buffer size: 1835008 vbv_delay: N/A
  Stream #0:1[0x1c0]: Audio: mp2, 48000 Hz, stereo, s16p, 224 kb/s
File 'output.mp4' already exists. Overwrite? [y/N] n
Not overwriting - exiting
PS D:\> .\ffmpeg -i input.mpg -vf 'scale=360:288' output.mp4
ffmpeg version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 11.2.0 (Rev7, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
Input #0, mpeg, from 'input.mpg':
  Duration: 02:26:12.00, start: 0.193178, bitrate: 6296 kb/s
  Stream #0:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bt470bg, top first), 720x576 [SAR 16:15 DAR 4:3], 25 fps, 25 tbr, 90k tbn
    Side data:
      cpb: bitrate max/min/avg: 8500000/0/0 buffer size: 1835008 vbv_delay: N/A
  Stream #0:1[0x1c0]: Audio: mp2, 48000 Hz, stereo, s16p, 224 kb/s
Stream mapping:
  Stream #0:0 -> #0:0 (mpeg2video (native) -> h264 (libx264))
  Stream #0:1 -> #0:1 (mp2 (native) -> aac (native))
Press [q] to stop, [?] for help
[libx264 @ 00000202ddab6e80] using SAR=16/15
[libx264 @ 00000202ddab6e80] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
[libx264 @ 00000202ddab6e80] profile High, level 2.1, 4:2:0, 8-bit
[libx264 @ 00000202ddab6e80] 264 - core 164 r3094 bfc87b7 - H.264/MPEG-4 AVC codec - Copyleft 2003-2022 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
Output #0, mp4, to 'output.mp4':
  Metadata:
    encoder         : Lavf59.16.100
  Stream #0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, bt470bg, top coded first (swapped)), 360x288 [SAR 16:15 DAR 4:3], q=2-31, 25 fps, 12800 tbn
    Metadata:
      encoder         : Lavc59.18.100 libx264
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
  Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s
    Metadata:
      encoder         : Lavc59.18.100 aac
frame=219300 fps=209 q=-1.0 Lsize=  711087kB time=02:26:12.01 bitrate= 664.1kbits/s speed=8.35x
video:566821kB audio:137780kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.920495%
[libx264 @ 00000202ddab6e80] frame I:1143  Avg QP:22.93  size: 10857
[libx264 @ 00000202ddab6e80] frame P:59982 Avg QP:25.64  size:  5013
[libx264 @ 00000202ddab6e80] frame B:158175 Avg QP:29.16  size:  1690
[libx264 @ 00000202ddab6e80] consecutive B-frames:  2.9%  1.9%  2.9% 92.3%
[libx264 @ 00000202ddab6e80] mb I  I16..4:  5.2% 71.9% 22.9%
[libx264 @ 00000202ddab6e80] mb P  I16..4:  2.2% 13.8%  3.0%  P16..4: 40.6% 26.7% 12.7%  0.0%  0.0%    skip: 1.1%
[libx264 @ 00000202ddab6e80] mb B  I16..4:  0.3%  1.1%  0.2%  B16..8: 43.7% 11.8%  2.6%  direct:14.1%  skip:26.3%  L0:38.2% L1:42.7% BI:19.1%
[libx264 @ 00000202ddab6e80] 8x8 transform intra:72.0% inter:73.2%
[libx264 @ 00000202ddab6e80] coded y,uvDC,uvAC intra: 75.8% 92.3% 56.3% inter: 31.9% 62.8% 4.8%
[libx264 @ 00000202ddab6e80] i16 v,h,dc,p: 30% 26%  3% 40%
[libx264 @ 00000202ddab6e80] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 24% 22% 12%  5%  7%  9%  7%  8%  7%
[libx264 @ 00000202ddab6e80] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 23% 26% 11%  5%  8%  9%  7%  7%  5%
[libx264 @ 00000202ddab6e80] i8c dc,h,v,p: 47% 21% 20% 11%
[libx264 @ 00000202ddab6e80] Weighted P-Frames: Y:31.1% UV:22.8%
[libx264 @ 00000202ddab6e80] ref P L0: 48.6% 19.1% 20.9%  9.5%  1.9%
[libx264 @ 00000202ddab6e80] ref B L0: 89.7%  8.4%  1.8%
[libx264 @ 00000202ddab6e80] ref B L1: 96.4%  3.6%
[libx264 @ 00000202ddab6e80] kb/s:529.34
[aac @ 00000202ddab8780] Qavg: 356.888

Потеря качества практически не заметна на экране телефона, а размер файла уменьшился до 694 МБ. Уже влезает в бесплатный лимит телеграма (и даже на CD, если кому-то отправить по почте).

Согласно документации, кодирование в H.265 займёт втрое больше времени, зато файл получится на 25–50% меньше, чем H.264. Но это пока относительно новый формат, который поддерживается не на всех старых устройствах. Даже FFmpeg по умолчанию его пока не использует. У меня не получилось закодировать в H.265 с настройками максимального качества и уменьшением разрешения в одной команде. Наверное, нужно сначала переконвертировать в lossless-формат, потом уменьшить до 50% кадра, а потом кодировать в H.265.

Кстати, перекодирование с уменьшением размера видео можно выполнить бесплатно на серверах Google, если залить оригиналы на YouTube, затем скачать результаты транскодинга программой yt-dlp и удалить исходники. Это удобно, если у вас сотни часов видеоматериала и не хочется нагружать свой ПК.

Эксперименты показывают, что любые кодеки с потерей качества заметно портят картинку, независимо от настроек. Казалось бы, надо найти вариант с перекодированием без потери качества (lossless). Теоретически, такие варианты есть. Ряд видеокодеков поддерживают режим сжатия без потерь, вот некоторые из них:

  • H.264 lossless,
  • H.265 lossless,
  • Motion JPEG 2000 lossless,
  • JPEG XS lossless,
  • FFV1,
  • AV1,
  • VP9,
  • Apple Animation (QuickTime RLE),
  • … и другие.

FFmpeg использует энкодеры x264/x265, а также нативно поддерживает свободный кодек без потерь FFV1, который по параметрам компрессии похож на Motion JPEG 2000 lossless, но за счёт более быстрых алгоритмов может кодировать в реальном времени.

▍ Извлечение аудиодорожки


Например, у нас большая видеозапись, а мы хотим её загрузить в плеер/смартфон для прослушивания, чтобы не записывать гигабайты сопутствующего видео. Нет ничего проще:

ffmpeg -i input.mpg -map 0:1 bbb_audio.mp3

Если не указаны дополнительные параметры, то всё кодируется с настройками по умолчанию для MP3.

Результат
ffmpeg -i input.mpg -map 0:1 bbb_audio.mp3
ffmpeg version 5.0.1-essentials_build-www.gyan.dev Copyright (c) 2000-2022 the FFmpeg developers
  built with gcc 11.2.0 (Rev7, Built by MSYS2 project)
  configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-libass --enable-libfreetype --enable-libfribidi --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-ffnvcodec --enable-nvdec --enable-nvenc --enable-d3d11va --enable-dxva2 --enable-libmfx --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
  libavutil      57. 17.100 / 57. 17.100
  libavcodec     59. 18.100 / 59. 18.100
  libavformat    59. 16.100 / 59. 16.100
  libavdevice    59.  4.100 / 59.  4.100
  libavfilter     8. 24.100 /  8. 24.100
  libswscale      6.  4.100 /  6.  4.100
  libswresample   4.  3.100 /  4.  3.100
  libpostproc    56.  3.100 / 56.  3.100
Input #0, mpeg, from 'input.mpg':
  Duration: 02:26:12.00, start: 0.193178, bitrate: 6296 kb/s
  Stream #0:0[0x1e0]: Video: mpeg2video (Main), yuv420p(tv, bt470bg, top first), 720x576 [SAR 16:15 DAR 4:3], 25 fps, 25 tbr, 90k tbn
    Side data:
      cpb: bitrate max/min/avg: 8500000/0/0 buffer size: 1835008 vbv_delay: N/A
  Stream #0:1[0x1c0]: Audio: mp2, 48000 Hz, stereo, s16p, 224 kb/s
Stream mapping:
  Stream #0:1 -> #0:0 (mp2 (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, mp3, to 'bbb_audio.mp3':
  Metadata:
    TSSE            : Lavf59.16.100
  Stream #0:0: Audio: mp3, 48000 Hz, stereo, s16p
    Metadata:
      encoder         : Lavc59.18.100 libmp3lame
size=  137063kB time=02:26:12.00 bitrate= 128.0kbits/s speed=31.5x
video:0kB audio:137063kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.000169%

С параметром -ss можно вырезать нужный фрагмент аудиодорожки.

▍ Любая магия


Даже самый лаконичный и понятный мануал по FFmpeg занимает сотню страниц печатного текста. Про официальную документацию не стоит даже упоминать, там объём скорее в тысячу страниц.

Глядя на фантастические примеры использования FFmpeg, поражаешься мощи этого инструмента. Например, вот пользователь захотел поиграть в игры PS2 на своём ноутбуке. Но поскольку тот недостаточно мощный для эмулятора PCSX2, ему пришла идея транслировать видео с домашнего сервера в другом конце города. То есть он пробросил геймпад на рабочую станцию через USB/IP и начал копать мануал FFmpeg, как транслировать игру на ноутбук. FFmpeg захватывает видео напрямую из буферов KMS, использует аппаратное ускорение GPU для транскодирования со снижением разрешения, захватывает аудио, всё перекодирует с параметрами для передачи по сети (в реальном времени) и передаёт результат в UDP-сокет. На другом конце он настроил плеер mpv для получения и воспроизведения потока.

ffmpeg \
  -f pulse \
  -i alsa_output.platform-snd_aloop.0.analog-surround-51.monitor \
  -f kmsgrab \
  -thread_queue_size 64 \   # уменьшает задержку ввода
  -i - \
  # Capture and downscale frames on the GPU:
  -vf 'hwmap=derive_device=vaapi,scale_vaapi=1280:720,hwdownload,format=bgr0' \
  -c:v libx264 \
  -preset:v superfast \     # максимально быстрое кодирование видео
  -tune zerolatency \       # настройка кодека на нулевую задержку
  -intra-refresh 1 \        # уменьшает задержку и уменьшает потери пакетов
  -f mpegts \               # объединение в поток mpegts, который хорошо подходит для данного случая
  -b:v 3M \                 # целевая полоса пропускания для итогового видео
  udp://$hackerspace:41841

Всего час изучения руководства — и мы с нуля составляем рабочую команду FFmpeg, чтобы играть в PS2 на ноутбуке через стрим с удалённого сервера. Практически Google Stadia своими руками (земля ей пухом).

Или вот пример из мануала:

ffmpeg -y  \
    -ss 20 -t 60 -i bbb_sunflower_1080p_60fps_normal.mp4 \
    -i train.jpg \
    -ss 4 -i voice_recording.wav \
    -filter_complex "[0:v]hue=h=80:s=1[main] ; [1:v]crop=w=382:h=304:x=289:y=227[train] ; [main][train]overlay=x=200:y=200,vignette=PI/4[video] ; [2:a]volume=1.5,aecho=0.8:0.9:100:0.3[speech] ; [0:a][speech]amix=duration=shortest,asplit[audio1][audio2]" \
    -map '[video]' -map '[audio1]' -metadata title="Editor's cut" bbb_edited.mp4 \
    -map '[audio2]' bbb_edited_audio_only.wav

Эта команда делает в том числе следующее:

  1. Открывает файл.
  2. Вырезает фрагмент (-ss 20 -t 60).
  3. Накладывает изображение train.jpg.
  4. Обрезает наложенное изображение (crop).
  5. Добавляет эффект виньетирования под углом PI/4.
  6. Накладывает фильтр для коррекции тона (hue).
  7. Накладывает дополнительную звуковую дорожку voice_recording.wav.
  8. Увеличивает громкость.
  9. Добавляет эхо.
  10. Экспортирует результат в разные форматы.
  11. Экспортирует оригинальную звуковую дорожку.

Одна команда в консоли заменяет десять минут редактирования в Premiere Pro!

Оригинал (видео, картинка поезда, звук) и результат (справа):


▍ Редактор LosslessCut как GUI для FFmpeg


Как мы уже говорили, многие программы для обработки видео «под капотом» используют FFmpeg. И похоже, что FFmpeg начинает осваивать веб-технологии. Например, недавно появился ffmpeg.wasm — чистый порт FFmpeg на WebAssembly/JavaScript. Это обработка видео нативно в браузере.

Ещё одна интересная новинка последнего времени — видеоредактор LosslessCut. Он вырезает и склеивает фрагменты видео практически мгновенно и без потери качества, не выполняя перекодирование, как Adobe Premiere Pro. Привычная получасовая операция тут занимает пять секунд, экономя при этом гигабайты дискового пространства.

LosslessCut

Конечно, такая магия работает только при условии, что фрагменты видео/аудио сжаты одинаковым кодеком. В данном случае не требуется повторная обработка и фрагменты достаточно просто склеить.

Такая функциональность лучше всего подходит для следующих задач:

  1. Быстрый монтаж небольших видеороликов.
  2. Вырезание/добавление фрагментов. Например, вот что можно сделать:
    • вырезать рекламные ролики из записанной телепередачи;
    • удалить аудио- или видеодорожку из файла;
    • добавить музыку в видео (или заменить существующую звуковую дорожку);
    • добавить субтитры (или произвольные надписи) в видеоряд;
    • выполнить слияние файлов (с идентичными параметрами кодирования);
    • извлечь любые/все дорожки из файла;


    • извлечь музыку, видео или субтитры из видео и обрезать их в соответствии с вашими потребностями;
    • повернуть видео, для которого установлен флаг неправильной ориентации, например, видео с телефона.

  3. Быстрое перекодирование H264 MKV в MOV или MP4 для воспроизведения на iPhone.
  4. Журнал последних команд ffmpeg, чтобы изменять и запускать эти команды из консоли.
  5. Зацикливание видео/аудио X раз без повторного кодирования.
  6. Экспорт/импорт вырезанных сегментов в CSV.

Примечание: доступность отдельных функций зависит от формата/кодека.


В общем, очень полезный инструмент. Неудивительно, что под его капотом тоже работает FFmpeg. То есть LosslessCut — просто удобный и эффективный FFmpeg GUI. Разумеется, исходный код тоже открыт. Если есть желание задонатить автору, то программу можно купить через Mac App Store или Microsoft Store. Версия под Linux распространяется через Snap Store и Flathub (а также напрямую с GitHub).



FFmpeg выполняет практически любые операции с мультимедийными файлами, какие только можно представить. Остаётся упомянуть добрым словом гениального программиста Фабриса Беллара, который запустил этот опенсорсный проект в 2000 году и несколько первых лет возглавлял разработку. Человечеству нужен был такой инструмент. Теперь он у нас есть, проблема решена, а Фабрис работает над другими крайне важными задачами.

Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх

Комментарии (82)


  1. akhmat-kat
    00.00.0000 00:00

    Очень удобная штука! Используем в своем проекте для обработки более полутора тысяч видео.


  1. andreymal
    00.00.0000 00:00
    +4

    И все всегда забывают указывать правильное цветовое пространство, чтобы плеерам не приходилось его угадывать. Поэтому совет: если лень разбираться с этим, то просто вставляйте эти опции в параметры кодирования видео, в большинстве случаев сойдёт:


    -color_primaries:v bt709 -color_trc:v bt709 -colorspace:v bt709


    1. An_private
      00.00.0000 00:00

      А смысл? В 99% при разрешении видео SD и ниже - bt470, всё что выше - b709. Тут, правда, есть подводный камень - если делаешь апскейл SD-HD или даунскейл HD-SD, то лучше прописать преобразование в явном виде. А в остальных случаях особо и не надо.


      1. andreymal
        00.00.0000 00:00
        +6

        Я как питонист воспитан, что явное лучше неявного, подводных камней будет поменьше)


        Плюс в такой формулировке возникает вопрос, что такое SD, а что такое HD. Слегка увеличенное видео 722x578 — это уже HD или ещё SD? Или наоборот, слегка обрезанное видео 1278x718 — это уже SD или ещё HD? А если «кинематографичное» соотношение сторон 1280x536? А если кому-то приспичило сделать неквадратный пиксель 640x536? У всех ли плееров одинаковый алгоритм «угадывания»? А у браузеров? https://habr.com/ru/company/vdsina/blog/560224/


        Я не хочу задаваться подобными вопросами, поэтому для удобства сделал себе в консоли переменную $BT709, которую теперь пихаю почти в любую команду ffmpeg: цветовое пространство в моих файлах указано, а если у кого-то видео отобразится некорректно, то это уже не мои проблемы)


        1. An_private
          00.00.0000 00:00
          +1

          Обычно считается по ширине - всё, что до 720 - SD, 721 и более - HD.

          Проблема в том, что для этого надо учитывать входное цветовое пространство. То есть можно, конечно, по умолчанию ставить видеофильтр приведения к 709, но это, скорее костыль.


        1. An_private
          00.00.0000 00:00
          +1

          Посмотрел статью, на которую дана ссылка, и стал понимать. Дело в том, что я в основном имею дело с профессиональными программами работы с видео. И у них алгоритм именно такой - если цветовое пространство прописано в файле - работать в нём. Не прописано - смотрим по разрешению файла.

          Если же данный алгоритм не гарантирован - то, конечно, лучше прописывать цветовое пространство в явном виде.

          Немного напоминает ранние компьютерные видеоплейера, программисты которых в принципе не понимали - что такое чересстрочная развертка и как пиксель может быть неквадратным


      1. Balling
        00.00.0000 00:00
        +1

        ITU-R BT.470 же закончился, когда Москва отключила аналоговый ТВ, и то там был SECAM, а значит https://en.wikipedia.org/wiki/YDbDr

        Вы вообще не понимаете, что несете.

        Primaries между SD и HD разные (причем в SD может быть два типа, а вообще могут быть любые) -- это надо тоже проконтролировать отдельно от матрицы.


    1. Balling
      00.00.0000 00:00

      Это баг, что это надо указывать постоянно.


  1. Neusser
    00.00.0000 00:00

    Метаданные умеет переносить? Геотэг, например.


    1. Vest
      00.00.0000 00:00

      вы про map_metadata?


      1. Neusser
        00.00.0000 00:00

        Может быть, я не знаю, как называется. Точка, где было снято видео.


    1. Balling
      00.00.0000 00:00

      Да, но не во всех случаях, это баг, новые метаданные не создаются.


  1. 13werwolf13
    00.00.0000 00:00

    Ряд видеокодеков поддерживают режим сжатия без потерь

    помню игрался с тем как хранить видео, HuffYUV отжирает просто непомерно места и довольно паршиво сжимается силами ФС, зато практически моментально обрабатывается серверами youtube (после многочасового ожидания выгрузки на эти самые сервера конечно).


    1. Eol78
      00.00.0000 00:00

      Я не так давно открыл для себя безпотерьный кодек utvideo. Сжатие гораздо лучше, чем HuffYUV, а скорость приблизительно такая же. ffmpeg в него умеет. А лучше всех из известных жмёт ffv1, правда он медленный, и как мне кажется, однопоточный


    1. Balling
      00.00.0000 00:00

      Математический lossless поддерживается в ffmpeg для AV1 (и даже AVIF), VP9, AVC, HEVC. Слышали про такие? Причем hevc и avc lossless даже с nvenc на Nvidia Turing.

      А еще есть MJPEG 2000 lossless. И даже JPEG lossless и JPEG-LS и даже JPEG XL.


  1. Conung_ViC
    00.00.0000 00:00
    +23

    Одна команда в консоли заменяет десять минут редактирования в Premiere Pro!

    Ага. и 2 суток курения мануалов, чтоб эту команду составить...


    Кстати, еще прекрасный мультимедиа комбайн/фреймворк - это GStreamer. Тоже позволяет творить мультимедиа магию в консоли, и может быть встроен в ваши приложения.


    1. LakesChueka
      00.00.0000 00:00
      +1

      Gstreamer ещё, кстати, используется в nvidia deepstream SDK. Т.е. при работе с jetson альтернатив, к сожалению, мало.


  1. emerald_isle
    00.00.0000 00:00

    Если не указаны дополнительные параметры, то всё кодируется с настройками по умолчанию для MP3.

    Не очень понял. А как вытащить аудиодорожку без перекодирования? Возможно ли это в принципе? Она же как-то уже закодирована, правильно? Во-первых, это по идее должно быть быстрее, а во-вторых, хочется без потери качества (а все эти кодирования туда-сюда по-любому могут что-то там портить).


    1. andreymal
      00.00.0000 00:00

      Да, -c:a copy — только вот в mpg-файлах будет скорее всего не mp3, а что-то другое, а значит или придётся заранее узнавать кодек и выбирать правильный контейнер для него, или всё-таки перекодировать


      1. Metotron0
        00.00.0000 00:00

        ffmpeg -i позволяет тут же на месте узнать кодек


        1. delvin-fil
          00.00.0000 00:00

          Вы хотели сказать ffprobe?!


          1. Metotron0
            00.00.0000 00:00

            Результат один и тот же. Разве что ffmpeg сетует, что нет выходного файла.


      1. ElvenSailor
        00.00.0000 00:00

        с хорошей вероятностью там будет AAC, и контейнер .m4a

        а вообще, сам же ffmpeg расскажет, что там и чем пожато.


        1. Balling
          00.00.0000 00:00

          И скорее всего m4a контейнер неправильный и это скорее всего mp4. Для m4a надо отдельно команду.


    1. Dr_Faksov
      00.00.0000 00:00

      Курите avidemux. Прекрасная программа-оболочка для ваших целей.


  1. saboteur_kiev
    00.00.0000 00:00
    +7

    Я обнаружил, что chatGPT заменяет все подобные статьи и документацию по ffmpeg. Примерно понимая что ffmpeg может, просто спрашиваешь у чатгпт как это сделать, получаешь готовую команду, и делаешь.


    1. 13werwolf13
      00.00.0000 00:00
      +3

      можно прям так


    1. Balling
      00.00.0000 00:00

      Да. Точно.


  1. Kaputmaher
    00.00.0000 00:00
    +1

    Еще для быстрого редактирования без перекодирования удобен Avidemux, только нужно удалять контент между ключевыми кадрами


    1. Dr_Faksov
      00.00.0000 00:00

      С перекодированием - тоже. С деинтерлейсингом, субтиррами, поворотами и прочими наворотами. Там возможностей - море.


  1. Javian
    00.00.0000 00:00

    мы оцифровали старую VHS-кассету в программе HandBrake

    Это как? HandBrake для перекодирования видеофайлов, а не для видеозахвата.


  1. An_private
    00.00.0000 00:00
    +3

    У меня не получилось закодировать в H.265 с настройками максимального качества и уменьшением разрешения в одной команде

    Эээээ. Что???

    А вообще - статья мне напомнила классический рисунок "как нарисовать сову".


  1. Loco2k
    00.00.0000 00:00
    +3

    Не могу не посоветовать открытый Avidemux для этих же целей.


  1. NNMTM
    00.00.0000 00:00
    +1

    Няшненько и ванильненько, самое главное не упоминать про интерлейс, правильные пропорции кадра и frame accuracy, что-бы не спугнуть маленьких "я-ж погромистов".


  1. beremour
    00.00.0000 00:00
    +4

    Одна команда в консоли заменяет десять минут редактирования в Premiere Pro!

    Эээ :) только всё наоборот: десять минут редактирования в Premiere Pro заменяет день курения мануалов для формирования "одной команды"


  1. Voenniy
    00.00.0000 00:00
    +1

    1. p0isk
      00.00.0000 00:00
      +2

      И h265 через hls тоже:

      ffmpeg -fflags nobuffer
      -rtsp_transport tcp -stimeout 1000000
      -i "rstp://ip/stream.265"
      -vsync 0 -copyts -vcodec copy
      -movflags frag_keyframe+empty_moov
      -c:a aac -method POST -f hls
      "https://a.upload.youtube.com/http_upload_hls?cid=YOUR_KEY&copy=0&file=index.m3u8"


      1. Balling
        00.00.0000 00:00

        И даже в HDR.


  1. peacemakerv
    00.00.0000 00:00

    А миллисекунды в имена файлов jpg-кадров до сих пор не умеет...


  1. p0isk
    00.00.0000 00:00

    Эффекты это, конечно, хорошо, но ещё поддержку HEIF/HEIC


  1. Flux
    00.00.0000 00:00
    +1

    Видео-версия статьи за 6 минут:



  1. Germanjon
    00.00.0000 00:00

    Фразы вида "Программа - швейцарский нож в такой-то области..." уже изрядно надоели, как будто нельзя найти другую аналогию или мем.


    1. Balling
      00.00.0000 00:00

      Это самая главная библиотека в мире после GMP/GCC/Clang. А это компилятор.


      1. Germanjon
        00.00.0000 00:00

        Не спорю, но фраза "швейцарский нож" на Хабре и в статьях к опенсорсным программам уже приелась. Возможно только мне.


      1. fshp
        00.00.0000 00:00

        glibc: "Ну да, ну да. Пошла я нахер".


        1. Balling
          00.00.0000 00:00

          Ну да, есть же Microsoft libm (или в код windows нужно смотреть) https://github.com/amd/win-libm/blob/master/pow.asm#L108

          libc++ в llvm есть тоже.

          Musl, uClibc.

          https://en.wikipedia.org/wiki/Bionic_(software)

          А вот у GMP там только GNU MPRF и ARB. И то спорно.


          1. fshp
            00.00.0000 00:00

            Пересекаемся в разных постах))

            glibc не имеет отношения непосредственно к c++. А Musl и uClibc не на столько популярны.


            1. Balling
              00.00.0000 00:00

              Альтернативы есть. У ffmpeg нет, даже близко. Gstreamer уступает в 10 раз, да и не имеет hdr zscale например. Что там ещё? Avisynth+? Смешно.

              Да и в любом случае GMP бесконечная арифметика самая важная библиотека, без неё gcc это тыква.


  1. yakimchuk-ry
    00.00.0000 00:00
    +4

    Закину кирпич, пока не знаю в чей огород.

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

    Вобщем, швейцарский нож да, инструмент огонь, но пытаясь собрать в одно целое видео разных форматов это как та картинка про CSS из грифинов. Постоянные артефакты, ограничения, дропы кадров, искажения, и прочее, и прочее, целое море всевозможных косяков с кодированием вылезло. Может быть готовить не умею.

    Я к тому, что круто оно круто, но как и любой инструмент который пытается собрать воедино всё и сразу, это не просто взять и использовать, это всё-равно море работы по исследованию совместимостей, отладке, и прочему.

    Но ffmpeg огонь в любом случае. Титаническая работа сделана.


    1. An_private
      00.00.0000 00:00

      Вот что он не любит - это собирать несколько клипов в один. Совершенно не его задача.

      А вот чего мне у него действительно не хватает - некоего внутреннего скриптового языка, чтобы можно было внутри него формировать командную строку в зависимости от формата входного файла. Поэтому у меня большинство задач решается либо через bat'ник - запустил ffmpeg, получил параметры входного файла, распарсил выход, сформировал командную строку, запустил ffmpeg на обработку. Либо через самописные программы, делающие примерно то же самое, но когда нужно что-то более наворочанное.

      Ну и, конечно, его библиотеки просто великолепны.


      1. qw1
        00.00.0000 00:00
        +2

        Вот что он не любит — это собирать несколько клипов в один. Совершенно не его задача.
        Я собирал. Нужно сконвертировать файлы в формат TransportStream (ts), т.е. поток без глобального заголовка, где заголовок есть у каждого фрейма, затем файлы бинарно склеить (copy /b), затем обратно из ts в mp4. Всё это можно делать без перекодирования (-c:a copy -c:v copy).


        1. An_private
          00.00.0000 00:00

          Да не, можно, конечно. Но далеко не всякий формат поддерживает ts. А уже тем более это не работает в случае " пытаясь собрать в одно целое видео разных форматов", как в исходном комментарии.

          Тут уже либо надо конвертить сперва в промежуточный формат и потом уже собирать всё это в кучу. Либо пытаться как-то извратиться через фрейм-сервера. Но этим лично я не занимался, поэтому не могу ничего конкретного сказать.


          1. qw1
            00.00.0000 00:00

            В исходном комментарии

            задача видео разных форматов приводить к одному формату
            То есть, вместо -c:v copy надо -c:v libx264 если кодек отличается.
            Тут уже либо надо конвертить сперва в промежуточный формат и потом уже собирать всё это в кучу
            Вы смешиваете в одну кучу контейнер и кодек. «Промежуточный формат» как контейнер — ничего страшного, это быстрое копирование потока. «Промежуточный формат» как кодек — не нужен, т.к. конвертить надо не в промежуточный, а сразу в окончательный h.264.

            Но в целом, замечание справедливое. Если надо смонтировать совсем разные клипы последовательно в один файл, в командной строке это целый квест, когда в GUI-редакторах это банальное мышекликание.


            1. Ulibka
              00.00.0000 00:00

              Дайте пожалуйста пример команд чтобы склеить два ролика разных форматов (для человека который ffmpeg никогда не пользовался ) :)


              1. qw1
                00.00.0000 00:00
                +1

                ffmpeg -i clip1.avi clip1.ts
                ffmpeg -i clip2.avi clip2.ts
                copy /b clip1.ts + clip2.ts clip_result.ts
                ffmpeg -i clip_result.ts -c:v copy -c:a copy clip_result.mp4

                в первых двух командах не указываю -c:v copy -c:a copy на случай, если аудио/видео в разных кодеках


                1. Balling
                  00.00.0000 00:00

                  Ваша 3 команда это плохая идея. Объединять так нельзя. Есть спец. фильтры в ffmpeg


              1. Metotron0
                00.00.0000 00:00
                +1

                А я сперва жму в одинаковые форматы с одинаковым размером кадра, а потом делаю mkvmerge -o file.mkv file1 + file2 + fileN


      1. fshp
        00.00.0000 00:00

        Отдельный скриптовый язык не нужен, когда есть биндинги для питона.


        1. andreymal
          00.00.0000 00:00
          +3

          А они есть? Всё, что я вижу в своём гугле, это просто обёртки над командной строкой, толку от которых почти нет


          1. fshp
            00.00.0000 00:00

            https://github.com/kkroening/ffmpeg-python

            Толк от них в том, что бы не парсить вывод ffmpeg в первую очередь. А например удобно получить разрешение видео через api, список стримов и т.п.

            Скажем вам нужно все что больше fullhd уменьшить вполовину, а все что меньше уменьшить на 80%. На cmd или баше это будет боль.


            1. andreymal
              00.00.0000 00:00
              +2

              Это не биндинги, а распарсить ffprobe -print_format json тривиально и без таких библиотек, поэтому я их не использую


              Ещё есть проблема, что это подразумевает два отдельных запуска (сперва ffprobe, потом ffmpeg), а между запусками свойства стримов имеют шанс внезапно поменяться — это было для меня проблемой, когда я пытался работать с RTSP-потоками IP-камер


              1. fshp
                00.00.0000 00:00

                Ну если нужны именно биндинги к либам, то https://pyav.org

                Тут конечно личные предпочтения. Но если мне нужно написать пару циклов с несколькими условиями, то я ни при каких обстоятельствах не выберу баш.


    1. Balling
      00.00.0000 00:00

      Так и есть. Это считается библиотека, а значит очень все хитро. Т.е. предполагается, что ты сам пишешь код, а не пользуешься ffmpeg/ffprobe и уж тем более ffplay.

      >Постоянные артефакты, ограничения, дропы кадров, искажения, и прочее, и прочее, целое море всевозможных косяков с кодированием вылезло. Может быть готовить не умею.

      Обычно с ffplay/mpv нет проблем. VLC это баг на баге.


  1. Borjomy
    00.00.0000 00:00
    -5

    Графическая оболочка для работы с графическим же контентом, предпросмотром, и визуальным выбором режимов, когда будет?

    В IrfanView же сделали. Один человек, между прочим, работал.


    1. Moskus
      00.00.0000 00:00
      +1

      IrfanView - никакая не "оболочка", а полноценная программа с GUI. (Наличие у нее интерфейса командной строки не делает ее консольной программой.)


  1. ElvenSailor
    00.00.0000 00:00

    Мужики, а можно дать примеры команд для hardware-accelerated encoding ? С масштабированием , к примеру, с 3840x2160 до fullhd , желательно тоже аппаратным ?


    1. qw1
      00.00.0000 00:00
      +2

      В официальной документации есть страница trac.ffmpeg.org/wiki/HWAccelIntro

      При запуске без параметров видно, с какими опциями скомпилен ваш ffmpeg.exe (например, --enable-nvenc).

      В ком. строку добавляется

      -c:v h264_nvenc
      или
      -c:v h264_cuvid
      для NVidia

      или для AMD
      Windows: -c:v h264_amf / hevc_amf
      Linux: h264_vaapi / hevc_vaapi


      1. Balling
        00.00.0000 00:00

        cuvid может быть как декодер (до -i), так и енкодер. А вот nvenc все сложнее. Это только енкодер. Для декодера используется программный h264, но можно добавить ускорение (-hwaccel cuda, имеено cuda, не nvdec, или другие). h264 при этом все равно активно используется.


  1. AmiGO1
    00.00.0000 00:00
    +1

    Кто вдруг не знает, хочу посоветовать конвертер с аппаратным ускорение HEVC(h265) кодека на картах nvidia - nvenc. После попыток обработки большого количества домашнего видео 2.7k в 265 кодек с помощью ffmpeg случайно пришёл к нему. Скорость обработки кратно быстрее длительности ролика( условно, ролик в 1 минуту обрабатывается за 20-25 секунд ) на карте 1060. Если говорит о более низких разрешениях-там вообще полёт. С телефона не удобно, позже дополню ссылкой.


    1. AmiGO1
      00.00.0000 00:00
      +1

      1. Balling
        00.00.0000 00:00

        Да, хороший пакет тоже. Но ffmpeg поглощает его потихоньку. Осталось полная HDR манипуляция.


    1. Metotron0
      00.00.0000 00:00

      https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new
      Вот тут указано, кто во что умеет сжимать. 1030 ни во что не умеет, если что. Потому что GT, а нужно GTX. Я разок так прокололся на покупке.


      1. p0isk
        00.00.0000 00:00

        Драйвера 1030 не раскапывали? Или в ней физически блоков кодирования нет


        1. Metotron0
          00.00.0000 00:00

          Как я понял, она железно не умеет.


  1. SneakyJoe
    00.00.0000 00:00

    Мне вот было интересно возможно ли как-то спарить ffmpeg и smooth video project чтобы конвертировать 30 фпс стримы в 60 фпс через командную строку. Я в своё время игрался, не нашёл. Мб кто знает?


    1. Balling
      00.00.0000 00:00

      Это бесполезно. Без LG C9 и новее аппаратной упловнялки артефактов будет слишком много.


      1. SneakyJoe
        00.00.0000 00:00

        Напоминает ответы на форумах когда попытка разобраться зачем человеку что-то надо заменяет простой ответ в стиле "вот, сделай так, но разочаруешься"
        Я транскодил стримы которые я смотрел с 30 фпс и мне было норм, артефактов было не так уж и много - тем более сильно зависит от стилистики контента. Хотелось бы и на отдачу это как-то запихнуть.


  1. alexkuzko
    00.00.0000 00:00

    Давненько не было тут такого...

    Подскажите кто что использует чтобы звук корректно растянуть из 23.976 в 25 кадров? Использовал раньше atempo, но на некоторых исходниках он заметно портит звук. Недавно попробовал rubberband, с ним пришлось долго параметры подбирать чтобы убрать одну проблему, правда в целом звук становится выше и несколько хуже...

    Есть ли что-то проф.уровня именно в ffmpeg?


    1. qw1
      00.00.0000 00:00

      Даже не подозревал, что есть такая проблема.
      Ведь звуковая дорожка идёт со своими параметрами (AAC, 192Kbps, 44.1KHz, 16-bit, stereo, например) и формально никак не связана с частотой кадров видео.


    1. Balling
      00.00.0000 00:00
      +1

      Для начала поймите 23.976 это на самом деле 24/1.001 и да это играет огромное значение.

      Вот есть такое. https://toolstud.io/video/framerate.php?inputfps=23.976&compare=network&duration=60&duration_unit=seconds&outputfps=25


      1. alexkuzko
        00.00.0000 00:00

        Это вы хорошо заметили... вот только я про это очень хорошо в курсе.

        И если я меняю частоту видео, то я использую setpts + atempo, причем мои значения отличаются от тех, что по вашей ссылке (проверял что чуть лучше результат именно из-за того что нет ошибки округления т.к. 23.976 != 24/1001).

        Как они хотят:
        ffmpeg -i [input] -r 25 -filter:v "setpts=0.959*PTS" -y [output]
        Как я пишу:
        ffmpeg -i [input] -r 25 -filter:v"setpts=0.959040959*PTS" -y [output]

        Почему?
        24000/1001 = 23.976023976/25 = 0.959040959 и 25/23.976023976 = 1.042708333

        Аналогично и по звуку

        Предлагается:
        ffmpeg -i [input] -filter:a "atempo=1.0427" -vn [output]
        Я же делаю иначе:
        ffmpeg -i [input] -filter:a "atempo=1.042708333" -vn [output]

        Но сути это не меняет, звук-то портится. Поэтому и ищу вариант получше.

        Пробовал (после тестов на слух) вариант с rubberband, искажения стали другими:
        rubberband=tempo=1.042708333:pitch=1.042708333:pitchq=quality:smoothing=on:channels=apart:phase=independent:detector=percussive:transients=crisp

        Вариант с тупым -r 25 не катит, т.к. видео заметно дергается...

        Т.е. я не совсем не в теме, хотя это не мой профиль. И если у вас есть иные советы - напишите, думаю что не только мне будет полезно. Спасибо!


  1. NasretdinovRR
    00.00.0000 00:00

    Считаю также важным отразить в примерах, что в зависимости от задачи стоит применять различные пресеты. Видеофайл, сжатый в H.264 с пресетом slower, будет примерно в 10 раз легче при таком же качестве, чем сжатый с пресетом ultrafast, но при этом процесс сжатия может быть до 10 раз медленнее. Также для новичков будет полезно знать, что пресеты veryslow и placebo в большинстве случаев не рекомендуются: экономия битрейта (в сравнении со slower) от них незначительная, обработка крайне медленная, могут быть проблемы при воспроизведении в некоторых плеерах.