Skip to content

drivers: video: forward packets between devices #89190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
josuah opened this issue Apr 28, 2025 · 0 comments
Open

drivers: video: forward packets between devices #89190

josuah opened this issue Apr 28, 2025 · 0 comments
Assignees
Labels
area: API Changes to public APIs area: Video Video subsystem Feature Request A request for a new feature

Comments

@josuah
Copy link
Collaborator

josuah commented Apr 28, 2025

Is your feature request related to a problem? Please describe.

Configuring and setting up video streams between devices is tedious (error-prone) and always the same (easy to automate).

Describe the solution you'd like

Provide video_connect(video_stream, video_in, video_out, fmt, num_bufs) to check if both devices are ready, configure a device pair, allocate buffers, enqueue them, specify the format, setup the poll signals

Provide video_forward(video_stream) that starts each device and run an endless loop with k_poll() that enqueues/dequeues

Describe alternatives you've considered

Letting the application route buffers between video devices like in Linux.

Make the video_stream above a global variable instead of argument

Additional context

Example implementation from #88839

camera_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
if (camera_dev == NULL || !device_is_ready(camera_dev)) {
LOG_ERR("%s is not ready or failed to initialize", camera_dev->name);
return -ENODEV;
}
pipe_dev = DEVICE_DT_GET(DT_NODELABEL(video_sw_pipeline));
if (pipe_dev == NULL || !device_is_ready(pipe_dev)) {
LOG_ERR("%s is not ready or failed to initialize", pipe_dev->name);
return -ENODEV;
}
uvc_dev = DEVICE_DT_GET(DT_NODELABEL(uvc));
if (uvc_dev == NULL || !device_is_ready(uvc_dev)) {
LOG_ERR("%s is not ready or failed to initialize", uvc_dev->name);
return -ENODEV;
}
video_sw_pipeline_set_source(pipe_dev, camera_dev);
uvc_set_video_dev(uvc_dev, pipe_dev);
sample_usbd = sample_usbd_init_device(NULL);
if (sample_usbd == NULL) {
return -ENODEV;
}
ret = usbd_enable(sample_usbd);
if (ret != 0) {
return ret;
}
LOG_INF("Waiting the host to select the video format");
/* Get the video format once it is selected by the host */
while (true) {
ret = video_get_format(uvc_dev, VIDEO_EP_IN, &fmt);
if (ret == 0) {
break;
}
if (ret != -EAGAIN) {
LOG_ERR("Failed to get the video format");
return ret;
}
k_sleep(K_MSEC(10));
}
LOG_INF("The host selected format %ux%u '%s'",
fmt.width, fmt.height, VIDEO_FOURCC_TO_STR(fmt.pixelformat));
LOG_INF("Preparing %u buffers of %u bytes",
CONFIG_VIDEO_BUFFER_POOL_NUM_MAX, fmt.pitch * fmt.height);
/* Half of the buffers between the camera device and the pipeline device */
for (int i = 0; i < CONFIG_VIDEO_BUFFER_POOL_NUM_MAX / 2; i++) {
vbuf = video_buffer_alloc(fmt.pitch * fmt.height, K_NO_WAIT);
if (vbuf == NULL) {
LOG_ERR("Failed to allocate the video buffer");
return -ENOMEM;
}
ret = video_enqueue(camera_dev, VIDEO_EP_OUT, vbuf);
if (ret != 0) {
LOG_ERR("Failed to enqueue video buffer");
return ret;
}
}
/* Half of the buffers between the pipeline device and the sink device */
for (int i = 0; i < CONFIG_VIDEO_BUFFER_POOL_NUM_MAX / 2; i++) {
vbuf = video_buffer_alloc(fmt.pitch * fmt.height, K_NO_WAIT);
if (vbuf == NULL) {
LOG_ERR("Failed to allocate the video buffer");
return -ENOMEM;
}
ret = video_enqueue(pipe_dev, VIDEO_EP_OUT, vbuf);
if (ret != 0) {
LOG_ERR("Failed to enqueue video buffer");
return ret;
}
}
LOG_DBG("Preparing signaling for %s input/output", camera_dev->name);
k_poll_signal_init(&sig);
k_poll_event_init(&evt[0], K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &sig);
ret = video_set_signal(camera_dev, VIDEO_EP_OUT, &sig);
if (ret != 0) {
LOG_WRN("Failed to setup the signal on %s output endpoint", camera_dev->name);
timeout = K_MSEC(1);
}
ret = video_set_signal(pipe_dev, VIDEO_EP_OUT, &sig);
if (ret != 0) {
LOG_WRN("Failed to setup the signal on %s output endpoint", pipe_dev->name);
timeout = K_MSEC(1);
}
ret = video_set_signal(uvc_dev, VIDEO_EP_IN, &sig);
if (ret != 0) {
LOG_WRN("Failed to setup the signal on %s input endpoint", uvc_dev->name);
timeout = K_MSEC(1);
}
LOG_INF("Starting the video transfer");
ret = video_stream_start(camera_dev);
if (ret != 0) {
LOG_ERR("Failed to start %s", camera_dev->name);
return ret;
}
ret = video_stream_start(pipe_dev);
if (ret != 0) {
LOG_ERR("Failed to start %s", pipe_dev->name);
return ret;
}
while (true) {
ret = k_poll(evt, ARRAY_SIZE(evt), timeout);
if (ret != 0 && ret != -EAGAIN) {
LOG_ERR("Poll exited with status %d", ret);
return ret;
}
if (video_dequeue(camera_dev, VIDEO_EP_OUT, &vbuf, K_NO_WAIT) == 0) {
LOG_DBG("Dequeued %p from %s, enqueueing to %s",
(void *)vbuf, camera_dev->name, uvc_dev->name);
ret = video_enqueue(pipe_dev, VIDEO_EP_IN, vbuf);
if (ret != 0) {
LOG_ERR("Failed to enqueue video buffer to %s", pipe_dev->name);
return ret;
}
}
if (video_dequeue(pipe_dev, VIDEO_EP_IN, &vbuf, K_NO_WAIT) == 0) {
LOG_DBG("Dequeued %p from %s, enqueueing to %s",
(void *)vbuf, pipe_dev->name, uvc_dev->name);
ret = video_enqueue(camera_dev, VIDEO_EP_OUT, vbuf);
if (ret != 0) {
LOG_ERR("Failed to enqueue video buffer to %s", uvc_dev->name);
return ret;
}
}
if (video_dequeue(pipe_dev, VIDEO_EP_OUT, &vbuf, K_NO_WAIT) == 0) {
LOG_DBG("Dequeued %p from %s, enqueueing to %s",
(void *)vbuf, pipe_dev->name, uvc_dev->name);
ret = video_enqueue(uvc_dev, VIDEO_EP_IN, vbuf);
if (ret != 0) {
LOG_ERR("Failed to enqueue video buffer to %s", uvc_dev->name);
return ret;
}
}
if (video_dequeue(uvc_dev, VIDEO_EP_IN, &vbuf, K_NO_WAIT) == 0) {
LOG_DBG("Dequeued %p from %s, enqueueing to %s",
(void *)vbuf, uvc_dev->name, pipe_dev->name);
ret = video_enqueue(pipe_dev, VIDEO_EP_OUT, vbuf);
if (ret != 0) {
LOG_ERR("Failed to enqueue video buffer to %s", pipe_dev->name);
return ret;
}
}
k_poll_signal_reset(&sig);
}

In Linux, applications such as Gstreamer provide this feature.

@josuah josuah added the Feature Request A request for a new feature label Apr 28, 2025
@josuah josuah self-assigned this Apr 28, 2025
@josuah josuah added area: API Changes to public APIs area: Video Video subsystem labels Apr 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: API Changes to public APIs area: Video Video subsystem Feature Request A request for a new feature
Projects
None yet
Development

No branches or pull requests

1 participant