3

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.

SomebodySysop
  • 141
  • 1
  • 1
  • 4

2 Answers2

5

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.

sstteevvee
  • 379
  • 2
  • 5
  • As an aside, I also tried using ffmpeg to copy the H265 stream inside RTSP directly to something the browser would play (e.g. via webm), with the hope that'd reduce the CPU load on ffmpeg as it'd be just copying raw frames as-is. I then found that due to codec licensing reasons Firefox (and another app I was using) wouldn't play anything H265. As I was pretty much forced into MJPEG at this point, I didn't pursue this approach any further. If I ever get a camera doing H264 over RTSP, then I might revisit it. – sstteevvee Jul 21 '21 at 14:25
  • Thank you. This is the best and most complete solution I've found utilizing tools I am familiar with. – SomebodySysop Jul 21 '21 at 19:09
  • Tested this. It works. I am seeing what you mean about the processor hit. Just one stream is showing 112% cpu usage. I am seeing what you mean about the processor hit. Just one stream is showing 112% cpu usage. 41737 www-data 20 0 673316 118156 34880 R 111.9 1.5 3:59.52 ffmpeg But it is working as advertised! – SomebodySysop Jul 22 '21 at 02:17
  • I don't think I can do this as mine is on a virtual machine, but if you have the right sort of video card, you might be able to use hardware acceleration and move some of the load onto it: https://trac.ffmpeg.org/wiki/HWAccelIntro / https://stackoverflow.com/questions/44510765/gpu-accelerated-video-processing-with-ffmpeg – sstteevvee Jul 23 '21 at 03:52
  • Its not what your original question asked, but if you're wanting to get CPU use down and your video source can generate individual JPEG frames, and don't mind a lower frame rate, you can do this: https://stevethemoose.blogspot.com/2021/08/converting-individual-frames-from-http.html I've been playing with cheap Chinese IP cameras, which at best seem to have only RTSP and JPEG. In case that's what you, or a future visitor is using, this may also be useful. – sstteevvee Aug 12 '21 at 08:02
  • What if the video source is hls? Would the mjpeg cgi athttps://stevethemoose.blogspot.com/2021/08/converting-individual-frames-from-http.html work? – SomebodySysop Aug 12 '21 at 19:04
  • Make sure that `mod_alias` is also available in your lighttpd config. This missing config has cost me an hour of debugging. – Pavlo Dyban Sep 03 '22 at 19:47
  • It works with Intel GPU acceleration/tapo C320WS camera: ffmpeg -hwaccel vaapi -hwaccel_device /dev/dri/renderD128 -hwaccel_output_format vaapi -i rtsp://user:password@192.168.3.69/stream1 -c:v mjpeg_vaapi -f mpjpeg -an - (more info in https://stackoverflow.com/questions/51545954/how-to-use-ffmpeg-with-mjpeg-vaapi-encoder-with-hardware-acceleration) – Henning May 03 '23 at 11:30
0

Convert RTSP to MJPEG via FFSERVER

ffmpeg download:

https://ffmpeg.org/releases/

choose old version before 3.4(since this version FFSERVER WAS REMOVED), recommand to use 3.2.16

Compile

./configure --prefix=/u/tool/ffserver
make && make install

FFSERVER

cd /u/tool/ffserver/bin

edit {ffserver.conf}

HTTPPort 8090
HTTPBindAddress 0.0.0.0
MaxHTTPConnections 2000
MaxClients 1000
MaxBandwidth 10000

<Feed feed.ffm>
File /tmp/feed.ffm
FileMaxSize 50M
</Feed>

<Stream live.mjpeg>
Feed feed.ffm
Format mpjpeg
VideoFrameRate 5
VideoIntraOnly
VideoSize 720x405
VideoQMin 5
VideoQMax 20
NoAudio
Strict -1
NoDefaults
</Stream>

<Stream still.jpg>
Feed feed.ffm
Format jpeg
VideoFrameRate 2
VideoSize 720x404
VideoQMin 1
VideoQMax 15
VideoIntraOnly
NoAudio
Strict -1
NoDefaults
</Stream>

Run FFSERVER

./ffserver -f ./ffserver.conf

pixel err

1280x720 == 720x405

if you use VideoSize 720x405,startup error message shows:

ffserver.conf "Image size is not a multiple of 2"

fix 405 to 404.

FEED STREAMING

ffmpeg feed, DO NOT USE SYSTEM BUILD FFMPEG!! CAUSE AFTER VERSION 3.4, IT WAS REMOVED!

use the ffmpeg you just compiled same directory with ffserver.

./ffmpeg -rtsp_transport tcp -i "rtsp://127.0.0.1:8554/000FFC52F1D3" -r 15 -an http://127.0.0.1:8090/feed.ffm

Browse mjpeg:

http://192.168.1.17:8090/live.mjpeg

Browse snap image:

http://192.168.1.17:8090/still.jpg

mjpeg status

http://localhost/tool/mjpeg.htm

Prevent RTSP stopped broke mjpeg image updating,loop update image path in JS every N seconds(ig: 15):

setInterval(function() {
    var myImg = $('#myJpeg').attr('src', "http://192.168.1.17:8090/live.mjpeg?rand=" + Math.random()); 
}, 15000);

run server

ffserver -f /etc/ffserver.conf

run debug mode

ffserver -d -f /etc/ffserver.conf

If your want to run FFMPEG in console background, try to use -nostdin to FFMPEG or run in terminal multiplexer like SCREEN or TMUX.

Lo Vega
  • 121
  • 1
  • 3