Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Solutions to stream from a decklink card to browsers (Gstreamer -> TCP MJPEG -> ?)

I need to live stream from a decklink card to a browser. I also must be able to do it with a very poor network link (128kbits/s...), so I need to be able to stream at a very low fps (1 fps is fine) and a very low image quality.

At the moment I'm using GStreamer to get the video from the card, to transcode it to MJPEG, and to stream it with TCP. This part is perfectly working, but now I need to tube this tcp stream to an HTTP stream.

I can do this with VLC and it works well at a "normal" framerate (15 fps -> 0.5 sec of latency). But if I feed VLC with a 1 fps stream, it introduces a latency of around 11 sec, which is not fine for my purpose.

So, now I'm looking for a replacement of VLC. I see 3 ways of doing it :

  • use the GStreamer's souphttpclientsink to stream to an HTTP streaming server

  • create my own HTTP server, wich listens to the TCP stream and re-streams it to the clients. I tried in Python and Node.js and it is nearly working, but I would prefer to have a more robust solution like the previous one

  • even more tricky : create my own HTTP server, listen to the TCP stream and send the data to the client with websockets, and then decode then stream client side...

Then, my questions are :

  • do you know which HTTP streaming servers (if possible free) are usable with souphttpclientsink (or tcpclientsink) ?

  • do you have any other idea to stream a GStreamer stream to a browser ?

Thanks for reading !

like image 781
Tim Autin Avatar asked Apr 29 '14 08:04

Tim Autin


1 Answers

I got the websockets solution working, thanks to the node Dicer module (and thanks to mscdex on this post ).

So here is what I did :

1°) Stream my Decklink card's video over TCP whith GStreamer :

gst-launch -v decklinksrc mode=10 connection=0 ! deinterlace ! videorate ! videoscale ! video/x-raw-yuv, framerate=1/5, width=256, height=144 ! jpegenc quality=20 ! multipartmux  boundary="--videoboundary" ! tcpserversink host=<TCP src stream IP address> port=<TCP src stream port>

2°) Listen to this stream with Node and send each image via socket.io :

// ------------------------------------------------
// Constants :
// ------------------------------------------------

var srcHost = "<TCP src stream IP address>";
var srcPort = <TCP src stream port>
var srcBoundary = "--videoboundary";

var destHost = "<dest IP address>";
var destPort = <dest port>;

// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------



// ------------------------------------------------
// Includes :
// ------------------------------------------------
var Http = require('http');
var Net = require('net');
var Dicer = require('dicer');
var SocketIO = require('socket.io');
// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------



// ------------------------------------------------
// TCP socket :
// ------------------------------------------------

var socket = Net.Socket();

socket.connect(srcPort, srcHost, function() {

    // Init socket IO :
    var io = SocketIO.listen(Http.createServer().listen(destPort, destHost), { log: false });

    // Init Dicer :
    var dicer = new Dicer({ boundary: srcBoundary });

    dicer.on('part', function(part) {

        var frameEncoded = '';
        part.setEncoding('base64');

        part.on('header', function(header) { });
        part.on('data', function(data) { frameEncoded += data; });
        part.on('end', function() { io.sockets.emit('image', frameEncoded); });
    });

    // Handle streams closing :
    dicer.on('finish', function() { console.log('Dicer stream finished'); });
    socket.on('close', function() { console.log('TCP socket closed'); });

    // Pipe :
    socket.pipe(dicer);
});
// ------------------------------------------------
// ------------------------------------------------
// ------------------------------------------------

3°) Listen to the websocket on the client :

<html>
    <head>

        <script src="jquery-1.9.1.js"></script>
        <script src="socket.io-client/socket.io.min.js"></script>

        <script>
        var socket = io.connect('http://<dest IP address>:<dest port>');
        socket.on('image', function (data) {

            $("#video").attr("src", "data:image/jpeg;base64," + data.toString("base64") );
        });
        </script>
    </head>

    <body>

    <img id="video" style="display:block; width:400px; height:auto;" src="" />

    </body>
</html>

I will update this post if I get other solutions working (but I may go with this one).

like image 194
Tim Autin Avatar answered Sep 28 '22 11:09

Tim Autin