18

I am recording video from Pi using Camera Module with picamera:

import picamera

with picamera.PiCamera() as camera:
    camera.resolution = (640, 480)
    camera.start_recording('1.h264')
    camera.wait_recording(5)
    for i in range(2, 11):
        camera.split_recording('%d.h264' % i)
        camera.wait_recording(5)
    camera.stop_recording()

I have seperately used a combination of raspivid and gstreamer to stream video from pi without any delay. Is there a way to store and stream footage using python simultaneously?

My thinking is there must be a way to use camera as input and create two output sources: a 720p video for storage and a downscaled 240p video for streaming using gstreamer...?

2
  • 1
    If you are piping raspivid you could tee the output to a file and gstreamer or whatever else (see man tee). As long as one stream is straight to disk, it won't add much overhead, but if you want to process the input into two different formats simultaneously I think that will be too much work for the pi to handle.
    – goldilocks
    Jan 23, 2015 at 17:41
  • 1
    Can you kindly post an example in code?
    – koogee
    Jan 24, 2015 at 11:16

2 Answers 2

8

The tee command reads from standard input and copies to any number of files plus standard output by default, see man tee for more details. This means you can ask tee to create a file from input and then pipe the output to something else.

The addition of an extra pipe does in theory add a bit of inefficiency. As to whether this is significant or not you will have to judge for yourself using your own streaming method. My current method is not satisfactory at full resolution. It's not a huge interest right now but when it is I will try to find something better (e.g. supposedly gstreamer works better than clvc).

However, worth noting that the file saved locally on the pi at the same time is perfect quality, so the activity does not interfere with raspivid. Here's an example:

raspivid -o - -t 0 | tee test_video.h264 |
cvlc -v stream:///dev/stdin --sout '#standard{access=http,mux=ts,dest=:8080' :demux=h264

I broke this into two lines for readability; you can hit return after | (pipe) and finish the command just as you can break a line with \. You can replace the cvlc with whatever you want. Again, although the stream was of poor quality, test_video.h264 came out perfect.

If I lower the resolution to 640x360 this arrangement is fine, with a second or two of latency which is what I normally get. I do not think the tee or the second pipe makes any difference to the quality of the stream; these are capable of much higher throughput than necessary here and do not require much in the way of system resources.

The CPU ran at 35-45%, which is the same as it does when streaming video sans tee.

2
  • Thank you for your post. As I want to do this within my script, I've been looking at the PiCamera 1.9 API and there is a method record_sequence that takes a splitter_port parameter. There is also an example of recording upto 4 simultaneous outputs from the camera.
    – koogee
    Jan 25, 2015 at 18:11
  • I'm struggling a bit with tying together recording a 240p stream and 720p video for storage that splits every hour but I feel this is a promising direction.
    – koogee
    Jan 25, 2015 at 18:13
15

Nothing wrong at all with goldilocks answer above, but here's an additional one that deals specifically with the picamera API. You can use a custom output to perform such a split (as many ways as you like) and send the output to a variety of destinations. In your case, if you wanted to record to a file and a socket you could do something like this:

#!/usr/bin/env python

import io
import picamera
import socket


# An output (as far as picamera is concerned), is just a filename or an object
# which implements a write() method (and optionally the flush() and close()
# methods)
class MyOutput(object):
    def __init__(self, filename, sock):
        self.output_file = io.open(filename, 'wb')
        self.output_sock = sock.makefile('wb')

    def write(self, buf):
        self.output_file.write(buf)
        self.output_sock.write(buf)

    def flush(self):
        self.output_file.flush()
        self.output_sock.flush()

    def close(self):
        self.output_file.close()
        self.output_sock.close()


# Connect a socket to a remote server on port 8000
sock = socket.socket()
sock.connect(('my_server', 8000))

with picamera.PiCamera() as camera:
    camera.resolution = (640, 480)
    camera.framerate = 24

    # Construct an instance of our custom output splitter with a filename
    # and a connected socket
    my_output = MyOutput('output.h264', sock)

    # Record video to the custom output (we need to specify the format as
    # the custom output doesn't pretend to be a file with a filename)
    camera.start_recording(my_output, format='h264')
    camera.wait_recording(30)
    camera.stop_recording()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.