Closed clavay closed 3 years ago
You don't say what FOV changes you want, nor what you've tried. Please be very aware that resize is not a free option - it is a software resize running on the GPU's processor.
The simple bit is creating multiple stream outputs, and StreamingOutputs. Use the basis of the web streaming example, but amend the calling code to:
with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
output = StreamingOutput()
output2 = StreamingOutput()
camera.start_recording(output, format='mjpeg')
camera.start_recording(output, format='mjpeg', splitter_port=2, resize=(320, 240))
try:
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
address2 = ('', 8001)
server2 = StreamingServer(address2, StreamingHandler)
server.serve_forever()
finally:
camera.stop_recording()
The more complex bit is that you've got to call both server.serve_forever()
and server2.serve_forever()
, and both block. You therefore need to look at threads, or otherwise waiting until either server has work to do.
I solve this with this code :
import io
import picamera
import picamera.array
import logging
import socketserver
from threading import Condition
from http import server
import cv2
import numpy as np
import time
PAGE="""\
<html>
<head>
<title>picamera MJPEG streaming demo</title>
</head>
<body>
<h1>PiCamera MJPEG Streaming Demo</h1>
<img src="stream1.mjpg"/>
<img src="stream2.mjpg"/>
</body>
</html>
"""
class StreamingOutput(object):
def __init__(self, im):
self.frame0 = None
self.frame1 = None
self.frame2 = None
self.buffer = io.BytesIO()
self.condition = Condition()
self.im = im
def write(self, buf):
self.buffer.truncate()
with self.condition:
self.im = np.frombuffer(buf, dtype=np.uint8)
im0 = self.im.reshape((1200, 1600, 3))[300:1000, 100:1300]
im1 = self.im.reshape((1200, 1600, 3))[600:900, 850:1300]
im2 = self.im.reshape((1200, 1600, 3))[450:600, 100:600]
is_success0, im_buf_arr0 = cv2.imencode(".jpg", cv2.resize(im0, (600, 350)))
is_success1, im_buf_arr1 = cv2.imencode(".jpg", im1)
is_success2, im_buf_arr2 = cv2.imencode(".jpg", im2)
self.frame0 = im_buf_arr0.tobytes()
self.frame1 = im_buf_arr1.tobytes()
self.frame2 = im_buf_arr2.tobytes()
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 == '/stream0.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()
frame0 = output.frame0
self.wfile.write(b'--FRAME\r\n')
self.send_header('Content-Type', 'image/jpeg')
self.send_header('Content-Length', len(frame0))
self.end_headers()
self.wfile.write(frame0)
self.wfile.write(b'\r\n')
except Exception as e:
logging.warning(
'Removed streaming client %s: %s',
self.client_address, str(e))
elif self.path == '/stream1.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()
frame1 = output.frame1
self.wfile.write(b'--FRAME\r\n')
self.send_header('Content-Type', 'image/jpeg')
self.send_header('Content-Length', len(frame1))
self.end_headers()
self.wfile.write(frame1)
self.wfile.write(b'\r\n')
except Exception as e:
logging.warning(
'Removed streaming client %s: %s',
self.client_address, str(e))
elif self.path == '/stream2.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()
frame2 = output.frame2
self.wfile.write(b'--FRAME\r\n')
self.send_header('Content-Type', 'image/jpeg')
self.send_header('Content-Length', len(frame2))
self.end_headers()
self.wfile.write(frame2)
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='1600x1200', framerate=24) as camera:
time.sleep(2)
im = np.empty((1200 * 1600 * 3,), dtype=np.uint8)
output = StreamingOutput(im)
camera.start_recording(output, format='bgr')
try:
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
finally:
camera.stop_recording()
Hello,
I'm trying to do web streaming and to set http://my-ip/stream.mjpg and http://my-ip/stream2.mjpg which are 2 different crops of the same live record.
I tried to modify the web streaming example but I don't know if it's the good way to achieve it. Do I have to use numpy array or to use capture instead of start_recording ? If someone have an idea...
Thanks, clavay