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.

Level: intermediateTime: about 20 minutesHardware: LT311 or LT313 (two inputs for layouts)Tools: ecurl or the SDK

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 , plus video for live sources and clear .
  • Every operation draws in a container defined by position (top-left corner) and size , with optional angle and anchor .
  • 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.

bash
$ 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 }
bash · file source
$ 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 :

bash
$ 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 settingValues
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.

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:

json · batch_ops.json
{
"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] }
]
}
bash
$ 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:

json · pip.json
{
"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.

bash
$ 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:

bash
$ 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:

json · POST lt300:/canvas/0/ops
{
"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.