ESP32P4驱动摄像头拍照和录视频故障

fengyuganyu
Posts: 1
Joined: Sun Mar 01, 2026 10:14 am

ESP32P4驱动摄像头拍照和录视频故障

Postby fengyuganyu » Sun Mar 01, 2026 11:15 am

项目描述:
参考esp_video中的例程image_storage/usb_msc,实现2个功能,功能如下:
F1、H.264视频录取并封装成MP4文件
F2、抓拍照片生成JPG格式文件
参数:
camera sensor: OV5647
采集分辨率:1920x1080
帧率:30fps

问题描述:
1、在运行过程中动态切换F1和F2功能,当完成F2功能之后,启动F1时,会报错,报错位置:esp_h264_enc_hw_new_param->"No memory for handle",根据描述是无法申请内存
2、由于功能F1 和 F2分别使用H.264和MJPEG进行编码,2种编码器是否会占用很大资源
3、当一直执行同一个功能时,不会出现问题1的报错。
每次启动都会配置代码

Code: Select all

 int type;
    struct v4l2_buffer buf;
    struct v4l2_format format;
    struct v4l2_requestbuffers req;
    uint32_t capture_fmt = 0;

    ESP_LOGD(TAG, "video start");

    if(video)
    {

        // init_h264_codec_video(cb_ctx);

        cb_ctx->format = V4L2_PIX_FMT_H264;
    }
    else
    {
        // init_jpeg_codec_video(cb_ctx);

        cb_ctx->format = V4L2_PIX_FMT_JPEG;
    }

    if (cb_ctx->format == V4L2_PIX_FMT_JPEG) {
        int fmt_index = 0;
        const uint32_t jpeg_input_formats[] = {
            V4L2_PIX_FMT_RGB565,
            V4L2_PIX_FMT_YUV422P,
            V4L2_PIX_FMT_RGB24,
            V4L2_PIX_FMT_GREY
        };
        int jpeg_input_formats_num = sizeof(jpeg_input_formats) / sizeof(jpeg_input_formats[0]);

        while (!capture_fmt) {
            struct v4l2_fmtdesc fmtdesc = {
                .index = fmt_index++,
                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
            };

            if (ioctl(cb_ctx->cap_fd, VIDIOC_ENUM_FMT, &fmtdesc) != 0) {
                break;
            }

            for (int i = 0; i < jpeg_input_formats_num; i++) {
                if (jpeg_input_formats[i] == fmtdesc.pixelformat) {
                    capture_fmt = jpeg_input_formats[i];
                    break;
                }
            }
        }

        if (!capture_fmt) {
            ESP_LOGI(TAG, "The camera sensor output pixel format is not supported by JPEG");
            return ESP_ERR_NOT_SUPPORTED;
        }
    } else {
        capture_fmt = V4L2_PIX_FMT_YUV420;
    }

    ESP_LOGI(TAG,"capture fmt :%x",capture_fmt);

    /* Configure camera interface capture stream */

    memset(&format, 0, sizeof(format));
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = width;
    format.fmt.pix.height = height;
    format.fmt.pix.pixelformat = capture_fmt;
    ESP_ERROR_CHECK(ioctl(cb_ctx->cap_fd, VIDIOC_S_FMT, &format));

  
    memset(&req, 0, sizeof(req));
    req.count = BUFFER_COUNT;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    ESP_ERROR_CHECK(ioctl(cb_ctx->cap_fd, VIDIOC_REQBUFS, &req));

    for (int i = 0; i < BUFFER_COUNT; i++) {
        memset(&buf, 0, sizeof(buf));
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        ESP_ERROR_CHECK(ioctl(cb_ctx->cap_fd, VIDIOC_QUERYBUF, &buf));

        cb_ctx->cap_buffer[i] = (uint8_t *) mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
                                                MAP_SHARED, cb_ctx->cap_fd, buf.m.offset);
        assert(cb_ctx->cap_buffer[i]);

        ESP_ERROR_CHECK(ioctl(cb_ctx->cap_fd, VIDIOC_QBUF, &buf));
    }
    
    

    /* Configure codec output stream */

    if(!video)
    {
        ESP_ERROR_CHECK(set_codec_control(cb_ctx->jpeg_fd,V4L2_CID_JPEG_CLASS, V4L2_CID_JPEG_COMPRESSION_QUALITY, compress));
    }

    memset(&format, 0, sizeof(format));
    format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    format.fmt.pix.width = width;
    format.fmt.pix.height = height;
    format.fmt.pix.pixelformat = capture_fmt;
    ESP_ERROR_CHECK(ioctl(video?cb_ctx->m2m_fd:cb_ctx->jpeg_fd, VIDIOC_S_FMT, &format));

    memset(&req, 0, sizeof(req));
    req.count = 1;
    req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    req.memory = V4L2_MEMORY_USERPTR;
    ESP_ERROR_CHECK(ioctl(video?cb_ctx->m2m_fd:cb_ctx->jpeg_fd, VIDIOC_REQBUFS, &req));

    /* Configure codec capture stream */

    memset(&format, 0, sizeof(format));
    format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    format.fmt.pix.width = width;
    format.fmt.pix.height = height;
    format.fmt.pix.pixelformat = cb_ctx->format;
    ESP_ERROR_CHECK(ioctl(video?cb_ctx->m2m_fd:cb_ctx->jpeg_fd, VIDIOC_S_FMT, &format));

    memset(&req, 0, sizeof(req));
    req.count = 1;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    ESP_ERROR_CHECK(ioctl(video?cb_ctx->m2m_fd:cb_ctx->jpeg_fd, VIDIOC_REQBUFS, &req));

 
    memset(&buf, 0, sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 0;
    ESP_ERROR_CHECK(ioctl(video?cb_ctx->m2m_fd:cb_ctx->jpeg_fd, VIDIOC_QUERYBUF, &buf));

    cb_ctx->m2m_cap_buffer = (uint8_t *) mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
                                            MAP_SHARED, video?cb_ctx->m2m_fd:cb_ctx->jpeg_fd, buf.m.offset);
    assert(cb_ctx->m2m_cap_buffer);

    ESP_ERROR_CHECK(ioctl(video?cb_ctx->m2m_fd:cb_ctx->jpeg_fd, VIDIOC_QBUF, &buf));
烦请分析下,想解决2个问题:
1、反复切换不同编码器是否可行
2、如果都使用H.264编码器进行输出,如何将CAM采集的YUV420帧转换成MJPEG实现拍照(曾经将CAM采集的YUV420保存输出,发现无法在电脑端正确转换出图片,是否是其他格式)

Who is online

Users browsing this forum: No registered users and 3 guests