Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
You can’t perform that action at this time.