Skip to content

Conversation

avolmat-st
Copy link

@avolmat-st avolmat-st commented Jun 18, 2025

This PR is still a WIP but should already give a good idea of the proposed SELECTION API allowing to the get capabilities of crop/compose as well as control it.
This is based on the Linux V4L2 SELECTION API (available in BSD-Clause): https://docs.kernel.org/6.6/userspace-api/media/v4l/selection-api.html

In order to give a better idea, I've also implemented the shell part as well as DCMIPP driver part (ongoing since only pixel pipes done for the time being, still need a few more code to also add the dump pipe support).

Basically, the setting a crop means that only part of the input is taken into account. The selected crop becomes the default compose size.
Setting a compose size means that the area selected via the crop would get modified (down or up) in order to lead to the rectangle defined by the compose. This lead to the output format at the end.

This leads for example to stuff as what can be seen in dcmipp modifications which is:

  • setting a crop lead to also setting the compose to the same rectangle and the output format width/height as well
  • setting a compose does not impact the crop but compose width/height also become the output format width/height
  • in such condition, set_fmt is mainly used to set the pixelformat, and the driver needs to check that the width/height of set_fmt do match with compose width/height.

In order to give a better idea I've modified the capture sample by adding new CONFIG_ in order to set the crop area and the sample app will, if available in the driver try to set the crop and do the compose to match with the requested output format.

Example of shell output, using DCMIPP driver on the STM32N6:

  1. get output format upon start
uart:~$ video format endpoint@1 out
Current format: 'pRAA' 2592x1944 (0 bytes per frame)
min vbuf count: 1
min line count: 4294967295
max line count: 4294967295
	[0]: 'pRAA' (10 bits per pixel)
		Size: Discrete: 2592x1944 (6298560 bytes per frame)
			Interval: Discrete 33 ms (30 FPS)
  1. Get current crop and apply a new one
uart:~$ video selection endpoint@1 out crop
	selection target: crop: (0,0)/2592x1944
uart:~$ video selection endpoint@1 out crop (10,10)/2400x1440
	selection target: crop: (10,10)/2400x1440
uart:~$ video selection endpoint@1 out crop
	selection target: crop: (10,10)/2400x1440
uart:~$ video format endpoint@1 out
Current format: 'pRAA' 2400x1440 (4331520 bytes per frame)
min vbuf count: 1
min line count: 4294967295
max line count: 4294967295
	[0]: 'pRAA' (10 bits per pixel)
		Size: Discrete: 2592x1944 (6298560 bytes per frame)
			Interval: Discrete 33 ms (30 FPS)
  1. Set a compose to perform downscale
uart:~$ video selection endpoint@1 out compose
	selection target: compose: (10,10)/2400x1440
                                                     ^^^^^
                                                     this is actually wrong, a but within the DCMIPP code I'll fix it in the next push
uart:~$ video selection endpoint@1 out compose (0,0)/800x480
	selection target: compose: (0,0)/800x480
uart:~$ video selection endpoint@1 out compose
	selection target: compose: (0,0)/800x480
uart:~$ video format endpoint@1 out
Current format: 'pRAA' 800x480 (483840 bytes per frame)
min vbuf count: 1
min line count: 4294967295
max line count: 4294967295
	[0]: 'pRAA' (10 bits per pixel)
		Size: Discrete: 2592x1944 (6298560 bytes per frame)
			Interval: Discrete 33 ms (30 FPS)

Upon performing crop / compose the DCMIPP will now generate a 800x480 frame which is a downscale from the a rectangle of 2400x1440 starting at offset 10,10 of an original sensor frame of 2592x1944

@avolmat-st avolmat-st requested review from josuah and ngphibang June 18, 2025 22:10
@kartben kartben requested a review from Copilot June 19, 2025 07:37
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds support for crop and compose selection in the video subsystem, with sample, shell, and DCMIPP driver updates.

  • Introduce video_selection API in video.h for crop/compose control
  • Extend the capture sample and Kconfig to configure source crop and compose
  • Implement selection handling in the shell and STM32 DCMIPP driver

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
samples/drivers/video/capture/src/main.c Apply optional crop and compose settings in sample
samples/drivers/video/capture/Kconfig Add VIDEO_SOURCE_CROP_* configuration options
include/zephyr/drivers/video.h Define video_selection structs and APIs
drivers/video/video_stm32_dcmipp.c Implement crop/compose logic and API callbacks
drivers/video/video_shell.c Add shell commands and parsing for selection
Comments suppressed due to low confidence (2)

drivers/video/video_stm32_dcmipp.c:647

  • [nitpick] Grammar in error message: 'Failed to configuration pipe crop' should be 'Failed to configure pipe crop'.
		LOG_ERR("Failed to configuration pipe crop");

drivers/video/video_shell.c:1223

  • Help text and parser disagree on rectangle syntax: the code expects parentheses (<left>,<top>)/<width>x<height>, but the help message omits them. Align documentation with parser behavior.
	SHELL_CMD_ARG(selection, &dsub_video_format_dev,


ret = video_shell_parse_in_out(sh, arg_in_out, &sel.type);
if (ret < 0) {
return -ret;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return -ret;
return ret;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corrected. Same issue within the cmd_video_format function at same place (I copied code from there). I add a commit to fix this in the cmd_video_format function as well.

__ASSERT_NO_MSG(sel != NULL);

api = (const struct video_driver_api *)dev->api;
if (api->set_selection == NULL) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (api->set_selection == NULL) {
if (api->get_selection == NULL) {

Copy link
Author

@avolmat-st avolmat-st Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oups, bad copy & paste. Corrected.

static int video_shell_selection_parse_rect(const struct shell *sh, char const *arg_rect,
struct video_rect *rect)
{
char *end_size = (char *)arg_rect;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't cast the const away, as per coding guidelines / MISRA


ret = HAL_DCMIPP_PIPE_SetCropConfig(&dcmipp->hdcmipp, pipe->id, &crop_cfg);
if (ret != HAL_OK) {
LOG_ERR("Failed to configuration pipe crop");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LOG_ERR("Failed to configuration pipe crop");
LOG_ERR("Failed to configure pipe crop");

Copy link
Contributor

@josuah josuah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for introducing this API! This will be convenient for image sensors as well, which I suppose will use the same API for their cropping region since it is not

I asked a few questions but it seems like being ready. Convenient to have V4L2 as a guideline!

I will give another cycle after your feedback, to make sure I understand what I review. Thank you!

@josuah
Copy link
Contributor

josuah commented Jun 19, 2025

@avolmat-st avolmat-st force-pushed the pr_video_selection_api branch from c7987b2 to ade64c1 Compare June 19, 2025 20:52
@avolmat-st
Copy link
Author

First force-push to see comments update.
I will shortly push a new version with DCMIPP selection support on the dump pipe.

*
* @param dev Pointer to the device structure for the driver instance.
* @param sel Pointer to a video selection structure
*
Copy link
Contributor

@josuah josuah Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[non-blocking]

Suggested change
*
* Some targets are inter-dependents. For instance, setting a @ref VIDEO_SEL_TGT_CROP will
* reset @ref VIDEO_SEL_TGT_COMPOSE to the same size when both are supported.

Here I propose some minimum hint for users who can't figure out why their firmware work only when calling functions in different order leads to different results. Overkill? Better just point at the V4L2 doc?

Thanks for the explanations earlier!

Addition of selection APIs (set/get) in order to be able
to control the crop and compose of a video device.

Signed-off-by: Alain Volmat <[email protected]>
@avolmat-st avolmat-st force-pushed the pr_video_selection_api branch 2 times, most recently from 1b8693a to 122b221 Compare June 20, 2025 11:59
@avolmat-st avolmat-st marked this pull request as ready for review June 20, 2025 11:59
@avolmat-st
Copy link
Author

Update the branch to take into consideration the comment from @josuah and also add support for the pipe0 (dump).

This update introduce an important modification in behavior compared to previous push in that set_selection(crop) and set_selection(compose) do not necessarily return an error if the parameters cannot be set and instead adjust those parameters. It would be later on up to the application to check the applied settings. This is I think an important behavior point to discuss about, what we would like to end up with. In this version, except when there is really an issue, the crop/compose do not return an error.
I thought this would be necessary especially in case of the pipe0 for which there are constraints in the crop value and I thought it would be easier for an application to get the setting updated rather than just having an error. However this is an open point, since here we are talking about FW for which usually the system is quite fixed so maybe there is no such need and it would be better to just send back an error.

@josuah josuah requested a review from kartben June 20, 2025 15:08
@avolmat-st
Copy link
Author

Thank you I understand better and agree.

If the information needed to make a choice is in the driver, then the driver has to expose that (is it even possible?) or choose and tell what it chose.

Yes, I think this depends on the HW so hard for an application to know that. That's why I chose to have the driver update the requested crop/compose and let the application know what has been set. But this implie that application check again after getting back the value and take some additional action if the applied setting aren't good for the application.

Such behavior is ok I think for a Linux application, but I am not sure if this match well what constraint of a Zephyr application, hence I am still wondering if this should be just "check if this can be applied to the HW and simply reject it if not".

josuah
josuah previously approved these changes Jun 20, 2025
Copy link
Contributor

@josuah josuah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking left I could find! Thank you for the modifications!

/* Compose not available on Pipe0 */
if (pipe->id == DCMIPP_PIPE0) {
sel->rect = pipe->crop;
goto out;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should ret = -EINVAL be set here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It depends, this is related to the discussion we are having about returning errors or not.
Here, since there is no compose, basically the applied compose will anyway always be the same as the crop.
A bit similar to when we do a set_frmival on a sensor which cannot change the framerate, we keep returning back the fixed framerate of the sensor.

Comment on lines +1363 to +1369
if (sel->rect.left != 0) {
sel->rect.left = 0;
}
if (sel->rect.top != 0) {
sel->rect.top = 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[non-blocking]
Is the if needed? It seems like a no-op:
Calling sel->rect.left = 0; unconditionally would have the same effect.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it set left and/or top to 0 if it not 0. if it is already 0 it won't do anything. But yes, always setting left and top to 0 would make the code easier to read/understand I think.

Comment on lines 175 to 181
if (err == 0) {
if (sel.rect.width != fmt.width || sel.rect.height != fmt.height) {
sel.target = VIDEO_SEL_TGT_COMPOSE;
sel.rect.left = 0;
sel.rect.top = 0;
sel.rect.width = fmt.width;
sel.rect.height = fmt.height;
err = video_set_selection(video_dev, &sel);
if (err != -ENOSYS && err < 0) {
LOG_ERR("Unable to set selection compose");
return 0;
}
}
} else if (err != -ENOSYS && err < 0) {
LOG_ERR("Unable to get selection crop");
return 0;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[non-blocking]
Proposal for making the error-handling idioms appear, just a minor nit:

err = video_get_selection();            //
if (err < 0 && err != -ENOSYS) {        // well-known C error handling idiom
    LOG_ERR("That did not work");       //
    return 0;                           //
}                                       //

if (err == 0) {
    err = video_set_selection();        //
    if (err < 0 && err != -ENOSYS) {    // well-known C error handling idiom
        LOG_ERR("That did not work");   //
        return 0;                       //
    }                                   //
}

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah indeed, don't know why I came up with such hard to follow pattern ;(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes what is logical to write is not the same as what is logical to read. I got myself tricked in this exactly earlier.

Copy link
Contributor

@ngphibang ngphibang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM except the constraint imposed on the sample where I think it should be up to the driver to decide.

Thanks for adding this API. The selection API looks simple enough but the complexity is left in the driver implementation and user's usage, especially its interaction with get/set_format(), e.g. what if format is set first, selection is set first, size does not mismatch, etc. It is left to the driver to decide to tightly couple with set_fmt() or simply return error. And users should always read back their original settings to decide ...

sel.rect.left, sel.rect.top, sel.rect.width, sel.rect.height);
#endif

#if CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: In a function, it is recommended to use if (IS_ENABLED()) but it is currently not consistent across the sample

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would also solve the CI issue.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added an additionnal prior commit to use if (IS_ENABLED(CONFIG_VIDEO_FRAME_HEIGHT) ... instead of preprocessor.

Alain Volmat added 3 commits June 23, 2025 13:00
Add possibility to perform crop on all pipes and compose (downscale) on
pixel pipes (endpoint zephyrproject-rtos#1 and endpoint zephyrproject-rtos#2).
Rework the code in order to move the downscale control from
the set_fmt into the set_selection (compose).

Signed-off-by: Alain Volmat <[email protected]>
Add shell handling in order to interact with drivers
via the set/get_selection APIs allowing to get/set
crop / compose and get HW capabilities such as
crop bound / compose bound or native size.

Signed-off-by: Alain Volmat <[email protected]>
Correct cmd_video_format return value in case of video_shell_parse_in_out
returns a negative value.

Signed-off-by: Alain Volmat <[email protected]>
@avolmat-st
Copy link
Author

Gave up usage of if (IF_ENABLED(...)) since those CONFIG_VIDEO_ .... are not y/n config but values and using them would lead to just never entering into the if true statement.

Demonstrate the crop/compose API by introducing 4 new
CONFIG options in order to define the crop area.
Moreover, if the selection API is available and if
the targetted size is different from the current crop
size, then try to apply a compose in order to reach
the targetted format size.

Signed-off-by: Alain Volmat <[email protected]>
@avolmat-st avolmat-st force-pushed the pr_video_selection_api branch from f1b088c to 0b9e6db Compare June 23, 2025 12:38
@sonarqubecloud
Copy link

@kartben kartben dismissed their stale review June 25, 2025 14:20

comments addressed

@dkalowsk dkalowsk merged commit 174dead into zephyrproject-rtos:main Jun 26, 2025
26 checks passed
case VIDEO_SEL_TGT_COMPOSE:
sel->rect = pipe->compose;
break;
case VIDEO_SEL_TGT_CROP_BOUND:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor:

Suggested change
case VIDEO_SEL_TGT_CROP_BOUND:
case VIDEO_SEL_TGT_CROP_BOUND:
__fallthrough;

josuah added a commit to tinyvision-ai-inc/zephyr that referenced this pull request Jun 28, 2025
Add a mention to the video_set_selection() and video_get_selection()
introduced in zephyrproject-rtos#91878.

Signed-off-by: Josuah Demangeon <[email protected]>
josuah added a commit to tinyvision-ai-inc/zephyr that referenced this pull request Jul 5, 2025
Add a mention to the video_set_selection() and video_get_selection()
introduced in zephyrproject-rtos#91878.

Signed-off-by: Josuah Demangeon <[email protected]>
josuah added a commit to tinyvision-ai-inc/zephyr that referenced this pull request Jul 9, 2025
Add a mention to the video_set_selection() and video_get_selection()
introduced in zephyrproject-rtos#91878.

Signed-off-by: Josuah Demangeon <[email protected]>
danieldegrasse pushed a commit that referenced this pull request Jul 10, 2025
Add a mention to the video_set_selection() and video_get_selection()
introduced in #91878.

Signed-off-by: Josuah Demangeon <[email protected]>
seyoungjeong pushed a commit to seyoungjeong/zephyr that referenced this pull request Jul 11, 2025
Add a mention to the video_set_selection() and video_get_selection()
introduced in zephyrproject-rtos#91878.

Signed-off-by: Josuah Demangeon <[email protected]>
Chenhongren pushed a commit to Chenhongren/zephyr that referenced this pull request Jul 23, 2025
Add a mention to the video_set_selection() and video_get_selection()
introduced in zephyrproject-rtos#91878.

(cherry picked from commit d491496)

Original-Signed-off-by: Josuah Demangeon <[email protected]>
GitOrigin-RevId: d491496
Cr-Build-Id: 8709689119827444849
Cr-Build-Url: https://cr-buildbucket.appspot.com/build/8709689119827444849
Copybot-Job-Name: zephyr-main-copybot-downstream
Change-Id: I73af2c5c58232bf1086837f435bafd40928478e6
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/zephyr/+/6725779
Commit-Queue: ChromeOS Copybot <[email protected]>
Bot-Commit: ChromeOS Copybot <[email protected]>
Tested-by: ChromeOS Copybot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: Samples Samples area: Video Video subsystem platform: STM32 ST Micro STM32

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants