diff --git a/doc/releases/migration-guide-4.3.rst b/doc/releases/migration-guide-4.3.rst index 757041e1b2a13..eee53fe79c626 100644 --- a/doc/releases/migration-guide-4.3.rst +++ b/doc/releases/migration-guide-4.3.rst @@ -251,6 +251,12 @@ PTP Clock ratio adjusting based on nominal frequency. Drivers implementing :c:func:`ptp_clock_rate_adjust` should be adjusted to account for the new behavior. +Video +***** + +* The ``min_line_count`` and ``max_line_count`` fields have been removed from :c:struct:`video_caps`. + Application should base on the new :c:member:`video_format.size` to allocate buffers. + Other subsystems **************** diff --git a/doc/releases/release-notes-4.3.rst b/doc/releases/release-notes-4.3.rst index c4d94c0f75bae..f6afed833f054 100644 --- a/doc/releases/release-notes-4.3.rst +++ b/doc/releases/release-notes-4.3.rst @@ -279,6 +279,7 @@ New APIs and options * Video * :c:member:`video_format.size` field + * :c:func:`video_estimate_fmt_size` .. zephyr-keep-sorted-stop diff --git a/drivers/video/video_common.c b/drivers/video/video_common.c index c77b3e704f06b..95793e66db689 100644 --- a/drivers/video/video_common.c +++ b/drivers/video/video_common.c @@ -443,3 +443,28 @@ int64_t video_get_csi_link_freq(const struct device *dev, uint8_t bpp, uint8_t l /* CSI D-PHY is using a DDR data bus so bitrate is twice the frequency */ return ctrl.val64 * bpp / (2 * lane_nb); } + +int video_estimate_fmt_size(struct video_format *fmt) +{ + if (fmt == NULL) { + return -EINVAL; + } + + switch (fmt->pixelformat) { + case VIDEO_PIX_FMT_JPEG: + /* Rough estimate for the worst case (quality = 100) */ + fmt->pitch = 0; + fmt->size = fmt->width * fmt->height * 2; + break; + default: + /* Uncompressed format */ + fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + if (fmt->pitch == 0) { + return -ENOTSUP; + } + fmt->size = fmt->pitch * fmt->height; + break; + } + + return 0; +} diff --git a/drivers/video/video_emul_rx.c b/drivers/video/video_emul_rx.c index 1048486974bd0..4506ace4568af 100644 --- a/drivers/video/video_emul_rx.c +++ b/drivers/video/video_emul_rx.c @@ -67,7 +67,11 @@ static int emul_rx_set_fmt(const struct device *const dev, struct video_format * } /* Cache the format selected locally to use it for getting the size of the buffer */ - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(fmt); + if (ret < 0) { + return ret; + } + data->fmt = *fmt; return 0; @@ -218,8 +222,10 @@ int emul_rx_init(const struct device *dev) return ret; } - data->fmt.pitch = - data->fmt.width * video_bits_per_pixel(data->fmt.pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(&data->fmt); + if (ret < 0) { + return ret; + } k_fifo_init(&data->fifo_in); k_fifo_init(&data->fifo_out); diff --git a/drivers/video/video_esp32_dvp.c b/drivers/video/video_esp32_dvp.c index 3ffeedd39c99e..5bd7d909a9b6d 100644 --- a/drivers/video/video_esp32_dvp.c +++ b/drivers/video/video_esp32_dvp.c @@ -248,9 +248,6 @@ static int video_esp32_get_caps(const struct device *dev, struct video_caps *cap /* Two buffers are needed to perform transfers */ caps->min_vbuf_count = 2; - /* ESP32 produces full frames */ - caps->min_line_count = caps->max_line_count = LINE_COUNT_HEIGHT; - /* Forward the message to the source device */ return video_get_caps(config->source_dev, caps); } @@ -268,7 +265,10 @@ static int video_esp32_get_fmt(const struct device *dev, struct video_format *fm return ret; } - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(fmt); + if (ret < 0) { + return ret; + } return 0; } @@ -284,7 +284,10 @@ static int video_esp32_set_fmt(const struct device *dev, struct video_format *fm return ret; } - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(fmt); + if (ret < 0) { + return ret; + } data->video_format = *fmt; diff --git a/drivers/video/video_mcux_csi.c b/drivers/video/video_mcux_csi.c index bb935a916be42..5ba4a356450ba 100644 --- a/drivers/video/video_mcux_csi.c +++ b/drivers/video/video_mcux_csi.c @@ -124,8 +124,6 @@ static inline void video_pix_fmt_convert(struct video_format *fmt, bool isGetFmt fmt->pixelformat = isGetFmt ? VIDEO_PIX_FMT_XYUV32 : VIDEO_PIX_FMT_YUYV; break; } - - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; } #endif @@ -168,6 +166,7 @@ static int video_mcux_csi_set_fmt(const struct device *dev, struct video_format } fmt->pitch = data->csi_config.linePitch_Bytes; + fmt->size = fmt->pitch * fmt->height; return 0; } @@ -181,7 +180,7 @@ static int video_mcux_csi_get_fmt(const struct device *dev, struct video_format video_pix_fmt_convert(fmt, true); #endif - return 0; + return video_estimate_fmt_size(fmt); } return -EIO; @@ -323,8 +322,6 @@ static int video_mcux_csi_get_caps(const struct device *dev, struct video_caps * /* NXP MCUX CSI request at least 2 buffer before starting */ caps->min_vbuf_count = 2; - /* CSI only operates on buffers of full frame size */ - caps->min_line_count = caps->max_line_count = LINE_COUNT_HEIGHT; /* no source dev */ return err; diff --git a/drivers/video/video_mcux_smartdma.c b/drivers/video/video_mcux_smartdma.c index ea2be98ddef25..408fac68deba5 100644 --- a/drivers/video/video_mcux_smartdma.c +++ b/drivers/video/video_mcux_smartdma.c @@ -239,6 +239,7 @@ static int nxp_video_sdma_set_format(const struct device *dev, struct video_form } fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + fmt->size = fmt->pitch * SDMA_LINE_COUNT; return 0; } @@ -271,6 +272,7 @@ static int nxp_video_sdma_get_format(const struct device *dev, struct video_form } fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + fmt->size = fmt->pitch * SDMA_LINE_COUNT; return 0; } @@ -279,8 +281,6 @@ static int nxp_video_sdma_get_caps(const struct device *dev, struct video_caps * { /* SmartDMA needs at least two buffers allocated before starting */ caps->min_vbuf_count = 2; - /* Firmware reads 30 lines per queued vbuf */ - caps->min_line_count = caps->max_line_count = SDMA_LINE_COUNT; caps->format_caps = fmts; return 0; } diff --git a/drivers/video/video_renesas_ra_ceu.c b/drivers/video/video_renesas_ra_ceu.c index 0cc815e46ecd5..385c30d7f6734 100644 --- a/drivers/video/video_renesas_ra_ceu.c +++ b/drivers/video/video_renesas_ra_ceu.c @@ -117,9 +117,7 @@ static int video_renesas_ra_ceu_get_format(const struct device *dev, struct vide return ret; } - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; - - return 0; + return video_estimate_fmt_size(fmt); } static int video_renesas_ra_ceu_set_format(const struct device *dev, struct video_format *fmt) @@ -169,7 +167,10 @@ static int video_renesas_ra_ceu_set_format(const struct device *dev, struct vide return -EIO; } - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(fmt); + if (ret < 0) { + return ret; + } memcpy(&data->fmt, fmt, sizeof(struct video_format)); @@ -181,8 +182,6 @@ static int video_renesas_ra_ceu_get_caps(const struct device *dev, struct video_ const struct video_renesas_ra_ceu_config *config = dev->config; caps->min_vbuf_count = 1; - caps->min_line_count = LINE_COUNT_HEIGHT; - caps->max_line_count = LINE_COUNT_HEIGHT; return video_get_caps(config->source_dev, caps); } diff --git a/drivers/video/video_shell.c b/drivers/video/video_shell.c index 87d22bbd87a42..e59f3c9a0282e 100644 --- a/drivers/video/video_shell.c +++ b/drivers/video/video_shell.c @@ -499,8 +499,6 @@ static int video_shell_print_caps(const struct shell *sh, const struct device *d int ret; shell_print(sh, "min vbuf count: %u", caps->min_vbuf_count); - shell_print(sh, "min line count: %u", caps->min_line_count); - shell_print(sh, "max line count: %u", caps->max_line_count); for (size_t i = 0; caps->format_caps[i].pixelformat != 0; i++) { ret = video_shell_print_format_cap(sh, dev, caps->type, &caps->format_caps[i], i); diff --git a/drivers/video/video_st_mipid02.c b/drivers/video/video_st_mipid02.c index 0b2493619a601..61d8b57b77bd9 100644 --- a/drivers/video/video_st_mipid02.c +++ b/drivers/video/video_st_mipid02.c @@ -252,9 +252,6 @@ static int mipid02_get_caps(const struct device *dev, struct video_caps *caps) } caps->format_caps = drv_data->caps; - caps->min_vbuf_count = 1; - caps->min_line_count = LINE_COUNT_HEIGHT; - caps->max_line_count = LINE_COUNT_HEIGHT; return 0; } diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c index 88013b5309734..3478d9262fda2 100644 --- a/drivers/video/video_stm32_dcmi.c +++ b/drivers/video/video_stm32_dcmi.c @@ -194,7 +194,10 @@ static int video_stm32_dcmi_set_fmt(const struct device *dev, struct video_forma return ret; } - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(fmt); + if (ret < 0) { + return ret; + } data->fmt = *fmt; @@ -213,7 +216,10 @@ static int video_stm32_dcmi_get_fmt(const struct device *dev, struct video_forma return ret; } - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(fmt); + if (ret < 0) { + return ret; + } data->fmt = *fmt; @@ -309,9 +315,6 @@ static int video_stm32_dcmi_get_caps(const struct device *dev, struct video_caps /* 2 buffers are needed for DCMI_MODE_CONTINUOUS */ caps->min_vbuf_count = 2; - /* DCMI produces full frames */ - caps->min_line_count = caps->max_line_count = LINE_COUNT_HEIGHT; - /* Forward the message to the sensor device */ return video_get_caps(config->sensor_dev, caps); } diff --git a/drivers/video/video_stm32_dcmipp.c b/drivers/video/video_stm32_dcmipp.c index d8608fc22f15f..37c7d1724598b 100644 --- a/drivers/video/video_stm32_dcmipp.c +++ b/drivers/video/video_stm32_dcmipp.c @@ -545,6 +545,9 @@ static inline void stm32_dcmipp_compute_fmt_pitch(uint32_t pipe_id, struct video fmt->pitch = ROUND_UP(fmt->pitch, 16); } #endif + + /* Update the corresponding fmt->size */ + fmt->size = fmt->pitch * fmt->height; } static int stm32_dcmipp_set_fmt(const struct device *dev, struct video_format *fmt) @@ -1370,8 +1373,6 @@ static int stm32_dcmipp_get_caps(const struct device *dev, struct video_caps *ca ret = video_get_caps(config->source_dev, caps); caps->min_vbuf_count = 1; - caps->min_line_count = LINE_COUNT_HEIGHT; - caps->max_line_count = LINE_COUNT_HEIGHT; return ret; } diff --git a/drivers/video/video_stm32_venc.c b/drivers/video/video_stm32_venc.c index 4f26977dcce10..abd1608454dfb 100644 --- a/drivers/video/video_stm32_venc.c +++ b/drivers/video/video_stm32_venc.c @@ -806,7 +806,6 @@ static int stm32_venc_get_caps(const struct device *dev, struct video_caps *caps } /* VENC produces full frames */ - caps->min_line_count = caps->max_line_count = LINE_COUNT_HEIGHT; caps->min_vbuf_count = 1; return 0; diff --git a/drivers/video/video_sw_generator.c b/drivers/video/video_sw_generator.c index 2effc1ef54dda..6c270646ef503 100644 --- a/drivers/video/video_sw_generator.c +++ b/drivers/video/video_sw_generator.c @@ -81,7 +81,10 @@ static int video_sw_generator_set_fmt(const struct device *dev, struct video_for return ret; } - fmt->pitch = fmt->width * video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + ret = video_estimate_fmt_size(fmt); + if (ret < 0) { + return ret; + } data->fmt = *fmt; return 0; @@ -365,9 +368,6 @@ static int video_sw_generator_get_caps(const struct device *dev, struct video_ca caps->format_caps = fmts; caps->min_vbuf_count = 1; - /* SW generator produces full frames */ - caps->min_line_count = caps->max_line_count = LINE_COUNT_HEIGHT; - return 0; } @@ -477,6 +477,7 @@ static int video_sw_generator_init(const struct device *dev) .fmt.height = 160, \ .fmt.pitch = 320 * 2, \ .fmt.pixelformat = VIDEO_PIX_FMT_RGB565, \ + .fmt.size = 320 * 2 * 160, \ .frame_rate = DEFAULT_FRAME_RATE, \ }; \ \ diff --git a/include/zephyr/drivers/video.h b/include/zephyr/drivers/video.h index 87eb0314a48d8..e50f49b0e382f 100644 --- a/include/zephyr/drivers/video.h +++ b/include/zephyr/drivers/video.h @@ -34,12 +34,6 @@ extern "C" { #endif -/* - * Flag used by @ref video_caps structure to indicate endpoint operates on - * buffers the size of the video frame - */ -#define LINE_COUNT_HEIGHT (-1) - struct video_control; /** @@ -128,22 +122,6 @@ struct video_caps { * the stream. */ uint8_t min_vbuf_count; - /** Denotes minimum line count of a video buffer that this endpoint - * can fill or process. Each line is expected to consume the number - * of bytes the selected video format's pitch uses, so the video - * buffer must be at least `pitch` * `min_line_count` bytes. - * `LINE_COUNT_HEIGHT` is a special value, indicating the endpoint - * only supports video buffers with at least enough bytes to store - * a full video frame - */ - int16_t min_line_count; - /** - * Denotes maximum line count of a video buffer that this endpoint - * can fill or process. Similar constraints to `min_line_count`, - * but `LINE_COUNT_HEIGHT` indicates that the endpoint will never - * fill or process more than a full video frame in one video buffer. - */ - int16_t max_line_count; }; /** @@ -988,6 +966,22 @@ void video_closest_frmival(const struct device *dev, struct video_frmival_enum * */ int64_t video_get_csi_link_freq(const struct device *dev, uint8_t bpp, uint8_t lane_nb); +/** + * @brief Estimate the size and pitch in bytes of a @ref video_format + * + * This helper should only be used by drivers that support the whole image frame. + * + * For uncompressed formats, it gives the actual size and pitch of the + * whole raw image without any padding. + * + * For compressed formats, it gives a rough estimate size of a complete + * compressed frame. + * + * @param fmt Pointer to the video format structure + * @return 0 on success, otherwise a negative errno code + */ +int video_estimate_fmt_size(struct video_format *fmt); + /** * @defgroup video_pixel_formats Video pixel formats * The '|' characters separate the pixels or logical blocks, and spaces separate the bytes. diff --git a/samples/drivers/video/capture/src/main.c b/samples/drivers/video/capture/src/main.c index bfb8e051f2993..fe702a1bdb367 100644 --- a/samples/drivers/video/capture/src/main.c +++ b/samples/drivers/video/capture/src/main.c @@ -105,7 +105,6 @@ int main(void) }; #endif unsigned int frame = 0; - size_t bsize; int i = 0; int err; @@ -276,16 +275,9 @@ int main(void) } #endif - /* Size to allocate for each buffer */ - if (caps.min_line_count == LINE_COUNT_HEIGHT) { - bsize = fmt.pitch * fmt.height; - } else { - bsize = fmt.pitch * caps.min_line_count; - } - /* Alloc video buffers and enqueue for capture */ if (caps.min_vbuf_count > CONFIG_VIDEO_BUFFER_POOL_NUM_MAX || - bsize > CONFIG_VIDEO_BUFFER_POOL_SZ_MAX) { + fmt.size > CONFIG_VIDEO_BUFFER_POOL_SZ_MAX) { LOG_ERR("Not enough buffers or memory to start streaming"); return 0; } @@ -295,7 +287,7 @@ int main(void) * For some hardwares, such as the PxP used on i.MX RT1170 to do image rotation, * buffer alignment is needed in order to achieve the best performance */ - vbuf = video_buffer_aligned_alloc(bsize, CONFIG_VIDEO_BUFFER_POOL_ALIGN, + vbuf = video_buffer_aligned_alloc(fmt.size, CONFIG_VIDEO_BUFFER_POOL_ALIGN, K_FOREVER); if (vbuf == NULL) { LOG_ERR("Unable to alloc video buffer"); diff --git a/samples/drivers/video/capture_to_lvgl/src/main.c b/samples/drivers/video/capture_to_lvgl/src/main.c index 020397cbf61c6..b57a9d1312130 100644 --- a/samples/drivers/video/capture_to_lvgl/src/main.c +++ b/samples/drivers/video/capture_to_lvgl/src/main.c @@ -34,7 +34,6 @@ int main(void) struct video_selection sel = { .type = VIDEO_BUF_TYPE_OUTPUT, }; - size_t bsize; int i = 0; int err; @@ -131,16 +130,9 @@ int main(void) (char)(fmt.pixelformat >> 16), (char)(fmt.pixelformat >> 24), fmt.width, fmt.height, fmt.pitch); - if (caps.min_line_count != LINE_COUNT_HEIGHT) { - LOG_ERR("Partial framebuffers not supported by this sample"); - return 0; - } - /* Size to allocate for each buffer */ - bsize = fmt.pitch * fmt.height; - /* Alloc video buffers and enqueue for capture */ for (i = 0; i < ARRAY_SIZE(buffers); i++) { - buffers[i] = video_buffer_aligned_alloc(bsize, CONFIG_VIDEO_BUFFER_POOL_ALIGN, + buffers[i] = video_buffer_aligned_alloc(fmt.size, CONFIG_VIDEO_BUFFER_POOL_ALIGN, K_FOREVER); if (buffers[i] == NULL) { LOG_ERR("Unable to alloc video buffer"); diff --git a/samples/drivers/video/tcpserversink/src/main.c b/samples/drivers/video/tcpserversink/src/main.c index 3ee04c1b32b7d..39c8810ac930b 100644 --- a/samples/drivers/video/tcpserversink/src/main.c +++ b/samples/drivers/video/tcpserversink/src/main.c @@ -211,7 +211,6 @@ int main(void) .type = VIDEO_BUF_TYPE_OUTPUT, }; #endif - size_t bsize; int i = 0; #if CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH int err; @@ -279,11 +278,6 @@ int main(void) LOG_INF("Video device detected, format: %s %ux%u", VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height); - if (caps.min_line_count != LINE_COUNT_HEIGHT) { - LOG_ERR("Partial framebuffers not supported by this sample"); - return 0; - } - /* Set the crop setting if necessary */ #if CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT sel.target = VIDEO_SEL_TGT_CROP; @@ -392,20 +386,13 @@ int main(void) tp_set_ret = video_set_ctrl(video_dev, &ctrl); } - /* Size to allocate for each buffer */ - if (caps.min_line_count == LINE_COUNT_HEIGHT) { - bsize = fmt.pitch * fmt.height; - } else { - bsize = fmt.pitch * caps.min_line_count; - } - /* Alloc Buffers */ for (i = 0; i < ARRAY_SIZE(buffers); i++) { /* * For some hardwares, such as the PxP used on i.MX RT1170 to do image rotation, * buffer alignment is needed in order to achieve the best performance */ - buffers[i] = video_buffer_aligned_alloc(bsize, CONFIG_VIDEO_BUFFER_POOL_ALIGN, + buffers[i] = video_buffer_aligned_alloc(fmt.size, CONFIG_VIDEO_BUFFER_POOL_ALIGN, K_FOREVER); if (buffers[i] == NULL) { LOG_ERR("Unable to alloc video buffer"); diff --git a/samples/subsys/usb/uvc/src/main.c b/samples/subsys/usb/uvc/src/main.c index e2520556ba10e..454bed7bdd9c5 100644 --- a/samples/subsys/usb/uvc/src/main.c +++ b/samples/subsys/usb/uvc/src/main.c @@ -29,7 +29,6 @@ int main(void) struct k_poll_signal sig; struct k_poll_event evt[1]; k_timeout_t timeout = K_FOREVER; - size_t bsize; int ret; if (!device_is_ready(video_dev)) { @@ -79,15 +78,8 @@ int main(void) VIDEO_FOURCC_TO_STR(fmt.pixelformat), fmt.width, fmt.height, CONFIG_VIDEO_BUFFER_POOL_NUM_MAX, fmt.pitch * fmt.height); - /* Size to allocate for each buffer */ - if (caps.min_line_count == LINE_COUNT_HEIGHT) { - bsize = fmt.pitch * fmt.height; - } else { - bsize = fmt.pitch * caps.min_line_count; - } - for (int i = 0; i < CONFIG_VIDEO_BUFFER_POOL_NUM_MAX; i++) { - vbuf = video_buffer_alloc(bsize, K_NO_WAIT); + vbuf = video_buffer_alloc(fmt.size, K_NO_WAIT); if (vbuf == NULL) { LOG_ERR("Could not allocate the video buffer"); return -ENOMEM;