This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ctypes as ct | |
from signal import pause | |
import numpy as np | |
from picamera import mmal, PiRenderer | |
from picamera.exc import ( | |
PiCameraRuntimeError, | |
PiCameraValueError, | |
mmal_check, | |
) | |
def _overlay_callback(port, buf): | |
mmal.mmal_buffer_header_release(buf) | |
_overlay_callback = mmal.MMAL_PORT_BH_CB_T(_overlay_callback) | |
class MyRenderer(PiRenderer): | |
def __init__( | |
self, source, size, layer=0, alpha=255, | |
fullscreen=True, window=None, crop=None, rotation=0, vflip=False, | |
hflip=False): | |
super(MyRenderer, self).__init__( | |
None, layer, alpha, fullscreen, window, crop, | |
rotation, vflip, hflip) | |
port = self.renderer[0].input[0] | |
fmt = port[0].format | |
fmt[0].encoding = mmal.MMAL_ENCODING_RGB24 | |
fmt[0].encoding_variant = mmal.MMAL_ENCODING_RGB24 | |
w, h = size | |
fmt[0].es[0].video.width = mmal.VCOS_ALIGN_UP(w, 32) | |
fmt[0].es[0].video.height = mmal.VCOS_ALIGN_UP(h, 16) | |
fmt[0].es[0].video.crop.width = w | |
fmt[0].es[0].video.crop.height = h | |
mmal_check( | |
mmal.mmal_port_format_commit(port), | |
prefix="Overlay format couldn't be set") | |
port[0].buffer_num = port[0].buffer_num_min | |
port[0].buffer_size = port[0].buffer_size_recommended | |
mmal_check( | |
mmal.mmal_component_enable(self.renderer), | |
prefix="Overlay couldn't be enabled") | |
mmal_check( | |
mmal.mmal_port_enable(port, _overlay_callback), | |
prefix="Overlay input port couldn't be enabled") | |
self.pool = mmal.mmal_port_pool_create( | |
port, port[0].buffer_num, port[0].buffer_size) | |
if not self.pool: | |
raise PiCameraRuntimeError("Couldn't create pool for overlay") | |
self.update(source) | |
def close(self): | |
super(PiOverlayRenderer, self).close() | |
if self.pool: | |
mmal.mmal_pool_destroy(self.pool) | |
self.pool = None | |
def update(self, source): | |
""" | |
Update the overlay with a new source of data. | |
The new *source* buffer must have the same size as the original buffer | |
used to create the overlay. There is currently no method for changing | |
the size of an existing overlay (remove and recreate the overlay if you | |
require this). | |
""" | |
port = self.renderer[0].input[0] | |
fmt = port[0].format | |
bp = ct.c_uint8 * (fmt[0].es[0].video.width * fmt[0].es[0].video.height * 3) | |
try: | |
sp = bp.from_buffer(source) | |
except TypeError: | |
sp = bp.from_buffer_copy(source) | |
buf = mmal.mmal_queue_get(self.pool[0].queue) | |
if not buf: | |
raise PiCameraRuntimeError( | |
"Couldn't get a buffer from the overlay's pool") | |
ct.memmove(buf[0].data, sp, buf[0].alloc_size) | |
buf[0].length = buf[0].alloc_size | |
mmal_check( | |
mmal.mmal_port_send_buffer(port, buf), | |
prefix="Unable to send a buffer to the overlay's port") | |
# A low battery icon | |
icon = [[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], | |
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], | |
[1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], | |
[1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], | |
[1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1], | |
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], | |
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]] | |
# Convert this to a numpy array padded to 32x16 (MMAL renderers need this) | |
img = np.zeros((16, 32, 3), dtype=np.uint8) | |
img[:7, :16, 0] = icon | |
img[:7, :16, 1] = icon | |
img[:7, :16, 2] = icon | |
img *= 255 | |
# Construct the renderer to display the image | |
overlay = MyRenderer(memoryview(img), size=img.shape[1::-1], layer=3, alpha=128) | |
# Make it big, but not fullscreen | |
overlay.fullscreen = False | |
overlay.window = (0, 0, 128, 64) | |
pause() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment