Pull to refresh

Стабильное вещание IPTV через VLC

IPTV *
С IPTV пришлось познакомиться поближе, когда в компании интернет-провайдера где я работал, решили организовать вещание IPTV. Выяснилось, что вещание осуществляется в linux и программой vlc, которая по слухам единственная в своем роде. Была установлена тарелка и DVB-карта SkyStar2, которая предположительно должна была без проблем заработать в linux'e. Так и было со всеми новыми машинами, где была установлена ubuntu server. На Debian заработало только после обновления ядра. Настройка прошла относительно легко, благо на то время уже было несколько статей на эту тему и документация к vlc была тоже очень полезна. После запуска начались некоторые проблемы с пропаданием звука и видео на каналах и другие проблемы, описанные ниже. После их появления были написаны скрипты, устраняющие эти проблемы. Сейчас на них работает 3 сервера с 5 dvb-картами в общей сложности и вещается 23 канала с 3х спутников. Под катом — перечисление проблем, которые могут появиться после запуска вещания IPTV через VLC в Linux и то как с ними бороться. Бороться будем с помощью bash.


Первоначальная настройка и запуск вещания IPTV хорошо описана в статье «Прием спутниковых тв каналов в linux».
Основные проблемы при вещании IPTV: утечка памяти и пропадание видео или звука в одном из каналов.

Утечка памяти


Проблема утечки памяти решается либо 1) перезагрузкой демона vlc раз в день или больше по необходимости через crontab либо 2) периодической проверкой свободной памяти и перезагрузкой демона при уменьшении сводной памяти до определенного значения.

1)
crontab:
# Перезагружаем vlc в 3 часа ночи
0 3 * * * /home/desecho/vlc/vlc_regular_reload.sh

vlc_regular_reload.sh:
#!/bin/bash<br/>echo "`date`;VLC regular reload" >> /home/desecho/vlc/logs/vlc_restart.log<br/>/home/desecho/vlc/vlc_starter.sh<br/>


2)
crontab:
#Проверяем каждые 5 минут
*/5 * * * * /home/desecho/vlc/memory_check.sh

memory_check.sh:
#!/bin/bash<br/>#Получаем переменную свободной памяти<br/>free_mem=$(free -m | grep ^M | awk -F' ' '{print $4 }')<br/>#Указываем предельное значение свободной памяти<br/>mem_limit=16<br/>#Если свободной памяти меньше или же она совпадает со значением предела то происходит перезагрузка демона<br/>if [ $free_mem -le $mem_limit ]<br/>    then<br/>    echo "`date`;Memory Overload" >> /home/desecho/vlc/logs/vlc_restart.log<br/>    /home/desecho/vlc/vlc_starter.sh<br/>fi <br/>


Пропадание видео или звука


Для решения проблемы необходимо периодически проверять наличие видео и звука в каналах.
Реализация скриптов на примере вещания двух каналов. Вещание идет в два потока — оригинального и сжатого. Иногда помогает перезагрузка проблемного канала, но иногда необходима полная перезагрузка демона.

Для работоспособности скрипта необходимо запустить следующие команды:

cp /usr/bin/vlc /usr/bin/vlc2<br/>touch /home/desecho/vlc/run.sh<br/>chmod +x /home/desecho/vlc/run.sh<br/>


Скрипт запуска и перезагрузки каналов:
vlc_starter.sh:
#!/bin/bash<br/>echo "`date`;Reloaded" >> /home/desecho/vlc/logs/vlc_restart.log<br/> <br/>#Выключаем все запущенные vlc процессы<br/>killall -9 vlc<br/>#Запуск вещания<br/>vlc --no-stats -vvv --color --daemon --ttl 12 --ts-es-id-pid --dvb-adapter 0 --programs=13,14 dvb: --dvb-frequency=10995000 --dvb-srate=20000000 --dvb-voltage=13 --sout '#duplicate{dst=std{access=http,mux=asf,url=0.0.0.0:8001},select="program=13",dst=std{access=http,mux=asf,url=0.0.0.0:8002},select="program=14"}'<br/>#Ждем несколько секунд для инициализации вещания<br/>sleep 5<br/>#Вещаем сжатый поток в 820Kbit/s видео и 70Kbit/s аудио<br/>vlc http://127.0.0.1:8001 -vvv --daemon --color --sout '#transcode{vcodec=mp4v,vb=820,scale=1,acodec=mpga,ab=70,channels=1}:duplicate{dst=std{access=http,mux=asf,url=0.0.0.0:8011}'<br/>vlc http://127.0.0.1:8002 -vvv --daemon --color --sout '#transcode{vcodec=mp4v,vb=820,scale=1,acodec=mpga,ab=70,channels=1}:duplicate{dst=std{access=http,mux=asf,url=0.0.0.0:8012}'<br/>


Скрипт проверки каналов:
vlc_restarter.sh:

#!/bin/bash<br/> <br/>#Запись канала<br/>#$1 - id порта сжатого канала<br/>function rec {<br/>    #Запись видео<br/>    b="vlc2 http://127.0.0.1:80$1 -vvv --color --daemon --noaudio --sout '#duplicate{dst=std{access=file,mux=asf,dst=\"/home/desecho/vlc/0$1.avi\"}}'"<br/>    #Создание временного исполняемого файла - такой способ необходим из-за наличия в строке запуска vlc различных ковычек<br/>    echo $b > /home/desecho/vlc/run.sh<br/>    /home/desecho/vlc/run.sh<br/>    #Запись аудио<br/>    b="vlc2 http://127.0.0.1:80$1 -vvv --color --daemon --novideo --sout '#duplicate{dst=std{access=file,mux=asf,dst=\"/home/desecho/vlc/0$1.mp3\"}}'"<br/>    echo $b > /home/desecho/vlc/run.sh<br/>    /home/desecho/vlc/run.sh<br/>    sleep 5<br/>    killall -9 vlc2<br/>}<br/> <br/>#Полная перезагрузка vlc<br/>#$1 - имя канала<br/>function reload {<br/>    echo "`date`;$1 - Reload" >> /home/desecho/vlc/logs/vlc_restart.log<br/>    /home/desecho/vlc/vlc_starter.sh<br/>}<br/> <br/>#Проверка канала<br/>#$1 - id порта сжатого канала<br/>#$2 - имя канала<br/>function check {<br/>    #Смотрим размер видео<br/>    y="$(du /home/desecho/vlc/0$1.avi | grep -oE --regexp='[0-9]+' | sed -n '1p')"<br/>    #Проверяем пустой ли файл<br/>    if [ $y -gt 10 ] ; then<br/>        x011=1<br/>    else<br/>        x011=0<br/>    fi<br/>    #Смотрим размер аудио<br/>    y="$(du /home/desecho/vlc/0$1.mp3 | grep -oE --regexp='[0-9]+' | sed -n '1p')"<br/>    if [ $y -gt 10 ] ; then<br/>        x012=1<br/>    else<br/>        x012=0<br/>    fi<br/>    echo "    $2 - $x011 $x012" >> /home/desecho/vlc/logs/vlc_restart.log<br/>    let x01=x011+x012<br/>    #Если отсутствует звук или видео, то переменная z=0<br/>    if [ $x01 != 2 ]<br/>    then<br/>        z=0<br/>    else<br/>        z=1<br/>    fi<br/>}<br/> <br/>#Полная проверка<br/>#$1 - id порта сжатого канала<br/>#$2 - имя канала<br/>function check_full {<br/>    #Запись канала<br/>    rec $1<br/>    #Проверка на отсутствие видео или звука<br/>    check $1 $2<br/>    #Если видео и звук в норме то помечаем переменную z канала<br/>    if [ $z = 1 ] ; then<br/>        z[$1]=1<br/>    fi<br/>}<br/> <br/>#Перезагрузка канала<br/>#$1 - id порта сжатого канала<br/>#$2 - имя канала<br/>#$3 - id порта исходного канала<br/>function restart {<br/>    echo "`date`;$2 - Restart" >> /home/desecho/vlc/logs/vlc_restart.log<br/>    #Выключение неработающего канала<br/>    a="$(ps -C vlc -o '%p%a' | grep "http://127.0.0.1:80$3 -vvv --daemon --color --sout" | grep -oE --regexp='[0-9]+' | sed -n '1p')"<br/>    kill $a<br/>    #Перезапуск вещания канала<br/>    b="vlc http://127.0.0.1:80$3 -vvv --daemon --color --sout '#transcode{vcodec=mp4v,vb=820,scale=1,acodec=mpga,ab=70,channels=1}:duplicate{dst=std{access=http,mux=asf,url=0.0.0.0:80$1}'"<br/>    echo $b > /home/desecho/vlc/run.sh<br/>    /home/desecho/vlc/run.sh<br/>}<br/> <br/>#Перезагрузка канала<br/>#$1 - id порта сжатого канала<br/>#$2 - имя канала<br/>#$3 - id порта исходного канала<br/>function fix {<br/>    #Если нет видео или звука на канале то перезагружается канал<br/>    if [ ${z[$1]} != 1 ] ; then<br/>        restart $1 $2 $3<br/>        sleep 5<br/>        #повторная проверка<br/>        check_full $1 $2<br/>    fi<br/>    #Если по прежнему нет звука то перезагружаем VLC полностью<br/>    if [ ${z[$1]} != 1 ] ; then<br/>        reload $2<br/>    exit<br/>fi<br/>}<br/>#Присваиваем значение 0 по умолчанию переменным z каналов<br/>z[11]=0<br/>z[12]=0<br/> <br/>#Проверка канала на отсутствие видео/звука<br/>check_full 11 perviy<br/>#Перезагрузка канала при проблемах с видео/звуком<br/>fix 11 perviy 01<br/> <br/>check_full 12 rossiya<br/>fix 12 rossiya 02<br/> <br/>echo "`date`;DVB - Status: Stable" >> /home/desecho/vlc/logs/vlc_restart.log<br/>


Осталось добавить запись в crontab:
*/5 * * * * /home/desecho/vlc/vlc_restarter.sh

В итоге получаем систему, которая автоматически восстановит вещание каналов при пропадании видео или аудио. Все действия скриптов восстановления вещания будут писаться в лог файл.
Удачного вещания!

UPD: Перенес в блог IPTV. P.S. Спасибо за карму!
UPD2: Для нейтрализации утечки памяти можно собрать vlc без флага «optimisememory» либо попробовать обновить vlc, см. статью «Вещание видеофайлов с помощью VLC multicast. С теорией». Спасибо Breaker.
Tags:
Hubs:
Total votes 50: ↑48 and ↓2 +46
Views 58K
Comments Comments 44