31

Is it possible to get the RTSP Streaming data into the web browser?

Below are some of my findings. Kindly correct me if I am wrong?

  1. Only Mac OS, and Safari supports RTSP Live Streaming.

  2. HTML 5 video does not support RTSP.

  3. I can use the VLC plugin, but I don't want to use that.

Possibility of mixing ffmpeg and websocket?

Assume my IP camera is connected with Ethernet.

In the client machine:

  1. I run ffmpeg to get the data from server (ie: IP)
  2. Client machine runs websocket.
  3. Once ffmpeg gets the data from RTSP Server, it decodes, and generates the raw image of any format (for example: yuv).
  4. Now, i have to send this image to browser through websocket.

Question:

  1. It is the right approach ?
  2. How can I get the decoded image from ffmpeg into the browser ?

I might be wrong in different places. Kindly provide input.

halfer
  • 19,824
  • 17
  • 99
  • 186
Whoami
  • 13,930
  • 19
  • 84
  • 140

5 Answers5

29

Here is a blog entry, or tutorial if you will, that achieves something very similar.

Their setup slightly different, but this is the summary:

use ffmpeg to convert your input into mpeg1video:

ffmpeg  -i rtsp://whatever -f mpeg1video -b 800k -r 30 http://localhost:8082/yourpassword/640/480/

Install node.js with stream-server.js script from jsmpeg and ws ws WebSocket package.

To view the stream, use the stream-example.html and jsmpg.js from the jsmpeg. Change the WebSocket URL in stream-example.html to localhost and open it in your favorite browser.

Update an SO topic suggest two other working solutions, with <video> tag: with stream-m Java server or with ffserver.

Paresh Gami
  • 4,777
  • 5
  • 23
  • 41
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Does this support audio? – Lama Sep 01 '15 at 18:23
  • In theory, it does. I would recommend the ` – Alex Cohn Sep 02 '15 at 09:28
  • I mean does it support streaming the audio of the video, just by using the video tag ? :) – Lama Sep 02 '15 at 09:56
  • Yes, ` – Alex Cohn Sep 02 '15 at 11:16
  • I cant find the stream-server.js script, could you explain that further, currently I set a local httpserver with nodejs and install jsmpeg aswell, thanks – utdev Jun 23 '17 at 07:24
  • I made it work somehow. Now how can I look at the stream currently, the stream is at this url `http://localhost:8081/secret/640/480` but the page is still loading and I do not get any view – utdev Jun 23 '17 at 07:46
  • Changing it to localhost leads to a cross origin error, how to fix this? – utdev Jun 23 '17 at 08:50
  • ffserver is not supported anymore. – jehon Jun 12 '20 at 20:18
9

If you want to stream that to only a very few clients, then you could use a cgi (or in nodejs, a child_process) that directly run ffmpeg:

NodeJS example:

app.getExpressApp().get('/camera/feed', (req, res) => {
    // Thanks to https://stackoverflow.com/q/28946904/1954789
    const child_process = require('child_process');

    res.header('content-type', 'video/webm');

    const cmd = `ffmpeg -i rtsp://user:pwd@somewhere/videoSub -c:v copy -c:a copy -bsf:v h264_mp4toannexb -maxrate 500k -f matroska -`.split(' ');

    var child = child_process.spawn(cmd[0], cmd.splice(1), {
        stdio: ['ignore', 'pipe', process.stderr]
    });

    child.stdio[1].pipe(res);

    res.on('close', () => {
        // Kill ffmpeg if the flow is stopped by the browser
        child.kill();
    });

CGI should be even more easier.

In the browser, you could just

<video autoplay=1 poster="camera.png" ><source src="/camera/feed"></video>

(Use a poster because the video may take some seconds before showing up).

Caveat: This will launch a ffmpeg for each connection to your setup, so it does not scale at all. This should be used only for a very personal website, where connections are limited (ex: to yourself only).

PS: the ffmpeg command may need a bit of tweaking.

jehon
  • 1,404
  • 15
  • 21
  • I believe that these days, the best approach is to [use WebRTC](https://stackoverflow.com/q/23461914/192373). I am surprised that this question of 6 years back is still relevant. I have personally worked with https://github.com/mpromonet/webrtc-streamer, and was quite happy. – Alex Cohn Jun 13 '20 at 09:15
  • 1
    I am afraid you intended to post your comment to another answer – Alex Cohn Sep 07 '22 at 19:43
2

vlc solution:

cvlc -v rtsp://user:password@camera_ip_address --sout='#transcode{vcodec=theo,vb=800,acodec=vorb,ab=128,channels=2,samplerate=44100,scodedec=none}:http{dst=:8080/webcam.ogg}'

Then check

http://localhost:8080/webcam.ogg

Or integrate this url to whatever webservice you want to run

If you are interested in the python api of vlc, here is an example:

import vlc

class WebcamStreamer:
    def __init__(self, config):
        """
        Expected rtsp url format:
        "rtsp://user:password@192.168.0.1"
        """
        self.instance = vlc.Instance()
        self.stream_name = "webcam".encode()
        self.rtsp_url = config["rtsp_url"].encode()

    def launch_webcam_stream_converter(self):
        """
        Basically here is what is done:
            cmd= ["cvlc", "-v", f"rtsp://user:password@192.168.0.16",
            f"--sout='#transcode{{vcodec=theo,vb=800,acodec=vorb,ab=128,channels=2,samplerate=44100,scodedec=none}}:http{{dst=:8080/webcam.ogg}}'"]
            subprocess.run(cmd)
        """
        ret = vlc.libvlc_vlm_add_broadcast(
            p_instance=self.instance,
            psz_name=self.stream_name,
            psz_input=self.rtsp_url,
            psz_output=f"#transcode{{vcodec=theo,vb=800,acodec=vorb,ab=128,channels=2,samplerate=44100,scodedec=none}}:http{{dst=:8080/webcam.ogg}}".encode(),
            i_options=0,
            ppsz_options=[],
            b_enabled=True,
            b_loop=False
        )
        assert (ret == 0)
        vlc.libvlc_vlm_play_media(self.instance, self.stream_name)
Tobbey
  • 469
  • 1
  • 4
  • 18
1

scandir.php (utilised by JS in viewcamera.php)

<?php

$folder = $_GET['name'];

$dir = "../cache/".$folder;

// Sort in descending order
$b = scandir($dir,1);

$myJSON = json_encode($b);

echo $myJSON;

?>

streamcam.php (run in crontab)

<?php

function live_view ($cameraip, $cameraname){

    echo shell_exec("/usr/bin/ffmpeg -rtsp_transport tcp -i rtsp://root:pass@".$cameraip."/ufirststream -s 1920x1080 -f image2 -vf fps=fps=5 /var/www/html/occupancy/cache/".$cameraname."/frame%04d.jpg >/dev/null 2>/dev/null &");

}

viewcamera.php - $camera_name variable is from SQL while loop where below repeats for all cameras in database. var cameraName if from below button data attributes...

<button
  style="font-size: 24px"
  class="btn2 fa fa-camera"
  id="<?php echo $image_id;?>"
  href="#<?php echo $camera_name_stripped;?>"
  data-toggle="modal"
  data-backdrop="false"
  data-keyboard="false"
  data-image-id="<?php echo $image_id;?>"
  data-camera-ip="<?php echo $ip;?>"
  data-camera-name="<?php echo $camera_name;?>"
  data-camera-name-stripped="<?php echo $camera_name_stripped;?>"
>
  <i style="font-size: 24px" title="Live View"></i>
</button>

 
<img width="100%" height="auto" id="img_cam<?php echo $camera_name_stripped;?>" src="">



<script>

 var cameraName = $(e.relatedTarget).data('camera-name-stripped');

 window.livetimer<?php echo $camera_name;?> = setInterval(function() {

          <?php echo $camera_name_stripped;?> = $.ajax({
              url: 'scandir.php?name='+cameraName,
              type: "POST",
              dataType: 'json' 
          }).done(function(result)  {
              $("#img_cam<?php echo $camera_name_stripped;?>").attr('src',"../cache/" + cameraName + "/" + result[0]);
          });

          }, 55);    

});

</script>
ImAtWar
  • 1,073
  • 3
  • 11
  • 23
0

I need to show a streaming in different plataforms and browsers. To make that without use of any pluggins (not sure it will works on smartphones and tablets), used a approach very similar to yours. A ffmpeg crontab task creates 3 images per second, and store into a directory. Using Jquery, an ajax call to a php read the directory and get the name of the file, to change the image (only changing the 'src' attribute of <img>), every 330ms. To solve the storage problem, used other crontab task that delete the files with more than 1 minute. It´s not real streaming, but is cross browser, and solves the problem pretty well.

The ffmpeg task

ffmpeg -i "rtsp://path/to/cam" -s 320x240 -f image2 -vf fps=fps=3 cache/%04d.jpg

Example ajax call

$.ajax({
        url: '_read_dir.php',
        type: 'POST',
        dataType: 'json'
    })
    .done(function(result) {        
        $("#img_cam").prop('src',"cache/" + result.img);            
    });

The storage control task

find /var/www/path/to/dir -mmin +1 -exec rm -f {} \;

Hope can help! :)

Rafael Basso
  • 112
  • 5