VLC Player: Удаленное управление с помощью связки PHP и Telnet. Настройка Video-on-Demand.

Сто лет назад я писал небольшой цикл по настройке файлопомойки под Linux’ом, тогда же обмолвился о том, что хочу прикрутить внутри сети потоковое видео. Потом как-то идея сошла на нет и заглохла, а вот сейчас вновь стала актуальной, в связи с чем погрузился в дебри изучения проблемы.

Сразу отмечу, что в качестве streaming server был выбран великий и ужасный VLC, который от релиза к релизу обрастает функциональностью и регулярно апдейтится. Я допускаю, что есть более интересные варианты или даже готовые out-of-the-box решения, но легких путей мы как обычно не ищем.

Схема работы всей связки VOD должна выглядеть примерно следующим образом:
> есть fronend — обычная веб-страница с индексом всех фильмов, которые доступны на файлопомойке;
> VLC настроен на управление по интерфейсу telnet и вещание по протоколу RTSP;
> при клике по названию ссылки front-end коннектится к VLC по telnet
> и посылает последовательность команд для создания нового VOD (Video-on-Demand) контейнера;
> после чего можно подсовывать RTSP линк плееру на другом конце и смотреть видео.

Прелесть VLC — в кроссплатформенности, поэтому решение будет работоспособно как под Windows, так и под Linux 🙂

Запуск VLC с telnet интерфейсом

vlc -vvv —color —ttl 2 -I telnet —telnet-port port —telnet-password password —telnet-host host_ip —rtsp-host 0.0.0.0:rtsp_port

—color подстветка уведомлений, ошибок и прочей полезной для дебага информации в терминале;
-I telnet собственно запуск telnet интерфейса;
—telnet-port port порт, на котором слушаются telnet подключения;
—telnet-password password пароль к telnet’у;
—telnet-host host_ip адрес интерфейса, на котором слушаются telnet подключения;
—rtsp-host host_ip:rtsp_port адрес интерфейса для RTSP трафика и порт;

—rtp-client-port=port_number вот эта опция позволяет в явном виде указать по какому порту пойдет трафик между клиентом и сервером, и соответственно решит проблему с фаерволами.

А вот замечательное чтиво про RTSP: http://soundscreen.com/streaming/firewall.html Для корректной работы протокола нужно довольно много открытых портов, что может стать проблемой при работе с NAT и фаерволами.

Создание VOD-контейнера в VLC

Создать VOD-контейнер в VLC не сложно. После подключения к VLC по telnet, достаточно выполнить следующую последовательность команд:
new title vod #title – название VOD контейнера, к нему мы будем обращаться клиентом
setup title input «media_path» #полный путь к файлу с видео
setup title mux mp2p #трафик инкапсулируется в MPEG Program Stream (PS)
setup title enabled #делаем VOD контейнер fактивным, теперь к нему можно подключаться по следующей сслыке rtsp://vlc_vod_server_address:rtsp_port/title
Вообще для передачи MPEG трафика по сети должен использоваться MPEG Transport Stream (TS) — опция mux mp2t, но по непонятной причине он отказался работать, а вот PS — нет.

Frontend для управления VLC  через Telnet

Для управления VLC через Telnet я написал маленький фронтэнд на PHP, использующий для подключения pfsockopen().

<!--?php
/*
VLC Over Telnet
*/
 
	$char = "\xA";
	$telnet_header=chr(0xFF).chr(0xFB).chr(0x1F).chr(0xFF).chr(0xFB).chr(0x20).chr(0xFF).chr(0xFB).chr(0x18).chr(0xFF)._
chr(0xFB).chr(0x27).chr(0xFF).chr(0xFD).chr(0x01).chr(0xFF).chr(0xFB).chr(0x03).chr(0xFF).chr(0xFD).chr(0x03).chr(0xFF)._
chr(0xFC).chr(0x23).chr(0xFF).chr(0xFC).chr(0x24).chr(0xFF).chr(0xFA).chr(0x1F).chr(0x00).chr(0x50).chr(0x00).chr(0x18)._
chr(0xFF).chr(0xF0).chr(0xFF).chr(0xFA).chr(0x20).chr(0x00).chr(0x33).chr(0x38).chr(0x34).chr(0x30).chr(0x30).chr(0x2C)._
chr(0x33).chr(0x38).chr(0x34).chr(0x30).chr(0x30).chr(0xFF).chr(0xF0).chr(0xFF).chr(0xFA).chr(0x27).chr(0x00).chr(0xFF)._
chr(0xF0).chr(0xFF).chr(0xFA).chr(0x18).chr(0x00).chr(0x58).chr(0x54).chr(0x45).chr(0x52).chr(0x4D).chr(0xFF).chr(0xF0);
 
	//call this to esteblish telnet connection to host on a specified port
	function Connect($server,$port,$pass) {
		global $fp;
		global $telnet_header;
		$fp=pfsockopen($server,$port);
		fputs($fp,$telnet_header);
		sleep(2);
		fputs($fp,$pass."\xA");
		return;
	}
 
	//if you need a complete telnet output, even after logout
	//use this function after Disconnect function abd use fclose($fp) after
	function GetResponce() {
		global $fp;
		$output=fread($fp,128);
		$stat=socket_get_status($fp);
		$output.=fread($fp, $stat["unread_bytes"]); 
 
		$output = explode("\n", $output);
		unset($output['0']);
		$output = implode("\n", $output); 
 
		$output = str_replace("\n", "
", $output);
		return $output;
 
	}
 
	//call this to properly log out from vlc telnet and close session
	function Disconnect() {
		global $fp;
		fputs($fp,"quit\xA");
		sleep(1);
		fclose($fp);
		$fp = null;
		return;
	}
 
	//call this to add a new vod container and setup it
	function AddMovie($vodname,$filepath) {
		global $fp;
		fputs($fp,"new ".$vodname." vod\xA");
		fputs($fp,"setup ".$vodname." input '".$filepath."'\xA");
		fputs($fp,"setup ".$vodname." mux mp2p\xA");
		fputs($fp,"setup ".$vodname." enabled\xA");
		sleep(1);
		return;
	}
 
	function DeleteMovie($vodname) {
		global $fp;
		fputs($fp,"del ".$vodname."\xA");
		sleep(1);
		return;
	}
 
	function ShowVODs() {
		global $fp;
		fputs($fp,"show\xA");
		sleep(1);
		return;
	}
 
?-->

Собственно код предельно прост и, полагаю, в особых комментариях не нуждается. Для соединения с VLC сначала вызывается функция Connect(), которой передаются адрес сервера, порт подключения и пароль, после чего ему можно передать необходимую последовательность команд. В моем случае, за это отвечает функция AddMovie(), которой в качестве аргументов передается название контейнера и путь к видеофайлу.
Каждая последовательность команд, переданных на сервер, должна завершаться управляющим символом перевода строки, то есть ‘\xA’ (по ссылке можно ознакомиться с другими управляющими символами: http://www.cs.tut.fi/~jkorpela/chars/c0.html).
Таким же образом, после вызова Connect(), можно вызвать DeleteMovie(), команде передается название VOD-контейнера.
В целях отладки, была еще написана функция GetResponse(), которая возвращает содержимое telnet сессии.
Последовательность функций, для взаимодействия с VLC завершается функцией Disconnect(), которая посылает VLC команду закрытия telnet сессии, а потом убивает сокет.

Ссылка, которая содержит параметры нового VOD-контейнера имеет следующий вид:
http://server_address/?add=createvod&vodname=name_of_the_vod_container&filepath=’absolute_path_to_video_path’
А следующий код обрабатывает указанный линк, забирает из него необходимые переменные и вызывает функции. Аналогичный код отвечает за удаление VOD-контейнеров с сервера. Разница только в том, что в качестве параметра, забирается только название VOD-контейнера.

	if ($_GET['add']="createvod") {
		$vodname=$_GET['vodname'];
		$filepath=$_GET['filepath'];
		$_GET['run'] = NULL;
		Connect($server,$port,$pass);
		AddMovie($vodname,$filepath);
		echo GetResponce()."<hr />";
		Disconnect();
		}

Полезные ссылки по теме:
Streaming How-To
Advanced streaming using the command line
Руководство пользователя VLC. Интерфейс командной строки

И плюс в качестве дополнения несколько инструментов, на которые я наткнулся в процессе работы над frontend:
> KpyM Telnet / SSH server http://www.kpym.com/2/kpym/index.htm
К сожалению в логах VLC telnet-сессия подробно не протоколируется, в лог идет только информация об открытии сокета, поэтому для отладки скрипта использовал этот сервер. Ну и плюс можно рулить Windows через консольку 😀
> Dokan SSHFS http://dokan-dev.net/en/
Утилита позволяет подмонтировать файловую систему *nix в качестве виртуального жесткого диска Windows с помощью SFTP. Обычно для переброса инфы на *nix машины я использую WinSCP, но вот понадобилось подмонтировать папку, а такого функционала не оказалось, так что использовал этот костыль. Во всех *nix системах это реализовано нативно и грамотно с помощью sshfs.

Оставить комментарий