一个使用 Python 和 MicroPython 编写的小型音视频项目
本项目以 Bad Apple!! 影绘 PV 为例,在电脑端预先处理好视频和乐谱,然后在 ESP32 上使用单色 OLED 以 128*64@60fps 或其他分辨率和帧率播放给定的视频,使用 PWM 驱动蜂鸣器 或 使用 I2S 驱动 DAC 播放给定的音频。
(右上角的 lcd 仅为显示头像使用,非项目必需,该项目不含其代码)
有录制视频并上传至 Bilibili 的计划
- 任意 ESP32 开发板核心板
- ssd1306 或 sh1106 驱动芯片的单色 OLED,分辨率 128*64,I2C 或 SPI 接口
- 无源蜂鸣器(需要驱动) 或 支持 I2S 协议的 DAC 模块
- SD 卡模块(可选)
- 一些连接线(杜邦线或面包板等)
- PZ-ESP32 开发板,其板载模块的屏蔽罩丝印的是 ESP-WROOM-32,但使用
esptool.exe flash_id
读取到Chip is ESP32-D0WD-V3 (revision v3.0)
- 普中-IIC OLED,0.96",蓝色,4 针,I2C,ssd1306
- 0.96OLED,0.96",白色,7 针,通信方式可选,ssd1306
- 1.3"OLED V2.0,1.3",白色,7 针,通信方式可选,sh1106
- 普中-ESP32 底板,使用 ULN2003D 驱动蜂鸣器,带有 SD 卡槽
- WCMCU-1334 UDA1334A I2S 立体声解码模块
- SanDisk 4GB MicroSD 卡,SDHC
为了在电脑上进行视频处理,需要额外安装的 Python 库
工具 | pip 库名 |
---|---|
video2frames.py |
opencv-python |
frames2videohex.py |
Pillow |
为了将进行视频的预处理,以及将视频处理为音频,需要额外安装 ffmpeg
- 对源视频按照需求先进行一些预处理,比如旋转视频、调整 fps 、删除黑边,让 ffmpeg 来干吧
- 将源视频放到项目文件夹里,默认名称为
original.mp4
- 修改
config.py
头部的参数,以符合需求(参考文件内配置说明) - 运行
video2frames.py
,将视频拆分为每一帧的图像,其存储在\OrigFrames-xxxxxp-xxfps\
中 - 运行
frames2videohex.py
,将每一帧的图像处理并合并为用于 ESP32 上显示的 hex 视频文件 - 将当前目录中生成的 hex 视频文件,例如
video-13926p-60fps-4a26a634.hex
,放进已格式化为 FAT32 文件系统的 SD 卡根目录中,\sd-files-for-test\
中有测试用文件,内容为 Bad Apple!! 影绘 PV。- 若无 SD 卡,可将文件写入 ESP32 设备内部文件系统的根目录中
- 使用 I2S 播放音乐:
ffmpeg -i original.mp4 audio.wav
- 将当前目录中生成的
audio.wav
放置到上述 SD 卡根目录中,\sd-files-for-test\
中有测试用文件,内容为 Bad Apple!! 影绘 PV。- 若无 SD 卡,可将文件写入 ESP32 设备内部文件系统的根目录中
- 使用蜂鸣器播放乐谱:
- 待补充
- 见后文硬件配置第二步
- 不播放音乐:
- 什么也不用做
-
修改
mpycode\main.py
头部定义的各模块与 ESP32 连接的引脚编号,并按需修改文件内其它参数模块 默认引脚编号 I2C OLED scl=25, sda=26 SPI OLED sck=16, mosi=17, dc=22, res=5, cs=21 SD 卡 sck=18, miso=19, mosi=23, cs=4 I2S sck=32, sd=33, ws=27 蜂鸣器 15 -
将开发板连接至电脑,利用 Thonny 或者别的适用于 SPIFFS 文件系统的软件将
mpycode\
中需要的文件写入 ESP32 设备内部文件系统的根目录中:- 必须上传的:
ssd1306.py
sh1106.py
main.py
- 可选上传的:
musicscore.py
musicscore.py
与audio.wav
仅需上传一个,都上传会播放audio.wav
,都不上传则不播放音频 - 必须上传的:
-
按照步骤 1 内的配置,连接 OLED 、蜂鸣器 / I2S 模块。 如果已在上文步骤中将文件放置到上述 SD 卡根目录中,则连接 SD 卡模块,插入 SD 卡
-
在 ESP32 上运行
main.py
,欣赏好康的画面与好汀的音乐
- I2C OLED 必须使用硬件 I2C,使用软件 I2C 时最大 fps 不超过 15
- I2C OLED 若未连接到 ESP32 的某个 I2C 通道默认的引脚,则可能由于经过 GPIO 交换矩阵或别的原因,导致 fps 达不到 60,画面会产生轻微卡顿与延迟
- 测得的最大 fps 在以下值左右:
驱动芯片 通信方式 fps ssd1306 I2C 70 ssd1306 SPI 160 sh1106 SPI 140 - 更高的 fps 数值设置并不会起效,会以最大 fps 播放
- SD 卡尽量使用 SDSC 卡(容量 ≤2GB)或 SDHC 卡(容量 2~32GB)
- 由于使用 Thonny 的
运行当前脚本
按钮运行main.py
后,ESP32 会向 Thonny 返回当前系统变量,启动时会有短暂卡顿;使用物理 RST 按键复位并运行时则无此现象 - 请确保 I2S 模块与 ESP32 有着良好且无干扰的连接,以取得最佳的音频播放效果
-
来自 Micropython 官方库 micropython/micropython-lib 的 ssd1306 OLED 驱动 ssd1306.py
-
来自 robert-hh/SH1106 的 sh1106 OLED 驱动 sh1106.py
-
本项目的音频部分由自己在 51 单片机上的项目移植、修改而来,该 C51 项目一开始参考了此视频的思路,并进行了优化:Bilibili 代码配布地址
-
初期参考了 maysrp/badapple 仓库的绘制方式,但是逐行划线对性能有较大影响,且每帧所耗时间不同,导致部分帧卡顿,故未采用
-
将视频的每一帧进行处理的代码参考了 Lei-Tin/BinaryBadApple
-
视频抽帧代码参考了 ChatGPT 的回答
-
I2S 部分代码参考了 miketeachman/micropython-i2s-examples
-
☑️ 添加适用于 SPI 接口 OLED 的代码
-
☑️ 添加适用于 SH1106 驱动的 1.3" OLED 的代码
-
⏩ 添加适用于其他分辨率的 OLED 的代码
-
☑️ 使用 ESP32 的 I2S 播放更清晰的音频
-
⏩ 测试 PCM5102、CS4344 等 I2S 模块的支持情况
-
使用 DAC 直接播放音频
-
提供自动由 .midi 或 .ust 转为乐谱文件的方法
-
添加用于 ESP32-S3、ESP32-C3 单片机上的 MicroPython 代码
-
(远期)添加用于 STM32F412RET6(类 pyboard)、RP2040 单片机上的 MicroPython 代码
-
录制效果视频
-
☑️ 添加将视频 hex 视频文件与 wav 上传于 flash 内的无 SD 卡的测试选项
-
编写可以预览视频 hex 视频文件中视频的桌面程序