Note

This is the documentation for the latest development branch and may refer to features that are not available in released versions. If you are looking for the documentation for a specific release, use the drop-down menu on the left and select the desired version.

v4l2_drm Python Usage Reference#

Overview#

k230_v4l2_drm is a Python binding library for V4L2 video capture and DRM display on the Kendryte K230 platform. It integrates Linux V4L2 (Video4Linux2) camera capture and DRM (Direct Rendering Manager) display output into a unified pipeline, supporting:

  • Multi-channel camera capture: capture multiple video streams simultaneously through multiple contexts

  • Zero-copy DRM display: V4L2 buffers are sent directly to DRM display without additional copying

  • OSD overlay: overlay ARGB8888/RGB888 layers (such as detection boxes, text) on video frames

  • Rotation/flip: hardware-level rotation (0°/90°/180°/270°) and mirror flip

  • Cropping/offset: set display offset and crop area

  • Background display thread: display_start() continuously refreshes the display in a background thread


Quick Start#

Example 1: Camera Direct Display#

The simplest mode: camera capture → DRM display, without AI inference.

import time
from k230_v4l2_drm import V4l2Drm, ROTATION_0, ROTATION_90

v4l2 = V4l2Drm(context_num=1)
display_width, display_height = v4l2.drm_init()
print(f"INFO: display {display_width}x{display_height}")

# Automatically select rotation angle based on display orientation
if display_width > display_height:
    rotation = ROTATION_0
else:
    rotation = ROTATION_90

v4l2.set_context(
    index=0, device=1,
    width=max(display_width, display_height), height=min(display_width, display_height),
    format="NV12", display=True
)
v4l2.set_rotation(0, rotation)

if not v4l2.setup():
    print("Error: V4L2-DRM setup failed!")
    exit(-1)

v4l2.display_start()

try:
    while True:
        time.sleep(1)  # After display_start, the background thread handles capture and display automatically; the main thread sleeps and waits
except KeyboardInterrupt:
    print("\nStopping...")

v4l2.display_stop()
print("Done!")

Example 2: AI Inference + OSD Overlay Display#

Dual contexts: one for display, one for AI inference, with OSD overlay of detection results.

import time
import numpy as np
import cv2
from k230_v4l2_drm import V4l2Drm, DRM_FORMAT_ARGB8888, ROTATION_0, ROTATION_90

# Create dual-instance, enable OSD
v4l2 = V4l2Drm(context_num=2, osd=True)
display_w, display_h = v4l2.drm_init()
print(f"INFO: display {display_w}x{display_h}")

# Automatically select rotation angle based on display orientation
if display_w > display_h:
    rotation = ROTATION_0
else:
    rotation = ROTATION_90

# Context 0: Camera 1 → Display (NV12)
v4l2.set_context(
    index=0, device=1,
    width=max(display_w, display_h), height=min(display_w, display_h),
    format="NV12", display=True
)

# Context 1: Camera 2 → AI inference input (BG3P format, no display)
v4l2.set_context(
    index=1, device=2,
    width=1280, height=720,
    format="BG3P", display=False
)

v4l2.set_rotation(0, rotation)

# Configure OSD format
v4l2.set_osd_format(DRM_FORMAT_ARGB8888)

# Initialize pipeline
if not v4l2.setup():
    print("Error: V4L2-DRM setup failed!")
    exit(-1)

v4l2.display_start()
v4l2.dump_start(index=1)  # Start AI channel capture

try:
    frame_count = 0
    fps = 0.0
    fps_start_time = time.time()

    while True:
        # Capture AI channel frame
        if not v4l2.dump_frame(index=1, timeout_ms=1000):
            continue

        # Get frame data (BG3P format: shape=(3, H, W))
        frame = v4l2.get_buffer_array(index=1)

        # Release frame buffer
        v4l2.dump_release(index=1)

        # AI inference (using nncaseruntime, etc.)
        # results = ai_inference(frame)

        # Frame rate statistics
        frame_count += 1
        elapsed = time.time() - fps_start_time
        if elapsed >= 1.0:
            fps = frame_count / elapsed
            frame_count = 0
            fps_start_time = time.time()
            print(f"[{time.strftime('%H:%M:%S')}] FPS: {fps:.1f}")

        # Generate OSD image (ARGB8888)
        osd_img = np.zeros((min(display_w, display_h), max(display_w, display_h), 4), dtype=np.uint8)
        # Draw detection boxes, text, etc. on osd_img...
        # cv2.rectangle(osd_img, (x1, y1), (x2, y2), (B, G, R, A), 2)

        # Display FPS on OSD
        cv2.putText(osd_img, f"FPS: {fps:.1f}", (10, 40),
                    cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 255, 0, 255), 2)

        # Update OSD display
        v4l2.osd_update(osd_img)

except KeyboardInterrupt:
    print("\nStopping...")

v4l2.dump_stop(index=1)
v4l2.display_stop()
print("Done!")

Comments list
Comments
Log in