Using ffmpeg for webcam streaming and timelapse support

Read the rest of the thread. I wanted to build a drop-in replacement for mjpg-streamer. So I did. And then talked about the possibility of adapting that technique for different formats.

I like h264 because the raspberry pi has hardware codecs for it. Just haven't had the time or inclination to properly test it myself yet. If you need it though, feel free to experiment with changing the format in the ffserver.conf file and ffmpeg commandline.

The whole point of pulling x264 is not to have mjpeg. Pulling x264 and streaming it should take just a few % of CPU time and 10-20 times less bandwidth.

Not saying sending h264 is off the table, but if h264->mjpeg ends up being easier for a pi to do than the pipeline that's in place now, then that's what I'll use.

Subscribed, would like to pull h264 stream from my logic c920 that natively supports this stream.

Just dont have the background to pull this off. Linux, raspberry pi, and ocotoprint newbie.

Thanks

Excellent! This seems like an improvement already, but if the x264 was working, maybe the load would be low enough to use it reliable on a zero. If you're interested, you'd reach a very large audience by getting these changes to the octopi github. As a professional sysadmin, I'm sure you'd be effective there. Guysoft's scripts are doing just what you would on the command line, but recording them and running them in a qemu environment to build the images. I'd love to see more stuff like this available.

Weird thing mjpeg streamer allready used just 3-7% on my old RPi1. It uses ~3% on my RPi3 (streaming 1920x1080x30), and about the same on my Odroid XU4. I'm also testing my cameras on a x86 Dell minipc with an i5 and I'm getting less that 1% CPU usage while streaming 3 cameras (1x c920 & 2x c930e) at once at 1920x1080x30.
This suggests there is something wrong with your config (note: I do NOT use octoPi - all above were installed manually)

To everyone waiting for x264 streaming. I'm not in any case a linux streaming video guru, but from what I've searched and read we can forget about it until OP will start using <video> html tag instead of <img> tag. After that it should be as easy as using a one liner per camera, something like:

cvlc v4l2:///dev/video0:chroma=h264:width=1920:height=1080:fps:30 --sout '#standard{access=http,mux=ts,dst=localhost:8080,name=stream,mime=video/ts}' -vvv

Too bad a little jQuery couldn't change the tag into a video...?

$('img').replaceWith(function(){
    return $("<video />", {html: $(this).html()});
});

But I guess more work would need to be done on that.

Well... it cost's me a complete evening to realise, that only the older C920's have h264/mp4 encoding. Logitech decided to drop this feature a while ago:

According to Wikipedia, there are not many Webcam's with mp4 left:
https://en.wikipedia.org/wiki/List_of_cameras_with_onboard_video_compression


But nontheless I've found a way for me to make it work on my Raspberry Pi 4 running OctoPi 0.17.0 with OctoPrint 1.4.00: Restreamer (https://datarhei.github.io/restreamer/). Here's what I did:

  • disabled/stopped webcamd and wait till port 8080 is free, check with netstat -tulpen
    sudo service webcamd stop
    sudo systemctl disable webcamd.service
    
  • installed Restreamer via Docker (ARM version) on the Pi: https://datarhei.github.io/restreamer/docs/guides-usb-camera.html using port 8080 (e.g.) and /dev/video0
  • installed @jneilliii's WebCamIframe-Plugin: https://community.octoprint.org/t/load-video-stream-instead-of-usb-camera/9772/19
  • Started streaming via Restreamers Webinterface in h264 mode. If your Webcam supports native h264 you can simply use copy in the encoding options
  • changed Octoprint's Stream-URL to: http://<network-ip-of-pi>:8080/player.html
  • changed Octoprint's Snapshot-URL to: http://127.0.0.1:8080/images/live.jpg
  • Configured and started restreamers Encoding on rtmp://127.0.0.1/live/usbcam.stream accordong to the guide.

I'm at 30-40% CPU with 720p@25fps (superfast, 4MBit/s) as I can't find anything on how to use the Pi's hardware mp4 unit for this.

But maybe some of you can help me out, as there is a second ffmpeg process eating up cpu time. I think this must be something from Octoprint itself. I don't know it this also blocks Port 8080, as I've disabled mjpeg_streamer by stopping webcamd.

Edit: Both ffmpeg processes are from Restreamer. One to fetch /dev/video0 and put it to /dev/video, the second to encode the video to h264.
Edit^2: Obviously I've not waited long enough to let free up mjpeg_streamer port 8080 after stopping it.

Before that I've fidled around with ffserver (https://trac.ffmpeg.org/wiki/ffserver), which is not maintained anymore. I've switched to Restreamer before I came to the conclusion, that my camera is lacking h264.

All in all it's kind of a mess. Every information you find regarding v4l2 is mostly from 2014/2015 and things like ffserver are discontinued. Don't get me wrong, I'm very thankfull for the work people put into this. But maybe I'm oversaw something as I went on the wrong path...

Would be great to get your input on my unsolved issues:

  • Disabling Octoprint's ffmpeg
  • Free up port 8080
  • Employ hardware encoding on the Pi

As the hardware encoding bit has to do something with Restreamer in my setup, I've openend up an issue there:
https://github.com/datarhei/restreamer/issues/148 - solved Hardware encoding of the usbcam stream on the Pi. Now max 10% cpu load.
Keep in mind, restreamer always reencodes the webcam to h264, so on the settings page you only need to use "copy" to get mp4.

Cheers,
Patrik

(As a new user I'm only allowed to put two links in a post, thus the links in parenthesis)

1 Like

Take a look at netstat -tulpen, it should point out the PID of the process that's listening on that (unprivileged) port, e.g.

$ netstat -tulpen | grep 8080
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1000       10825210   5829/./mjpg_streame
tcp6       0      0 :::8080                 :::*                    LISTEN      1000       10825211   5829/./mjpg_streame

This tells us that it's PID 5829 listening on 8080 on both IPv4 and IPv6. It also tells us a truncated version of the process name here, but we can also cross check the PID:

$ ps -ef | grep 5829
pi        4923  4892  0 11:49 pts/0    00:00:00 grep --color=auto 5829
pi        5829  5801  0 Feb24 ?        00:20:39 ./mjpg_streamer -o output_http.so -w ./www-octopi -n -i input_uvc.so -r 640x480 -f 10 -d /dev/video1

Hey @foosel,

thank you. Of course netstat should have come to my mind.
Oviously I've tried to fire up the docker container with restreamer while mjpeg_streamer was still running... or shutting down and the port was not free, yet.

Currently there is no process on 8080, so it should be fine. Thanks again.
And sorry, that I did not double check this before posting.

Cheers,
Patrik

1 Like

GREAT solution, and thanks so much for sharing this. I couldn't believe I was watching a 5 fps low res jittery stream in 2020. Took me a bit to puzzle out your light instructions but I (like you I'm guessing) do this for a living so it wasn't that bad. On my Pi 4 I'm chugging along with a 1920x1080 30fps stream just a scratch to the cpus.

One odd thing though, the webcam tab video frame is quite small at least on my Octoprint page. Is that the case for you? If it was, did you by chance figure out a way to solve that? I haven't dug into code to see if there's some width and height vars I can change to display this better.

Replying to my own comment as I found a way to change the iframe size. It's in ~/.octoprint/generated/webassets/packed_plugins.js

Look for the line
$('#webcam_container').replaceWith('');

I set mine to 1920 x 1080 in that line, I think the original was 588 x 33x? I forget, something low. Being javascript you can just reload your your browser tab with octoprint and it will take effect immediately.

Hey, great to hear. Yes, this was not meant to be a step-by-step guide, just wanted to share how I did it, as the documentation of restreamer is quite good.
If there's a demand I can maybe write this down in more detail.

Same here... that's why I meant that the whole thing is kind of a mess :wink:

How much cpu load do you have at 1080p@30? Here all 4 cores are lifting between 30-60% for 720p. See htop for info.
Thus I'm seeking the hardware encodig ffmpeg. I've found an old NUC with a Pentium G5400... I will test about the cpu load on this.

Do you have an h264 capable camera?
How long is your delay? I have around 5-10 seconds.

Hmm, I think I did not have the size hassle, or do I?
But I admit, that I've also exposed a standalone player through nginx (https, letsencrypt) to only watch without the Octoprint controls.

Pi 4 is a four core device and load average sits at around 1.36, but no single CPU is maxed ever. At most I see Chromium taking up a good chunk of CPU but usually sub 50%, sometimes as high as 80. ffmpeg sits sub 10%. Looking at ffmpeg's parameters it's just do a copy rather than any transcoding so this doesn't really surprise me. My camera is a Raspberry Pi v2 camera which natively outputs H264, hence the transcoding not being necessary.

My delay is like 5-10 seconds. I hate that, I was trying to see if it's the player that's buffering it, or something in streaming. I mean it doesn't really matter, seeing the printer delayed doesn't really change the usefulness of this that much, but it does bug me :slight_smile:

Your screen shot shows pretty low res to my eyes for that window. I am using a 1920x1080 stream, so I wanted my window to match. I'm using the Themify plugin to expand the interface making room for the Webcam iframe.

Ah, then it's clear that this is easy going.
I'm using a Logitech C920, sadly the new version without hardware encoding.
That's why I've opened an issue over at restreamers github as the Pi has hardware h264 encoding capabilities that would be great to use.

I've found this regarding the delay, but did not implement it, yet:

Well, I got an 1080p monitor and cause of the software encoding I thought 720p is enough for the video. Maybe I will bump it up once propper hardware encoding or the NUC is in place.

Rather than patching a generated file it might be a little safer to use Themeify and just make the edit there.

1 Like

Oh yeah you're 100% right there. I have no idea (yet) how to make the tweak via Themeify but I suspected that would be the ultimate solution.

I tried copying the configs from the container and mounting them outside and editing the nginx.conf with the hls setting changes mentioned in that link about lag, and they didn't improve the lag at all for me. I'm staring at it wondering if I did something wrong.

Search the forum for "pimp" for a wide variety of edits we've all made.