Ниже – схема, как через Docker и FFmpeg перегнать HLS (M3U8) в RTMP, например на сервер трансляции Telegram. Параметром eqon/eqoff включается или отключается визуализация волны (showwaves), чтобы на «чисто аудио» потоке было хоть какое-то видео для RTMP.
Что нужно
- Docker – изоляция и простой запуск без локальной сборки FFmpeg.
- FFmpeg – чтение M3U8, фильтры, кодирование, отдача в FLV/RTMP (в образе уже есть).
- Источник в формате HLS: URL
.m3u8. - RTMP endpoint: URL сервера и ключ потока (ingest Telegram или свой nginx-rtmp / mediaMTX и т.п.).
Установка Docker
На Debian/Ubuntu, если Docker ещё не стоит:
sudo apt update sudo apt install docker.io
На серверах чаще ставят официальный Docker Engine; для домашней лаборатории пакета docker.io обычно достаточно. Пользователя можно добавить в группу docker, чтобы не писать sudo каждый раз.
Скрипт stream.sh
Скрипт принимает M3U8, RTMP URL, ключ и флаг визуализации. При eqon из аудио строится видеоряд showwaves 1280×720; при eqoff в map уходит только аудио (для многих RTMP-приёмников без видео это может быть проблемой – смотрите требования платформы).
#!/bin/bash
# Проверка аргументов
if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then
echo "Usage: $0 <M3U8_URL> <RTMP_URL> <RTMP_KEY> <eqon/eqoff>"
exit 1
fi
M3U8_URL=$1
RTMP_URL=$2
RTMP_KEY=$3
EQ_STATUS=$4
FULL_RTMP_URL="$RTMP_URL/$RTMP_KEY"
if [ "$EQ_STATUS" == "eqon" ]; then
EQ_FILTER="[0:a]showwaves=s=1280x720:mode=line:colors=blue,format=yuv420p[v]"
MAP_FILTER="-map '[v]' -map 0:a"
else
EQ_FILTER=""
MAP_FILTER="-map 0:a"
fi
ffmpeg -re -i "$M3U8_URL" \
-filter_complex "$EQ_FILTER" \
$MAP_FILTER \
-c:v libx264 -preset veryfast -tune zerolatency -c:a aac -ar 44100 -b:a 128k \
-f flv "$FULL_RTMP_URL"
Сохраните как stream.sh, сделайте исполняемым: chmod +x stream.sh.
Параметры FFmpeg
-re– читать вход примерно в реальном времени (для live-источника, не для «прогнать файл как можно быстрее»).-i "$M3U8_URL"– вход: плейлист HLS.-filter_complex+showwaves– картинка из аудио: размерs=1280x720, режимmode=line, цветcolors=blue, пиксельный форматyuv420pдля совместимости с x264/RTMP.-map '[v]' -map 0:a– при eqon: сгенерированное видео и исходное аудио; при eqoff – только аудио.-c:v libx264 -preset veryfast -tune zerolatency– быстрое кодирование с низкой задержкой.-c:a aac -ar 44100 -b:a 128k– AAC, 44.1 кГц, 128 кбит/с.-f flv "$FULL_RTMP_URL"– контейнер FLV на RTMP (URL + ключ).
Важно: при пустом EQ_FILTER строка -filter_complex "" в части сборок FFmpeg ведёт себя капризно. Если eqoff падает, либо не передавайте -filter_complex совсем (разветвить команду в if/else), либо всегда держите простой null/anull-фильтр. В проде лучше две явные ветки ffmpeg.
Dockerfile
FROM jrottenberg/ffmpeg:4.4-ubuntu COPY stream.sh /usr/local/bin/stream.sh RUN chmod +x /usr/local/bin/stream.sh ENTRYPOINT ["/usr/local/bin/stream.sh"]
Базовый образ уже содержит FFmpeg. Скрипт – единственная точка входа: аргументы контейнера уходят в stream.sh.
Сборка и запуск
docker build -t m3u8-to-rtmp-eq .
docker run m3u8-to-rtmp-eq <M3U8_URL> <RTMP_URL> <RTMP_KEY> eqon
Аргументы:
<M3U8_URL>– URL плейлиста HLS;<RTMP_URL>– база RTMP без ключа (напримерrtmps://.../s);<RTMP_KEY>– ключ/stream key;eqonилиeqoff– визуализация волны вкл/выкл.
Автозапуск и перезапуск
Чтобы контейнер поднимался после ребута и после падения FFmpeg:
docker run --restart unless-stopped m3u8-to-rtmp-eq \ <M3U8_URL> <RTMP_URL> <RTMP_KEY> eqon
Для логов удобно добавить --name m3u8-rtmp и смотреть docker logs -f m3u8-rtmp. Ключ RTMP не светите в публичных репозиториях и CI.
Готовый образ и пример
Код и образ выложены автором схемы: репозиторий на GitHub и образ на Docker Hub (ссылки в блоке источников). Пример живой отдачи – канал Telegram с online-потоком; для своего кейса подставьте свой M3U8 и ключ ingest.
Итог
Схема простая: контейнер с FFmpeg читает M3U8, при необходимости рисует showwaves, кодирует x264+AAC и шлёт FLV на RTMP. Удобно для радио/аудио-источников, которым нужен «видео» слой, и для перегона HLS на платформы с RTMP-ingest. Дальше – мониторинг логов, лимиты CPU на veryfast/zerolatency и запас по сети.