Tuesday 10 September 2013

Raspberry Pi - Run Raspivid with Python

I've been looking for a way to control raspivid with Python and it seems that a few people have also struggled particularly with starting and stopping raspivid, so I thought I would put together a Python class to control raspivid.

Its a simple class called RaspiVidController which uses threading to not block the calling program but stay alive while the raspivid is running and shut down if you choose to stop it or it times out.

Usage
The class is created by passing 3 parameters:
  • filePath - the path of the file where the video is to be saved
  • timeout - the time in milliseconds raspivid should run for
  • preview - whether raspivid should preview output to the screen
There is also an optional parameter, otherOptions, which can be used to pass any other options to raspivid as a list e.g. ["-fps", "25", "-vf"].

The 3 key methods in the class are:
  • start - start raspivid, this immediately returns to the calling program, but raspivid is running in the background
  • stopController - stops the controller and raspivid if its running
  • isAlive - returns True if raspivid is still running
There is a more complex example in the code below, but a simple example would be:

#create the controller class
vidcontrol = RaspiVidController("/home/pi/test.h264", 10000, False)

#start raspivid
vidcontrol.start()

#DO SOME STUFF

#stop raspivid 
vidcontrol.stopController()

Code
import os
import subprocess
import threading
import time

RASPIVIDCMD = ["raspivid"]
TIMETOWAITFORABORT = 0.5

#class for controlling the running and shutting down of raspivid
class RaspiVidController(threading.Thread):
    def __init__(self, filePath, timeout, preview, otherOptions=None):
        threading.Thread.__init__(self)
        
        #setup the raspivid cmd
        self.raspividcmd = RASPIVIDCMD

        #add file path, timeout and preview to options
        self.raspividcmd.append("-o")
        self.raspividcmd.append(filePath)
        self.raspividcmd.append("-t")
        self.raspividcmd.append(str(timeout))
        if preview == False: self.raspividcmd.append("-n")

        #if there are other options, add them
        if otherOptions != None:
            self.raspividcmd = self.raspividcmd + otherOptions

        #set state to not running
        self.running = False
        
    def run(self):
        #run raspivid
        raspivid = subprocess.Popen(self.raspividcmd)
        
        #loop until its set to stopped or it stops
        self.running = True
        while(self.running and raspivid.poll() is None):
            time.sleep(TIMETOWAITFORABORT)
        self.running = False
        
        #kill raspivid if still running
        if raspivid.poll() == True: raspivid.kill()

    def stopController(self):
        self.running = False

#test program
if __name__ == '__main__':

    #create raspivid controller
    vidcontrol = RaspiVidController("/home/pi/test.h264", 10000, False, ["-fps", "25"])

    try:
        print("Starting raspivid controller")
        #start up raspivid controller
        vidcontrol.start()
        #wait for it to finish
        while(vidcontrol.isAlive()):
            time.sleep(0.5)

    #Ctrl C
    except KeyboardInterrupt:
        print "Cancelled"

    #Error
    except:
        print "Unexpected error:", sys.exc_info()[0]

        raise

    #if it finishes or Ctrl C, shut it down
    finally: 
        print "Stopping raspivid controller"
        #stop the controller
        vidcontrol.stopController()
        #wait for the tread to finish if it hasn't already
        vidcontrol.join()
        
    print "Done"


19 comments:

  1. Brilliant stuff, Martin. Everyone should use this!

    ReplyDelete
    Replies
    1. Ta Mr Horne. I just had to pull something together, more than anything it was driving me mental that something so simple was seemingly so difficult!

      Delete
  2. Hey this is awesome Martin! I got this to work tonight and can't wait to show my students how they can capture video from their own program!

    ReplyDelete
  3. SyntaxError: invalid syntax def __init__(self, filePath, timeout, preview, otherOptions=None):

    ReplyDelete
    Replies
    1. Wierd. Wondering whether it is due to non printable characters in the code. Sometimes browsers bring across odd characters when you cut and paste.

      Delete
  4. Hey we tried you code and its awesome but,
    I can't do pictures "raspistill" at the same time we are recording the video :(
    You know how to take a picture while running a video at same time ?

    ReplyDelete
    Replies
    1. Hi Albert,

      Im glad it worked for you, however this post is a bit old now and there are better ways of running the raspberry pi camera from python now, check out http://www.stuffaboutcode.com/2014/01/raspberry-pi-camera-python-picamera.html and the picamera module.

      Picamera has the ability to take pictures at the same time you are recording video.

      Delete
  5. error

    pi@raspberrypi ~ $ python RaspiVidController.py
    File "RaspiVidController.py", line 44
    def stopController(self):
    ^
    IndentationError: unindent does not match any outer indentation level

    ReplyDelete
    Replies
    1. As per your previous comment, I think this is due to an issue with the indents in the code and more than likely due to cutting and pasting from the web browser

      Delete
  6. Hi Martin, congratulations for the script, it works fine!
    I'm working with a project to create a keybinds to start and stop the raspivid in bash but yours works well! I only need one change because i don't know how python works. I need that the script create the videos with different names without user interaction, putting the date&time; a $n,$n+1 number... it's indifferent!
    Thanks for all!

    ReplyDelete
  7. Using python-3.2.3
    Raspberry pi model B+
    Debian wheezy 2014-06-04

    Traceback (most recent call last):
    File "/home/pi/raspivid_proj/test/test.py", line 12, in
    class RaspiVidController(threading.Thread):
    File "/home/pi/raspivid_proj/test/test.py", line 54, in RaspiVidController
    vidcontrol =
    RaspiVidController("/home/pi/raspivid_proj/test/test.h264", 10000,
    False, ["-fps", "25"])
    NameError: name 'RaspiVidController' is not defined

    ReplyDelete
    Replies
    1. I am not sure why you are getting the error, it could be python 3 related as I wrote this in Python 2.

      However if you need to drive the pi camera from python I would recommend you have a look at the picamera module:

      http://www.stuffaboutcode.com/2014/01/raspberry-pi-camera-python-picamera.html

      Delete
    2. This comment has been removed by the author.

      Delete
    3. I already done PiCamera b4

      Delete
  8. Hi, i'm trying to put into the filepath a variable that contains the date&time like "20140824-20:30" to filter the different videos with the date & time parameter. How can i put it into your code? Thanks in advance

    ReplyDelete
    Replies
    1. If I was you, I would have a look at the python module picamera. Its a much easier method of using the raspberry pi camera from python https://picamera.readthedocs.org http://www.stuffaboutcode.com/2014/01/raspberry-pi-camera-python-picamera.html

      Delete
  9. Martin thanks for the code. I was able to see a full screen preview by adding an addition line:
    self.raspividcmd.append("-p"). But is there a way to change the preview window size such as in raspistill (-p 100,100,300,200).?
    Thanks,
    Danny

    ReplyDelete
    Replies
    1. Hi Danny,

      There probably is a way of making it work, however I would recommend that you have a look at the python picamera module https://picamera.readthedocs.org/en/release-1.10/ its a much better and easy way of interacting with the pi camera with python.

      Delete
  10. Hi and thanks for the great module!

    I am trying to run the example as follows, and then convert it to an MP4 with mp4box. I have modified the class to use only the filepath and otherOptions, because I want to start and stop recording with a GPIO button.

    the constructor now looks like this:
    class RaspiVidController(threading.Thread):
    def __init__(self, filePath, otherOptions=None):
    threading.Thread.__init__(self)

    #setup the raspivid cmd
    self.raspividcmd = RASPIVIDCMD

    #add file path, timeout and preview to options
    self.raspividcmd.append("-o")
    self.raspividcmd.append(filePath)


    I am instantiating the controller like this:

    vidcontrol = RaspiVidController("/home/pi/newvid.h264,", ["-t", "5000","-rf", "rgb" , "-pf", "high", "-drc", "low", "-sa", "-50", "-vs", "-br", "40", "-fps", "30", "-b", "12000000" ])

    and trying to make the file with
    vidcontrol.start()
    and
    vidcontrol.stop()

    The problem is that it does not create newvid.h264 anywhere. Any ideas? I also had the same result with your code and the simple example too.

    Any help would be greatly appreciated!

    ReplyDelete

Note: only a member of this blog may post a comment.