Youtube Live Streaming Camera

7,327

82

10

Introduction: Youtube Live Streaming Camera

As a YouTuber, I'm always looking for ways to streamline different tasks. Live streaming is definitely something that has the opportunity to be a LOT simpler. It would be nice if you just had a camera that you can take with you, turn on, and live stream. So that will be the primary goal of this project: to make a simple dedicated camera for live streaming to YouTube.


My idea is to make a simple video camera using a Raspberry Pi 3, 2.8" LCD Touchscreen, and the Pi Camera as the basic platform. We'll also need a small USB microphone to record audio, and some type of rechargeable battery to power it all. Then I'm going to 3D print a custom case shaped like the YouTube logo to power it all.

Don't feel like reading? Feel free to watch the video instead!

Step 1: Parts You Will Need

Along with various tools (soldering equipment, 3D printer, dremel, etc), I used these parts in order to complete this project:

  1. Raspberry Pi 3 Model B
  2. Adafruit 2.8" Touchscreen
  3. Raspberry Pi Camera Module
  4. Mini USB Microphone
  5. USB Cable On/Off switch
  6. 2500 maH Cell Phone Charger Battery Bank

Step 2: Setting Up the Raspberry Pi

As with any project using a Raspberry Pi, the first step is to get it set up. To do this, you'll need:

  • A Raspberry Pi 3
  • A micro SD Card (8gb or greater)
  • HDMI or composite monitor and cable
  • Keyboard and Mouse
  • Power supply

With the hardware set, we next need to load the software onto the PI. You can download the latest Raspbian software from here. It's a large file, so it may take a while to download.

But once it has, you can burn it to your SD card using the Etcher.io software for Windows, Mac and Linux.

After you've successfully copied the files to the SD card, you can put it in your Raspberry Pi, plug in the monitor, keyboard, mouse and then the power. After a minute or so, it should boot to the Desktop.

The first thing you want to do is connect to your internet by clicking on the internet icon in the upper right and selecting your wireless network. Then inter your password and click "connect". Next you can right click on that same icon, and select "Wireless and Wired Network Settings". Here, you'll want to make sure wlan0 is selected and then give it a static IP address that matches the IP scheme of your network.

To finish up, click on the start menu in the upper left go to Preferences > Raspberry Pi Configuration. On the "Interfaces" tab, select to enable SSH. Then on the "Localisation" tab, set your keyboard language settings to match your country. Then reboot your machine. Now you should be able to log in from a remote computer using SSH.

Step 3: Adding the Camera

The camera I'm using is the Raspberry Pi Camera Module v2. I like it because it's very flat in shape and doesn't take up any USB ports. It has it's own dedicated IO port. So with the Pi off, insert the Camera Module (as seen below). Then power your PI back on.

Before we can use the camera, we have to enable it. So after the Pi boots back up, you can SSH into it and run

sudo raspi-config
#Choose Interfacing Options > Camera > Enable
sudo reboot

Once your Pi boots back up, you should be able to utilize the camera.

Step 4: Setting Up the Touchscreen

I'm using an Adafruit 2.8" Touchscreen LCD. It comes connected with header pins that make it easy to fit right on top of the Raspberry Pi GPIO Pins.











Adafruit has some great documentation about setting up the Raspberry Pi, and they even have their own Raspbian Image that you can download and install with everything already on it. Sadly, the pre-made image didn't work for me, which is why I installed a fresh version of Raspbian.

The LCD requires a Kernel in order for it to work, so I'll need to download it manually from the Adafruit website (these steps are also on their instruction page).

sudo apt-get update
curl -SLs https://apt.adafruit.com/add-pin | sudo bash
sudo apt-get install raspberrypi-bootloader

Installing the bootloader will take a few minutes, but when it's done, you can shutdown your Pi, and unplug any other external monitors before turning it back on.
Once the Pi boots back up, we'll need to modify the Pi's boot config file and adjust it so that it displays to the LCD properly.

sudo nano /boot/config.txt 

and then add this text to the bottom of it:

dtparam=i2c_arm=on 
dtparam=i2s=on
dtparam=spi=on
dtoverlay=pitft28-resistive,rotate=90,speed=32000000,fps=20

In order to get anything to display on the LCD, we need to tell the operating system to use it as it's primary display. To do this, you can use these commands:

export FRAMEBUFFER=/dev/fb1 
startx

Now we can test it by displaying an image on it using the fbi (not that F.B.I.) image viewer.

sudo apt-get install fbi
wget http://www.tinkernut.com/wp-content/uploads/2015/01/logo_gear_sm3.png -O image.png
sudo fbi -T 2 -d /dev/fb1 -noverbose -a image.png

The LCD part works. Now we need to test the touch screen. By default, the touchscreen should work with the Adafruit kernel. But there are a few commands you can run to help calibrate it.

sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen ts_calibrate
sudo TSLIB_FBDEVICE=/dev/fb1 TSLIB_TSDEVICE=/dev/input/touchscreen ts_test

These commands will give you visual feedback on your screen that you can touch to calibrate your screen.

Step 5: Issue With Adafruit PiTFT Touchscreens

If you have an Adafruit PiTFT touchscreen like I do, you may find that no matter how much you calibrate the LCD, it still won't work with your Pygame code. This is because there is an issue with the Adafruit touchscreens and the current version of Raspbbian.

The touchscreens work well with the Raspbian "Wheezy" distro, but they don't play well with Raspbian "Jessie". There is a workaround, however, to get it functional again. It involves downloading and installing the "Wheezy" driver.

#enable wheezy package sources
echo "deb  http://archive.raspbian.org/raspbianwheezy  main
" >> /etc/apt/sources.list.d/wheezy.list
#set stable as default package source (currently jessie)
echo "APT::Default-release \"stable\";
" >> /etc/apt/apt.conf.d/10defaultRelease
#set the priority for libsdl from wheezy higher then the jessie package
echo "Package: libsdl1.2debian
Pin: release n=jessie
Pin-Priority: -10
Package: libsdl1.2debian
Pin: release n=wheezy
Pin-Priority: 900
" >> /etc/apt/preferences.d/libsdl
#install
apt-get update
apt-get -y --force-yes install libsdl1.2debian/wheezy

Running the above code should fix the issue and the touchscreen will now work with Pygame. So let's go ahead and create our own test script that sets a background, creates a button, and checks for touch input to perform an action.
pygame_test.py

import pygame 
import os 
from time import sleep 
import random 
os.environ['SDL_FBDEV']= '/dev/fb1' 
os.environ["SDL_MOUSEDEV"] = '/dev/input/touchscreen' 
os.environ['SDL_MOUSEDRV'] = 'TSLIB' 
pygame.init() 
lcd = pygame.display.set_mode((320,240)) 
lcd.fill((255,0,0)) 
def make_button(text, xpo, ypo, color): 
       font=pygame.font.Font(None,24) 
       label=font.render(str(text),1,(color)) 
       lcd.blit(label,(xpo,ypo)) 
       pygame.draw.rect(lcd, cream, (xpo-5,ypo-5,110,35),1) 
def random_color(): 
   rgbl=[255,0,0] 
   random.shuffle(rgbl) 
   return tuple(rgbl) 
blue = 26, 0, 255 
white = 255, 255, 255 
cream = 254, 255, 250 
lcd.fill(blue) 
pygame.mouse.set_visible(False) 
while 1: 
       make_button("Menu item 1", 20, 20, white) 
       for event in pygame.event.get(): 
               if (event.type == pygame.MOUSEBUTTONDOWN): 
                       print "screen pressed" 
                       lcd.fill(random_color()) 
                       pos = (pygame.mouse.get_pos()[0],pygame.mouse.get_pos()[1]) 
                       print pos 
       pygame.display.update() 

Step 6: Adding a Microphone

Since the Raspberry Pi doesn't have audio input by default, we're gonna have to use a USB based audio input. I just got a cheap mini USB microphone and plugged it in.

The Pi should automatically detect it and make it useable. I'm going to be using the microphone in conjunction with the Alsa audio library, so we'll need to install that first. Then we can test out the microphone by making a simple 30 second recording (make sure to have some speakers or headphones plugged in in order to hear the playback).

sudo apt-get install libasound2-dev
arecord -D plughw:1 --duration=30 -f cd -vv ~/test.wav 
omxplayer -p -o hdmi ~/test.wav  

Step 7: Streaming to Youtube

Although I'm using Youtube in this tutorial, the concept should also work with other streaming services like Twitch.tv and FacebookLive. Most of these streaming services use a protocol called Real-Time Messaging Protocol (RTMP). So in order to stream to Youtube, we'll need the RTMP URL as well as a private key for our specific stream.

To get your key and URL, go to your Youtube Dashboard and select "Live Streaming" and select either "Stream now" or "Events" and create a new event.

Following those steps will allow you to generate a new RTMP URL and private key. With our URL and key, we can now turn back to the Raspberry Pi to make a streaming program using Python. When it comes to streaming from a Raspberry Pi, there are actually several different methods. One of the easier ways is by installing avconv (part of the libav-tools package) and using raspivid to pipe the stream to the RTMP URL. Here's a sample of how that would work from the command line:

sudo apt-get install libav-tools 
raspivid -o - -t 0 -vf -hf -fps 30 -b 6000000 | avconv -re -ar 44100 -ac 2 -acodec pcm_s16le -f s16le -ac 2 -i /dev/zero -f h264 -i - -vcodec copy -acodec aac -ab 128k -g 50 -strict experimental -f flv rtmp://a.rtmp.youtube.com/live2/[your-secret-key-here]

This method might work alright through the command line, but whenever I tried to incorporate it into python code, it wouldn't work. There seems to be an issue with avconv and Youtube.
The program that worked the best for me was FFMpeg. Most of you may know that avconv is a 99% compatible replacement for FFMpeg, but Youtube streaming seems to fall within that 1%. Those of you that have worked with FFMpeg on the Raspberry Pi before know how difficult (and how long) it can be to install. I clocked it at just slightly over an hour from beginning to end using a Raspberry Pi 3 using the steps below (based on these steps https://github.com/tgogos/rpi_ffmpeg).

sudo sh -c 'echo "deb <a href="http://www.deb-multimedia.org">  http://www.deb-multimedia.org  </a> jessie main non-free" >> /etc/apt/sources.list.d/deb-multimedia.list' 
sudo sh -c 'echo "deb-src <a href="http://www.deb-multimedia.org">  http://www.deb-multimedia.org  </a> jessie main non-free" >> /etc/apt/sources.list.d/deb-multimedia.list' 
sudo apt-get update  
sudo apt-get install deb-multimedia-keyring 
sudo apt-get update  
sudo apt-get install build-essential libmp3lame-dev libvorbis-dev libtheora-dev libspeex-dev yasm libopenjpeg-dev libx264-dev libogg-dev
cd ~
sudo git clone git://git.videolan.org/x264 
cd x264/ 
sudo ./configure --host=arm-unknown-linux-gnueabi --enable-static --disable-opencl 
sudo make -j4
sudo make install 
cd ~
sudo git clone <a href="https://github.com/FFmpeg/FFmpeg.git">  http://www.deb-multimedia.org  </a> 
cd FFmpeg/ 
sudo ./configure --arch=armel --target-os=linux --enable-gpl --enable-libx264 --enable-nonfree 
sudo make -j4 
sudo make install 

Now that you're back from a nice break after letting all this install, we can finally write a simple streaming script to test it out. Basically we can use the subprocess PIPE command to emulate entering the command in a terminal and then "pipe" the camera stream through FFMpeg to Youtube. Getting the FFMpeg command just right is kinda tricky, but the one I used below seems to work well for me. The value that you might need to adjust is the itsoffset value. It's what helps sync the audio with the video. It basically "offsets" the video by a number in seconds. In my example, the offset is for 5.5 seconds. So if your audio and video or out of sync, you can try adjusting this number. NOTE*** If you start getting a lot of "Alsa X Buffer" errors, then that means your itsoffest is probably too high. Adjusting it to lower will fix this issue. Depending on the type of microphone your using, you may also need to change the hw value in the script. Mine is listed as card 1, so my hw value is 1,0 below. You can find what your audio device is listed as by typing the command:

arecord -l

This will list all of your recording devices and tell you what card number they're listed as.

stream_test.py

#!/usr/bin/env python3 
import subprocess 
import picamera 
import time 
YOUTUBE="rtmp://a.rtmp.youtube.com/live2/" 
KEY= #ENTER PRIVATE KEY HERE# 
stream_cmd = 'ffmpeg -f h264 -r 25 -i - -itsoffset 5.5 -fflags nobuffer -f alsa -ac 1 -i hw:1,0 -vcodec copy -acodec aac -ac 1 -ar 8000 -ab 32k -map 0:0 -map 1:0 -strict experimental -f flv ' + YOUTUBE + KEY 
stream_pipe = subprocess.Popen(stream_cmd, shell=True, stdin=subprocess.PIPE) 
camera = picamera.PiCamera(resolution=(640, 480), framerate=25) 
try: 
  now = time.strftime("%Y-%m-%d-%H:%M:%S") 
  camera.framerate = 25 
  camera.vflip = True 
  camera.hflip = True 
  camera.start_recording(stream.stdin, format='h264', bitrate = 2000000) 
  while True: 
     camera.wait_recording(1) 
except KeyboardInterrupt: 
     camera.stop_recording() 
finally: 
  camera.close() 
  stream.stdin.close() 
  stream.wait() 
  print("Camera safely shut down") 
  print("Good bye") 

Step 8: Creating a Touchscreen Interface

With the touchscreen, camera, and Youtube streaming all working, all we need now is a simple interface to control it. My vision is to have it so that you can preview the camera, using the touchscreen as a view finder, and then click a button to stream it to Youtube.

The vision I have is very similar to the Adafruit Pi Camera project. I like it because it uses the camera feed as the background of the touchscreen. It basically uses the io.BytesIO library to stream the buffer of camera images to use as background images on the touchscreen. We want to have 3 buttons on the touchscreen:

  • Stream - Pressing this will stream the camera and audio to Youtube
  • Preview - Pressing this will show a preview of the camera on the LCD screen
  • Power - Pressing this will shutdown the Operating System

So combining that with our streaming code, and our touchscreen code, I came up with something like this:

youtube_stream.py

#!/usr/bin/env python 
import os 
import time 
import io 
import pygame 
import picamera 
import subprocess 
os.environ['SDL_VIDEODRIVER'] = 'fbcon' 
os.environ['SDL_FBDEV'] = '/dev/fb1' 
os.environ['SDL_MOUSEDEV'] = '/dev/input/touchscreen' 
os.environ['SDL_MOUSEDRV'] = 'TSLIB' 
pygame.init() 
lcd = pygame.display.set_mode((0,0), pygame.FULLSCREEN) 
pygame.mouse.set_visible(False) 
img_bg = pygame.image.load('/home/pi/camera_bg.jpg') 
preview_toggle = 0 
stream_toggle = 0 
blue = 26, 0, 255 
white = 255, 255, 255 
cream = 254, 255, 250 
YOUTUBE="rtmp://a.rtmp.youtube.com/live2/"		 
KEY= #ENTER PRIVATE KEY HERE#				 
stream_cmd = 'ffmpeg -f h264 -r 25 -i - -itsoffset 5.5 -fflags nobuffer -f alsa -ac 1 -i hw:1,0 -vcodec copy -acodec aac -ac 1 -ar 8000 -ab 32k -map 0:0 -map 1:0 -strict experimental -f flv ' + YOUTUBE + KEY
stream_pipe = subprocess.Popen(stream_cmd, shell=True, stdin=subprocess.PIPE) 
camera = picamera.PiCamera() 
camera.resolution = (1080, 720) 
camera.rotation   = 180	 
camera.crop       = (0.0, 0.0, 1.0, 1.0) 
camera.framerate  = 25 
rgb = bytearray(camera.resolution[0] * camera.resolution[1] * 3) 
def make_button(text, xpo, ypo, color): 
       font=pygame.font.Font(None,24)	 
       label=font.render(str(text),1,(color)) 
       lcd.blit(label,(xpo,ypo)) 
       pygame.draw.rect(lcd, cream, (xpo-5,ypo-5,150,35),1) 
def stream(): 
	camera.wait_recording(1) 
def shutdown_pi(): 
       os.system("sudo shutdown -h now") 
def preview(): 
	stream = io.BytesIO() 
	camera.vflip = True
	camera.hflip = True 
	camera.capture(stream, use_video_port=True, format='rgb', resize=(320, 240)) 
	stream.seek(0) 
	stream.readinto(rgb) 
	stream.close() 
	img = pygame.image.frombuffer(rgb[0:(320 * 240 * 3)], (320, 240), 'RGB') 
	lcd.blit(img, (0,0)) 
	make_button("STOP", 175,200, white) 
	pygame.display.update() 
try: 
	while True: 
		if stream_toggle == 1: 
			stream() 
		elif preview_toggle == 1: 
			preview() 
		else: 
			click_count = 0		 
			lcd.fill(blue) 
			lcd.blit(img_bg,(0,0)) 
			make_button("STREAM", 5, 200, white) 
			make_button("PREVIEW",175,200, white) 
                        make_button("POWER", 200, 5, white) 
			pygame.display.update() 
		for event in pygame.event.get(): 
			if (event.type == pygame.MOUSEBUTTONDOWN): 
				pos = pygame.mouse.get_pos() 
			if (event.type == pygame.MOUSEBUTTONUP): 
				pos = pygame.mouse.get_pos() 
				print pos 
				x,y = pos 
				if y > 100: 
					if x < 200: 
						print "stream pressed" 
						if stream_toggle == 0 and preview_toggle == 0: 
							stream_toggle = 1 
							lcd.fill(blue) 
							lcd.blit(img_bg,(0,0)) 
							make_button("STOP", 20, 200, white) 
							pygame.display.update() 
							camera.vflip=True 
							camera.hflip = True 
							camera.start_recording(stream_pipe.stdin, format='h264', bitrate = 2000000) 
						elif preview_toggle == 1: 
							preview_toggle = 0 
							lcd.fill(blue) 
							lcd.blit(img_bg,(0,0)) 
							make_button("STREAM", 5, 200, white) 
							make_button("PREVIEW",175,200, white) 
							pygame.display.update() 
						else: 
							stream_toggle = 0 
							lcd.fill(blue) 
							make_button("STREAM", 5, 200, white) 
							make_button("PREVIEW",175,200, white) 
							pygame.display.update() 
							camera.stop_recording() 
					elif x > 225: 
						print "preview pressed" 
						if preview_toggle == 0 and stream_toggle == 0: 
							preview_toggle = 1 
							lcd.fill(blue) 
							make_button("STOP", 175,200, white) 
							pygame.display.update() 
						elif stream_toggle == 1: 
							stream_toggle = 0 
							lcd.fill(blue) 
							make_button("STREAM", 5, 200, white) 
							make_button("PREVIEW",175,200, white) 
							pygame.display.update() 
							camera.stop_recording() 
						else: 
							preview_toggle = 0 
							lcd.fill(blue) 
							make_button("STREAM", 5, 200, white) 
							make_button("PREVIEW",175,200, white) 
							pygame.display.update() 
except KeyboardInterrupt: 
	camera.stop_recording() 
	print ' Exit Key Pressed' 
finally: 
	camera.close() 
	stream_pipe.stdin.close() 
	stream_pipe.wait() 
	print("Camera safely shut down") 
	print("Good bye") 

Customize the script the way you want to make it work for you, and then test it out. Just run it using

sudo python youtube_stream.py

Then click on the "Preview" button to preview your camera. Press "Stop" to go back to the main menu. Then click the "Stream" button to start streaming to Youtube. Now you should be able to go to your Youtube Live dashboard and preview your live stream! Once you're happy with the results, the last thing to do is to make the script executable and add it to the Pi's rc.local file so that it auto-launches whenever the Pi boots up

sudo chmod +x youtube_stream.py
sudo nano /etc/rc.local

Towards the bottom of the rc.local file, right before "exit 0", add this line:

sudo python /home/pi/youtube_stream.py &

Save it and reboot the Pi. Once it's through rebooting, you should see your new touchscreen interface!

Step 9: Adding a Power Source

Obviously we want to make this camera portable, so we're going to need a battery. I like to use "emergency cell phone chargers" because they can last for a while, they can be recharged, and a lot of them even have a built in USB cable that can plug directly into the Pi!

The only thing one of these battery banks doesn't have is an an/off switch. There are a couple ways to go about this: You could either solder a switch onto the battery bank yourself, or you could buy a premade micro-usb on/off switch, which is a much safer way to go than soldering near a lithium polymer battery.

This will take care of turning the power on and off, but it's generally not a good idea to cut the power to a Pi while it's running software. This can corrupt the software and/or the Pi itself. You eagle eyed code monkeys may have noticed that the code above generates a "Power" button that can shut down the Raspberry Pi OS.
So you can switch the USB cable "on" to power on the Pi, and then touch the "Power" touchscreen button to turn off the Raspberry Pi OS before switching the USB cable to "off".

Step 10: Making an Enclosure

The finishing touch for this project is 3D printing an epic case to contain everything! There are plenty of great CAD programs out there, but for simplicities sake, I'm using Tinkercad. You'll want to 3D print the enclosure using supports.

The LCD, Raspberry Pi and Camera should basically snap into place, as long as you're using the same parts as me.

The LiPo battery will sit in between the camera and the Pi, but you won't be able to plug the battery directly into the USB port of the Pi because there isn't enough room in the case. As an alternative, we can strip the wires coming from the battery and solder them to the PP2 and PP5 ports on the back of the Raspberry Pi Micro USB port.

I used hot glue to hold everything into place within the camera case, but DO NOT USE HOT GLUE DIRECTLY ON THE LIPO BATTERY!!! Once all the pieces are together, you can test it out. If it works, you can hot glue the two halves of the case together!

Step 11: Testing It Out!

With the pieces together, and your Youtube account open, turn it on and use the touchscreen interface to start streaming! Below is a sample recorded from a live stream done using this device.

Share

    Recommendations

    • Water Contest

      Water Contest
    • Fix It! Contest

      Fix It! Contest
    • Metalworking Contest

      Metalworking Contest

    10 Discussions

    I would add a mic jack so I could use my wireless lapel mic, that way I could get better audio. Just a thought.

    0
    None
    Gabo18

    Question 4 months ago

    Hi, how are you? I have a question about this awesome project:

    Can you make multiple cameras and use something like OBS to switch between them, still using YouTube live as your output source?

    Thanks

    Great project

    Downfall is not everyone has hdmi moniter/tv like myself

    can any version of raspberry pi be used ?

    I was thinking of the one with yellow video connection

    4 replies

    the pi 3 has a 4 pin headphone connector that has left right, video and ground. with the right cable you can use a standard monitor

    Which version of pi are you reffering to ?

    Thanks for answer(s)

    Even the Raspberry Pi 3 has the ability to connect using a "yellow" connection. You just need to wire it directly to the board.

    Wow! That is awesome! I really didn't expect video quality that good from that little camera module.

    Very elegant. Exceptionally high standard of explanation and visuals. This I should receive a prize!

    Dang, you got skills man! When I need a camera, I think: hmmm, let's see if Amazon has got something for cheap.

    You: "guess it's time to make another one."