Возникла необходимость проводить мониторинг мультикаст потоков. Начался поиск готовых решений. Первое что удалось нагуглить: IPTV-Analyzer, NetUP IPTVProbe. У каждого решения были свои недостатки или стоили немалых денег. Было принято решение создать свой собственный мониторинг. Основная задача уведомлять и логировать падение мультикаст потока.
Механизм:
С помощью ffmpeg подключаемся к потоку в течение NN времени, кадр начинает снимать с NN секунды, чтобы не было артефактов на картинке. Если в течение NN секунд не получается что-то получить, то пишем в базу с ошибкой снятия. Все довольно просто.
Приступим к установке основных компонентов:
apache – для web-интерфейса.
mysql — в базе будем хранить данные, необходимые для статистики, и список каналов.
ffmpeg – нам будет необходим для снятия скриншотов с мультикаст-потока.
Основные компоненты установлены, приступим к настройке.
В директории (по умолчанию используемая apache2 /var/www/ ) создаем файл dbinit.php c настройками подключения к базе:
Структура базы:
date – TIMESTAMP (Дата падения или поднятия канала)
name – TEXT (Имя канала)
state – TEXT (Состояние: true-поднятие, false-падение)
Необходимо это для дальнейшего расчета сколько времени канал был в дауне.
Создаем скрипт, который будет генерировать ну и, собственно, «мониторить» каналы.
Назовем его gen.php
Рассмотрим подробнее строки скрипта.
Для выполнения скрипта ставим таймаут выполнения (timeout 20s ), если канал будет недоступен — он будет висеть очень долго.
Время снятия скриншота пишем в файл:
Снятие скриншота
Получение результатов и добавление их в базу:
Создадим файл rez.php
При удачном снятии скриншота время выполнения записывается в файл, если не получилось файл будет пустой. В скрипте выполняем проверку на содержимое в файле.
Рассылаем по джаберу о упавшем канале
jabber_alert.pl
Создаем index.php
Выводим упавшие/поднятые каналы и раскрашиваем их.
Добавляем в крон выполнение двух скриптов.
Решение не столь изящно, но оно работает и свои задачи выполняет.
Доработав можно получить такое:

Механизм:
С помощью ffmpeg подключаемся к потоку в течение NN времени, кадр начинает снимать с NN секунды, чтобы не было артефактов на картинке. Если в течение NN секунд не получается что-то получить, то пишем в базу с ошибкой снятия. Все довольно просто.
Приступим к установке основных компонентов:
sudo apt-get install apache2 php5 mysql-server libapache2-mod-php5 libapache2-mod-auth-mysql php5-mysql ffmpegapache – для web-интерфейса.
mysql — в базе будем хранить данные, необходимые для статистики, и список каналов.
ffmpeg – нам будет необходим для снятия скриншотов с мультикаст-потока.
Основные компоненты установлены, приступим к настройке.
В директории (по умолчанию используемая apache2 /var/www/ ) создаем файл dbinit.php c настройками подключения к базе:
<?php $dbhost = "localhost"; $dbname = "name"; $dbuser = "user"; $dbpass = "password"; mysql_connect($dbhost, $dbuser, $dbpass); mysql_query("set character_set_client='utf8'"); mysql_query("set character_set_results='utf8'"); mysql_query("set collation_connection='utf8_general_ci'"); mysql_select_db($dbname); ?>
Структура базы:
date – TIMESTAMP (Дата падения или поднятия канала)
name – TEXT (Имя канала)
state – TEXT (Состояние: true-поднятие, false-падение)
Необходимо это для дальнейшего расчета сколько времени канал был в дауне.
Создаем скрипт, который будет генерировать ну и, собственно, «мониторить» каналы.
Назовем его gen.php
<?php include "dbinit.php"; $query = "SELECT * FROM `name`"; $result = mysql_query($query); if (!$result) { print "<center>ошибка:" . mysql_error() . "</center>"; } elseif (mysql_num_rows($result) == 0) { print ""; } else { $rows = array(); while ($row = mysql_fetch_assoc($result)) { $rows[]= $row; } foreach($rows as $row) { echo exec('/usr/bin/timeout 20s /usr/bin/time -f %U -o /var/www/tmp/'.$row['name'].'.txt /usr/bin/ffmpeg -i udp://@'.$row['mcast'].' -y -f image2 -sameq -t 0.001 -ss 00:00:4 -s 120*80 /var/www/screen/'.$row['mcast'].'.jpg'); echo exec('/bin/cp -f /var/www/tmp/'.$row['mcast'].'.txt /var/www/rez/'); } ?>
Рассмотрим подробнее строки скрипта.
Для выполнения скрипта ставим таймаут выполнения (timeout 20s ), если канал будет недоступен — он будет висеть очень долго.
Время снятия скриншота пишем в файл:
/usr/bin/time -f %U -o /var/www/tmp/'.$row['name'].'.txt
Снятие скриншота
/usr/bin/ffmpeg -i udp://@'.$row['name'].' -y -f image2 -sameq -t 0.001 -ss 00:00:4 -s 120*80 /var/www/screen/'.$row['name'].'.jpg
Получение результатов и добавление их в базу:
Создадим файл rez.php
<?php $lines = file ('rez/'.$row['mcast'].'.txt'); if ($lines[0]=='') { $last_result=mysql_result(mysql_query("select state from name where name='".$row['name']."' order by date desc limit 0,1"),0); if($last_result=='true') { $query = "INSERT INTO `name` (`date`, `name`, `state`) VALUES ('{$date}', '{$row['name']}', 'false');"; mysql_query($query) or die(mysql_error()); } foreach ($A as $v) { echo exec('/usr/bin/perl /usr/local/scripts/jabber_alert.pl -e '.$v.'@jabber.server -n tv@jabber.server -w password -y '.translitIt ($row['name']).'-'.$row['mcast'].' << "EOF" read -d "^D" input'); } } else { $last_result=mysql_result(mysql_query("select state from name where name='".$row['name']."' order by date desc limit 0,1"),0); echo $last_result; if($last_result=='false') { $query = "INSERT INTO `name` (`date`, `name`, `state`) VALUES ('{$date}', '{$row['name']}', 'true');"; mysql_query($query) or die(mysql_error()); } echo $row['name']." ". $lines[1]."Работает "; } ?>
При удачном снятии скриншота время выполнения записывается в файл, если не получилось файл будет пустой. В скрипте выполняем проверку на содержимое в файле.
Рассылаем по джаберу о упавшем канале
echo exec('/usr/bin/perl /usr/local/scripts/jabber_alert.pl -e '.$v.'@jabber.server -n tv@jabber.server -w password -y '.translitIt ($row['name']).'-'.$row['mcast'].' << "EOF" read -d "^D" input');
jabber_alert.pl
Создаем index.php
<?php foreach($rows as $row) { $work=mysql_result(mysql_query("select date from name where date>'".$row['date']." order by date limit 0,1'"),0); $date1 = new DateTime($work); $date2 = new DateTime($row['date']); $interval = $date2->diff($date1); if($work=="") { $style="red"; } else { $style="";} echo "<tr><td style='color:".$style."'><font color='red'>".$row['date']; if($work!="") { echo "</font> - <font color='green'>".$work."</font>"; } echo "</td><td>"; if($interval->format("%h") != 0) { echo $interval->format("%hч. "); } echo $interval->format("%iм. %sс.")."</td><td style='color:".$style."'>".$row['name']."</td></tr>"; } ?>
Выводим упавшие/поднятые каналы и раскрашиваем их.
Добавляем в крон выполнение двух скриптов.
Решение не столь изящно, но оно работает и свои задачи выполняет.
Доработав можно получить такое:
