Skip to content

Conversation

hfruchet-st
Copy link
Contributor

@hfruchet-st hfruchet-st commented Jul 9, 2025

This PR introduces H264 hardware video compression thanks to VENC peripheral of STM32N6.

A new stm32 video encoder driver has been introduced which relies on vc8000nanoe software stack [1].
This is a first basic porting to enable H264 encoding use-case.
RAM memory resources required by VENC encoding process are allocated in external PSRAM, camera frames
captured by DCMIPP and encoded by VENC are also allocated in external PSRAM.
The video encoder driver currently lack of controls to configure the encoding process, default configuration
targets H264 1080p 2Mb/s constant bitrate.

In order to test, the tcpserversink video sample has been enhanced to support video compression in order to stream small H264 compressed video chunks instead of big raw uncompressed images [2].

[1] zephyrproject-rtos/hal_stm32#295
[2] #95862

Copy link

github-actions bot commented Jul 9, 2025

The following west manifest projects have changed revision in this Pull Request:

Name Old Revision New Revision Diff
hal_stm32 zephyrproject-rtos/hal_stm32@dc7c254 (main) zephyrproject-rtos/hal_stm32#295 zephyrproject-rtos/hal_stm32#295/files

DNM label due to: 1 project with PR revision

Note: This message is automatically posted and updated by the Manifest GitHub Action.

Copy link

sonarqubecloud bot commented Jul 9, 2025

@avolmat-st avolmat-st self-requested a review July 9, 2025 11:12
@josuah josuah added the area: Video Video subsystem label Jul 19, 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.

Thank you for preparing VENC!

This will really make video over network on Zephyr interesting.

It seems like Zephyr lacks a few APIs from Linux (no H.264 format definition, no planar API for NV12...), so if anything feels like missing, let us know so that the missing API can be provided in parallel.

Comment on lines 721 to 724
input = k_fifo_get(&data->fifo_input, K_NO_WAIT);
if (!input)
return 0;
LOG_DBG("input=%p\n", input);
Copy link
Contributor

Choose a reason for hiding this comment

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

In the meantime that a better buffering model is worked on, the way to video_buffer_free() a buffer is by giving it back to the application which video_dequeue() it and reuse it in the next cycle, for instance via data->fifo_input_out (in addition to a data->fifo_input_in).

If encountering errors where running out of buffers hopefully this can help.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't get the point sorry. If no input buffer is there we silently exit and we will retry at next encoding, do you see a problem around that ?

}

data->pixelformat = fmt->pixelformat;
data->pitch = fmt->pitch;
Copy link
Contributor

@josuah josuah Jul 19, 2025

Choose a reason for hiding this comment

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

Following these changes, when the application sets the format, the driver sets the ->pitch field.

But for H.264 the pitch might as well be 0 as a convention for variable data size...

case VIDEO_PIX_FMT_ARGB32:
case VIDEO_PIX_FMT_ABGR32:
case VIDEO_PIX_FMT_RGBA32:
case VIDEO_PIX_FMT_BGRA32:
return 32;
default:
/* Variable number of bits per pixel or unknown format */
return 0;
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pitch is used by tcpserversink application to allocate buffers, see

buffers[i] = video_buffer_alloc(fmt.pitch * fmt.height, K_FOREVER);

@josuah josuah added the platform: STM32 ST Micro STM32 label Jul 19, 2025
hfruchet-st referenced this pull request in avolmat-st/zephyr-stm32-mw-isp Aug 13, 2025
No specific processing is necessary currently as part of the
stm32_dcmipp_isp_start function hence remove the assert(0)
currently preventing stop of the isp.

Signed-off-by: Alain Volmat <[email protected]>
hfruchet-st referenced this pull request in avolmat-st/hal_stm32 Aug 13, 2025
Allow to call HAL_DCMIPP_PIPE_SetConfig when the pipe state
is READY. Currently it is only possible to use this function
if the pipe state is RESET and ERROR states.
Indeed, it is possible to reconfigure the PIPE as soon as the
pipe is not currently being used, aka in the READY state.
With that done, it becomes possible to change the PIPE
configuration between two use-cases without having to
DeInit / Init the HAL_DCMIPP or use the unitary pixel packer
functions.

Signed-off-by: Alain Volmat <[email protected]>
@ngphibang ngphibang self-requested a review August 14, 2025 06:29
Copy link
Member

@erwango erwango left a comment

Choose a reason for hiding this comment

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

First round of comment, driver aside.
Please split the PR and do a specific PR for the first commits that are not directly linked to the VENC driver. These can be reviewed and integrated faster.
For the changes on the sample, I let video team decide if this should be kept within the tcpserver sample or split into a different sample

Copy link
Member

@erwango erwango left a comment

Choose a reason for hiding this comment

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

Some pending comments, not sure why they were missing

@hfruchet-st hfruchet-st force-pushed the iso_stm32n6_1080p_h264_streaming branch from a32b1da to deac1fb Compare September 11, 2025 14:14
@github-actions github-actions bot removed the manifest label Sep 11, 2025
@hfruchet-st hfruchet-st marked this pull request as ready for review September 11, 2025 14:19
@github-actions github-actions bot added manifest-hal_stm32 DNM (manifest) This PR should not be merged (controlled by action-manifest) labels Sep 24, 2025
@hfruchet-st hfruchet-st force-pushed the iso_stm32n6_1080p_h264_streaming branch 2 times, most recently from 99e9938 to 2f05a7c Compare September 24, 2025 14:27
@hfruchet-st hfruchet-st force-pushed the iso_stm32n6_1080p_h264_streaming branch from 2f05a7c to 4422502 Compare September 24, 2025 15:08
Copy link
Contributor

@mathieuchopstm mathieuchopstm left a comment

Choose a reason for hiding this comment

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

One nit, but otherwise LGTM (though I haven't reviewed every single detail).

Copy link
Contributor

@JarmouniA JarmouniA left a comment

Choose a reason for hiding this comment

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

The commit pulling hal_stm32 PR should be the 1st.

@hfruchet-st hfruchet-st force-pushed the iso_stm32n6_1080p_h264_streaming branch from 4422502 to a0f000d Compare September 24, 2025 15:46
Copy link
Contributor

@JarmouniA JarmouniA left a comment

Choose a reason for hiding this comment

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

@mathieuchopstm
Copy link
Contributor

SonarQube issues that need attention https://sonarcloud.io/project/issues?id=zephyrproject-rtos_zephyr&pullRequest=92884&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true

The first two are incorrect because instance is really &ewl_instance returned by:

const void *EWLInit(EWLInitParam_t *param)
{
__ASSERT_NO_MSG(param != NULL);
__ASSERT_NO_MSG(param->clientType == EWL_CLIENT_TYPE_H264_ENC);
/* sync */
k_sem_init(&ewl_instance.complete, 0, 1);
k_sem_reset(&ewl_instance.complete);
/* set client type */
ewl_instance.clientType = param->clientType;
ewl_instance.irq_cnt = 0;
return (void *)&ewl_instance;
}

The third one is the opposite: API takes an opaque void* which the consumer (RCC driver) never writes to, so dropping the const qualified is not incorrect.

Comment on lines +143 to +142
k_sem_init(&ewl_instance.complete, 0, 1);
k_sem_reset(&ewl_instance.complete);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the k_sem_init plus k_sem_reset required because the instance may get recycled or something? Usually, a single k_sem_init is enough.


uint32_t mem_counter;

typedef struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is a typedef necessary? struct venc_ewl should work and would better suit the snake case coding guideline.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's a type declared in the Encoder Wrapping Layer and needs to be defined.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you refer to ewl_impl.h. I don't see the same structure from that header file. It seems to me that this current structure is internal to this driver and passed back and forth between this driver and the EWL as an opaque structure reference/pointer.

uint32_t mem_counter;

typedef struct {
uint32_t clientType;
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto about snake case for structure fields, prefer:

	uint32_t client_type;
	uint32_t *chunks[MEM_CHUNKS];
	uint32_t *aligned_chunks[MEM_CHUNKS];
	uint32_t total_chunks;

Copy link
Contributor

Choose a reason for hiding this comment

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

field name is defined by Encoder Wrapping Layer

static int encoder_end(struct video_stm32_venc_data *data);
static int encoder_start(struct video_stm32_venc_data *data);

static inline H264EncPictureType to_h264pixfmt(uint32_t pixelformat)
Copy link
Contributor

Choose a reason for hiding this comment

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

You can can drop the inline keyword.

Comment on lines +21 to +23
#include "ewl.h"
#include "h264encapi.h"
#include "reg_offset_v7.h"
Copy link
Contributor

@etienne-lms etienne-lms Sep 25, 2025

Choose a reason for hiding this comment

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

These include file are found from the header path, not locally.
Prefer #include <...>.

(edited) May be addressed in a later P-R.

return -ENODATA;
}
output->bytesused = encOut.streamSize;
break;
Copy link
Contributor

Choose a reason for hiding this comment

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

Indentation

Suggested change
break;
break;

Ditto below.

data->resync = true;

return -EIO;
break;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can remove the break instruction.

/* Stop VENC */
encoder_end(data);

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.

Remove this instruction?

inst->irq_status = irq_status;
inst->irq_cnt++;

if (!hw_handshake_status && (irq_status & ASIC_STATUS_FUSE)) {
Copy link
Contributor

@etienne-lms etienne-lms Sep 25, 2025

Choose a reason for hiding this comment

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

Suggested change
if (!hw_handshake_status && (irq_status & ASIC_STATUS_FUSE)) {
if (hw_handshake_status == 0 && (irq_status & ASIC_STATUS_FUSE) != 0) {

(edited) May be addressed in a later P-R.

static void video_stm32_venc_irq_config_func(const struct device *dev)
{
IRQ_DIRECT_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),
stm32_venc_isr, 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

Indentation

@hfruchet-st hfruchet-st force-pushed the iso_stm32n6_1080p_h264_streaming branch from a0f000d to 107c233 Compare September 29, 2025 14:06
@zephyrbot zephyrbot added area: Tests Issues related to a particular existing or missing test area: Devicetree Bindings area: Boards/SoCs labels Sep 29, 2025
@zephyrbot zephyrbot requested a review from nashif September 29, 2025 14:07
@hfruchet-st hfruchet-st force-pushed the iso_stm32n6_1080p_h264_streaming branch from 107c233 to 6a03a6d Compare September 30, 2025 09:22
thecapn32 and others added 3 commits September 30, 2025 17:07
Pull hal_stm32 vc8000nanoe library.

Signed-off-by: Hugues Fruchet <[email protected]>
Addition of description for the STM32 Video encoder (VENC).

Signed-off-by: Hugues Fruchet <[email protected]>
The STM32 video encoder (VENC) peripheral is a hardware
accelerator allowing to compress RGB/YUV frames into
H264 video bitstream chunks.

Signed-off-by: Hugues Fruchet <[email protected]>
Add node describing the venc in stm32n6.dtsi

Signed-off-by: Hugues Fruchet <[email protected]>
@hfruchet-st hfruchet-st force-pushed the iso_stm32n6_1080p_h264_streaming branch from ac3fb6b to ae105ff Compare September 30, 2025 16:00
#define VIDEO_PIX_FMT_H264_NO_SC VIDEO_FOURCC('A', 'V', 'C', '1')

/**
* H264 without start code
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
* H264 without start code
* H264 MVC video elementary stream.

Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: Boards/SoCs area: Build System area: Devicetree Bindings area: Devicetree area: Tests Issues related to a particular existing or missing test area: Video Video subsystem DNM (manifest) This PR should not be merged (controlled by action-manifest) manifest manifest-hal_stm32 platform: STM32 ST Micro STM32
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants