Close

Lessons learned in duck streaming

wjcarpenterWJCarpenter wrote 05/06/2023 at 23:04 • 8 min read • Like

In the Spring of 2023, a mallard duck hen made a nest in our yard. We knew that meant ducklings in a few weeks, so I scrambled to figure out how to stream it for the enjoyment of friends, neighbors, and strangers. Of course, I don't mean the kind of stream where you might expect to find a duck. I mean a video stream. It's all over now, and the ducks have gone. Here is my Youtube playlist of the highlights.

I already had a few video cameras scattered about watching the outdoors. Even though we live in a suburb, and even though we have a fenced yard, we do get occasional visits from wildlife: cats, raccoons, cats, a possum, cats, squirrels, cats, and birds. None of those cameras cover the area where the duck nested (I'm pretty sure she didn't think about that when she picked the spot, but who knows). None of my current cameras were suitable for exposure to the amount of rain we're getting this Spring, and none of them have a big friendly button with a label liike "click here to stream to the universe".

This is a write-up of the ultra-fast learning I did to get my live stream going. 

I had to work fast because we didn't know how long the duck had already been nesting when we found out about it. A duck will lay eggs for about 10 days before starting incubation. Then all of the eggs incubate for about 28 days. All of the ducklings will hatch within a few hours of each other. Ducklings are "precocial". The mother duck does not actually feed them directly. Instead, within a day or so of hatching, she leads them to some place where they can feed themselves.

The first thing I did was order an outdoor surveillance camera. My criteria were:

Fast delivery and cheap requirements funnelled me to the many, many no-name Chinese cameras on Amazon that could arrive next day or the day after. Without time to really study the matter, 3rd party access to me meant a camera supporting Real Time Streaming Protocol  (RTSP). I later discovered that ONVIF is a sort of profile of conventions and discovery that uses RTSP. I only know a little bit about video codecs, but I had a hunch that H.264 was a good thing to have, and that H.265 was OK but not great to have (for reasons not completely clear to me). Most of the no-name Chinese cameras don't say anything about any of that stuff in their descriptions, but a few do. Most are locked into some proprietary access scheme developed by a chipset maker and need a dedicated mobile app to view the videos.

I'm not going to bother mentioning the particular model of camera that I got because they come and go anyhow, and it might not even be available by the time you read this. I'll just say that the Amazon description did explicitly mention RTSP support, and it met my other requirements. I'll also mention that the mobile app to configure it was Tuya Smart, which I was already using for other reasons.

OK, now I had the camera, and I'm skipping the step about running a long orange extension cord and mounting the camera to my fence with an amazing variety of boards and clamps. I was able to get the camera configured in the Tuya Smart app so that I could access the video stream over WiFi. How to get from there to live streaming?

One of the first things I did, after some Google searching, was install the Agent DVR application from ISpyConnect. This application is pretty cool and supports a huge variety of IP cameras. Since my camera supported ONVIF and RTSP, Agent DVR was able to work out the connection particulars with no trouble at all. Once that was working, it was also willing to tell me what it had discovered about RTSP streams. I found that my camera had a main stream of 1080p and a secondary stream of VGA (640x480). Agent DVR does have the ability to read an RTSP stream and relay it out to a server for live streaming, but that feature is not available in the free, unlicensed version. (That includes not working with the free trial of what you get with the license.) I'm not opposed to paying for a license for something like that, but for this brief adventure it didn't seem worth it unless I couldn't figure out any other way to do it. In my time of using Agent DVR, I was pretty impressed with it.

The natural place to want to live stream is Youtube since it has the right price (free). I learned that Youtube will accept a video feed over a protocol called Real-Time Messaging Protocol (RTMP). I also found that the extremely popular "does everything" open source ffmpeg application can read RTSP and write RTMP with any necessary conversions in the middle. I set about looking for recipes for doing that for live streaming to Youtube. Most of the recipes I found actually had too many ffmpeg options. I don't know if their authors needed them, but I was hoping I didn't. I eventually discovered that ffmpeg has a fake codec called "copy" which you can use to simply copy input to output with no resolution or encoding changes. I cross my fingers and tried it, and it worked with Youtube.

Here's my initial ffmpeg command line:

ffmpeg \
    -f lavfi -i anullsrc \
    -rtsp_transport udp -i "rtsp://my-camera-uri" \
    \
    -codec:v copy \
    \
    -f flv \
    "rtmp://a.rtmp.youtube.com/live2/my-youtube-livesteam-key"

I was able to run this on a Raspberry Pi 4 with 4mb RAM at only about 20-25% CPU. (That particular RPi does a few other things for me, but they are not resource intensive.) 

The "-f lavfi -i anullsrc" options are to provide silence instead of the actual audio stream. I didn't want to risk exposing incidental audio in case any of my neighbors were shouting their credit card numbers at the duck or whatever.

The RTMP URI for the output is readily available when you set up a live stream on Youtube. In fact the Youtube live streaming user experience is pretty good if you are doing something like a video show or podcast. There are some puzzlers if you are trying to do what I was doing, which is live stream a camera 24/7 for weeks (which, I have to admit, seems somewhat abusive to me).

One of the first things I learned is that if you just tell it to "start streaming now", it will automatically stop the live stream if your feed stops sending it video. That was a pretty big hitch for me for a couple of reasons. First, in my early days with this camera, it crashed once in a while and needed a power cycle to get it going again. That might have been somehow my fault because it stopped happening after a couple of days. Second, ffmpeg was sensitive to lots of things like network glitches and would throw errors and quit. When that happened, I had to first notice it, and then I had to log onto the RPi and restart ffmpeg, and then I had to start a new Youtube live stream. I resolved this with two different things.

I learned from some web site somewhere (sorry, lost the link) that if you schedule your Youtube live stream for a future date (for example, a month from now), you can still start streaming right away. But a side-effect of doing it that way is that it won't stop the live stream if your video feed stops sending for a while. So, if ffmpeg needed restarting, the Youtube live stream would pick up again automatically. In the interim, it would just show the spinning circle indicating buffering.

I read up on the error conditions under which ffmpeg would quit. It was pretty easy to configure it to keep going under most realistic glitchiness. But since this was during the time when I was still afraid my camera would crash now and then, and since ffmpeg didn't seem to recover when the camera was restarted, I wanted ffmpeg to automatically restart once in a while. I didn't find an option for "quit after X seconds", but I did find an option for "quit after X seconds of CPU time", which turned out to be close enough. I gave ffmpeg that command line option and put it into a loop in a simple shell script.

Here's what that looks like:

while true; do

ffmpeg \
    -loglevel error \
    -timelimit 600 \
    -abort_on empty_output_stream \
    \
    -f lavfi -i anullsrc \
    -rtsp_transport udp -i "rtsp://my-camera-uri" \
    \
    -codec:v copy \
    \
    -f flv \
    "rtmp://a.rtmp.youtube.com/live2/my-youtube-livestream-key"

date
echo restarting in 5s
sleep 5
done

Because the camera was controlled by Tuya Smart, I had planned to wire it into my Home Assistant setup. The power for the camera was plugged into a smart outlet. I would be able to detect the camera going offline and then script an action that would turn the outlet off and back on again to restart the camera. The script running ffmpeg would take care of automatically restarting the feed to Youtube after a reasonably short delay. The camera stopped crashing, so I never got around to doing this part.

I wanted to be able to save all of my live stream video on Youtube, but they have a 12 hour time limit. It's not a limit on the live stream, which you can keep going indefinitely as far as I can tell. It's a limit on saving or editing the video. If this were going to last more than a couple of weeks, I'd explore the possibility of using an API to restart the livestream every 11 hours or whatever. Instead, I just stopped it manually every once in a while. I found that the 12 hour limit was not always rigidly enforced, and I hypothesize that it's something to do with the background queuing system they use. I could sometimes stop the stream after more than 12 hours and be able to use the Youtube Studio editor to split it into chunks of less than 12 hours and save them. At other times, I couldn't do that. That's why if you look at the playlist you'll see some gaps in the coverage timeline.

Another thing I noticed early on was that each live stream session had a normal looking Youtube URL. If I restarting the stream, I got a new URL. Anybody visiting the old URL just saw that the stream was ended. They could replay it if it was one of the ones that was less than 12 hours and was saved. The solution to that is to give a live streaming pointer to the Youtube channel. This website is where I found out how to do that. The livestream URL for my channel is http://www.youtube.com/channel/UCCwsOcRtixI4AjSCQIEKErg/live.  It's the same format for everybody, with the unique looking part being the channel ID. You can find the channel ID in the advanced settings.

Youtube has a pretty nice feature called a clip, where you can create a link to a segment of a video up to 60 seconds long. I was sending my family those clips when I'd spot something interesting on the live stream, but when the live stream went away (if it was too long to save), the clip didn't work. My guess is that it does work on a live stream that is able to be saved (because it's shorter than 12 hours).

Like

Discussions