![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Чем разделить видеопоток? [D7, WinXP]
ABolnykh © (2009-10-06 15:25:00)Здравствуйте, уважаемые Мастера!
Кто-нибудь может подсказать направление решения следующей задачи?
Имеется сетевая видеокамера со встроенным web-сервером.
Когда к видеокамере подключается клиент, она начинает транслировать на его IP свой видеопоток.
Когда к камере подключается второй клиент, она начинает транслировать свой видеопоток (тот же самый) и на его IP тоже.
Когда к камере подключается десятый клиент, суммарное количество идентичных видеопотоков становится равно десяти.
А если таких камер в сети - десятка полтора... Затык сети очевиден.
Стоит задача: разработать некоторый дивайс (компьютер с программой с неким компонентом), в котором между видеокамерой и этим компонентом существовал бы один видеопоток, а уже этот компонент рассылал бы этот видеопоток всем подключившимся клиентам.
Видеокамеры находятся в одной сети, клиенты - в другой.
Прочитав "Глубины Indy", я, по простоте душевной, в качестве искомого компонента выбрал TIdMappedPort, посчитав, что на каждое подключение он, по умолчанию, самостоятельно создаст отдельный поток (Thread), что и требуется.
Каково же было моё удивление, когда, написав пробный кусок программы и подключив через TIdMappedPort к камере трёх клиентов, а потом запросив лог видеокамеры, я обнаружил, что к камере подключены ТРИ клиента, а не один, как я ожидал. То есть, TIdMappedPort просто смаппировал обращённые к нему запросы к адресу камеры, а потоки же (Threads) если и создал для каждого подключения, то потоки обработки кода, а не видеопотоки. То есть, выбранный мною подход оказался неверным.
Полазав как следует по Интернету в поисках ответа на вопрос, как же всё-таки люди решают подобную проблему, ничего не нашёл. :-( А судя по тому, что "видеонаблюдательные" программы сейчас плодятся, как грибы, проблема должна иметь простое или несложное решение.
Может быть, кто-нибудь сталкивался с подобной задачей и может посоветовать если не готовый компонент, то хотя бы направление, в котором следует копать. Буду благодарен за любые наводящие мысли и советы.
Пишу на Delphi 7, Indy 9.
DVM (2009-10-22 13:23:00) [1]В коде выше /jpeg.cgi это виртуальный путь, по которому вебсервер должен понять что от него хотят картинку, а параметр channel - определяет с какой камеры картинку.
DVM (2009-10-22 13:21:00) [2]
> ABolnykh ©
Ты научился получать отдельные кадры.
Теперь научи TIDHTTPServer отдавать эти отдельные кадры по запросу, не надо пока формировать MJPEG поток.
И все уже будет работоспособно более-менее. И смотреть тогда можно в браузере с пом например такого кода:
JavaScript
var ch=1;
errorimg = 0;
function LoadImage() {
uniq = Math.random();
document.images.webcam1.src = " http://127.0.0.1:80/jpeg.cgi?channel=" + ch + "&uniq=" + uniq;
document.images.webcam1.onload = DoIt;
}
function ErrorImage() {
errorimg++;
if (errorimg > 3) {
document.images.webcam1.onload = "";
document.images.webcam1.onerror = "";
document.images.webcam1.src = " http://127.0.0.1:80/images/failure.gif";
} else {
uniq = Math.random();
document.images.webcam1.src = " http://127.0.0.1:80/jpeg.cgi?channel=" + ch + "&uniq=" + uniq;
}
}
function DoIt()
{
errorimg = 0;
window.setTimeout("LoadImage();", 40);
}
Просмотр видео (JavaScript)
Получится подобие видео.
DVM (2009-10-22 13:09:00) [3]
> ABolnykh © (22.10.09 11:36) [40]
> DVM, огромное Вам спасибо за полезные советы!
Не за что.
> Кстати, Вам приходилось иметь дело с компонентом TVideoGrabber
Давным давно, когда он был вроде бесплатный и с исходниками даже чуть-чуть я его изучал, в частности смотрел как там был сделан детектор движения (точнее активности, не знаю остался ли он там), мне не понравилось, ибо было медленно и на этом мое с ним знакомство закончилось.
> Так чего делать-то, как жить дальше?
Если хочешь транслировать через UDP, да еще мультикастом, то тебе придется либо изобретать свой протокол, либо обратить свой взор на связку RTSP/RTP/RTCP.
А чтобы смотреть это дело через браузер, надо для браузера писать либо JavaApplet, либо FlashPlayer, либо QuickTime, либо ActiveX компонент (только для IE) или Silverlight компонент, который будет принимать поток в нужном формате. Сам браузер ясное дело не умеет.
Из браузеров только FireFox умеет принимать и показывать MJPEG over HTTP без всяких дополнений.
Я тебе потому и советую безо всяких мультикастов и UDP для начала обойтись. Это проще в реализации как на сервере так и на клиенте.
Сергей М. (2009-10-22 12:58:00) [4]Для передачи потокового видео используются ряд сетевых протоколов, из которых важнейшими являются протокол RTSP и протокол IGMP.
RTSP (Real-Time Streaming Protocol) - это протокол, с возможностью контролируемой передачи видео-потока в интернете. Протокол обеспечивает пересылку информации в виде пакетов между сервером и клиентом. При этом получатель может одновременно воспроизводить первый пакет данных, декодировать второй и получать третий.
Протокол из этой же группы RTP (Real-time transport protocol) определяет и компенсирует потерянные пакеты, обеспечивает безопасность передачи контента и распознавание информации. Вместе с RTP работает протокол RTCP (Real-Time Control Protocol). Он отвечает за проверку идентичности отправленных и полученных пакетов, идентифицирует отправителя и контролирует загруженность сети.
Для присоединения к сети или выхода из группы рассылки используется стандартный протокол IGMP (Internet Group Membership Protocol).
Сергей М. (2009-10-22 12:49:00) [5]Для этого каст-сервер и каст-клиент должны взаимодействовать по единому известному обоим прикладному потоковому протоколу.
А что у тебя за протокол используется - ты и сам поди не знаешь)
ABolnykh (2009-10-22 12:44:00) [6]
> Сергей М. © (22.10.09 11:52) [41]
>
> Браузер понятия не имеет что делать с поступающими оттуда данными, ибо udp не является протоколом прикладногго уровня.
Похоже, что так. :-(
Так чего делать-то, как жить дальше? Есть какой-нибудь способ отобразить смультикасченные данные?
Сергей М. (2009-10-22 11:52:00) [7]
> ввожу
> udp://224.0.0.1:10500
> получаю "The page cannot be displayed".
Браузер понятия не имеет что делать с поступающими оттуда данными, ибо udp не является протоколом прикладногго уровня.
VideoGrabber тоже понятия не имеет, но пытается интерпретировать их в соответствии известнымиему прикладными потоковыми протоколами. Соответствия не обнаруживает, потому и не рисует картинку.
ABolnykh (2009-10-22 11:36:00) [8]DVM, огромное Вам спасибо за полезные советы!
Специалист ТАКОГО уровня в тяжкую и голодную годину без персонального бутерброда с красной икрой уж точно не останется!
Но собственную шишку нужно набивать самостоятельно, отрицательный опыт - это тоже опыт, хотя бы для того, чтобы в будущем знать, как не надо делать, и потому желательно все плюсы и минусы увидеть своими глазами.
Поэтому, прикинув мышь к носу, я для начала решил избрать следующую последовательность действий:
1. Запрашиваю от камеры 1 кадр видеопотока по HTTP;
2. Копирую его в буфер.
3. Мультикастю буфер процедурой SendBuffer MCast-сервера на групповой адрес 224.0.0.1, порт 10500.
4. Даю задержку на 100 мс.
5. Перехожу на шаг 1.
Какой-то поток от меня начинает исходить, я вижу его трафик в окошке DUMeter-а.
Теперь очередной идиотский вопрос: как мне этот поток принять и отобразить? Если в строке адреса Internet Explorer-а я ввожу
udp://224.0.0.1:10500
то неизменно получаю "The page cannot be displayed".
Если пытаюсь поймать поток ВидеоГраббером, устанавливая его свойство
IpCameraUrl на тот же групповой адрес и порт, то тоже не получаю никакой картинки. :-(
Кстати, Вам приходилось иметь дело с компонентом TVideoGrabber (www.datastead.com)? Можете сказать про него что-нибудь хорошего или плохого?
DVM (2009-10-21 13:12:00) [9]
> > И потом: где задавать частоту обновления? В команде
> > http:///axis-cgi/mjpg/video.cgi?nbrofframes=1&fps=7
> > ???
>
> fps и есть частота обновления. Частоту обновления лучше
> всего задавать в пути.
Только в данном случае (nbrofframes=1) задание fps=7 бессмысленно, т.к. кадр один. Если бы nbrofframes=10, тогда при fps=5 мы получили бы все кадры за 2 секунды, а так бессмсленно. Задание в пути fps имеет смысл только для потоков видео, а не для одиночных кадров. Для одиночных надо фпс задавать на принимающей стороне, т.е. выполнять запросы к камере через нужные промежутки времени.
DVM (2009-10-21 12:57:00) [10]
> ABolnykh © (21.10.09 11:05) [37]
> http:///axis-cgi/mjpg/video.cgi?nbrofframes=_____?
>
> А если каждый раз запрашивать по одному кадру (nbrofframes=1),
> то, опять же, непонятно, зачем искать границу кадра?
Когда я все писал, параметра nbrofframes несуществовало и я им не пользуюсь.
Если брать по одному кадру то проще будет вообще так:
http:///axis-cgi/jpg/image.cgi
Камера пришлет один единственный JPEG кадр. И никакаих --myboundary !!!
Когда нужен будет еще один, надо обратиться еще раз к камере. Паузу между обращениями можете регулировать сами, тем самым получите желаемый фпс.
> и заканчивающегося какими-то хитрыми двоичными данными,
> - копируй его в буфер и мультикасть!
Это JPEG данные. Начинаются и заканчиваются маркерами FFD8 и FFD9 соответственно.
> И потом: где задавать частоту обновления? В команде
> http:///axis-cgi/mjpg/video.cgi?nbrofframes=1&fps=7
> ???
fps и есть частота обновления. Частоту обновления лучше всего задавать в пути.
> И опять же: если мы запрашиваем у камеры "в лоб" 7 кадров
> в секунду, получаем каждый раз по 1 кадру и тут же их мультикастим
> - зачем нам самим формировать Sleep?
Потому что возможности клиентов/сети камеры часто расходятся с желаниями/потребностями. В идеальных условиях локальной сети может и можно так как ты описал, но в условиях Интернет вряд ли.
Начнутся затыки, расхождения, в результате все начнет отставать и т.д.
> DVM, какой населённый пункт нашей необъятной планеты
(с) рядом с моим ником нажми.
ABolnykh (2009-10-21 11:05:00) [11]Несколько проясню подробности нашего текущего техзадания.
Пока мы не волшебники, а только учимся, и потому решили сами несколько упростить себе ситуацию. А именно:
- камеры используем ТОЛЬКО Axis 207, потому возможная чехарда с несовпадением возможностей различных камер отпадает сама собой;
- все операторы смотрят картинку в одинаковом разрешении;
- аналогично - никакого волюнтаризма со стороны клиентов в вопросе самостоятельного выбора частоты кадров изображения (что тебе дали - то и смотри; чай, не у себя дома сидишь :-) );
- никаких дополнительных функций на ретранслятор, в целях упрощения задачи, не возлагаем;
- никакого прямого обращения операторов к видеокамерам не допускается. Если диспетчер (человек) захочет зачем-то напрямую обратиться к видеокамере (посмотреть лог, установить часы, прописать юзера etc.), для этих целей предусматриваем прямой доступ к камерам через TIdMappedPortTCP. Через них же будем посылать камере и все дополнительные команды, не связанные с трансляцией видеопотока.
Клиентскую часть (программу для операторов) тоже пишем самостоятельно, и поскольку тоже не волшебники, все основные приёмно-отображательные функции решили возложить на лицензионно-покупной компонент TVideoGrabber. (Кстати, вопрос ретрансляции потока мы тоже попробовали возложить на него. Как ни странно, но работает (!), правда ОБАЛДЕННО грузит процессор: ретрансляция подключения ОДНОГО клиента (127.0.0.1) к ОДНОЙ видеокамере, подключенной к своей же сетевой карте, занимает примерно 65-70% процессорного времени моего P4 Celeron 2400 MHz. Плюс ко всему - огромная, секунд в 15-20, задержка отображения происходящего.)
DVM,ещё раз: ОГРОМНОЕ ВАМ СПАСИБО ЗА ЦЕННЫЕ СОВЕТЫ И КОНСУЛЬТАЦИИ!!!
И очередная порция идиотских вопросов.
Как я понял, частоту обновления (frames per second) Вы рекомендуете выбирать = 7 - исходя из условия достаточности этого значения для наблюдения за происходящим. Я-то спрашивал, какой размер потока лучше задавать при подключении в команде
http:///axis-cgi/mjpg/video.cgi?nbrofframes=_____?
А если каждый раз запрашивать по одному кадру (nbrofframes=1), то, опять же, непонятно, зачем искать границу кадра? Камера и так прислала один кадр, , начинающейся с "--myboundary, Content-Type" и заканчивающегося какими-то хитрыми двоичными данными, - копируй его в буфер и мультикасть! И потом: где задавать частоту обновления? В команде
http:///axis-cgi/mjpg/video.cgi?nbrofframes=1&fps=7 ???
И опять же: если мы запрашиваем у камеры "в лоб" 7 кадров в секунду, получаем каждый раз по 1 кадру и тут же их мультикастим - зачем нам самим формировать Sleep? Сам TVideoGrabber разве не способен правильно (во времени) отобразить полученное?
Кстати, DVM, какой населённый пункт нашей необъятной планеты Вы осчастливили, избрав местом своего проживания и творения? Если ответ на этот вопрос каким-то образом нарушает правила этого форума, можно ответить мне в личном сообщении.
DVM (2009-10-20 16:04:00) [12]Кстати, раз уж речь зашла о функциях ретранслятора. Ретранслятор должен уметь работать в обе стороны. Т.е. не только передавать видеопоток от камер клиентам, но и передавать команды клиентов камерам (например PTZ команды ил управление выходами DIO и т.д.)
Fr0sT (2009-10-20 15:57:00) [13]> [32] Сергей М. © (20.10.09 15:42)
Ок, точку зрения понял
> [34] DVM © (20.10.09 15:49)
Ага, вот оно что, на ретранслятор уже накладываются дополнительные функции! Тогда действительно, придётся разбирать.
DVM (2009-10-20 15:49:00) [14]
> Fr0sT (20.10.09 15:10) [29]
Дело в том что скорость на участке камера - ретранслятор может быть выше чем скорость на участке ретранслятор - клиент и куда девать тогда лишние кадры. Их из потока не выкинешь просто так. А если пытаться в таких условиях отдать все что прислала камера то получится отставание изображения которое все более будет нарастать и занимать память (куда кадры то девать).
Кроме этого отдельные клиенты могут захотеть принимать с меньшей частотой кадров изображение или другого размера и т.д. тут вариантов масса поэтому лучше ретранслировать собирая поток самому.
Еще разные модели камер могут транслировать по разному устроенный поток а для клиента лучше чтобы он был единообразным, так лучше если ретранслятор будет адаптирован под разного вида потоки чем клиент.
DVM (2009-10-20 15:44:00) [15]
> ABolnykh © (19.10.09 14:06) [28]
> Какое количество кадров можно считать оптимальным при приёме
> потока
Я считаю оптимальной 7 кадров в секунду. Это же все таки наблюдение за ситуацией а не кинофильм. Есть конечно маньяки которые с пеной у рта доказывают что надо 25, но сами не могут отличить 15 от 25 когда им показываешь.
> а с другой стороны - не слишком раздувать буфер потока
А у меня лично буфер всего на один кадр. Один буфер в один кадр на одну камеру. Камера обновляет буфер, клиенты получают обновления буфера.
> и чем (как) формировать задержку между отправкой кадров?
Формировать то ее можно банальным Sleep() но с расчетом ее мне пришлось повозиться.
> Как только получил и выделил очередной кадр - сразу смультикастил
> его во вторичную сеть, и не надо формировать никаких задержек.
>
Еще раз повторю, не надо копить кадры. Достаточно всегда иметь один кадр последний, его и шлем клиентам.
> и потом - куда воткнуть процедуру нахождения "--myboundary"
> в
> try http.get (url, stream);
С пом TIdHTTP можно получить только отдельный кадр (камеры аксис кстати могут отдавать и покадрово а не потоком). Отдельными кадрами тоже выход, правда несколько более грузит ПК и камеру. Для принятия потока лучше брать TidTCPClient (или как он там называется). Я вообще на чистых сокетах делал без обертки (пример разбора потока есть в коде ZoneMinder в файле remote_camera.c ).
Сергей М. (2009-10-20 15:42:00) [16]Потому что TCP подразумевает гарантию доставки (квитирование) , что делает его ощутимо медленнее протоколов без квитирования, что, в свою очередь, может быть не приемлемым для доставки поточных данных клиентам с оч узким каналом доступа.
Fr0sT (2009-10-20 15:36:00) [17]Почему?
Сергей М. (2009-10-20 15:28:00) [18]
> разве нельзя просто его ретранслировать всем подключившимся
> клиентам?
>
Ретрансляция по TCP может быть неприемлемой
Fr0sT (2009-10-20 15:10:00) [19]Очень интересная тема, особенно в предчувствии того, что мне тоже предстоит делать нечто подобное. Возник вопрос: зачем влезать внутрь потока, разве нельзя просто его ретранслировать всем подключившимся клиентам?
ABolnykh (2009-10-19 14:06:00) [20]
> DVM © (08.10.09 17:03) [16]
>
> Задача не так проста, как кажется. Просто тупо ретранслировать поток не выйдет, поток нужно принять, выделить кадры, затем собрать аналог потока. который транслировать клиенту.
>
> Работа ретранслятора грубо говоря выглядит следующим образом.
>
> 1) Ретранслятор подключается к камере по HTTP и начинает принимать видеопоток.
> 2) Выделяет очередной кадр (как разделены кадры в потоке см на сайте аксис HTTP API)
> 3) После того как кадр выделен, мы его откладываем в некий буфер, затирая предыдущий.
> 4) Продолжаем принимать входящий поток, обновляя наш буфер.
> 5) Тут к ретранслятору подключается очередной клиент.
> 6) Выдаем клиенту заголовок в соответствии с Axis HTTP API
> 7) Начинаем высылать клиенту кадры, отделяя их друг от друга разделителями. Кадры берем из буфера. Между кадрами делаем паузы чтобы поддерживать нужную частоту кадров, которую например клиент может передать нам в запросе. Кадровый буфер причем должен быть потокобезопасный.
> 8) Аналогично для второго третьего нн-ого клиентов.
> 9) Кроме этого следует наверное отключаться от камеры если клиентов нет.
>
> В двух словах не расскажешь, т.к. каждый шаг здесь отдельная длинная история.
[b]DVM[/b], ОГРОМНОЕ СПАСИБО ЗА ТАКОЙ ДЕТАЛЬНО ПРОРАБОТАННЫЙ "БИЗНЕС-ПЛАН"!
И ещё парочка вопросов.
Какое количество кадров можно считать оптимальным при приёме потока (чтобы, с одной стороны, не было эффекта "дёрганья" от частого переподключения к камере, а с другой стороны - не слишком раздувать буфер потока), и чем (как) формировать задержку между отправкой кадров?
В идеале, конечно, было бы задать количество кадров = 0 (unlimited), тогда бы и все вопросы отпали. Как только получил и выделил очередной кадр - сразу смультикастил его во вторичную сеть, и не надо формировать никаких задержек. Но сразу встаёт вопрос переполнения потока при круглосуточном видеонаблюдении, и потом - куда воткнуть процедуру нахождения "--myboundary" в
try http.get (url, stream);
finally http.free;
end;