Hello. I am using LVGL to open a USB camera and capture NV12 640*512 video at 30fps.
I want to compress NV12 video to H264 using /dev/video1 hantro-vpu stm32mp-venc-enc and save the video to /mnt/sdcard/video.h264.
I'm trying to configure /dev/video1 by looking at the kernel driver's stm32mp25_vpu_hw.c, but I can't seem to get it to set up.
Below is the source section that has been set.
void enc_close(hantro_enc_t *enc)
{
if (!enc) return;
for (int i = 0; i < 2; i++){
if (enc->out_buf[i]) munmap(enc->out_buf[i], enc->out_len[i]);
if (enc->in_len_y[i]) munmap(enc->in_len_y[i], enc->in_len_y[i]);
if (enc->in_len_uv[i]) munmap(enc->in_len_uv[i], enc->in_len_uv[i]);
}
if (enc->fd > 0) close(enc->fd);
if (enc->outfile) fclose(enc->outfile);
}
void enc_init(hantro_enc_t *enc, int width, int height)
{
struct v4l2_format fmt;
struct v4l2_requestbuffers reqbuf;
struct v4l2_buffer buf;
struct v4l2_plane planes[2];
enc->fd = open(ENC_DEVICE_PATH, O_RDWR);
if (enc->fd < 0) {
LV_LOG_USER("open encoder");
exit(1);
}
enc->outfile = fopen(H264_FILE_PATH, "wb");
if (!enc->outfile) {
LV_LOG_USER("fopen output");
enc_close(enc);
exit(1);
}
enc->width = width;
enc->height = height;
// --- Output queue (input to encoder) ---
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; // Input NV12
fmt.fmt.pix_mp.width = width;
fmt.fmt.pix_mp.height = height;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M; // NV12
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
// fmt.fmt.pix_mp.num_planes = 2;
if (ioctl(enc->fd, VIDIOC_S_FMT, &fmt) < 0) {
LV_LOG_USER("Set input format failed");
enc_close(enc);
exit(1);
}
// --- Capture queue (output from encoder) ---
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.width = width;
fmt.fmt.pix_mp.height = height;
fmt.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264_SLICE;
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
// fmt.fmt.pix_mp.num_planes = 1;
if (ioctl(enc->fd, VIDIOC_S_FMT, &fmt) < 0) {
LV_LOG_USER("Set output format failed");
enc_close(enc);
exit(1);
}
// --- request buffers ---
// buffer type check :: V4L2_MEMORY_MMAP | V4L2_MEMORY_DMABUF
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.count = 2;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
reqbuf.memory = V4L2_MEMORY_MMAP;
if (ioctl(enc->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
LV_LOG_USER("Request V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffers failed");
enc_close(enc);
exit(1);
}
memset(&reqbuf, 0, sizeof(reqbuf));
reqbuf.count = 2;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
reqbuf.memory = V4L2_MEMORY_MMAP;
if (ioctl(enc->fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
LV_LOG_USER("Request V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE buffers failed");
enc_close(enc);
exit(1);
}
// --- mmap capture buffer ---
for (int i = 0; i < 2; i++) {
memset(&buf, 0, sizeof(buf));
memset(planes, 0, sizeof(planes));
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
buf.length = fmt.fmt.pix_mp.num_planes;
buf.m.planes = planes;
if (ioctl(enc->fd, VIDIOC_QUERYBUF, &buf) < 0) {
LV_LOG_USER("VIDIOC_QUERYBUF failed for output - index[%d]",i);
enc_close(enc);
exit(1);
}
enc->in_buf_y[i] = mmap(NULL, buf.m.planes[0].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
enc->fd, buf.m.planes[0].m.mem_offset);
enc->in_len_y[i] = buf.m.planes[0].length;
enc->in_buf_uv[i] = mmap(NULL, buf.m.planes[1].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
enc->fd, buf.m.planes[1].m.mem_offset);
enc->in_len_uv[i] = buf.m.planes[1].length;
if(enc->in_buf_y[i] == MAP_FAILED || enc->in_buf_uv[i] == MAP_FAILED) {
LV_LOG_USER("mmap failed");
enc_close(enc);
exit(1);
}
}
for (int i = 0; i < 2; i++) {
memset(&buf, 0, sizeof(buf));
memset(planes, 0, sizeof(planes));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
buf.length = fmt.fmt.pix_mp.num_planes;
buf.m.planes = planes;
if (ioctl(enc->fd, VIDIOC_QUERYBUF, &buf) < 0) {
LV_LOG_USER("VIDIOC_QUERYBUF failed for capture - index[%d]",i);
enc_close(enc);
exit(1);
}
enc->out_len[i] = buf.m.planes[0].length;
enc->out_buf[i] = mmap(NULL, buf.m.planes[0].length,
PROT_READ | PROT_WRITE, MAP_SHARED,
enc->fd, buf.m.planes[0].m.mem_offset);
if (enc->out_buf[i] == MAP_FAILED)
LV_LOG_USER("mmap failed for capture buffer");
}
enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
if(ioctl(enc->fd, VIDIOC_STREAMON, &type) < 0) {
LV_LOG_USER("VIDIOC_STREAMON V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE buffers failed");
enc_close(enc);
exit(1);
}
type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
if(ioctl(enc->fd, VIDIOC_STREAMON, &type) < 0) {
LV_LOG_USER("VIDIOC_STREAMON V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE buffers failed");
enc_close(enc);
exit(1);
}
LV_LOG_USER(":white_heavy_check_mark: Hantro Encoder Initialized (W=%d, H=%d)", width, height);
}
int enc_encode_frame(hantro_enc_t *enc, uint8_t *y_plane, uint8_t *uv_plane, int idx)
{
int width = enc->width;
int height = enc->height;
int uv_size = (width/2)*(height/2);
uint8_t tmp_y[width*height];
uint8_t tmp_uv[uv_size*2];
nv12_to_ym12(y_plane, uv_plane, tmp_y, tmp_uv, width, height);
memcpy(enc->in_buf_y[idx], tmp_y, enc->in_len_y[idx]);
memcpy(enc->in_buf_uv[idx], tmp_uv, enc->in_len_uv[idx]);
struct v4l2_buffer buf;
struct v4l2_plane planes[2];
memset(&buf,0,sizeof(buf));
memset(planes,0,sizeof(planes));
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = idx;
buf.m.planes = planes;
planes[0].length = enc->in_len_y[idx];
planes[1].length = enc->in_len_uv[idx];
if(ioctl(enc->fd, VIDIOC_QBUF, &buf) < 0){
LV_LOG_USER("VIDIOC_QBUF output failed");
return -1;
}
// --- Capture dequeue ---
memset(&buf,0,sizeof(buf));
memset(planes,0,sizeof(planes));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = V4L2_MEMORY_MMAP;
buf.m.planes = planes;
if(ioctl(enc->fd, VIDIOC_DQBUF, &buf) < 0){
LV_LOG_USER("VIDIOC_DQBUF capture failed");
return -1;
}
if(buf.m.planes[0].bytesused > 0){
fwrite(enc->out_buf[buf.index], 1, buf.m.planes[0].bytesused, enc->outfile);
fflush(enc->outfile);
}
if(ioctl(enc->fd, VIDIOC_QBUF, &buf) < 0){
LV_LOG_USER("VIDIOC_QBUF capture failed");
return -1;
}
return 0;
}
[User] (11394.008, +3) enc_init: VIDIOC_QUERYBUF failed for output - index[0] uvc_cam.c:577
The error message keeps occurring at if (ioctl(enc->fd, VIDIOC_QUERYBUF, &buf) < 0) {
LV_LOG_USER("VIDIOC_QUERYBUF failed for output - index[%d]",i);
enc_close(enc);
exit(1);
}.
How can I configure the overall settings to insert NV12 footage and compress H264 video and save it to sdcard?