Добавить в корзинуПозвонить
Найти в Дзене
Кодовые решения

Как я собирал FFmpeg для Android и чуть не сошёл с ума: история одной линковки

Каждый, кто пытался скомпилировать FFmpeg под Android, знает: это не просто сборка — это квест. С багами, подставами и финалом, который заставляет поверить в чудо. Когда я впервые решил упаковать медиафайлы прямо в C++ на Android, я думал: FFmpeg же open source, скачал — собрал — profit. Ха. Реальность оказалась такой: ❌ Windows NDK не работает в WSL
❌ .so файлы без символов
❌ Дублирующиеся символы
❌ Ассемблер «включён», но по факту нет
❌ NTFS тормозит сборку в 10 раз Каждая ошибка — это 2-3 часа гугления, стакан кофе и вопрос «зачем я вообще это делаю». Но я сделал это. И сейчас расскажу все грабли, на которые наступил — чтобы вы не повторяли моих ошибок. Это была самая коварная ошибка. Всё компилировалось, линковалось... а потом: Что?! Я же линкую libavutil.so и libavcodec.so! Символы там есть! Нет. Их там нет. Оказалось, что в скрипте сборки была строка: --strip-all — это не «убрать отладочную информацию». Это УДАЛИТЬ ВСЁ, включая таблицу динамических символов .dynsym. Ту самую, кот
Оглавление

Каждый, кто пытался скомпилировать FFmpeg под Android, знает: это не просто сборка — это квест. С багами, подставами и финалом, который заставляет поверить в чудо.

Пролог: «Ну что сложного, просто make и всё»

Когда я впервые решил упаковать медиафайлы прямо в C++ на Android, я думал: FFmpeg же open source, скачал — собрал — profit. Ха.

Реальность оказалась такой:

❌ Windows NDK не работает в WSL
.so файлы без символов
❌ Дублирующиеся символы
❌ Ассемблер «включён», но по факту нет
❌ NTFS тормозит сборку в 10 раз

Каждая ошибка — это 2-3 часа гугления, стакан кофе и вопрос «зачем я вообще это делаю».

Но я сделал это. И сейчас расскажу все грабли, на которые наступил — чтобы вы не повторяли моих ошибок.

Грабли №1: --strip-all — невидимый убийца символов

Это была самая коварная ошибка. Всё компилировалось, линковалось... а потом:

-2

Что?! Я же линкую libavutil.so и libavcodec.so! Символы там есть!

Нет. Их там нет.

Оказалось, что в скрипте сборки была строка:

-3

--strip-all — это не «убрать отладочную информацию». Это УДАЛИТЬ ВСЁ, включая таблицу динамических символов .dynsym. Ту самую, которую линкер ищет при подключении библиотеки.

Решение:

-4
-5

Урок: Если ваш .so не линкуется — сначала проверьте, что символы вообще существуют: nm -D libavutil.so | grep av_dict_set.

Грабли №2: Windows NDK в WSL — бинарники не того формата

WSL — это Linux. Но если вы скачали NDK для Windows и положили его на /mnt/c/... внутри лежат PE/.exe бинарники, а не ELF.

FFmpeg configure запускает тест: «может ли C компилятор создать объектный файл?». И получает ошибку, потому что Windows clang не понимает Linux-пути типа /tmp/ffconf....

Как определить, что у вас Windows NDK:

-6

Решение: Скачайте Linux-версию NDK:

-7

Грабли №3: NTFS — тихий убийца производительности

Если ваш проект на /mnt/c/ (NTFS), сборка будет в 5-10 раз медленнее. Я не преувеличиваю.

Причина: NTFS через WSL9P не поддерживает chmod +x, mmap работает криво, а I/O — как через модем 56K.

Решение: Копируем исходники на ext4:

-8

Сборка, которая на NTFS шла 40 минут, на ext4 — 5 минут.

Грабли №4: Дублирование символов — два файла, один класс

У меня в проекте было два файла с одним и тем же классом FFmpegPackager:

  • packager.cpp — JNI-версия для Android
  • cli_packager.cpp — CLI-версия для десктопа

Оба в одном CMakeLists.txt. Линкер:

-9

Решение: CLI-файлы не нужны в Android-сборке. Убрал из CMake:

-10

Грабли №5: Ассемблер «включён», но его нет

В конфигурации FFmpeg было:

-11

Но без --enable-asm в глобальных флагах FFmpeg мог тихо отключить ассемблер, если nasm не найден.

А без ассемблера декодирование H.264 — в 3-5 раз медленнее. На бюджетном ТВ это разница между «смотрю видео» и «слайд-шоу».

Решение:

  1. --enable-asm — глобально в configure
  2. nasm — обязательная зависимость (скрипт останавливается без него)
  3. Проверка после configure:
-12

Финальный рецепт: 4 команды и FFmpeg готов

Всё, что нужно для сборки FFmpeg 7.1.1 под Android с ассемблерными оптимизациями:

-13

Результат — 5 .so файлов для 3 архитектур (arm64-v8a, armeabi-v7a, x86_64) с NEON/SSE оптимизациями и MediaCodec поддержкой.

Чеклист перед сборкой

-14

Итог

Сборка FFmpeg под Android — это не ракетостроение. Но это поле мин, где каждая ошибка стоит часа отладки.

5 главных правил:

  1. --strip-unneeded, никогда --strip-all
  2. Linux NDK в WSL, не Windows
  3. ext4, не NTFS
  4. nasm обязателен — без ассемблера FFmpeg в разы медленнее
  5. Проверяй символы после strip — nm -D твой лучший друг

Если статья спасла вам хотя бы один вечер — ставьте лайк и подписывайтесь! В следующей статье расскажу, как настроить MediaCodec аппаратное декодирование через JNI.