Как отображать видео с IP-камеры с помощью сокета с помощью actionscript?

Пока решение, которое я нашел, требует crossdomain.xml для работы, но это недоступно на IP-камере:

<?xml version="1.0" encoding="utf-8"?>  
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init()">  
    <mx:Script>  
        <![CDATA[  
            import utils.video.mjpeg.MJPEG;  
            public function init():void{  
                Security.loadPolicyFile("xmlsocket:http://10.8.0.54/crossdomain.xml");  
                trace("xmlsocket:http://10.8.0.54/crossdomain.xml")  
                var vid:MJPEG = new MJPEG("10.8.0.54", "", 8081);  
                video.rawChildren.addChild(vid);  
            }  
        ]]>  
    </mx:Script>  
    <mx:VBox id="video"></mx:VBox>  
</mx:Application>  
//////////////////////////  
package  utils.video.mjpeg  
{  
    import flash.display.Loader;  
    import flash.events.Event;  
    import flash.events.ProgressEvent;  
    import flash.net.Socket;  
    import flash.utils.ByteArray;  

    import mx.utils.Base64Encoder;  

    /** 
     * This is a class used to view a MJPEG 
     * @author Josh Chernoff | GFX Complex 
     *  
     */  
    public class  MJPEG extends Loader  
    {  
        private var _user:String;                                   //Auth user name  
        private var _pass:String;                                   //Auth user password  

        private var _host:String;                                   //host server of stream  
        private var _port:int;                                      //port of stream          
        private var _file:String;                                   //Location of MJPEG  
        private var _start:int = 0;                                 //marker for start of jpg  

        private var webcamSocket:Socket = new Socket();             //socket connection  
        private var imageBuffer:ByteArray = new ByteArray();        //image holder  

        /** 
         * Create's a new instance of the MJPEG class. Note that due a sandbox security problem, unless you can place a crossdomain.xml  
         * on the host server you will only be able to use this class in your AIR applications. 
         *  
         * @example import MJPEG; 
         *          var cam:MJPEG = new MJPEG("192.168.0.100", "/img/video.mjpeg", 80); 
         *          addChild(cam); 
         *           
         * @param   host:String | Host of the server. Do not include protocol  
         * @param   file:String | Path to the file on the server. Start with a forward slash 
         * @param   port:int    | Port of the host server; 
         * @param   user:String | User name for Auth 
         * @param   pass:String | User password for Auth 
         */  
        public function MJPEG (host:String, file:String, port:int = 80, user:String = null, pass:String = null )  
        {  
            _host = host;  
            _file = file;  
            _port = port;  
            _user = user;  
            _pass = pass;  

            webcamSocket.addEventListener(Event.CONNECT, handleConnect);  
            webcamSocket.addEventListener(ProgressEvent.SOCKET_DATA, handleData);  
            webcamSocket.connect(host, port);  

        }  

        private function handleConnect(e:Event):void   
        {  
            // we're connected send a request  
            var httpRequest:String = "GET "+_file+" HTTP/1.1\r\n";  
            httpRequest+= "Host: localhost:80\r\n";  
            /*  
            if(_user != null && _pass != null){ 
                            var source:String = String(_user + ":" + _pass); 
                            var auth:String = Base64.encode(source); 
                            httpRequest += "Authorization: Basic " + auth.toString()+ "\r\n";   //NOTE THIS MAY NEEED TO BE EDITED TO WORK WITH YOUR CAM 
            } 
             */  
            httpRequest+="Connection: keep-alive\r\n\r\n";  
            webcamSocket.writeMultiByte(httpRequest, "us-ascii");  
        }  

        private function handleData(e:ProgressEvent):void {  
            //trace("Got Data!" + e);  
            // get the data that we received.  

            // append the data to our imageBuffer  
            webcamSocket.readBytes(imageBuffer, imageBuffer.length);  
            //trace(imageBuffer.length);  
            while(findImages()){  
            //donothing  
            }  


        }  


        private function findImages():Boolean  
        {  

            var x:int = _start;  
            var startMarker:ByteArray = new ByteArray();      
            var end:int = 0;  
            var image:ByteArray;  

            if (imageBuffer.length > 1) {  
                if(_start == 0){  
                    //Check for start of JPG  
                    for (x; x < imageBuffer.length - 1; x++) {  

                        // get the first two bytes.  
                        imageBuffer.position = x;  
                        imageBuffer.readBytes(startMarker, 0, 2);  

                        //Check for end of JPG  
                        if (startMarker[0] == 255 && startMarker[1] == 216) {  
                            _start = x;  
                            break;                    
                        }  
                    }  
                }  
                for (x; x < imageBuffer.length - 1; x++) {  
                    // get the first two bytes.  
                    imageBuffer.position = x;  
                    imageBuffer.readBytes(startMarker, 0, 2);  
                    if (startMarker[0] == 255 && startMarker[1] == 217){  

                        end = x;  

                        image = new ByteArray();  
                        imageBuffer.position = _start;  
                        imageBuffer.readBytes(image, 0, end - _start);  

                        displayImage(image);  

                        // truncate the imageBuffer  
                        var newImageBuffer:ByteArray = new ByteArray();  

                        imageBuffer.position = end;  
                        imageBuffer.readBytes(newImageBuffer, 0);  
                        imageBuffer = newImageBuffer;  

                        _start = 0;  
                        x = 0;  
                        return true;  
                    }  
                }  
            }  

            return false;  
        }  

        private function displayImage(image:ByteArray):void  
        {  
            this.loadBytes(image);  
        }  

    }  

}  

person ollydbg    schedule 03.10.2010    source источник


Ответы (1)


Может быть, я не понимаю вашего вопроса, но если мы говорим об одном и том же...

В моей флэш-памяти (которая была написана в AS2, поэтому вам, возможно, придется посмотреть, чем она отличается от AS3, я заметил, что вы не используете класс безопасности System... возможно, они удалили его), у меня есть эта строка. .

System.security.loadPolicyFile("xml_root.socket://" + _root.HOST + ":" +_root.GAME_PORT );

Я почти уверен, что это просто достает статический файл crossdomain.xml из docroot моего сервера.

На стороне сервера ваш код сокета (на чем он написан?) может напрямую доставлять междоменную политику.

Вот фрагмент моего Perl-сокета, который отвечает на первоначальный запрос flash-сокета. Я написал это давным-давно, но оказалось, что сокет отправляет этот крошечный фрагмент xml в качестве своего первоначального сообщения сокету «‹policy-file-request/›», в ответ на который вы хотите сделать следующее...

if($input eq "<policy-file-request/>"){ #if the string arriving on the socket == <policy-file-request>"

  #assemble the printed response to look just like a crossdomain policy file. Set permissions as you normally would.
  #if you don't know perl, the qq~ is just a way to provide a chunk of multiline code in one fragment.  But note the \0 at the end. All socket messages have to be null terminated manually by you.
  $MESSAGE =      qq~<?xml version="1.0"?>
                      <cross-domain-policy>
                      <allow-access-from domain="*" to-ports="*"/>
                      </cross-domain-policy>\0~;
}
print "$MESSAGE"; #send the string back on the socket

Убедитесь, что это действительно то, что вам нужно. Иногда все, что вам нужно, это чтобы сервер просто располагал файлом политики crossdomain.xml в корневом каталоге документа.

person Yevgeny Simkin    schedule 03.10.2010
comment
Но я не контролирую серверную часть, это внутренняя часть самой IP-камеры. - person ollydbg; 03.10.2010
comment
Ах. Я вижу сейчас. Мне пришлось поискать, что такое IP-камера... никогда раньше не слышал такого выражения. Я думаю, что самый простой способ справиться с этим - создать реле через сервер и подключить к нему ваш флэш-сокет. Пусть это говорит с камерой через другой порт сокета, так что... IP-камера -> сокет сервера -> Flash. Серверный сокет не заботится о безопасности, он может общаться с камерой и может обеспечить необходимую безопасность Flash. Предполагая, что ваша IP-камера находится в той же сети, что и ваш компьютер, вы можете легко запустить на ней сокет. - person Yevgeny Simkin; 03.10.2010
comment
Почти как USB-камеры, но доступ к ним можно получить по URL-адресу. - person ollydbg; 03.10.2010