agsh / onvif

ONVIF node.js implementation
http://agsh.github.io/onvif/
MIT License
692 stars 234 forks source link

Speed improvements? #224

Closed rodrigograca31 closed 2 years ago

rodrigograca31 commented 2 years ago

Hi!

I've noticed it takes 1-2 seconds for the commands to take effect....

Lets say thats because the video isnt instantaneous or some other performance issue.... I still would like to ask that we replace xml2js with a more up-to-date library. Its 2+ years outdated.

Here is an alternative: https://github.com/NaturalIntelligence/fast-xml-parser

is there other ways we can improve the speed of the PTZ commands? maybe some camera settings? 🤔

chriswiggins commented 2 years ago

Have you timed which commands take a while to run inside the library? I'd doubt the XML parser is the bottleneck?

agsh commented 2 years ago

@rodrigograca31 Yes, please check your network lags to the device

rodrigograca31 commented 2 years ago

Have you timed which commands take a while to run inside the library? I'd doubt the XML parser is the bottleneck?

ok. to be honest I agree with you. but Im using cat 5e and good routers.... but yeah sometimes the video takes 1-2 seconds to load at first.... maybe its something with the cameras themselves....

the command would be absoluteMove.

any ideas how I can improve the network? yes I do realize thats a very relative question.... I guess I need to spend more € on cables, switches, cameras? 🤔 but im mostly just a coder.... 😂

agsh commented 2 years ago

@rodrigograca31 Seriously I don't think that xml parsing of a small response is the bottleneck. Do you have the same troubles with other onvif libraries? The simpliest way to find out, just to add console.time to log the time between request to the camera and its response here: https://github.com/agsh/onvif/blob/master/lib/cam.js#L204 If the response is quick, this is your cam problem. If the response is slow, this is the network problem. Sample code replacement:

Cam.prototype._request = function(options, callback) {
    if (typeof callback !== 'function') {
        throw new Error('`callback` must be a function');
    }
    const _this = this;
    let callbackExecuted = false;
    let reqOptions = options.url || {
        hostname : this.hostname
        , port     : this.port
        , agent    : this.agent // Supports things like https://www.npmjs.com/package/proxy-agent which provide SOCKS5 and other connections
        , path     : options.service
            ? (this.uri[options.service] ? this.uri[options.service].path : options.service)
            : this.path
        , timeout : this.timeout
    };
    reqOptions.headers = {
        'Content-Type'   : 'application/soap+xml'
        , 'Content-Length' : Buffer.byteLength(options.body, 'utf8')// options.body.length chinese will be wrong here
        , charset          : 'utf-8'
    };

    reqOptions.method = 'POST';
    const httpLib = this.useSecure ? https : http;
    reqOptions = this.useSecure ? ({ ...this.secureOpts, ...reqOptions}) : reqOptions;
    const req = httpLib.request(reqOptions, (res) => {
        const bufs = []; let length = 0;
        res.on('data', (chunk) => {
            bufs.push(chunk);
            length += chunk.length;
        });
        res.on('end', () => {
            console.timeEnd('request');
            if (callbackExecuted === true) {
                return;
            }
            callbackExecuted = true;
            const xml = Buffer.concat(bufs, length).toString('utf8');
            /**
             * Indicates raw xml response from device.
             * @event Cam#rawResponse
             * @type {string}
             */
            _this.emit('rawResponse', xml);
            parseSOAPString(xml, callback);
        });
    });

    req.setTimeout(this.timeout, () => {
        if (callbackExecuted === true) {
            return;
        }
            callbackExecuted = true;

        callback(new Error('Network timeout'));
        req.abort();
    });

    req.on('error', (err) => {
        if (callbackExecuted === true) {
            return;
        }
        callbackExecuted = true;
        /* address, port number or IPCam error */
        if (err.code === 'ECONNREFUSED' && err.errno === 'ECONNREFUSED' && err.syscall === 'connect') {
            callback(err);
            /* network error */
        } else if (err.code === 'ECONNRESET' && err.errno === 'ECONNRESET' && err.syscall === 'read') {
            callback(err);
        } else {
            callback(err);
        }
    });
    /**
     * Indicates raw xml request to device.
     * @event Cam#rawRequest
     * @type {Object}
     */
    this.emit('rawRequest', options.body);
    console.time('request');
    req.write(options.body);
    req.end();
};
rodrigograca31 commented 2 years ago

doing a simple absoluteMove seems to have a quick response. so Im thinking its the camera video thats actually slow....

RogerHardiman commented 2 years ago

If you are viewing your video with 'ffplay' or 'vlc', then both add a large delay to the video before they show the pixels on the screen to smooth out network buffering. You can configure VLC to not use buffering and for ffplay there are some command line options to add. I forget what they are now.

The ONVIF library is fast. I use it in several commercial projects which include Pan and Tilt control, often with the Continuous Move API where you send Start and Stop commands.

chriswiggins commented 2 years ago

@rodrigograca31 if you're using ffplay, try the following command

ffplay - analyzeduration 0.2 -probesize 1000 rtsp://x.x.x.x

RogerHardiman commented 2 years ago

ffplay -fflags nobuffer rtsp://x.x.x.x is what I use

note it is double 'f', ie 'f''flags' = fflags