Files
dora-webcam/dora-node.yml
T
cristhian 3c0e0f327d
validate / validate (push) Successful in 59m15s
add dora-webcam node
Captures frames from a V4L2 camera and publishes them as std/media/v1/Image:
an Arrow struct of width, height, encoding and data, so a receiver needs
nothing from the message metadata. For a compressed encoding the recorded
dimensions are the image's, not the length of the payload.

Based on opencv-video-capture from dora-hub, with three changes. The output is
the typed image struct rather than a flat UInt8 buffer plus metadata. Camera
selection by id reads /dev/v4l/by-id/ only; the upstream macOS system_profiler
and Windows PowerShell enumeration is not carried. CAPTURE_FRAMES bounds a run
so a test ends on its own, in place of upstream's ten-second CI cutoff -- a
timeout would have made the CI step exit non-zero.

CI=true keeps a failed capture from raising, publishing a labelled black frame
instead, which is what lets dataflow.yml run on a machine with no camera.

Two dataflows, run one at a time, as dora has no cross-dataflow wiring:
dataflow.yml is the camera alone and the CI gate; dataflow_view.yml wires it
into dora-image-view and is not run by CI, since it fetches that node over the
network and needs a tag to exist there.
2026-09-15 06:04:25 -03:00

85 lines
2.9 KiB
YAML

# Node manifest: the typed contract a consumer wires against.
#
# No source package is shared between node repositories, so this file and its
# type URNs are the only contract a consumer has. `dora validate` checks a
# dataflow against it without running the node, so CI needs neither a camera nor
# OpenCV.
apiVersion: 1
name: dora-webcam
namespace: liria
description: Captures frames from a webcam and publishes them as std/media/v1/Image
categories: [sensor]
keywords: [opencv, camera, webcam, video, capture, image, v4l2]
runtime: python
entrypoint: dora-webcam
# `dora build --uv` / `dora run --uv` rewrites this to `uv pip install .` and
# gives the node its own managed venv under `.dora/python-envs/`, so the
# dependencies it sees at runtime are the ones installed here.
build: pip install .
dora: ">=1.0"
inputs:
tick:
required: true
description: >-
Reads and publishes one frame. Wire to dora/timer/millis/N. The node stops
when this input closes.
outputs:
image:
type: std/media/v1/Image
description: >-
Captured frame as an Arrow struct {width, height, encoding, data}. For a
compressed encoding, width and height are the image's dimensions rather
than the length of data, so a receiver can size a buffer without decoding
first.
env:
CAMERA_ID:
description: >-
Substring of an entry in /dev/v4l/by-id/. Stable across reboots and across
which USB port the camera is in, unlike an index, so it takes precedence
over CAPTURE_PATH. Linux only.
CAPTURE_PATH:
default: "0"
description: Device path such as /dev/video1, or an index. A numeric string is read as an index.
IMAGE_WIDTH:
type: int
description: Requested capture width; frames are also resized to it. Defaults to the camera's native width.
IMAGE_HEIGHT:
type: int
description: Requested capture height; frames are also resized to it. Defaults to the camera's native height.
ENCODING:
default: bgr8
description: One of bgr8, rgb8, yuv420, jpeg/jpg/jpe, png, bmp, webp.
JPEG_QUALITY:
type: int
default: 95
description: Quality 0-100, used only by the JPEG encodings.
FLIP:
description: Flip the frame. One of VERTICAL, HORIZONTAL or BOTH. Unset means no flip.
CAPTURE_FRAMES:
type: int
default: 0
description: >-
Stop after this many frames. 0, the default, runs until the tick input
closes. A positive count is what lets a test run the dataflow to
completion rather than killing it on a timeout.
CI:
type: bool
description: >-
When true, a failed read publishes a labelled black frame instead of
raising, which is what lets the dataflow run on a machine with no camera.
example: |
- id: camera
git: ssh://git@gitea.liria.cl:5001/liria/dora-webcam.git
tag: v0.1.0
build: pip install .
path: dora-webcam
inputs:
tick: dora/timer/millis/33
outputs:
- image