3 ms·
I have been running for some time a small single-stream video streaming server. When I saw Owncast mentioned here my immediate thought was to switch over to it,
by jcrawfordor 6y ago
I have been running for some time a small single-stream video streaming server. When I saw Owncast mentioned here my immediate thought was to switch over to it, because it has features beyond my homegrown solution (based on nginx-rtmp and a Python/Flask application which performs "management" functions such as authentication of the publisher and injecting an "idle" animation when there is no publisher). For reasons largely of laziness I run this on a cheap VPS instead of on the larger machine I have colo'd.
Unfortunately I immediately ran into huge performance issues with owncast compared to my solution, with input bitrates stuck at 200-300kbps. I haven't looked into it exhaustively but I think the main problem is that owncast seems to encode the video n+1 times where n is the number of desired quality levels (extra encoding pass on the published stream to smooth out publishing problems), while my solution sends out the original published stream as the high-quality variant and so encodes n-1 times with a couple additional steps of putting the same streams into new containers. Of course I have also set ffmpeg/libx264 to very high performance options, and I think owncast is less conservative here.
Really just an FYI for anyone else looking at making a switch or doing something similar. Video encoding is CPU intensive so if you want to run it on a small/inexpensive VPS, it's helpful to 1) architect to absolutely minimize the number of encoding passes required (even when new containers are needed), 2) provide fine-tuning of the encoder settings, since just the change from "fast" to "veryfast" with libx264 makes a pretty big difference on CPU time without a very noticeable difference in the video output.
Another issue with owncast is that it has choppy/unreliable response from the video player to the actual stream starting/stopping. My solution has the same problems. We're both using the same frontend video player, and I think it's a combination of limitations of that video player and inherent limitations of HLS/MPEG-DASH (the "download a playlist over and over again" model of HLS has some intrinsic issues when it comes to the generation of the playlist starting and stopping). I almost solved this in my own solution by 1) making it so that, in theory, there is always a video stream because the server "plays a video to itself" when there is no publisher, 2) a very lazy fix of having the frontend page auto-refresh periodically when playback fails to start. These are far from perfect and there is still some choppiness/buffering/repeated playback of a small segment when publishing starts and stops (and thus the management server starts/stops feeding the idle animation).
I think the way to really fix these problems is to write a custom demuxer for ffmpeg that uses a small buffer of a "technical difficulties" still or whatever to feed into the processing chain when the stream publisher (whether internal or external) fails to deliver a packet for a certain time period, thus preventing generation of the HLS playlist ever halting for long enough for the video player to stall. I'm currently feeding an ffmpeg encoder with named pipes of uncompressed media streams and this is kind of an off-label use that ffmpeg handles but isn't entirely happy about, and particularly requires some hacking to get ffmpeg to never think the stream ended even when the container says so. A custom demuxer is is on my list of things to do but I'm not much of a C++ person so it's a little daunting for me.
Perhaps one day I will publish my solution but it's extremely janky right now and has a lot of hard-coded config. I also think it's fairly easy to come up with on your own with some basic Linux knowledge and a willingness to spend an evening messing around with ffmpeg, pipes, different containers, and just seeing what it lets you get away with. Hint: getting ffmpeg to completely ignore the DTS timestamps on the incoming container was surprisingly confusing, know that the -re and -r flags have special meanings when used on the "input side" of the command.
Finally, if you're especially latency/synchronization sensitive (e.g. multiple are watching and you want them to be strictly in sync), HLS and MPEG-DASH both become a nightmare. This is frustrating enough that I originally decided to just provide RTMP and make people use a native client but ofc there's a large portion of people who don't want to expose their computer to anything that isn't a web browser, so instead I spent a lot of time trying to tune the HLS production to both be stable and low latency, and, well, HLS just doesn't do that well. The HLS settings that I got to provide a really stable stream lead to up to 60s, occasionally greater out-of-sync.
- joshspankit 6y agoThe fact that the media streaming space is so challenging is supremely frustrating to me. Encoding/decoding aside as codecs are understandably challenging, end-to-end latency is basically a nightmare even at scale (I feel like I’ve tried every one-to-many video streaming apps starting with Periscope, and I have yet to see one with less than 15s latency from broadcaster to recipient) As well, viewer sync seems to either be a “problem” no one wants to “solve”, or it’s in the realm of magic. Plex clients even report their playback position every second or less and yet the variation on the “watch together” feature is all over the place. We also now have PTP which feels like a perfect fit for “clock” synchronization, but I have yet to see a single streaming technology use it or anything close to it.