Привет! Вот уже больше двух месяцев в свободное время я создаю веб-приложение для конвертации HLS и DASH в MP4, используя emscripten и ffmpeg, поэтому мне хочется поделиться, как мне это удалось сделать.
В этой статье я не буду приводить исходный код правок и патчей ffmpeg, потому что.
Большинство из них делались у меня на коленях, и я не очень хорошо владею C. Но сейчас есть достаточно статей, которые могут вам помочь.
Введение
Два года назад у меня возникла цель объединить аудио и видео дорожку в один файл mp4. Тогда я как раз погружался в emscripten и нашел репозиторий с основами ffmpeg.js из которого я многому научился.Тогда мне почти удалось добиться цели, хотя я был очень неуверен в C. Разбираясь в исходниках ffmpeg, я сделал патч для работы с файловой системой, где чтение из файла вызывало асинхронную функцию в js, из которой я читал блоб файла и передал буфер, а при записи вызывалась js-функция который отправил данные буфера в хранилище.
Но возникла проблема с асинхронными функциями, которую я не смог решить корректно, они работали через asyncify (fastcomp), который в некоторых случаях работал некорректно, а именно не приостанавливалось выполнение кода в васме, от чего не было дождаться получения результата от js-функции - все сломалось.
Эту проблему исправили через флаг EMTERPRETIFY_WHITELIST, который видимо переводил код с wasm на asm, одновременно замедляя его, и при каждом исключении приходилось отлаживать стек вызовов и добавлять в список сломанную функцию.
В общем, при таких проблемах это нельзя было назвать рабочим решением, поэтому всё это так и осталось маленькой демкой.
Полтора года спустя
После просмотра выступления на 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 расширения не позволяет управлять питанием, что, к сожалению, не может помешать вашему компьютеру заснуть.
Расширение выглядит следующим образом:
Также я немного улучшил страницу, на которой находился сайт, добавил Material-UI и доработал все места, которые были сделаны на скорую руку.
Протестировав разные способы хранения данных, я выявил ряд проблем: Блоб - Chrome записывает их в оперативную память и сбрасывает на диск, когда она заполнена, но в OSX, когда память заполнена, операционная система выходит из учетной записи и закрывает все приложения, которые были открыты.
А Firefox вообще всегда хранил данные в памяти.
Хранение кэша - работает как IndexedDb, но после записи данных в Chrome блобы остаются в ОЗУ (то ли баг, то ли особенность), но получается, что данные записываются в кэш-хранилище (на диск) и при заполнении памяти происходит также отбрасывает один и тот же том на диск в виде больших двоичных объектов.
Индекседдб — работает как шарм, умеет хранить блобы, пишет данные без излишеств, но Firefox жёстко ограничивает объём 2Гб.
Поработал над этим понемногу, сумел сделать функцию прерывания процесса ffmpeg (через указатель), разобрался с выбором форматов (ffprobe) и обработкой сетевых ошибок.
И теперь вы можете попробовать результат самостоятельно Здесь
Для меня это незаменимая вещь, когда нужно записать стрим на Twitch или скачать VOD. Также работает с YouTube, микшером и любыми другими сайтами, транслирующими контент в HLS или DASH (увы, реализация DASH в ffmpeg очень условна и лайв может не корректно скачиваться, поскольку не учитывает интервал запроса фрагмента) .
Спасибо за чтение! Если есть вопросы по ffmpeg и emscripten — пишите, постараюсь ответить.
Теги: #JavaScript #WebAssembly #hls #ffmpeg #webassambly
-
Лучший (Не Совсем) Фонарик В Мире
19 Oct, 24 -
Загрузка Gnu/Linux Без Стороннего Загрузчика
19 Oct, 24 -
`Мы С Яндексом На Вас!` Или Seo В России
19 Oct, 24