Streaming from Raspberry Pi to YouTube only when someone is watching

Introduction

In this project I will show how to stream an video from a USB camera connected to Raspberry Pi to YouTube. Streaming will not be continuous – the camera will be turned on and streamed to YouTube only when someone opens a page with a YouTube window.

What will be needed

  • USB camera – I use the A4Tech PK-910H model – before buying the camera, please check if it will work with Rasbian
  • Raspberry Pi – I use RPI4 with 4GB Ramu, I also tested on RPI3 (below screen with Rpi4 htop when streaming video with a resolution of 1280x720 as you can see processor cores are used in 36% at one core)
  • Heatsink for Raspberry Pi CPU – streaming can make Raspberry Pi hot, therefore heatsink is needed, I use Flirc Raspberry Pi 4 Case (Silver)

    it is an aluminum box that also acts as a heat sink. When using it, the processor temperature is around 45C at an outside temperature of 24C. More about this box on the Mr. Andreas Spiess channel, the only caveat I have for this box is that there is no output for the belt from the camera connected directly to the RPI board, and to output PINS with a 40-pin belt you need to saw the sides of the tape plug

How it will work

To start stream the following command will be run:

ffmpeg -threads 0 -f v4l2 -i /dev/video0 -ar 44100 -ac 2 -acodec pcm_s16le -f s16le -ac 2 -i /dev/zero -acodec aac -ab 128k -strict experimental -s 1280x720 -b 6000000 -aspect 16:9 -vcodec h264_omx -vb 820k -pix_fmt yuv420p -g 60 -r 30 -f flv rtmp://a.rtmp.youtube.com/live2/SECRET_KEY

of course you must install ffmpeg before if you don’t have one(sudo apt-get install ffmpeg )

the script will be run when our website with a YouTube frame will be displayed by at least one person, when the page is closed and not re-opened within 10 seconds, the script will be ‘killed’ the webcam will turn off and will not stream to YouTube ‘ anymore.

Because we will actually create a new stream each time, iframe with the stream address must point not to a specific stream but to the active stream of the given user, i.e.

https://www.youtube.com/embed/live_stream?channel=CHANNEL_ID&autoplay=1

Because of that our streams has to be public

 

Let’s do this 🙂

in fact, it takes a few clicks to start a project – because this project is already in the quick projects tab(https://app.remoteme.org/en/#/app/quickstart)

click “Read More or Build It” on the project:

then in  Build It tab:

we filled YouTube stream name / key, which we download from YouTube at https://www.youtube.com/live_dashboard

it will have a form similar to: 7awp-w65c-zbas-61c9 - however, you can enter anything and then complete it with the correct secret key in the file youtuberun.sh

When we have not streamed anything before, we need to activate the service – activation takes up to 24h only then we will be able to start streaming

Channel id is taken from the address https://www.youtube.com/account_advanced

in my case it’s  ZCPuP7AKof_poZY664N4yJCA

after filled

then click Next step – choose or add Raspberry Pi (in case of problems please refer to the article about Raspberry Pi in RemoteMe i python devcies in RemoteMe ) , then next step and the green “build the project” button and after successfully creating the project we close the window.

What happened

A page has been created, a python script has been added:

we can open the page to see if everything works:

after opening we will see the page where after a while the image from streaming will appear.

How exactly it works (and what to do if the image is not displayed)

Let’s start by discussing the files on your device python script:

1) youtuberun.sh – after open we will see  ffmpeg command:

ffmpeg -threads 0 -f v4l2 -i /dev/video0 -ar 44100 -ac 2 -acodec pcm_s16le -f s16le -ac 2 -i /dev/zero -acodec aac -ab 128k -strict experimental -s 1280x720 -b 6000000 -aspect 16:9 -vcodec h264_omx -vb 820k -pix_fmt yuv420p -g 60 -r 30 -f flv rtmp://a.rtmp.youtube.com/live2/SECRET_KEY

if the image is not streaming to YouTube, I recommend run this command directly in the console and check the logs, it may turn out that we do not have ffmpeg installed (then install by calling sudo apt-get install ffmpeg) or our camera is at a different address than / dev/video0 (then edit the file and save), in this file we can also change the parameters of our stream sent to YouTube – a preview of the stream can be found at: https://www.youtube.com/live_dashboard

2) python.py is more complicated – to understand how it works, remember that our website has id 2:

and that the value of the youtube_state variable (read about variables in RemoteMe) keeps the current state of YouTube stream and it is:

-1:Youtube FAIL
0:Youtube OFF
1: Youtube ON
2:Youtube STARTING
3:Youtube CLOSING

I will now discuss individual parts of the file code python.py

because we want to enable streaming when our website with deviceId = 2 connects – we set the function onDeviceConnectionChange will be called as any device changes the connection status with the RemoteMe platform – and in the function itself we only filter status changes for the device with id 2 (because it is the deviceId of our website), then the current state is saved to the receiveDeviceConnected global variable

variable state readout takes place in a separate thread whose code looks like this:

the function has an infinite loop that checks if the device is connected and, depending on what was the previous status, starts streaming or closes streaming 10 seconds after disconnecting the website.

Streaming enables the function

which runs the youtuberun.sh script in a separate thread, and the function:
calls the pkill command on our thread – to end it with its “children” threads (then the webcam turns off and we don’t stream anything anymore)

in addition, both functions set youtube_state variables by calling the function:

the value of the youtube_state variable is read by the website (discussed below) and displays the appropriate message to the user and injects the iframe code with YouTube preview.

a function worth discussing is also the function:

it checks by scanning the script output youtuberun.sh whether the message “speed =” appeared within 40s if so it means that our ffmpeg is streaming correctly, if it doesn’t mean that something went wrong and the appropriate value of the youtube_state variable is set

In addition, python.py checks the temperature of our raspberry and sets the variable cpu_temp which is displayed on the webpage.

What’s happening on the website

here you will find a detailed description about websites is in RemoteMe, and here about RemoteMe components

and now let’s discussed script.js files because only it requires explanations:

we check if our RPI is connected, if so we call the function

this feature notifies the user of notifications, and when YouTube is actively enabled it injects a YouTube frame into html:

    $("#youtubeContainer").html(<iframe width="100%" height="100%" src="https://www.youtube.com/embed/live_stream?channel=CHANELID&autoplay=1" frameborder="0" allowfullscreen></iframe>);

however, this only happens if the active transmission status is the first received – otherwise we refresh the page after 10 seconds (for unknown reasons this solution turns out to be better than simply injecting the YouTube frame) – then the first received state is the active state (set through the page before refreshing, and because Python waits 10 seconds after disconnecting the page will not be able to turn off the transmission) and we inject the frame.

Problems I noticed

Sometimes (I can’t determine the exact scenario) the YouTube frame shows the recorded previous broadcast – then it helps refreshing the page, or you need to delete the recorded broadcasts directly on YouTube. In the Python stopYoutube function, the pkill command is invoked three times – sometimes the first call does not kill the thread.

Conclusion

I hope that the project will prove useful, and thanks to it you will give your cams and internet connections a break :). If you have an idea to improve scripts, write on the project’s Facebook page. I remind you that there is documentation of remoteMe libraries where you will find a description of the JavaScript, Python and ESP functions that I use in my examples