loading & playing a mjpeg via flash with as3 - Socket errors

Refresh

November 2018

Views

5.4k time

2

I would like to create a flash MJPEG player so unsupported browsers can view it.

I have tried 2 routes here, one with a urlStream and other with Sockets. I am going with the sockets because it seems to be getting farther.

The MJPEG player will play a camera stream from a remote IP camera. Because the camera is located behind a router, it is on port 8006. I have uploaded a crossdomain.xml file at the root of the camera at that port

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
    <site-control permitted-cross-domain-policies="master-only" />
    <allow-access-from domain="*" to-ports="*" />
</cross-domain-policy>

This is located at h**p://domainofcam.com:8006/crossdomain.xml

Attached you will find my as3 code that I am using. In my flash file I have on frame 1,

Security.loadPolicyFile("xmlsocket:h**p://domainofcam_com:8006/crossdomain.xml"); 
trace("xmlsocket:h**p://domainofcam_com:8006/crossdomain.xml")  
var cam:MJPEG = new MJPEG("h**p://domainofcam.com", "/mjpeg.cgi", 8006);
addChild(cam);

and my MJPEG as3 file is as such:

package 
{
    import flash.display.Loader;
    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.net.URLRequest;
    import flash.net.URLRequestMethod;
    import flash.net.URLRequestHeader;
    import flash.net.URLStream;
    import flash.net.Socket;
    import flash.utils.ByteArray;
    import com.dynamicflash.util.Base64;

    /**
     * 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


        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.addEventListener(IOErrorEvent.IO_ERROR, IOErrorSocket);
            webcamSocket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
            webcamSocket.connect(host, port);

        }

        private function IOErrorSocket(event:IOErrorEvent):void {
                var date:Date = new Date();
                trace(event);
        }

        private function securityError(event:SecurityErrorEvent):void {
            var date:Date = new Date();
            trace(event);
        }

        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");
        }

        function handleData(e:ProgressEvent):void {
            // 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);
        }

    }

}

When I run debug I get the following output:

[IOErrorEvent type="ioError" bubbles=false cancelable=false eventPhase=2 text="Error #2031: Socket Error. URL: h*p://domainofcam.com"] [SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2048: Security sandbox violation: file:///Repository/projects/Surfcam/mjpg/MJPG.swf cannot load data from h*p://domainofcam.com:8006."]

3 answers

3

Я столкнулся с той же проблемой. Раствор при помощи URLStream вместо сокета. Здесь работает исходный код с небольшими изменениями - Я сделал компонент MXML, чтобы использовать его в Flex.

package ru.idecide.olimpstroy
{
    import com.dynamicflash.util.Base64;

    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.HTTPStatusEvent;
    import flash.events.IOErrorEvent;
    import flash.events.ProgressEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.Socket;
    import flash.net.URLLoader;
    import flash.net.URLLoaderDataFormat;
    import flash.net.URLRequest;
    import flash.net.URLRequestHeader;
    import flash.net.URLRequestMethod;
    import flash.net.URLStream;
    import flash.utils.ByteArray;

    import mx.core.IMXMLObject;

    public class  MJPG extends EventDispatcher implements IMXMLObject
    {
        [Bindable]
        public var user:String;                       //Auth user name
        [Bindable]
        public var pass:String;                       //Auth user password
        [Bindable]
        public var host:String;                       //host server of stream
        [Bindable]
        public var port:int = 80;                     //port of stream
        [Bindable]
        public var file:String;                       //Location of MJPEG


        private var start:int = 0;                    //marker for start of jpg

        private var imageBuffer:ByteArray = new ByteArray();  //image holder


        public function MJPG()
        {
            loader = new Loader;
        }

        private var stream:URLStream;

        public function initialized(document:Object, id:String):void
        {
            stream = new URLStream();
            var request:URLRequest = new URLRequest(host + ":" + port.toString() + file);
            request.requestHeaders.push(new URLRequestHeader("Authorization", "Basic " + Base64.encode(user + ":" + pass)));
            configureListeners(stream);
            try {
                stream.load(request);
            } catch (error:Error) {
                trace("Unable to load requested URL.");
            }
        }

        private function configureListeners(dispatcher:EventDispatcher):void {
            dispatcher.addEventListener(Event.COMPLETE, completeHandler);
            dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
            dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            dispatcher.addEventListener(Event.OPEN, openHandler);
            dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
            dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
        }

        private function parseHeader():void {
            trace("parseHeader", "length: " + imageBuffer.length);
            stream.readBytes(imageBuffer, imageBuffer.length)

            while(findImages()){
                //donothing
            }
        }

        private function completeHandler(event:Event):void {
            trace("completeHandler: " + event);
            parseHeader();
        }

        private function openHandler(event:Event):void {
            trace("openHandler: " + event);
        }

        private function progressHandler(event:Event):void {
            trace("progressHandler: " + event);
            parseHeader();
        }

        private function securityErrorHandler(event:SecurityErrorEvent):void {
            trace("securityErrorHandler: " + event);
        }

        private function httpStatusHandler(event:HTTPStatusEvent):void {
            trace("httpStatusHandler: " + event);
        }

        private function ioErrorHandler(event:IOErrorEvent):void {
            trace("ioErrorHandler: " + event);
        }

        private function onLoaded(e:Event):void {
            //var bytes:ByteArray = loader.data;
            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 var loader:Loader;

        private var _bitmapData:BitmapData;

        private function displayImage(image:ByteArray):void
        {
            loader.loadBytes(image);
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete_handler);
        }

        private function loaderComplete_handler(event:Event):void
        {
            if (_bitmapData)
                _bitmapData.dispose();
            _bitmapData = Bitmap(loader.content).bitmapData;
            dispatchEvent(new Event("bitmapDataUpdate"));
        }

        [Bindable(event="bitmapDataUpdate")]
        public function get bitmapData():BitmapData
        {
            return _bitmapData;
        }
    }
}

Я использую это следующим образом:

<fx:Declarations>
<mp:MJPG host=""http://example.com" file="/mjpg/video.mjpg" user="{user}" pass="{password}" id="videoProvider"/>
</fx:Declarations>
<s:BitmapImage source="{videoProvider.bitmapData}" smooth="true" width="100%"/>

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

0

Вы можете попробовать это: https://github.com/alloyking/Foscam-Flex

Надеется быть предназначены для мобильных приложений - Android.

Tim
0

вы вызываете метод неправильно, должно быть, как:

вар кулачковый: MJPEG = новый MJPEG ( "192.168.1.10", «/video.mjpeg",8080);

(Падение ведущего Http: // в хост)