Hls В Mp4 С Использованием Ffmpeg В Браузере

Привет! Вот уже больше двух месяцев в свободное время я создаю веб-приложение для конвертации HLS и DASH в MP4, используя emscripten и ffmpeg, поэтому мне хочется поделиться, как мне это удалось сделать.

В этой статье я не буду приводить исходный код правок и патчей ffmpeg, потому что.

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



Введение

Два года назад у меня возникла цель объединить аудио и видео дорожку в один файл mp4. Тогда я как раз погружался в emscripten и нашел репозиторий с основами ffmpeg.js из которого я многому научился.

Тогда мне почти удалось добиться цели, хотя я был очень неуверен в C. Разбираясь в исходниках ffmpeg, я сделал патч для работы с файловой системой, где чтение из файла вызывало асинхронную функцию в js, из которой я читал блоб файла и передал буфер, а при записи вызывалась js-функция который отправил данные буфера в хранилище.

Но возникла проблема с асинхронными функциями, которую я не смог решить корректно, они работали через asyncify (fastcomp), который в некоторых случаях работал некорректно, а именно не приостанавливалось выполнение кода в васме, от чего не было дождаться получения результата от js-функции - все сломалось.

Эту проблему исправили через флаг EMTERPRETIFY_WHITELIST, который видимо переводил код с wasm на asm, одновременно замедляя его, и при каждом исключении приходилось отлаживать стек вызовов и добавлять в список сломанную функцию.

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



HLS в MP4 с использованием ffmpeg в браузере



Полтора года спустя

После просмотра выступления на Google Dev Summit о новых возможностях в WebAssembly , я зашел посмотреть, как дела у emscripten и увидел такое сообщение:
Emscripten создает WebAssembly, используя исходный бэкэнд LLVM wasm, начиная с версии 1.39.0 (октябрь 2019 г.

), а старый бэкэнд fastcomp устарел.

Я хотел пойти попробовать пересобрать свой форматный репакер.

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

Изменений было не так уж много, но она не собралась из-за нового компоновщика библиотек, и уже отчаявшись собрать хоть что-то, я просто вырезал проблемные библиотеки (как оказалось, сами библиотеки подключены и нет больше нет необходимости указывать их вручную при сборке).

И вот, настал тот момент, когда все собралось и начало работать! Проблема с асинхронным кодом исчезла, не нужно было ничего отлаживать, все работало так, как должно было изначально.

Здесь я вроде бы добился своей цели, но.

появилась новая.



Перепишите протокол HTTP

Эта мысль была у меня уже давно.

Это позволит вам загрузить HLS или DASH не только готовый плейлист, но и прямую трансляцию.

Я никогда не видел ничего подобного в Интернете.

На то, чтобы сделать хоть что-то работающее, у меня ушло около трёх недель, с небольшими перерывами.

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

После первых успехов это придало нам еще больше энтузиазма довести идею до конца.

Еще пара недель и мне наконец удалось сделать первую итерацию работающего http-протокола и, казалось бы, все?

Когда самое сложное позади

К этому моменту у меня была готова база, небольшая HTML-форма с полем ввода URL-адреса и кнопкой «Пуск», в принципе все работало.

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

В общем, пришло время наконец-то сделать возможным его использование.

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

Еще пара дней и было готово расширение для Chrome и Firefox, которое с помощью webRequest собирало все hls-ссылки, которые загружает браузер при просмотре видео.

В Firefox, как оказалось, API расширения не позволяет управлять питанием, что, к сожалению, не может помешать вашему компьютеру заснуть.

Расширение выглядит следующим образом:

HLS в MP4 с использованием ffmpeg в браузере

Также я немного улучшил страницу, на которой находился сайт, добавил Material-UI и доработал все места, которые были сделаны на скорую руку.



HLS в MP4 с использованием ffmpeg в браузере

Протестировав разные способы хранения данных, я выявил ряд проблем: Блоб - Chrome записывает их в оперативную память и сбрасывает на диск, когда она заполнена, но в OSX, когда память заполнена, операционная система выходит из учетной записи и закрывает все приложения, которые были открыты.

А Firefox вообще всегда хранил данные в памяти.

Хранение кэша - работает как IndexedDb, но после записи данных в Chrome блобы остаются в ОЗУ (то ли баг, то ли особенность), но получается, что данные записываются в кэш-хранилище (на диск) и при заполнении памяти происходит также отбрасывает один и тот же том на диск в виде больших двоичных объектов.

Индекседдб — работает как шарм, умеет хранить блобы, пишет данные без излишеств, но Firefox жёстко ограничивает объём 2Гб.

Поработал над этим понемногу, сумел сделать функцию прерывания процесса ffmpeg (через указатель), разобрался с выбором форматов (ffprobe) и обработкой сетевых ошибок.



HLS в MP4 с использованием ffmpeg в браузере



HLS в MP4 с использованием ffmpeg в браузере

И теперь вы можете попробовать результат самостоятельно Здесь Для меня это незаменимая вещь, когда нужно записать стрим на Twitch или скачать VOD. Также работает с YouTube, микшером и любыми другими сайтами, транслирующими контент в HLS или DASH (увы, реализация DASH в ffmpeg очень условна и лайв может не корректно скачиваться, поскольку не учитывает интервал запроса фрагмента) .

Спасибо за чтение! Если есть вопросы по ffmpeg и emscripten — пишите, постараюсь ответить.

Теги: #JavaScript #WebAssembly #hls #ffmpeg #webassambly

Вместе с данным постом часто просматривают: