NodeJS, OpenCV and Streaming Images Using Net Sock

2020-05-24 06:20发布

My end goal is to stream video from my laptop to a server. I'm trying to accomplish this by using NodeJs on the laptop & the server. I use the OpenCV library to capture the video on the laptop and save it to a jpg file. I then read the file and convert it to base64 so that I can transport it using the Net.socket module in Node. This is a continous process: capture, encode, and send.

Here is the server code for just transmitting one jpg file:

var cv = require('opencv');
var fs = require('fs');
var net = require('net');
var camera = new cv.VideoCapture(0);
var server = net.createServer();
server.listen('50007', '127.0.0.1');

server.on('connection', function(socket){
    camera.read(function(image){
        image.save('original.jpg');

        fs.readFile('original.jpg', 'base64', function(err, image){
            socket.write(image, 'base64', function(){
                socket.end();
            });
        });
    });
});

On the client I loop until the FIN is received from the server. Here is the client code:

var net = require('net');
var fs = require('fs');
var client = new net.Socket();
var buffer ='';
client.setEncoding('base64');

client.connect('50007', '127.0.0.1', function(){
    console.log('Connecting to server...');
});

client.on('data', function(data){
    buffer += data;
});

client.on('end', function(){
    var dataBuffer = new Buffer(buffer, 'base64');
    fs.writeFile('copy.jpg', dataBuffer, function(err){
        if(err){
            console.log(err);
        }
    });
});

The problem is that the entire image does not actually get sent. When I open the received file, copy.jpg, there is always a chunk missing at the bottom.

In the final version the goal is to send one jpg after another and delimit the end of each 'jpg' via a keyword such as 'EndOfFile'. I tried to do this by appending the keyword 'EndOfFile' to my base64 encoded image before sending but on the receiving end that really got screwed up.

Sample Advanced Server:

fs.readFile('original.jpg', 'base64', function(err, image){
    image += 'EndOfFile';
    socket.write(image, 'base64');
}); 

One the client side the loop would examine each chunk of data for the keyword and if it found it then whatever is in the buffer would be written to file and the buffer reset, ready for the next file.

Sample Advanced Client

client.on('data', function(data){
    if(data.indexOf('EndOfFile') > 0){
        buffer += data.substr(0, data.indexOf('EndOfLine'));
        var dataBuffer = new Buffer(buffer, 'base64');

        fs.writeFile('copy.jpg', dataBuffer, function(err){
            if(err){
                console.log(err);
            }
        });

        buffer = '';
    } else {
        buffer += data;
    }
});

I've gotten this to work in Python so I think my logic is correct but I'm not as confortable in NodeJS.

If someone could tell me if this is a sane way to do this and where may I have gone wrong.

Thanks in advance!

1条回答
孤傲高冷的网名
2楼-- · 2020-05-24 06:56

I suspect you're seeing end event while the last bit of data is still buffered.

Try waiting for the close event rather than the end event. I'm not sure about sockets, but in other Node APIs like spawn, the end event is fired early, before related streams are flushed, so there may still be buffered data waiting.

You could avoid managing this yourself by piping. Use fs.createWriteStream() and .pipe() the socket stream to the file.

查看更多
登录 后发表回答