Having managed to get VLC streaming from Pi Camera to Nexus 7 Android tablet working, it was only a matter of time before I wanted to stream from the RasPiCamcorder. But when I tried it, I came across an annoying problem. RPi.GPIO needs to run as root (that’s why we always use sudo for our GPIO stuff)
But VLC refuses to run as root. This means you can’t run them both from the same program. There’s all sorts of clever solutions people proposed (and I wasted a lot of time unsuccessfully trying them all out) about changing IDs within a script. VLC seemed to be immune to all that. So, for a time, I gave up. But the mind didn’t switch off and a workaround came to me while I was doing something else.
I needed a way to separate out the GPIO part from the VLC streaming part. But how to get the two parts to talk to each other?
And then it hit me. “Everything in Linux is a file.”
So, what’s to stop me writing to and reading from a file (not owned by root) to check GPIO status? Nothing at all! It’s a bit of a ‘cludgy’ workaround, but it works – and here’s a picture of the RasPiCamcorder streaming to my phone and Nexus 7 simultaneously, while I took the photo with my main camcorder…
Here’s a short video of it working
OK let’s back up and explain
So basically, I’m running the (sudo) GPIO part as a second script. Each time the status of the button inputs changes, it writes the new status (1 or 0) to a file that can be read by the first script (non-root user, VLC streaming control).
I think I’ve made that sound much more difficult than it really is, so I’ll try and summarise it.
- You run the non-sudo script (controls VLC and camera)
- This script creates a file (owns it) which the other one will write to [script 1, line 49]
- Then it starts the second script as root (the GPIO part) [script 1, line 54]
- Second script reads the buttons (input ports) [script 2, lines 83 & 91]
- If start button pressed, it writes 1 to the file [script 2, line 53], if stop button pressed, 0 [script 2, line 98]
- Script 1 reads this file 10 times per second and switches streaming on or off in response to whether the file contains a 1 or a 0 [script 1, lines 60-77]
So, yes. It’s a ‘cludgy’ workaround, but it works, and it made me feel very clever for a while because I made it do what I wanted it to do. ;)
If you want to see the scripts that use this trick, they are picamstreamer.py and picamstream-sudo.py below…
Script 1 picamstreamer.py
#!/usr/bin/env python2.7 # script by Alex Eames https://raspi.tv from subprocess import call import sys import time front_led_status = sys.argv[-1] if front_led_status == "0": print "front LED off" front_led_status = 0 streaming_on = 0 streaming_file = "/home/pi/streaming.txt" if front_led_status == 0: sudo_file = "sudo python /home/pi/picamstream-sudo.py 0 &" else: sudo_file = "sudo python /home/pi/picamstream-sudo.py &" stream = "raspivid -o - -t 9999999 -w 640 -h 360 -fps 25|cvlc stream:///dev/stdin --sout '#standard{access=http,mux=ts,dst=:8090}' :demux=h264 &" # you can change -w and -h numbers for whatever suits your network. # Depending on what I'm streaming to, mine can cope with 720p, # which is -w 1280 -h 720 def stream_video(): print "starting streaming\n%s" % stream call ([stream], shell=True) def stop_stream(): print "stopping streaming" call (["pkill raspivid"], shell=True) call (["pkill vlc"], shell=True) def check_streaming_status(): # read file streaming_file, make into int() set streaming_on equal to it vrn = open(streaming_file, 'r') streaming_on = int(vrn.readline()) #print "streaming_on is %d" % streaming_on vrn.close() return streaming_on def write_streaming_status(streaming_on): vrnw = open(streaming_file, 'w') vrnw.write(str(streaming_on)) vrnw.close() try: write_streaming_status(0) except: print "couldn't write streaming status" sys.exit() call ([sudo_file], shell=True) previous_streaming_on = 0 counter = 0 #have a file containing the streaming_on variable value while True: streaming_on = check_streaming_status() #print "streaming status = %d" % streaming_on if streaming_on != previous_streaming_on: if streaming_on == 1: stream_video() elif streaming_on == 0: stop_stream() else: stop_stream() print "Closing picamstreamer.py" sys.exit() if counter % 50 == 0: print "streaming status = %d" % streaming_on previous_streaming_on = streaming_on counter += 1 time.sleep(0.1)
Script 2 picamstream-sudo.py
#!/usr/bin/env python2.7 # script by Alex Eames https://raspi.tv import RPi.GPIO as GPIO import sys import os import time from time import sleep front_led_status = sys.argv[-1] if front_led_status == "0": print "front LED off" front_led_status = 0 streaming_on = 0 streaming_file = "/home/pi/streaming.txt" time_off = 0 GPIO.setmode(GPIO.BCM) # GPIO 23 set up as input, pulled up to avoid false detection. # wired to connect to GND on button press. # So we'll be setting up falling edge detection GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_UP) # GPIO 24 set up as an input, pulled down, connected to 3V3 on button press GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # Set up GPIO 5 for camera LED control and rear LED control GPIO.setup(5, GPIO.OUT) GPIO.setup(22, GPIO.OUT) def write_streaming_status(streaming_on): vrnw = open(streaming_file, 'w') vrnw.write(str(streaming_on)) vrnw.close() def check_streaming_status(): # read file streaming_file, make into int() set streaming_on equal to it vrn = open(streaming_file, 'r') streaming_on = int(vrn.readline()) #print "streaming_on is %d" % streaming_on vrn.close() return streaming_on # threaded callback function runs in another thread when event is detected # this increments variable rec_num for filename and starts recording def stream_button(channel): global time_off time_now = time.time() if (time_now - time_off) >= 0.3: streaming_status = check_streaming_status() if streaming_status == 0: write_streaming_status(1) print "stream button pressed" if front_led_status != 0: GPIO.output(5, 1) GPIO.output(22, 1) time_off = time.time() def flash(interval,reps): for i in range(reps): GPIO.output(5, 1) GPIO.output(22, 1) sleep(interval) GPIO.output(5, 0) GPIO.output(22, 0) sleep(interval) def shutdown(): print "shutting down now" flash(0.05,50) GPIO.cleanup() os.system("sudo halt") sys.exit() try: write_streaming_status(0) except: print "couldn't write streaming status" sys.exit() # when a falling edge is detected on blue stream button port 23 stream_button() will be run GPIO.add_event_detect(23, GPIO.FALLING, callback=stream_button) try: while True: # this will run until black button attached to 24 is pressed, then # if pressed long, shut program, if pressed very long shutdown Pi # stop recording and shutdown gracefully print "Waiting for button press" # rising edge on port 24" GPIO.wait_for_edge(24, GPIO.RISING) #print "Stop button pressed" time_now = time.time() if (time_now - time_off) >= 0.3: streaming_status = check_streaming_status() if streaming_status == 1: write_streaming_status(0) print "Stop button pressed" GPIO.output(5, 0) GPIO.output(22, 0) time_off = time.time() # poll GPIO 24 button at 20 Hz continuously for 2 seconds # if at the end of that time button is still pressed, shut down # if it's released at all, break for i in range(60): if not GPIO.input(24): break sleep(0.05) if 25 <= i < 58: print "Closing program" flash(0.02,50) # interval,reps write_streaming_status(2) # 2 will close the host program GPIO.cleanup() sys.exit() if GPIO.input(24): if i >= 59: shutdown() finally: write_streaming_status(0) GPIO.cleanup() # clean up GPIO on exit
I hope to release the entire suite of RasPiCamcorder software soon – I just need to do a little work on the documentation before I can unleash it on the world.
I hope you found this little trick useful. It’s a bit convoluted, but it gets the job done.
The video is still marked as “private” ?
Thanks. Sorted now. I had changed the description to include “(<1 min)" at the same time as making it public but it was rejected by YT. All fixed now.
Thanks. Works fine now. :-)
Brilliant stuff!
I’m looking into doing something along similar lines at my squash club.
I’d like to record matches, but also want the ability to stream the live play to a nearby TV.
The recording should be remote controlled.
This all looks very doable and affordable, using a Pi, from what I’ve seen on your site.
You won’t even need the VLC GPIO fix for that if you’re going to control it by ssh or bluetooth. You could just remotely record and hook up monitors to HDMI. Of course, there’s loads of other ways to do it. :)
TV is about 40-50 meter from court. Probably rules out hdmi?
I would be keen to weigh up different options.
Care to elaborate on some of the other ways.
In that case the options are more limited. I haven’t yet figured out how to stream AND record at the same time. But it must be doable. But if not, you could record the stream with another device. You’ll need a good router, either fast wifi or better yet ethernet.
You’ll have to try and see what throughput your network can handle. No reliable way of judging that in advance.
50m HDMI? Sounds a bit long.No idea what the specs are though.
It’s actually dead easy – just use the ‘tee’ command in the middle of your pipe, i.e. change the streaming command to:
raspivid -o - -t 9999999 -w 640 -h 360 -fps 25 | tee videofilename.h264 | cvlc stream:///dev/stdin --sout '#standard{access=http,mux=ts,dst=:8090}' :demux=h264
Excellent. Thanks Andrew:)
I’ve finally got round to having a bit of a fiddle with this, and came up with two approaches to getting this working (tested in a Bash script being run as root).
The first (easier) approach simply runs the whole streaming command as the ‘pi’ user:
And the second (more flexible) approach continues to run raspivid as ‘root’, but just runs the vlc part as ‘pi’:
Sorry I never investigated this earlier, to save you from all this extra hassle!
Andrew ‘Linux’ Scheller ;-)
You can operate the GPIO as a non-root user. Just use WiringPi instead of RPi.GPIO.
How do you do that with WiringPi for Python then? I know it’s theoretically possible, but don’t know how to do it.
I am look for a program/code to setup a Live Stream for my video production company …
With network cable for indoors
and
3G Dongle for outdoors
the live stream will run on my web site, using YOUTUBE live events http://www.photosofafrica.com/live-broadcast-youtube
so Live stream will be in HD using my HD Professional video Camera..not the Raspberry 5mp Camera…
any ideas ? PLEASE ADVISE…
You won’t be able to use the RaspberryPi for this then, it’s not fast enough to process video transmitted over USB (which must go via the CPU). It’s only able to process video from the Pi Camera because it connects directly to the GPU via the CSI connector, bypassing the CPU. (the GPU and CPU are both part of the same BCM2835 SoC, but the GPU is much more powerful than the CPU)
If you don’t think the CPU can handle video transmitted over USB then try connecting any usb webcam after installing motion “apt-get install motion”.
I’ve used this for years and it can do motion detection, streaming, masking, snapshots, and many more, and can do this with upto 4 webcams!!!
You can hack VLC to allow running it as root. Make a backup copy of the binary (/usr/bin/vlc) then open vlc with a hex editor and search for the ASCII string “geteuid” and change it to “getppid”. Now it will run as root (or anyone else).
what i have to do is , i’m working on a project which is a stair climbing robot which can detect explosive ( which has metal in it) along with live video streaming using Raspberry pi B+ and i am totally unware about how to play with camera stuff. A little help would have been great. I want to make it look like when i press the V button it will start making video and stream it on web or vlc similarly S button for stop. A little help would have been great, please !
This is a great tutorial. I have one question How do I copy and paste the code to the Rasberry Pi I am using the Pi headless via SSH Thank you
SCP or SFTP
https://www.raspberrypi.org/documentation/remote-access/