ESP32 S3 虚拟摄像头播放 SPIFFS 内容

这次带来一个好玩的 ESP32 项目:虚拟摄像头,就是将ESP32 S3 的板子烧录之后,系统中会出现一个USB摄像头,打开Camera后能够看到播放出来的视频。

下面介绍具体的实现方式。

目前 Arduino ESP32 尚不支持 USB Camera,因此,这次的项目是基于IDF 来完成的。特别注意:对于硬件有如下要求:

1.必须是 ESP32 S2或者 S3,其他型号的ESP32 目前不支持原生USB编程,所以只能使用 S2 或者 S3;

2.必须带有 PSRAM,因为这个项目是根据Demo 修改而来,Demo 要求带有 PSRAM。我对编译环境不熟悉,这部分没有修改, 理论上移除对于 Camera 的支持即可在没有 PSRAM 的板子上使用;

3.必须是 16MB 的 ESP32 模块,如果想在更小容量的板子上使用,可以删除项目中的JPEG素材缩减体积,同时修改项目配置为 4MB 或者8MB.

如果你对ESP32 IDF环境比较熟悉,可以修改去掉上面提到的2的限制;同样的,可以删除部分图片使得4MB的ESP32 也可以支持。如果你无法做到这两点,可以像我一样使用 ESP32 S3 EYS 兼容版。

先介绍一下如何使用我的代码:

安装 ESP32 IDF 编译环境

2.下载安装 esp-iot-solution,解压后放在c: 根目录下

3.尝试编译C:\esp-iot-solution\examples\usb\device\usb_webcam 确保编译环境无误

4.基本的命令有

               a. 编译命令 idf.py build (特别注意编译时需要联网)

b.烧录 idf.py -p COM端口 flash

c.串口监视器 idf.py -p COM端口 monitor

d.上述指令可以放在一起,例如:

                               idf.py -p com6 build flash monitor

e.监视器可以使用 ctrl+] 退出

f.项目配置 idf.py menuconfig ()

5.将usb_webcam1 解压到C:\esp-iot-solution\examples\usb\device目录下

使用 idf.py -p com6 build flash monitor 编译后会自动烧录然后打开串口监视器。

6.打开系统自带的相机程序,切换到ESP32 摄像头即可看到播放内容

上面介绍了如何直接使用代码,接下来介绍一下项目基本实现原理。

  1. esp-iot-solution 提供了一个USB摄像头的例子。它将自己报告为一个USB相投设备,从板载的摄像头读取数据,然后从USB端口输出;
  2. 我代码的修改是在上报数据中使用SPIFFS存放的数进行替换了摄像头的数据
  3. 下面介绍一下 SPIFFS中存放的内容是如何制作的
  4. 使用 Easy2Convert GIF to JPG 工具将GIF 每一帧转化为 JPG 格式

5. 使用 XnView 处理上面的 JPG 文件。需要将所有的图片名为为 0000、0001…..0XXX 这种名称;同样使用这个软件将所有的图片都修改为 320*240 大小。

修改的代码主要部分在动作就是按照孙旭检查 SPIFFS 中,storage 下面是否有XXXX.jpg 这样的文件,如果有就读取出来作为摄像头数据上报,如果XXXX.JPG 不存在,那么就说明读取完毕,再从 0000开始。

static uvc_fb_t* camera_fb_get_cb(void *cb_ctx)
{
	s_fb.uvc_fb.timestamp.tv_usec++;
	
	char buffer[64];
	struct stat file_stat;
	int  filesize;
	FILE *fd = NULL;
	sprintf(buffer,"/storage/%04d.jpg",PicIndex);
	ESP_LOGI(TAG, "p1 %s %d",buffer,PicIndex);
		
	if (stat(buffer, &file_stat) == -1) {
		PicIndex=0;
		ESP_LOGI(TAG, "ZivHer2");
		sprintf(buffer,"/storage/%04d.jpg",PicIndex);
	} else {PicIndex++;}
	fd = fopen(buffer, "rb");
	ESP_LOGI(TAG, "ZivHer3");
    fseek(fd, 0, SEEK_END);  
    filesize = ftell(fd);  
    rewind(fd);
	ESP_LOGI(TAG, "send %d",filesize);

	fread(&PicBuffer, 1, filesize, fd);
	s_fb.uvc_fb.buf = PicBuffer;
	s_fb.uvc_fb.len=filesize;
	fclose(fd);
	vTaskDelay(pdMS_TO_TICKS(100));
    return &s_fb.uvc_fb;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注