Вводное руководство по FFmpeg libav
Я искал учебник/книгу, которая показала бы, как начать использовать FFmpeg в качестве библиотеки (также известной как libav), и нашел руководство «How to Write a Video Player in Less Than 1000 Lines» (как написать видеоплеер менее чем за 1000 строк). К сожалению, оно устарело, поэтому я решил написать своё.
Большая часть кода здесь будет на C, но не беспокойтесь: вы можете легко его понять и применить к предпочитаемому вами языку. FFmpeg libav имеет множество привязок для многих языков, таких как python, go, и даже если для вашего языка ее нет, вы все равно можете поддерживать ее через ffi
(вот пример с Lua).
Мы начнем с краткого урока о том, что такое видео, аудио, кодек и контейнер, затем перейдем к ускоренному курсу о том, как использовать командную строку FFmpeg, и, наконец, мы напишем код, не стесняйтесь сразу перейти к разделу «Сложный способ изучения FFmpeg libav».
Некоторые люди говорили, что потоковое видео в Интернете – это будущее традиционного телевидения, в любом случае FFmpeg – это то, что стоит изучить.
Содержание
Введение
Видео – это то, что вы видите!
Если у вас есть последовательность изображений, и вы меняете их с заданной частотой (скажем, 24 изображения в секунду), вы создадите иллюзию движения. Таким образом, это самая основная идея видео: последовательность изображений/кадров, воспроизводимых с заданной скоростью.
Аудио – это то, что вы слышите!
Хотя видео с отключенным звуком может выражать самые разные чувства, добавление звука привносит больше ощущений.
Звук – это вибрация, которая распространяется в виде волны давления в воздухе или любой другой передающей среде, такой как газ, жидкость или твердое тело.
В цифровой аудиосистеме микрофон преобразует звук в аналоговый электрический сигнал, затем аналого-цифровой преобразователь (АЦП) – обычно с использованием импульсно-кодовой модуляции (ИКМ) – преобразует аналоговый сигнал в цифровой сигнал.
Кодек – сжатие данных
Кодек – это электронная схема или программное обеспечение, которое сжимает или распаковывает цифровые аудио/видео данные. Он преобразует необработанное (несжатое) цифровое аудио/видео в сжатый формат или наоборот.
Но если мы решим упаковать миллионы изображений в один файл и назовем его фильмом, у нас может получиться огромный файл. Давайте посчитаем:
Предположим, мы создаем видео с разрешением 1080 x 1920 (высота x ширина) и, что мы тратим 3 байта на пиксель (самая маленькая точка на экране) для кодирования цвета (т.е. 24 бита для цвета, что дает нам 16 777 216 разных цветов), и это видео воспроизводится со скоростью 24 кадра в секунду и длится 30 минут.
toppf = 1080 * 1920 //total_of_pixels_per_frame (общее количество пикселей в кадре)
cpp = 3 //cost_per_pixel (стоимость одного пикселя)
tis = 30 * 60 //time_in_seconds (время в секундах)
fps = 24 //frames_per_second (кадров в секунду)
// необходимый размер хранилища
required_storage = tis * fps * toppf * cpp
Для этого видео потребуется примерно 250,28 ГБ памяти или пропускная способность 1,11 Гбит/с! Вот почему нам нужно использовать кодек.
Контейнер – удобное место для хранения аудио и видео
Формат контейнера или оболочки – это формат метафайла, спецификация которого описывает, как различные элементы данных и метаданных сосуществуют в компьютерном файле.
Это один файл, который содержит все потоки (в основном аудио и видео), а также обеспечивает синхронизацию и общие метаданные, такие как заголовок, разрешение и т.д.
Обычно мы можем определить формат файла, взглянув на его расширение: например, video.webm – это, вероятно, видео, использующее контейнер webm.
Командная строка FFmpeg
Полное кроссплатформенное решение для записи, преобразования и потоковой передачи аудио и видео.
Для работы с мультимедиа мы можем использовать УДИВИТЕЛЬНЫЙ инструмент/библиотеку под названием FFmpeg. Скорее всего, вы уже знаете/используете его прямо или косвенно (вы используете Chrome?).
У него есть программа командной строки под названием ffmpeg
, очень простой, но мощный бинарный файл. Например, вы можете преобразовать mp4 в контейнер avi, просто введя следующую команду:
$ ffmpeg -i input.mp4 output.avi
Мы только что выполнили ремультиплексирование, то есть преобразование из одного контейнера в другой. Технически FFmpeg также может выполнять перекодирование, но мы поговорим об этом позже.
Основы инструмента командной строки FFmpeg
У FFmpeg есть документация, которая отлично объясняет, как он работает.
Короче говоря, программа командной строки FFmpeg для выполнения своих действий ожидает аргументы в следующем формате
ffmpeg {1} {2} -i {3} {4} {5}
где
- глобальные параметры;
- параметры входного файла;
- входной URL;
- параметры выходного файла;
- выходной URL.
Частей 2, 3, 4 и 5 может быть столько, сколько вам нужно. Этот формат аргументов легче понять на примере:
# ВНИМАНИЕ: этот файл весит примерно 300 Мб
$ wget -O bunny_1080p_60fps.mp4 http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_60fps_normal.mp4
$ ffmpeg \
-y \ # глобальные параметры
-c:a libfdk_aac -c:v libx264 \ # входные параметры
-i bunny_1080p_60fps.mp4 \ # входной url
-c:v libvpx-vp9 -c:a libvorbis \ # выходные параметры
bunny_1080p_60fps_vp9.webm # выходной url
Эта команда берет входной файл mp4, содержащий два потока (аудио, закодированное с помощью кодека aac, и видео, закодированное с помощью кодека h264), и преобразует его в webm, также изменяя его аудио- и видеокодеки.
Мы могли бы упростить приведенную выше команду, но имейте в виду, что FFmpeg примет или угадает значения по умолчанию. Например, когда вы просто набираете ffmpeg -i input.avi output.mp4
, какой аудио/видео кодек используется для создания output.mp4?
Werner Robitza написал обязательное к прочтению руководство по кодированию и редактированию с помощью FFmpeg.
Основные операции с видео
При работе с аудио/видео мы обычно выполняем набор задач по обработке медиаконтента.
Перекодирование
Что это? Действие по преобразованию одного из потоков (аудио или видео) из одного кодека в другой.
Зачем? Иногда некоторые устройства (телевизоры, смартфоны, консоли и т.д.) не поддерживают кодек X, но поддерживают кодек Y; кроме того, более новые кодеки обеспечивают лучшую степень сжатия.
Как? Например, преобразование видео H264 (AVC) в H265 (HEVC).
$ ffmpeg \
-i bunny_1080p_60fps.mp4 \
-c:v libx265 \
bunny_1080p_60fps_h265.mp4
Ремультиплексирование
Что это? Преобразование из одного формата (контейнера) в другой.
Зачем? Иногда некоторые устройства (телевизоры, смартфоны, консоли и т. д.) не поддерживают формат X, но поддерживают формат Y, а иногда более новые контейнеры предоставляют современные необходимые функции.
Как? Например, преобразование mp4 в ts.
$ ffmpeg \
-i bunny_1080p_60fps.mp4 \
-c copy \ # просто говорим ffmpeg пропустить кодирование
bunny_1080p_60fps.ts
Изменение скорости
Что это? Изменение скорости передачи данных или создание других представлений.
Зачем? Люди будут пытаться смотреть ваше видео через 2G (edge) соединение с помощью не очень мощного смартфона или через оптоволоконное интернет-соединение на своих 4K-телевизорах, поэтому вам следует предлагать более одного представления одного и того же видео с разным битрейтом.
Как? Например, создание воспроизведения с битрейтом от 964K до 3856K.
$ ffmpeg \
-i bunny_1080p_60fps.mp4 \
-minrate 964K -maxrate 3856K -bufsize 2000K \
bunny_1080p_60fps_transrating_964_3856.mp4
Обычно мы будем использовать изменение скорости одновременно с изменением разрешения. Вернер Робица (Werner Robitza) написал еще одну серию обязательных к прочтению статей об управлении скоростью с помощью FFmpeg.
Изменение разрешения
Что это? Преобразование от одного разрешения к другому. Как было сказано ранее, изменение разрешения часто используется с изменением скорости.
Зачем? Причины примерно те же, что и для изменения скорости.
Как? Например, изменение разрешения 1080p на разрешение 480p.
$ ffmpeg \
-i bunny_1080p_60fps.mp4 \
-vf scale=480:-1 \
bunny_1080p_60fps_transsizing_480.mp4
Бонус: адаптивная потоковая передача
Что это? Создание множества разрешений (битрейтов) и разделение медиаконтента на куски и их выдача через http.
Зачем? Для обеспечения гибкого медиаконтента, который можно смотреть на бюджетном смартфоне или на телевизоре 4K, его также легко масштабировать и развертывать, но это может увеличить задержку.
Как? Например, создание адаптивного WebM с использованием DASH.
# видеопотоки
$ ffmpeg -i bunny_1080p_60fps.mp4 -c:v libvpx-vp9 -s 160x90 -b:v 250k -keyint_min 150 -g 150 -an -f webm -dash 1 video_160x90_250k.webm
$ ffmpeg -i bunny_1080p_60fps.mp4 -c:v libvpx-vp9 -s 320x180 -b:v 500k -keyint_min 150 -g 150 -an -f webm -dash 1 video_320x180_500k.webm
$ ffmpeg -i bunny_1080p_60fps.mp4 -c:v libvpx-vp9 -s 640x360 -b:v 750k -keyint_min 150 -g 150 -an -f webm -dash 1 video_640x360_750k.webm
$ ffmpeg -i bunny_1080p_60fps.mp4 -c:v libvpx-vp9 -s 640x360 -b:v 1000k -keyint_min 150 -g 150 -an -f webm -dash 1 video_640x360_1000k.webm
$ ffmpeg -i bunny_1080p_60fps.mp4 -c:v libvpx-vp9 -s 1280x720 -b:v 1500k -keyint_min 150 -g 150 -an -f webm -dash 1 video_1280x720_1500k.webm
# аудиопотоки
$ ffmpeg -i bunny_1080p_60fps.mp4 -c:a libvorbis -b:a 128k -vn -f webm -dash 1 audio_128k.webm
# манифест DASH
$ ffmpeg \
-f webm_dash_manifest -i video_160x90_250k.webm \
-f webm_dash_manifest -i video_320x180_500k.webm \
-f webm_dash_manifest -i video_640x360_750k.webm \
-f webm_dash_manifest -i video_640x360_1000k.webm \
-f webm_dash_manifest -i video_1280x720_500k.webm \
-f webm_dash_manifest -i audio_128k.webm \
-c copy -map 0 -map 1 -map 2 -map 3 -map 4 -map 5 \
-f webm_dash_manifest \
-adaptation_sets "id=0,streams=0,1,2,3,4 id=1,streams=5" \
manifest.mpd
PS: этот пример я украл из Инструкции по воспроизведению адаптивного WebM с помощью DASH.
Это еще не всё
Есть много других способов использования FFmpeg. Я использую его вместе с iMovie для создания/редактирования видео для YouTube, и вы, безусловно, можете использовать его профессионально.