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

Опубликовано:

С 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 * * * /usr/local/script/vlc_regular_reload.sh

vlc_regular_reload.sh:

#!/bin/bash
 echo "`date`;VLC regular reload" >> /var/log/vlc/vlc_restart.log
 /usr/local/script/vlc_starter.sh
chmod +x /usr/local/script/vlc_regular_reload.sh

2)
crontab:

#Проверяем каждые 5 минут
*/5 * * * * /usr/local/script/memory_check.sh

memory_check.sh:

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

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

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

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

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

Скрипт запуска и перезагрузки каналов:

vlc_starter.sh:

#!/bin/bash
 echo "`date`;Reloaded" >> /var/log/vlc/vlc_restart.log
#Выключаем все запущенные vlc процессы
 killall -9 vlc
 #Запуск вещания
 vlc --no-stats -vvv --color --daemon --ttl 12 --ts-es-id-pid --dvb-adapter0 --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"}'
 #Ждем несколько секунд для инициализации вещания
 sleep 5
 #Вещаем сжатый поток в 820Kbit/s видео и 70Kbit/s аудио
 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}'
 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}'
 chmod +x /usr/local/script/vlc_starter.sh

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

#!/bin/bash
 #Запись канала
 #$1 - id порта сжатого канала
 function rec {
 #Запись видео
 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"}}'"
 #Создание временного исполняемого файла - такой способ необходим из-за наличия в строке запуска vlc различных ковычек
 echo $b > /home/desecho/vlc/run.sh
 /home/desecho/vlc/run.sh
 #Запись аудио
 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"}}'"
 echo $b > /home/desecho/vlc/run.sh
 /home/desecho/vlc/run.sh
 sleep 5
 killall -9 vlc2
 }
#Полная перезагрузка vlc
 #$1 - имя канала
 function reload {
 echo "`date`;$1 - Reload" >> /home/desecho/vlc/logs/vlc_restart.log
 /home/desecho/vlc/vlc_starter.sh
 }
#Проверка канала
 #$1 - id порта сжатого канала
 #$2 - имя канала
 function check {
 #Смотрим размер видео
 y="$(du /home/desecho/vlc/0$1.avi | grep -oE --regexp='[0-9]+' | sed -n '1p')"
 #Проверяем пустой ли файл
 if [ $y -gt 10 ] ; then
 x011=1
 else
 x011=0
 fi
 #Смотрим размер аудио
 y="$(du /home/desecho/vlc/0$1.mp3 | grep -oE --regexp='[0-9]+' | sed -n '1p')"
 if [ $y -gt 10 ] ; then
 x012=1
 else
 x012=0
 fi
 echo "    $2 - $x011 $x012" >> /home/desecho/vlc/logs/vlc_restart.log
 let x01=x011+x012
 #Если отсутствует звук или видео, то переменная z=0
 if [ $x01 != 2 ]
 then
 z=0
 else
 z=1
 fi
 }
#Полная проверка
 #$1 - id порта сжатого канала
 #$2 - имя канала
 function check_full {
 #Запись канала
 rec $1
 #Проверка на отсутствие видео или звука
 check $1 $2
 #Если видео и звук в норме то помечаем переменную z канала
 if [ $z = 1 ] ; then
 z[$1]=1
 fi
 }
#Перезагрузка канала
 #$1 - id порта сжатого канала
 #$2 - имя канала
 #$3 - id порта исходного канала
 function restart {
 echo "`date`;$2 - Restart" >> /home/desecho/vlc/logs/vlc_restart.log
 #Выключение неработающего канала
 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')"
 kill $a
 #Перезапуск вещания канала
 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}'"
 echo $b > /home/desecho/vlc/run.sh
 /home/desecho/vlc/run.sh
 }
#Перезагрузка канала
 #$1 - id порта сжатого канала
 #$2 - имя канала
 #$3 - id порта исходного канала
 function fix {
 #Если нет видео или звука на канале то перезагружается канал
 if [ ${z[$1]} != 1 ] ; then
 restart $1 $2 $3
 sleep 5
 #повторная проверка
 check_full $1 $2
 fi
 #Если по прежнему нет звука то перезагружаем VLC полностью
 if [ ${z[$1]} != 1 ] ; then
 reload $2
 exit
 fi
 }
 #Присваиваем значение 0 по умолчанию переменным z каналов
 z[11]=0
 z[12]=0
#Проверка канала на отсутствие видео/звука
 check_full 11 perviy
 #Перезагрузка канала при проблемах с видео/звуком
 fix 11 perviy 01
check_full 12 rossiya
 fix 12 rossiya 02
echo "`date`;DVB - Status: Stable" >> /home/desecho/vlc/logs/vlc_restart.log
 chmod +x /usr/local/script/vlc_restarter.sh

Осталось добавить запись в crontab:

*/5 * * * * /usr/local/script/vlc_restarter.sh

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

Для нейтрализации утечки памяти можно собрать vlc без флага «optimisememory» либо попробовать обновить vlc, см. статью
«Вещание видеофайлов с помощью VLC multicast. С теорией».

http://habrahabr.ru/post/66351/

Понравилась статья, расскажи о ней друзьям, нажми кнопку!