node-modules / urllib

Request HTTP(s) URLs in a complex world.
MIT License
725 stars 114 forks source link

Timeout when downloading a MJPEG Stream #374

Open idoodler opened 2 years ago

idoodler commented 2 years ago

I am using this library to download a continuous MJPEG stream. It works and I can extract the specific images from the stream, however the connection alwas times out automatically. Is there a way to prevent the timeout.

I already tried to set null, -1 and 0 as the Timeout, nothing worked.

fengmk2 commented 2 years ago

Can you provide a reproduction demo code?

idoodler commented 2 years ago

I do not find a public MJPEG stream, so I can only share you the code.

var writable = new stream.Writable();
    writable._write = function(chunk, encoding, done) {
        contentTypeRequest.abort();
        done();
    }

    // Validate the contentType to prevent us from downloading a MJPG stream instead of JPG
    var contentTypeRequest = urllib.request(url, {
        writeStream: writable // Set a writeStream to be able to abort the request as soon as we got a response
    }, function(err, data, res) {
        contentTypeRequest.abort();
        if (err) {
            this._errorCallback(err);
        } else {
            if(res.statusCode !== 200) {
                this._errorCallback(response);
                return;
            } else {
                // Note: Its important to stop any currently active streams. This plugin can only handle one stream at a time!
                this.stopStream();
                if (res.headers['content-type'].indexOf("multipart/x-mixed-replace") !== -1) {
                    this._fetchMjpgFrame(url, config);
                } else {
                    this._fetchJpg(url, config);
                }
            }
        }
    }.bind(this));
function _fetchMjpgFrame(url, config) {
    var writable = new stream.Writable()
        chunks = [],
        soi = new Buffer.from([0xff, 0xd8]), // Start Of Input
        eoi = new Buffer.from([0xff, 0xd9]); // End Of Input

    writable._write = function(chunk, encoding, done) {
        if(chunk.indexOf(soi) !== -1) { // Check if the data chunk contains the JPEG start magic
            chunks = [];
            chunks.push(chunk.slice(chunk.indexOf(soi), chunk.length));
        } else {
            if(chunk.indexOf(eoi) === -1) {  // The data chunk doesn't contain the JPEG end magic, add it to the the received chunks
                chunks.push(chunk);
            } else { // The data chunk contains the JPEG end magic, extract the data until  the JPEG end magic and send the buffer to the successCallback
                chunks.push(chunk.slice(0, chunk.indexOf(eoi) + 1 + 1)); // +1 is for the second bit of the eoi buffer, the other +1 is for get the length instead of the index
                this._successCallback(Buffer.concat(chunks).toString("base64"));
            }
        }
        done();
    }.bind(this);

    config.writeStream = writable;
    this._request = urllib.request(url, config, function(err, data, res) {
        if (err) {
            this._errorCallback(err);
        } else {
            if(response.statusCode !== 200) {
                this._request.abort();
                this._errorCallback(response.statusCode);
            }
        }
    }.bind(this));
};

The Timeout cancels the download of the MJPEG stream in the _fetchMjpgFrame function. I just want to indefinitely download and process the stream.