ffmpegrtspmjpeg

How to convert rtsp stream to mjpeg (http) using ffmpeg


I wish to capture an rtsp stream and convert it to an mjpeg (over http) stream using ffmpeg. I am running Ubuntu 20. I have searched and searched for the solution, and mostly find:

a) solutions requiring ffserver (deprecated)

b) solutions converting from mjpeg to rtsp

c) solutions converting from rtsp to hls (nginx, wowza, etc...) which doesn't work in my application. I need http output as mjpeg.

d) vlc - which does work but requires way too much of my available processor (80%)

e) rtsp2mjpg - github project which I installed, but could not get to work and can't get any support.

I am not an ffmpeg expert, so if someone could step me through an ffmpeg solution to this, if it exists, I'd really appreciate it.


Solution

  • I've very recently solved this myself, after finding the exact same things as you. The two parts are you need are (1) ffmpeg conversion in a script, and (2) something like lighttpd+cgibin or nginix+fastcgi to serve it over http/https. I don't expect you'll be able to do much better in terms of CPU use than vlc, though.

    This bash script will do the ffmpeg conversion to MJPEG, and send the output to stdout. Put this in lighttpd's cgi-bin folder (/var/www/cgi-bin for me). Call it something like "webcamstream", and adjust the rtsp:// URL to suit your camera:

    #!/bin/bash
    
    echo "Content-Type: multipart/x-mixed-replace;boundary=ffmpeg"
    echo "Cache-Control: no-cache"
    echo ""
    ffmpeg -i "rtsp://192.168.60.13:554/user=admin&password=SECRET&channel=1&stream=0.sdp" -c:v mjpeg -q:v 1 -f mpjpeg -an -
    

    Enable cgi-bin for lighttpd:

    ln -s /etc/lighttpd/conf-available/10-cgi.conf /etc/lighttpd/conf-enabled/10-cgi.conf
    

    ..and then adjust lighttp's cgi-bin configuration (/etc/lighttpd/conf-enabled/10-cgi.conf) as shown below. The stream-response-body setting is important, as it'll both stop the stream when the client disconnects, and also avoid having lighttpd try to buffer the entire infinite stream before sending anything to the client.

    server.modules += ( "mod_cgi" )
    
    $HTTP["url"] =~ "^/cgi-bin/" {
            server.stream-response-body = 2
            cgi.assign = ( "" => "" )
            alias.url += ( "/cgi-bin/" => "/var/www/cgi-bin/" )
    }
    

    Make the cgi-bin script executable and restart lighttpd:

    chmod +x /var/www/cgi-bin/webcamstream
    systemctl restart lighttpd
    

    ...and that should be it. You can then access the MJPEG stream at a URL like this, where the last part is your script's name:

    http://serveraddress/cgi-bin/webcamstream
    

    I've written it up in more detail here: Converting RTSP to HTTP on demand

    As far as I can tell, you can't avoid taking the CPU hit of the conversion -- the format/encoding of RTSP vs. MJPEG frames are different. I reduced my CPU load by configuring the camera to reduce the source's framerate and resolution until it was an acceptable load on ffmpeg. You can change the resolution and framerate with ffmpeg arguments as well, but it would still have to decode the full frames first and do the work of resizing.

    The paths above are on Debian, so you may need to adjust them to suit your Ubuntu system.