Виртуальная машина для кодирования видео. Компиляция FFmpeg во FreeBSD с поддержкой libfdk_aac и libvvenc
Ранее я рассказал о компиляции FFmpeg для Linux и Windows. Однако для длительных задач кодирования, будучи в некотором роде сторонником и популяризатором FreeBSD, я решил завести себе виртуальную машину под управлением именно этой операционной системы. Как ни странно, в ней штатный комбайн не содержит не только fdk-aac, что логично по лицензионным соображениям, но и VVenC. К тому же x265 был старым, а возможно и сейчас есть. Так что только компиляция, только хардкор.
Виртуальная машина
Зачем вообще она потребовалась? В зависимости от длительности исходного видео и настроек кодирования, процесс запросто может длиться несколько суток. Если есть возможность держать компьютер включенным 24/7 – отлично, но в дело вступает еще и фактор электричества. Уверяю вас, на 96 процентах оно обязательно вырубится и придется начинать все с начала. Либо крайне нетривиальным образом пытаться синхронизировать куски, но лично у меня не получилось в подобной ситуации.
Виртуалку же мы можем в любое время буквально поставить на паузу и сохранить состояние, выключить компьютер и возобновить работу когда это будет удобно. Если же еще и снимки регулярно делать, то при неблагоприятной ситуации мы потеряем лишь несколько часов работы, а не весь прогресс целиком!
Особенности настройки
Эти самые особенности в немалой степени заключаются в выделении непривычно больших ресурсов по сравнению с виртуальными машинами для веб-программирования и т.п. В частности, я выделил 8 «процессоров» из имеющихся в распоряжении 12. Мой AMD Ryzen 5 2600 вообще-то 6-ядерный, но 12-поточный, отсюда такое количество процессоров с точки зрения операционной системы хоста (у меня Windows 10). На самом деле выделять больше виртуальных процессоров, чем реальных (т.е. ядер в данном случае) VirtualBox не рекомендует, но на шести, как мне кажется, вообще никуда не уедешь. К тому же VVenC базово распараллеливается как раз на 8 потоков, так что предупреждение было проигнорировано.
Оперативки поставил 8 гигабайт (по гигабайту на процессор), хотя ffmpeg вроде до нее не столь жаден, как можно было бы ожидать. Под виртуальный носитель я зарезервировал аж 120 гигов, чтобы никому мало не показалось. Я не стал сразу выделять все место, хотя может быть и стоило.
После создания я немного меняю настройки виртуальной машины. В разделе «Система» ставлю чипсет ICH9, часы UTC, графику VBoxSVGA, PAE/NX и скорее машинально Nested-VT-x/AMD-V, хотя в данном случае вложенная виртуализация как будто не нужна.
Подключаю два сетевых адаптера – NAT (по умолчанию) и виртуальный сети хоста.
Первый нужен для доступа «изнутри» в интернет, а второй – с хоста на виртуальную машину (главным образом по SSH). Звук не нужен, как и USB-контроллер.
Установка FreeBSD
Похоже я ни в одной из статей так и не описал сам процесс установки FreeBSD на виртуальную машину, но на первый взгляд он прост. Нужно лишь отправить SMS на короткий номер скачать установочный образ для соответствующей архитектуры (скорее всего это будет bootonly для amd64), виртуально загрузиться с него и, что называется, следовать инструкциям мастера установки (на примере актуальной нынче 15.1):
- Собственно запустить мастер – Install;
- Клавиатура – Continue with default keymap (по умолчанию);
- Имя хоста – по желанию;
- Тип установки – а здесь внимание, я предлагаю выбрать «новый» Packages (tech preview), чтобы в дальнейшем обновлять менеджером пакетов не только ПО, но и саму операционную систему;
- В образе bootonly на этом этапе предупреждают о необходимости настройки сети;
- Сетевой адаптер
em0– Auto; - Файловая система – Auto (UFS). Считаю, для целей кодирования видео она подходит куда лучше ZFS;
- Задействовать весь диск (Entire Disk);
- Схему разделов наверное уже лучше выбрать GPT;
- Подтвердить предложенное разбиение на разделы (Finish);
- Еще раз подтвердить очистку всего диска (Commit);
- Системные компоненты – оставить только base;
- Задать пароль администратора;
- Выбрать часовой пояс и подтвердить его;
- Пропустить (Skip) установку даты и времени (скорее всего там будет все в порядке);
- Сервисы – sshd обязателен (отмечен по умолчанию), а остальные вроде бы и не нужны;
- Защита системы (System Hardening) – можно ничего не активировать, но я обычно включаю произвольные идентификаторы процессов (random_pid), очистку временной файловой системы при загрузке (clear_tmp) и отключаю некий сетевой сокет Syslogd (disable_syslogd);
- Добавлять пользователей мы скорее всего не хотим (No), хотя по всем правилам конечно надо бы создать непривилегированного пользователя и работать в основном под ним;
- Зато хотим завершить установку (Finish), впрочем на этом этапе можно изменить большинство ранее принятых решений;
- Не хотим вносить изменения вручную (No);
- Установка завершена – перезагружаемся (Reboot).
В соответствующий момент лучше нажать F12, изъять диск из виртуального привода и принудительно загрузиться с жесткого диска (1).
Интересное начинается уже после установки. Нужно включить второй сетевой адаптер, например:
sysrc ifconfig_em1="DHCP"
reboot
Для компиляции x264 в явном виде понадобится bash, поэтому установим его не только в систему, но и выберем в качестве оболочки:
pkg install bash mc
chsh -s /usr/local/bin/bash
exit
«Под шумок» я заодно и Midnight Commander устанавливаю. Наконец, нужно разрешить root'у вход по SSH. В файле /etc/ssh/sshd_config пишем:
PermitRootLogin yes
И перезагружаем сервис:
service sshd restart
Получить IP-адрес можно командой ifconfig, либо успеть увидеть при загрузке ОС.
Общие папки
Гонять файлы туда-сюда можно по SSH, который SFTP. Лично я пользуюсь для этого FileZilla. Однако получилось так, что я разместил машину на самом неподходящем для этого внешнем SSD, который у меня внезапно образовался из очень китайских комплектующих.
«Фрешка» при этом SATA-шная и при записи крайне медлительная, а для кодирования видео вообще-то нужно заливать большие объемы. CDM еще что-то там рисует, а на самом деле скорость в районе 12 MB/s.
Н-да, немного отвлеклись, но в общем SFTP показывал себя как-то не очень хорошо. В надежде на улучшение я даже установил PureFTPd, как в свое время на VPS. Поддержка докачки, конечно, дело хорошее, но в целом тоже не понравилось. Тогда я решил попробовать общую папку, и вот она-то показала себя хорошо. С точки зрения хоста эти самые папки настраиваются в VirtualBox:
В гостевой же операционной системе требуется установить соответствующие расширения и добавить их в «автозапуск» (в случае чего, об этом и о типе видео напоминают при установке пакета):
pkg install virtualbox-ose-additions-nox11-72
service vboxguest enable
service vboxservice enable
При этом указанная в настройках точка монтирования игнорируется (поэтому я ее и не написал), как и флаг авто-подключения. Вместо этого требуется добавить запись в /etc/fstab:
bsdffshare /mnt/bsdffshare vboxvfs rw,late 0 0
Создать директорию (mkdir /mnt/bsdffshare) и перезагрузить машину, чтобы все заработало.
Казалось бы, можно конвертировать прямо в общем каталоге, но нет. Даже простое сохранение состояния и возобновление работы ведет к проблемам с файловыми дескрипторами и прерыванию процесса. Поэтому использовать общую директорию можно только для обмена файлами, а вся работа должна идти внутри виртуальной машины.
Компиляция FFmpeg
Точнее наверное с маленькой буквы – ffmpeg, так как на ffprobe и тем более ffplay я вновь бессовестным образом забил. Аналогично поступил с непривилегированным пользователем и работаю прямо под root.
Преимуществом Dockerfile является то, что директивы RUN суть shell-скрипты, так что по большому счету можно взять наработки по кросс-компиляции и адаптировать их под FreeBSD. Разве что вместо статической сборки на сей раз я предлагаю сделать «динамическую» (т.е. с использованием разделяемых библиотек), поскольку никуда дальше виртуальной машины результат не уйдет.
Также я решил еще дальше продвинуться по пути минимизации и убрать почти вообще все: dav1d, VMAF и Libbluray пошли под нож. Будем надеяться, декодировать AV1 не потребуется. Кстати zlib может подтягиваться через зависимости от условного mc или еще кого-то, но в общем случае даже поддержки PNG может не быть. Честно говоря, SVT-AV1 первоначально тоже не было, но так как я все еще готовлю большую статью про кодеки, к сожалению пришлось ее подключить. Почему к сожалению? Узнаете из исследования.
Таким образом, в состав нашего персонального ffmpeg войдут:
В предыдущий раз x264 и x265 собирались «полностью», а для FreeBSD я решил оставить только необходимые «цвета». Особенно не хотелось работать с тремя x265. Помня о проблемах с Opus, решил «тупо» установить его из пакетов; нашелся также и zimg. В результате компилировать будем только библиотеки для кодирования видео, fdk-aac и сам ffmpeg.
Подготовка
Начинаем формировать скрипт:
#!/bin/sh
set -ex
pkg upgrade -y
pkg install -y \
bash \
git \
devel/cmake \
devel/gmake \
devel/nasm \
devel/pkgconf \
opus \
sekrit-twc-zimg
cpu_count=$(nproc)
. $PWD/.env
[ -d /usr/src ] || mkdir /usr/src
cd /usr/src
set -ex устанавливает вывод команд на экран и остановку работы скрипта при ошибке.
Я решил принудительно обновлять все пакеты перед началом работы, однако вопрос немного спорный: удобно, но в общем случае небезопасно. Далее гарантируем установку нужным нам средств сборки и библиотек. В отличие от Linux, этих самых средств немного: CMake, GNU make (gmake) для пущей важности (хотя BSD-шный вроде тоже работал), ассемблер NASM, да и pkgconf. Компилятор C/C++ входит в состав операционной системы, поэтому дополнительно устанавливать его не надо. В определенной степени от dav1d я отказался из-за парочки meson с ninja, не хотел тащить во FreeBSD еще и их.
Запоминаем количество процессоров и считываем файл .env с версиями библиотек. Он выглядит так же, как и для кросс-компиляции, за вычетом ненужного:
FFMPEG_VERSION=9.0.2
X264_VERSION=stable
X265_VERSION=4.3
SVTAV1_VERSION=v4.2.0
VVENC_VERSION=release
FDK_AAC_VERSION=v2.0.3
Наконец, убедившись, что каталог /usr/src существует, переходим в него. Компилировать будем там.
x264
По сравнению с кросс-компиляцией пришлось явно указать компилятор C (видимо предполагался gcc). Также, как выяснилось, скрипт конфигурирования оказался строго bash'евским, поэтому вызываем его в явном виде. Еще вместо компиляции статической библиотеки включаем сборку разделяемой (shared), а также меняем make на gmake (в дальнейшем я не буду заострять на этом внимание). Как и обещал, поставил ограничение на 8-битные форматы пикселей, так как 10-битный AVC не нужен. 
# libx264
git clone --depth 1 --branch $X264_VERSION https://code.videolan.org/videolan/x264.git
cd x264
CC=cc bash configure \
--disable-cli \
--enable-shared \
--enable-strip \
--bit-depth=8 \
--disable-lavf \
--disable-swscale
gmake -j${cpu_count}
gmake install
cd /usr/src
rm -rf x264
x265
Благодаря CMake отличий от кросс-компиляции по сути нет (разве что убрал настройки этой самой кросс-компиляции).
# libx265 10bit
git clone --depth 1 --branch $X265_VERSION https://github.com/Multicorewareinc/x265.git
# patch build info
sed -i '' 's/Unk-OS/FreeBSD/' x265/source/common/version.cpp
mkdir x265/build/freebsd
cd x265/build/freebsd
cmake ../../source -Wno-dev \
-DCMAKE_BUILD_TYPE=Release \
-DENABLE_SHARED=ON \
-DENABLE_CLI=OFF \
-DENABLE_ALPHA=ON \
-DHIGH_BIT_DEPTH=ON \
-DENABLE_HDR10_PLUS=ON
gmake -j${cpu_count}
gmake install
cd /usr/src
rm -rf x265
Ах да, я тут немного пропатчил x265 под FreeBSD – подменил Unk-OS, иначе информация о версии была какой-то некрасивой. Что вообще-то странно: поддержка OpenBSD есть, а FreeBSD, видите ли, неизвестная операционная система.
Еще один из многочисленных приколов – зачем-то наряду с разделяемыми библиотеками компилируются еще и статические версии. Как от них избавиться, кроме как удалять постфактум (а надо ли?), я к своему стыду не разобрался. 
SVT-AV1
# libsvtav1
git clone --depth 1 --branch $SVTAV1_VERSION https://gitlab.com/AOMediaCodec/SVT-AV1.git
cd SVT-AV1/Build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_APPS=OFF \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TESTING=OFF
gmake -j${cpu_count}
gmake install
cd /usr/src
rm -rf SVT-AV1
VVenC
# libvvenc
git clone --depth 1 --branch $VVENC_VERSION https://github.com/fraunhoferhhi/vvenc.git
cd vvenc
cmake -S . -B build/release-shared \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/usr/local \
-DBUILD_SHARED_LIBS=ON \
-DVVENC_LIBRARY_ONLY=ON
cmake --build build/release-shared -j${cpu_count}
cmake --build build/release-shared --target install
cd /usr/src
rm -rf vvenc
fdk-aac
Если предыдущие два товарища компилировались совершенно стандартно, то здесь все же стоит сказать пару слов. К сожалению, autoreconf во FreeBSD не захотел работать. К счастью, автор предусмотрел вариант компиляции с помощью CMake (по умолчанию как раз в виде разделяемой библиотеки), чем мы и воспользуемся.
git clone --depth 1 --branch $FDK_AAC_VERSION https://github.com/mstorsjo/fdk-aac.git
mkdir fdk-aac/build
cd fdk-aac/build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . -j${cpu_count}
cmake --build . --target install
cd /usr/src
rm -rf fdk-aac
FFmpeg
Напомню, что Opus и zimg были установлены пакетным менеджером, а остальные библиотеки, как я надеюсь, благополучно скомпилировались. Кстати про компиляцию, в данном случае пришлось явно указать PKG_CONFIG_PATH, иначе библиотеки не находились, а также, подобно x264, компиляторы C и C++. Для красоты прописал --extra-version=vvenc+fdk-aac, а остальные флаги по сути такие же, как и в прошлый раз с поправкой на состав сборки.
# FFmpeg
fetch -o ffmpeg.tar.bz2 https://ffmpeg.org/releases/ffmpeg-${FFMPEG_VERSION}.tar.bz2
tar xf ffmpeg.tar.bz2
rm ffmpeg.tar.bz2
cd ffmpeg*
PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure \
--cc=cc \
--cxx=c++ \
--extra-version=vvenc+fdk-aac \
--enable-gpl \
--enable-nonfree \
--disable-debug \
--disable-static \
--enable-shared \
--disable-ffplay \
--disable-ffprobe \
--disable-network \
--enable-libfdk-aac \
--enable-libopus \
--enable-libsvtav1 \
--enable-libvvenc \
--enable-libx264 \
--enable-libx265 \
--enable-libzimg \
|| tail -n 30 ffbuild/config.log
gmake -j${cpu_count}
gmake install
cd /usr/src
rm -rf ffmpeg*
# smoke test
ffmpeg -version
Как обычно, проверяем результат «дымовым» тестом, т.е. выводом информации о версии программы. Кстати на сей раз я не стал отключать документацию, поэтому man ffmpeg работает. Почитать, что ли, как-нибудь?.. 
Вместо заключения
Скрипт ориентирован на «чистую» систему и не проверяет наличие уже установленного из пакетов FFmpeg или библиотек, поэтому возможные конфликты остаются на вашей совести. Также я вообще не рассматривал вопрос удаления. При оной необходимости придется вручную чистить недра /usr/local/lib, /usr/local/bin и т.д. Наверное, по мере обновлений в lib'ах могут скапливаться устаревшие версии библиотек, но учитывая объем виртуального накопителя, думаю этим можно пренебречь.
Категория: Решение проблем | Опубликовано 16.10.2026
Похожие материалы
Кросс-компиляция FFmpeg в Linux для Windows с поддержкой libfdk_aac
В свое время при изучении вопроса кодирования видео меня зацепила фраза из руководств по FFmpeg, что библиотека fdk-aac обеспечивает лучшее качество звука по сравнению с нативными реализациями aac и ac3. К сожалению, в соответствии с лицензией, ее нельзя включать в сборку для распространения. Однако ничто не мешает скомпилировать свой ffmpeg с libfdk_aac и libvvenc.
Компиляция FrankenPHP во FreeBSD. Контейнер Podman
Воодушевленный созданием контейнера PHP для FreeBSD, я поставил перед собой более амбициозную цель: скомпилировать FrankenPHP. Напомню, что это веб-сервер на базе Caddy, который взаимодействует с PHP как с библиотекой и помимо этого предоставляет еще ряд различных оптимизаций. В целом все получилось, но, как говорится, есть нюансы.












