motioneye-project / motioneye

A web frontend for the motion daemon.
GNU General Public License v3.0
4.01k stars 662 forks source link

FPS throttling (stream_motion on) is not affecting preview stream to motioneye web ui #676

Open Harvie opened 7 years ago

Harvie commented 7 years ago

Please add low_cpu 1 and stream_motion on to generated motion.conf. In most cases there's no reason to go at full FPS while there's no motion.

Harvie commented 7 years ago

oh sorry, low_cpu is deprecated and stream_motion is already there.

Harvie commented 7 years ago

In fact it seems there's some problem, because when i have motioneye open in browser, all cams report 10 FPS, which is max i've set. It shoud stream slower to browser when nothing happens.

When i open motioneye in browser the internet bandwidth is quite high (16 Mbps for 3 cams) and all 4 CPU cores are geting significantly loaded until i close the browser window again. I think this is OK while there's motion, but should not happen when there's no motion (it should be throttled to 1 FPS). I am not sure why "stream_motion on" has no affect on live preview in motioneye. It seems to me that you are getting image from somewhere else. Not directly from motion stream output that is properly throttled when there's no motion.

I can use "FPS dimmer" in motioneye UI, that works great, but it is not working automaticaly based on motion detection. Eg. when i have 30 FPS input, reduced by dimmer to 50% i expect it to have 1 FPS when there's no motion and 15 FPS during motion. This would drasticaly relief load of my server and network connectivity.

ccrisan commented 7 years ago

motionEye uses the MJPEG streams provided by motion. However it "intercepts" each JPEG frame thus being able to do stuff (such as detect when the stream has stopped or calculate the frame rate). The browser asks for a JPEG as often as indicated by the streaming framerate, regardless of the motion detection status.

In theory we could limit the browser-induced framerate when no motion is detected but this could introduce a(nother) delay between the moment the motion takes place and the moment the corresponding image reaches the browser.

There are now two ways to circumvent this:

  1. Reduce the actual framerate using the dimmer, as you have already mentioned. The disadvantage is the fact that the dimmer is static (manually controlled).
  2. Add the camera as a Simple MJPEG Camera, in which case you'll get the "raw" MJPEG stream offered by motion. Disadvantages include the lack of settings (you could add a second camera of this type, as a workaround) and the fact that Chrome recently stopped allowing including credentials in the URL - so the stream might not work.
Harvie commented 7 years ago

What if motioneye just acted as proxy for motion stream? In fact i've been doing this exact thing in my homebrew 10 lines PHP script that i've been using before motioneye to show all motion cameras on single page. It worked flawlessly and efficiently. I wanted everything to go through single port apache is runing on (security reasons, firewall, HTTPS, etc...), so the php just connected to motion, sent login credentials and passed the stream to apache without any modifications or intercepting of individual frames, which resulted in relatively nice performance.

ccrisan commented 7 years ago

This is what motionEye does when you add a camera as a Simple MJPEG Camera.

Harvie commented 7 years ago

But that does not really make any sense, since i need motion detection and similar features. And having every camera twice is ugly solution. And it's not even solution, since the first instance will still eat resources...

ccrisan commented 7 years ago

@Harvie I understand, but this is what we currently have, without additional work.

Harvie commented 7 years ago

@ccrisan I understand, but i'd like to find some consent on whether this should and can be fixed... That's why we have issue tracker after all.

Is motioneye somehow dependent on grabing frames individualy rather than just connecting to HTTP/MJPEG stream given by motion and using that?

BTW what interface are you using for that? I wasn't familiar with the fact that motion has other interface besides of throttled mjpeg stream (which may not be enabled every time and can be even disabled in motioneye ui) and individual still pictures stored to disk, which might also be disabled and wouldn't be much efficient to convert back to stream.

ccrisan commented 7 years ago

@Harvie

That's why we have issue tracker after all.

When you have to deal with 1600+ issues (motionEye + motionEyeOS), believe me that you start to question the role of these issues :)

Is motioneye somehow dependent on grabing frames individualy rather than just connecting to HTTP/MJPEG stream given by motion and using that?

Yes it is, just like I said before. Reasons include:

BTW what interface are you using for that? I wasn't familiar with the fact that motion has other interface besides of throttled mjpeg stream (which may not be enabled every time and can be even disabled in motioneye ui) and individual still pictures stored to disk, which might also be disabled and wouldn't be much efficient to convert back to stream.

motionEye uses the MJPEG streams provided by Motion. There's no other interface (that I know of). When you disable streaming from the motionEye's UI, you actually disallow accessing the stream from outside (binding the server on 127.0.0.1); Motion's MJPEG streamer can't (and shouldn't) be completely disabled.

Harvie commented 7 years ago

Maybe i've found the problem. There's stream_motion 1 but according to man motion it really should be stream_motion on in /etc/motioneye/thread-*.conf.

Harvie commented 7 years ago

motionEye uses the MJPEG streams provided by Motion. when streaming MJPEG directly into the browser, a framerate dimmer (such as the one motionEye has right now) can't be implemented (unless done in Motion)

But i still don't get how do you increase the FPS. If stream_motion parameter of motion works properly it should give you 1 FPS stream when there's no motion. But motioneye still gives me bigger FPS (even after correcting 1 to on. Are you artificialy sending more frames than motion gives you? Or you just count boundary strings and occasionaly prevent some frames from being forwarded when using fps dimmer? I still don't get how motioneye can eat more CPU than my original setup using plain motion.

UPDATE: aaah i get it. the javascript generates sh*tload of GET requests. wow, that's so inneficient. I wondered why motioneye was so hard on my apache2 which provides me reverse proxy and HTTPS. Now i see.

This has two bad effects:

1.) It redownloads frame even when there was no new frame sent by motion to motioneye. 2.) It creates new HTTP connection which in worst case might lead to restarting TLS session, which is quite cpu heavy.

This has couple of possible solutions:

1.) RECCOMENDED: Stream MJPEG from motioneye to browser (don't put credentials to URL, use cookies. screw legacy browsers). Throttle on server-side simply by omiting some frames from original motion stream. 2.) Check if there really is new frame before downloading it (even more requests = still relatively inefficient) 3.) From time to time (every second or two?) ask server about rate of redownloading, so server can throttle the requests from clients if fps of streams given by motion drops. (unresponsive and still quite inefficient, because it will still make lots of requests).