0

How can I have a stream like rtsp, that is accesible in a program on another computer?

2

3 Answers 3

1

I solved the problem by using the following code from here.

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server

PAGE="""\
<html>
<head>
<title>picamera MJPEG streaming demo</title>
</head>
<body>
<h1>PiCamera MJPEG Streaming Demo</h1>
<img src="stream.mjpg" width="640" height="480" />
</body>
</html>
"""

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
    output = StreamingOutput()
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

Now I have a constantly updating mjpg-file at a local server and I can e.g. refer to the mjpg link (something like http://raspberrypi:8000/stream.mjpg) in a html/node/electron application from somewhere else, which is exactly what I wanted. First I thought it would be better to do it via rtsp or some streaming protocol, but it turned out, that the html/mjpg way has actually much less delay (almost zero being streamed over local network) than the rtsp way (maybe 3 seconds).

Cheers

0

If both the Pi and the computer are on the same network, this can easily be done using ffmpeg, to both capture the stream from the camera and broadcast it over the network.

0

I send a stream of JPEG files using zmq which is a kind of wrapper over sockets that handles most of the ugly for you. It's not a standard protocol though.

from picamera import PiCamera
import io
import zmq


context = zmq.Context()
socket = context.socket(zmq.PUB)
# CONFLATE=1 disables the send queue so it will drop frames instead of creating latency.
socket.setsockopt(zmq.CONFLATE, 1)
socket.bind("tcp://*:12103")

camera = PiCamera()
camera.resolution = (320, 240)
camera.framerate = 10
camera.exposure_mode = 'sports'
camera.rotation = 0

stream = io.BytesIO()

for _ in camera.capture_continuous(stream, 'jpeg', use_video_port=True):
  stream.truncate()
  stream.seek(0)
  socket.send(stream.read())
  stream.seek(0)

At the receiving end:

import zmq

context = zmq.Context()
video_socket = .context.socket(zmq.SUB)
video_socket.setsockopt(zmq.CONFLATE, 1)
video_socket.setsockopt(zmq.SUBSCRIBE, b"")
video_socket.connect("tcp://192.168.1.2" + ":12103")

def get_image():
  # Read the latest image. None if there are no new images since the last read.
  if video_socket.poll(timeout=0) == zmq.POLLIN:
    return video_socket.recv()
  else:
    return None

You can also use raspivid to streams video from the camera without writing your own code.

Your Answer

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

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