Guide · Overlays
Text, logo and multi-view overlays with the canvas API
Use the canvas API of LT-300 series cards to burn text and logos into the HDMI output, build side-by-side and picture-in-picture layouts from several inputs, and record the result — all rendered by the board, from a few JSON operations.
1What is a canvas?
A canvas is a virtual video source that you draw on. It can show text, shapes, images and live inputs, be applied as an overlay on the HDMI output, or be recorded like any input. The agent provides four canvases by default,
canvas/0
to
canvas/3
(
numCanvases
in the agent configuration).
- Drawing operations:
text,line,ellipse,rectangle,image, plusvideofor live sources andclear. - Every operation draws in a container defined by
position(top-left corner) andsize, with optionalangleandanchor. - Rendering order: drawings stack in the order you send them; live video sources are always rendered on top. There are no layers to reorder afterwards.
Agent version: since v1.5.0 the LT310 series is named LT300, so this guide uses
lt300:
URLs and the
lt300agent
command. With an older agent, replace them with
lt310:
and
lt310agent
.
2Initialise the canvas
Start with
init
: the background colour (RGBA, use alpha 0 for a transparent overlay), the size and the frame rate. You can also give a JPEG, PNG, BMP or MP4 file as
source
— the canvas then takes its size and frame rate from the file.
$ ecurl post lt300:/canvas/0/init -d @init.json
# init.json — transparent 1080p canvas for an overlay
{ "op": "init", "color": [0, 0, 0, 0], "size": [1920, 1080], "framerate": 30.0 }
$ ecurl post lt300:/canvas/0/init \
-d source=$video.mp4 # canvas playing a file
3Add a text banner
A semi-transparent rounded banner with centred white text at the bottom of the image. Each operation has its own endpoint, and simple values can be passed with
-d
:
$ ecurl post lt300:/canvas/0/rectangle \
-d position=50,900 \
-d size=1200,100 \
-d fill=0,0,0,180 \
-d rounded=10
$ ecurl post lt300:/canvas/0/text \
-d position=50,900 \
-d size=1200,100 \
-d text="Hello, World!" \
-d fontSize=48 \
-d color=255,255,255,255 \
-d align=center
| Text setting | Values |
|---|---|
align
|
top-left
,
top
,
top-right
,
left
,
center
,
right
,
bottom-left
,
bottom
,
bottom-right
|
font
|
regular
,
mono
,
smallcaps
|
fontSize
| points (default 32) |
bold
,
italic
|
true
/
false
|
color
| RGBA, e.g.
[255, 255, 255, 255]
|
Rectangles also take a stroke
width
and
color
, a dash
pattern
and corner
rounded
radius — useful for frames and highlight boxes.
4Add a logo
The
image
operation draws a JPEG, PNG or BMP file. With a
size
, the image is scaled to fit the container while keeping its aspect ratio:
{
"op": "image",
"source": "/opt/branding/logo.png",
"position": [1620, 40],
"size": [260, 90]
}
$ ecurl post lt300:/canvas/0/image -d @logo.json
From code you can also send the image as a data buffer with its
format
(
png
,
jpeg
,
bmp
, or raw
rgba
/
rgb
with
width
and
height
).
5Side-by-side and picture-in-picture
The
video
operation places a live input on the canvas, scaled to its container. With the
ops
batch endpoint, the whole layout is set up in one request. Two SDI inputs side by side on a 4K canvas, with labels:
{
"ops": [
{ "op": "init", "size": [3840, 2160], "color": [0, 0, 0, 255], "framerate": 30.0 },
{ "op": "video", "source": "0/sdi-in/0", "position": [0, 600], "size": [1920, 1080] },
{ "op": "text", "text": "SDI 0", "fontSize": 48, "color": [255, 255, 255, 255],
"align": "center", "position": [0, 1680], "size": [1920, 100] },
{ "op": "video", "source": "0/sdi-in/1", "position": [1920, 600],
"size": [1920, 1080] },
{ "op": "text", "text": "SDI 1", "fontSize": 48, "color": [255, 255, 255, 255],
"align": "center", "position": [1920, 1680], "size": [1920, 100] }
]
}
$ ecurl post lt300:/canvas/0/ops -d @batch_ops.json
Picture-in-picture
Same idea: the main input fills a 1080p canvas and the second one sits in a corner. If the small window does not end up on top, swap the order of the two
video
operations:
{
"ops": [
{ "op": "init", "size": [1920, 1080], "color": [0, 0, 0, 255], "framerate": 30.0 },
{ "op": "video", "source": "0/sdi-in/0", "position": [0, 0], "size": [1920, 1080] },
{ "op": "video", "source": "0/sdi-in/1", "position": [1380, 60], "size": [480, 270] }
]
}
6Show it on the HDMI output
A canvas can be applied as an overlay on the board's HDMI output, on top of the input routed to it. The
overlayMode
setting chooses between
performance
and
quality
rendering.
$ ecurl post lt300:/0/hdmi-out/0 -d overlay=canvas/0
Agent v1.6.0 moved overlay management to its own dedicated endpoint. The command above is the one documented for earlier versions; with v1.6.0, attach the canvas through the new overlay endpoint described in your SDK documentation.
Record the composite
A canvas can be recorded exactly like an input, with the same encoder settings as in the recording guide:
$ ecurl rec lt300:/canvas/0/file \
-d media=video/mp4 \
-d extra.hw=nvenc \
-d extra.codec=hevc
7Update without flicker
To change what is drawn, use
clear
. Without parameters it wipes every drawing and keeps the live video sources. It can also clear just an area (
position
,
size
, optional
thickness
padding) or remove video sources (
source
, or
"all"
).
For animated content — a clock, a counter, detection boxes — send the
clear
and the new drawings in the same
ops
batch. A batch is applied in one go — all its operations succeed or fail together — so the old drawing is replaced by the new one without an empty step in between:
{
"ops": [
{ "op": "clear", "position": [50, 900], "size": [1200, 100] },
{ "op": "rectangle", "position": [50, 900], "size": [1200, 100],
"fill": [0, 0, 0, 180], "rounded": 10 },
{ "op": "text", "text": "Recording — 00:12:45", "fontSize": 48,
"color": [255, 255, 255, 255], "align": "center",
"position": [50, 900], "size": [1200, 100] }
]
}
This is exactly how the YOLO on Jetson guide draws live detection boxes.
Custom overlays
Need a specific layout or overlay?
Medical displays, multi-camera monitoring, branded outputs: our engineers can help you build it.