cancel
Showing results for 
Search instead for 
Did you mean: 

How to compress and save NV12 640*512 30fps video with VPU H264 on STM32MP257F-DK board?

jhkim
Associate II

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.

typedef struct {
    int fd;
    FILE *outfile;
    void *out_buf[2];    
    void *in_buf_y[2];    
    void *in_buf_uv[2];  
    size_t in_len_y[2];   
    size_t in_len_uv[2];  
    size_t out_len[2];    
    int width;
    int height;
} hantro_enc_t;
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?

 

0 REPLIES 0