Преамбула:
Наклевывался как то один заказик от охранной конторы. Типа забубенить плеер для показа видео с камер наблюдения с возможностью просмотра видео как в режиме он-лайн, так и в офф-лайн. В офф-лайн было все понятно, просто гнать с сервера записанное видео, проблема встала с режимом он-лайн трансляции. У заказчика использовались ip-камеры, которые отдают видео в виде mjpeg-потока и решение проблемы трансляции mjpeg-потока я таки нарыл.
Проблема:
Трансляция mjpeg-потока в flash-приложении.
Решение:
Помощники: flasher.ru, codeproject.com
Прим.: используемый в примере url реальный, можно прям в браузере видео-поток посмотреть.
UPD: Был как то случай с получением mjpeg-потока с камеры которая требовала базовую авторизацию, как это сделать описано в посте Доступ к ресурсам защищенным Basic authentication.
Наклевывался как то один заказик от охранной конторы. Типа забубенить плеер для показа видео с камер наблюдения с возможностью просмотра видео как в режиме он-лайн, так и в офф-лайн. В офф-лайн было все понятно, просто гнать с сервера записанное видео, проблема встала с режимом он-лайн трансляции. У заказчика использовались ip-камеры, которые отдают видео в виде mjpeg-потока и решение проблемы трансляции mjpeg-потока я таки нарыл.
Проблема:
Трансляция mjpeg-потока в flash-приложении.
Решение:
Помощники: flasher.ru, codeproject.com
package { import flash.display.*; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.*; import flash.utils.*; public class VideoMJPEG extends Sprite { private var _stream:URLStream = new URLStream(); private var _loader:Loader = new Loader() private var _buffer:ByteArray; private var _write:Boolean = false; private var _markerDetection:Boolean = false; private var _request:URLRequest = new URLRequest("http://146.176.65.10/axis-cgi/mjpg/video.cgi"); public function VideoMJPEG() { mouseEnabled = false; mouseChildren = false; addEventListener(Event.ADDED_TO_STAGE, onAddedToStage); } private function onAddedToStage(e:Event):void { removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage); addChild(_loader); _stream.load(_request); _stream.addEventListener(ProgressEvent.PROGRESS, onProgress); } private function onProgress(event:ProgressEvent):void { var byte:int; // Если есть доступные байты - обработать их while(_stream.bytesAvailable > 0) { byte = _stream.readUnsignedByte(); if(_write) _buffer.writeByte(byte); if(_markerDetection) { switch(byte) { case 0xD8: _write = true; _buffer = new ByteArray(); _buffer.writeByte(0xFF); _buffer.writeByte(0xD8); break; case 0xD9: _write = false; _buffer.writeByte(0xD9); _loader.loadBytes(_buffer); break; } } _markerDetection = (byte == 0xFF); } } } }
Прим.: используемый в примере url реальный, можно прям в браузере видео-поток посмотреть.
UPD: Был как то случай с получением mjpeg-потока с камеры которая требовала базовую авторизацию, как это сделать описано в посте Доступ к ресурсам защищенным Basic authentication.
Ну перестаньте вы уже так писать!
ОтветитьУдалить_markerDetection = (byte == 0xFF) ? true : false;
Достаточно же!!!
_markerDetection = (byte == 0xFF);
Код взят "as is". Надеюсь Автор данного кода не обидеться если я исправлю сей "не высокохудожественный мазок". Сам я таким макаром тринарный оператор не юзаю, чесс пионерское!
ОтветитьУдалитьСпасибо за наколку!
Зачетный блог, пеши исчо!
ОтветитьУдалитьПодскажи плз, как захваченый поток отрисовать-то? Если можно на мыло_)
ОтветитьУдалитьСпасибо!
В примере есть строчка:
ОтветитьУдалить_loader.loadBytes(_buffer);
собственно в инстансе класса Loader отображается картинка полученная из потока
PS: мыла на которое ты просил написать я не обнаружил в каменте
Прости, мыло и впрямь забыл написать :) Ещё вопрос, что делать если камера не даёт просматривать анонимно, требует залогиниться? URLStream ловит ошибку потока :( Посылать предварительно запрос для аутентификации?
УдалитьДоброго дня!
ОтветитьУдалитьТоже не понял, как выводить поток, даже после вашего комментария :-(
Как там это делается?) Если можно, то на емеил: basstazz [at] yandex.ru
Доброго!
УдалитьА что собственно не понятно? Пример рабочий.
Тут всего лишь делается две операции:
1. сбор байтов для jpg-кадра в буфер ByteArray;
2. загрузка этих байтов в Loader.loadBytes и соотв. отображения этого лоадера на сцене.
Все.
Да суть в том, что сказали, чтобы было сделано.
УдалитьУ меня есть видео-сервер. С вебки по примерам научился передавать данные на сервер, а тут вот непонятно даже, как данные отдавать =( Пытаюсь скрестить аудио с микрофона и вот этот jmpeg поток.
Loader.loadBytes я как понимаю находится внутри класса VideoMJPEG, мне значит нужно принимать эти байты для каждого изображения и передавать их.
Тут пример не как отдавать, а как принимать и отображать MJPEG поток который генерит вебка (в моем случае это была ip-вебка). Если у вас отдельно есть источник mjpeg-потока и отдельно источник аудио потока то дело за малым, грузить их по отдельности с должной синхронизацией, либо замутить свой протокол который бы передавал в поток как видео так и аудио.
УдалитьВесело. А я думал, что тут можно и с помощью вашего примера сделать. Спасибо!
УдалитьЭтот комментарий был удален автором.
ОтветитьУдалитьДобрый день, можно поподробнее как этот код заставить работать? т.е. куда нужно его вставить?
ОтветитьУдалитьВставить можно в ActionScript3-проект, скомпилить, получить swf-файл на выходе и пользоваться :)
УдалитьВкратце как-то так.
Разобрался, скопировал скрипт назвал VideoMJPEG, создал новый проект AS3 там прописал класс VideoMJPEG, скомпилировал в swf и всё заработало!
УдалитьСпасибо!
Пожалуйста, выложи исходник, ничего не показывает - пустой экран :(
УдалитьВ исходнике будет тоже самое, что и в листинге выше. Подставьте реальный адрес айпи камеры транслирующей mjpeg поток и возможно экран не будет пустым.
Удалитьда я подставил, у меня там локальный адрес, "\\3DPLAY-10\htdocs\streem.mjpeg" - это файл, в котором обновляется видеопоток. У меня проблема не в этом. А в понимании как правильно подвязать скрипт к файлу флеша. Мои знания ограничены AS2, и то только на уровне дилетанта. Или может я адрес не правильно прописываю, но когда я его подставляю в компонент UILoader, который просто вытягиваю на первый кадр, то он мне показывает картинку, но естественно статичную, тот кадр, который UILoader подгружает на момент компиляции :(
УдалитьЕсли у вас обновляется файл, то тут скорей всего у вас не потоковое вещание.
УдалитьПроверьте фактический формат этого файла. Скорей всего он окажется простым jpeg-файлом.
Если это так, то случай описанный в этом посте, не ваш.
Решением в вашем случае будет периодическая загрузка файла streem.mjpeg в UILoader или простой Loader.
и да, там не вебка, там прога, которая снимает скриншоты с экрана каждые 10мс, и стримит в файл.
УдалитьВ браузере chrome возникает проблема (при встраивании на страницу). В debug'ре хрома видно в разделе networks такую строку
ОтветитьУдалитьGET (canceled) multipart/x-mixed-replace
хотя в остальных браузерах все нормально, какова проблема?
Спасибо, очень простая реализация. Использую для стриминга видеопотока с Motion (сервер видеонаблюдения), всё прекрасно работает, но у flash-приложения снизилась производительность. Как можно оптимизировать код?
ОтветитьУдалитьПроизводительность в любом случае падает с появлением новой функциональности в приложении. Вопрос насколько и на чем это падение сказывается.
УдалитьКак вариант можно писать бинарные данные в лоадер не на каждый фрейм пришедший из потока, а пропуская N фреймов. Возможно это повлияет на производительность.