Начнем с небольшого пролога.

Что такое серверные плейлисты и зачем они нужны? (с офсайта flussonic)
Серверные плейлисты на сегодняшний день не рекомендованы к использованию в интернете.

Эта технология растет корнями из телевизионного оборудования и ПО, позволявшего запускать видео под контролем оператора. В обновленном виде плейлисты нужны и сегодня, поскольку практика показывает, что пользователям приятнее смотреть то, что им предлагают, а не искать самим.

Вместо серверных плейлистов сегодня рекомендуется использовать клиентские плейлисты из-за следующих проблем:

невозможность таргетировать рекламу;
невозможность учитывать рекламу через adriver и другие подобные сети;
сложность сделать мультибитрейтной доставки: разные файлы могут иметь разное количество разных битрейтов;
технически неоправданно сложно делать отмотку назад, а это одно из основных преимуществ интернет-доставки по сравнению с эфирной;
пауза так же слишком сложна в реализации.

На самом деле невозможность реализации адекватной системы учета рекламы сводит на нет все желания использовать серверные плейлисты.

Но мы с учетом своих особенностей, все таки рискнем рекламой в пользу программы передач.

Прежде чем написать, как сделать программу передач, давайте приготовим файлы и расположим их на корне своего сайта.
Файлы, для трансляции обычно положим в папку /media/liv
Обязательно создаем файл плейлиста playlist.txt (кладем в папку /pls) примерно с таким содержимым:

liv/i_out.mp4
liv/ss1.mp4
liv/i_out.mp4
liv/c1g.mp4
liv/i_out.mp4
liv/vv.mp4
liv/i_out.mp4
liv/tr1be.mp4
liv/i_out.mp4
liv/sg1.mp4


Файл конфигурации flussonic.conf под нашу задачу выглядит так:

# Global settings:
http 80;
http 8080;
rtsp 554;
rtmp 1935;
loglevel error;
logrequests true;
auth http://yourchannel.ru:8080/tv/auth;
pulsedb /var/run/flussonic;
edit_auth login password;

# DVRs:

# Remote sources:

# Ingest streams:
stream playlist1 {
  url playlist://http://yourchannel.tv/pls/playlist.txt;
  auth false;
  allowed_countries ru;
  disallowed_countries us;
  domains yourchannel.tv;
  meta comment "yourchannel.tv server channel";
}
stream tunneling {
  url rtmp://yourchannel.tv:1935/static/playlist1;
  auth false;
  allowed_countries ru;
  disallowed_countries us;
  domain yourchannel.tv;
  transcoder vb=copy;
}

# Dynamic rewrites:

# Publish locations:

# Disk file caches:

# VOD locations:
file vod {
  path priv;
  auth true;
  domain yourchannel.ru;
}
file liv {
  path /home/yourchannel/data/www/yourchannel.tv/media/liv;
}

# Plugins:
plugin iptv {
  database sqlite:///opt/flussonic/priv/iptv.db;
}

# Includes:



Давайте рассмотрим, как можем сделать программу передач, используя данные медиасервера Flussonic, предоставляемые в JSON запросе в виде HTTP API — flussonic/flussonic/api/playlist/playlist1

Надо заметить, что доступ к заветной строке проходит с обязательной HTTP аутентификацией и вывести данные во внешний скрипт не удастся. Решим таким «костылем»:

Файл result.php

<?
$contents = file_get_contents('http://login:password@yourchannel.tv:8080/flussonic/api/playlist/playlist1');
print $contents;
?>


Получаем ответ вроде такого:

{"current_entry":"liv/c1g.mp4","current_type":"file","duration":null,"position":1739946.5416666667} 


, где нас интересует следующее: current_entry (текущий воспроизводимый медиафайл) и position(позиция по времени в файле).

Приступим к созданию прототипа программы передач с извлечением всех параметров и сравнением с существующими данными:

1) Создаем таблицу базу данных media:

CREATE TABLE IF NOT EXISTS `media` (
`id` int(11) NOT NULL,
  `name` varchar(255) NOT NULL,
  `media` varchar(50) NOT NULL,
  `duration` time NOT NULL,
  `next_duration` varchar(20) NOT NULL,
  `description` text NOT NULL,
  `cc` enum('yes','no') NOT NULL,
  `shedule_time` varchar(20) NOT NULL
) ENGINE=MyISAM AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;


2) Создадим такой листинг программы передач:

Файл data.php

Посмотреть исходник
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>

<?
// путь к файлу с инициализацией к БД
include ('db.php');

$userstable = "media";

$query = "SELECT * FROM $userstable ORDER by id ASC";
$result = MYSQL_QUERY($query);
$number = MYSQL_NUMROWS($result);

$i = 0;

if ($number == 0) {
print "<center><P>Данных по каналу нет..</center>";
} elseif ($number > 0) {
print "<div class=\"container-fluid\"><div class=\"row\"><h4>Программа передач:</h4>";

while ($i < $number)
 {
$namer = mysql_result($result,$i,"name");
$media = mysql_result($result,$i,"media");
$duration = mysql_result($result,$i,"duration");
$description = mysql_result($result,$i,"description");
$shedule_time = mysql_result($result,$i,"shedule_time");


$contents = file_get_contents('http://yourchannel.tv/result.php');
$my_file = 'infotrack.txt';
$pfile = 'playinfo.txt';
$handle = fopen($my_file, 'w') or die('Cannot open file:  '.$my_file);
$data = $contents;
fwrite($handle, $data);

$info = json_decode($contents);
$name = $info->current_entry;
$time = $info->position;

//обрезаем liv/ получаем только название файла с расширением
$fullname = substr($name, 4);

// считаем временную метку в настоящем времени
$second = $time / 1000;

sscanf($duration, "%d:%d:%d", $hour, $minutes, $seconds);

// считаем длительность файла
$ms = $seconds * 1000 + $minutes * 60 * 1000 + $hour * 30 * 60 * 1000;

$ostatok = ($ms - $second);


if ($fullname == $media) {

print "<a href=\"#\" class=\"list-group-item active\" title=\"".$description."\"><h4 class=\"list-group-item-heading\"><span class=\"label label-success\">В эфире!</span> ".$namer."</h4>";


echo "<h4><i class=\"fa fa-play-circle-o\"></i>";
$estimated = gmdate("H:i:s", $second);
echo $estimated;
$elapsed = gmdate("H:i:s", $ostatok-25500);

$conv_total_time = strtotime($duration);
$conv_est_time = strtotime($estimated);
$calc_time = $conv_total_time - $conv_est_time;
$calctime = gmdate("H:i", $calc_time);

$nowtime = time();
$next_time = $nowtime + $calc_time;
$res_time = date("H:i", $next_time);

echo " | <i class=\"fa fa fa-clock-o\"></i> ".$duration." <br><i class=\"fa fa-cc fa-2x\" title=\"Русские субтитры\"></i></h4>";

echo "Осталось до конца: ".$calctime."<br>";
echo "Время начала следующей передачи: ".$res_time."<br>";

print "</a>
  <div class=\"list-group\">
  <div class=\"progress\">
  <div class=\"progress-bar progress-bar-success progress-bar-striped active\" role=\"progressbar\" aria-valuenow=\"100\" aria-valuemin=\"0\" aria-valuemax=\"100\" style=\"width: 100%\"></div></div></div>";
}
else
{
    $conv_duration = strtotime($duration);
    $conv_res_time = strtotime($res_time);
    $res_final_time = $conv_duration + $conv_res_time;
    $res_time2 = date("H:i",$res_final_time+3600);
    print "<div class=\"list-group\"><a href=\"#\" class=\"list-group-item\" title=\"".$description."\">
    <h4 class=\"list-group-item-heading\"><span class=\"label label-default\">".$res_time."</span> ".$namer."</h4>
    <p class=\"list-group-item-text\"><h5>Длительность: ".$duration." <i class=\"fa fa-cc fa-2x\" title=\"Русские субтитры\"></i></h5></a></div>";

}

$i++;
}
print "</center></div></div>";
}
?>




Получаем такой вид:
image

Теперь нам надо сделать, чтобы программа передач обновлялась через определенный промежуток времени (ставим 15 секунд).

Пишем небольшой скрипт:

<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
var jq = $.noConflict();     // для предовращения возможного конфликта со стандартной библиотекой Jquery, используемой в шаблоне сайта 
jq(document).ready(function() {
var auto_refresh = setInterval(function ()
{
jq('#info').load('data.php');
}, 15000); // обновляем каждые 15 секунд
});
</script>
<div id="info">Программа передач загружается, подождите..<br><center><i class="fa fa-refresh fa-spin fa-4x"></i></center></div>  
    </body>  
    </html>  


Пока необходимого функционала хватает, программа передач радует глаза:

image

Буду рад вашему мнению и идеям по модернизации программы передач.

Дополнительная информация:
Серверные плейлисты
Подготовка файла к вещанию
Публикация видео на сервер

Комментарии (5)


  1. vladimir-vg
    30.07.2015 10:49

    Круто, спасибо.


  1. Arahnid
    30.07.2015 12:08

    Жаль, что этот медиасервер не бесплатен


    1. Paul_Nice
      30.07.2015 15:15

      На неделю-другую можно и триал взять.
      А так продукт B2B всё-таки.
      И если использование некоммерческое, то всегда можно договориться, благо разговариваем на одном языке.


      1. Arahnid
        30.07.2015 15:42

        лично для меня триал не актуален, т.к. пользуюсь в личных целях (читать: «для дома»). Но с b2b понятно, любая работа должна оплачиваться и я с этим согласен.

        У меня, кстати, один вопрос остался не закрытым. Я не понял из документации (возможно невнимательно читал), может ли медиасервер Flusonic в качестве источника видео для IPTV брать RTSP-видео поток?
        В сети есть плейлисты, в которых ТВ-каналы представлены не в виде HTTP-стрима, а в виде RTSP.


        1. Paul_Nice
          31.07.2015 00:55

          Из документации следует, что может:
          erlyvideo.ru/doc/description#protocols
          erlyvideo.ru/doc/howto/source.md
          А на счет домашнего использования можно и объяснить ситуацию. Возможно решение и найдется.