开始前适用开发板:ESP32-S3 Korvo · 开发框架:ESP-IDF
适用开发板:Korvo S3 · 工程
04.advanced.avi_player· targetesp32s3
屏幕:SPI ST7789 240×280 · 解码:JPEG 软解
学习时长:约 25 分钟 · 难度:★★★☆☆
学习目标
完成本节后,你将能够:
- 理解 AVI 容器格式的基本结构(视频轨 + 音频轨)
- 掌握 MJPEG 编码原理与 JPEG 逐帧解码流程
- 学会使用 ffmpeg 制作适合嵌入式播放的 AVI 视频
- 了解 Korvo 与 P4C5 在视频播放能力上的差异
1. 这个例子在干嘛
从存储(SD 卡或 SPIFFS)读取 AVI 格式视频文件,逐帧解码并在 SPI LCD 上连续播放。如果 AVI 中包含音频轨(PCM),还会通过 ES8311 同步播放声音。
简单来说:用 ESP32-S3 播放视频。
数据流:
┌─────────┐ ┌───────────┐ ┌────────────┐ ┌──────────┐
│ SD/SPIFFS│───→│ AVI 解析器 │───→│ MJPEG 帧 │───→│ JPEG 解码│
│ 读文件 │ │ 分离音视频 │ │ 逐帧取出 │ │ → RGB565 │
└─────────┘ └─────┬─────┘ └────────────┘ └────┬─────┘
│ │
│ PCM 音频轨 │ 刷屏
▼ ▼
┌──────────┐ ┌──────────┐
│ ES8311 │ │ SPI LCD │
│ I2S 播放 │ │ 240×280 │
└──────────┘ └──────────┘
与 P4C5 版的关键区别:P4 有 JPEG 硬件解码器 + PPA 缩放,可以播放 480×800 高分辨率视频;Korvo 只能软解,分辨率和帧率远低于 P4。但 AVI 容器解析逻辑完全一致。P4 版见 P4C5 AVI。
2. AVI 格式速览
AVI(Audio Video Interleave)是微软定义的一种音视频容器格式:
AVI 文件
├── 头信息:宽高、帧率、编码格式
├── 数据块(交错排列):
│ ├── 视频帧 1 (JPEG 压缩)
│ ├── 音频块 1 (PCM 原始数据)
│ ├── 视频帧 2 (JPEG 压缩)
│ ├── 音频块 2 (PCM 原始数据)
│ └── ...
└── 索引表
为什么用 MJPEG? 因为 MJPEG 的每一帧就是一张独立的 JPEG 图片,解码简单(不需要参考前后帧),非常适合嵌入式。
3. 视频文件准备
3.1 ffmpeg 转码命令
ffmpeg -i input.mp4 \
-vcodec mjpeg -vf scale=240:280 -r 10 -q:v 20 \
-acodec pcm_s16le -ar 16000 \
output.avi
参数说明:
| 参数 | 含义 | Korvo 推荐值 |
|---|---|---|
-vcodec mjpeg | 视频编码为 MJPEG | 必须 |
-vf scale=240:280 | 分辨率缩放到屏幕大小 | 匹配 ST7789 |
-r 10 | 帧率 | 10~15 fps(SPI 带宽限制) |
-q:v 20 | JPEG 质量(越小越好,文件越大) | 15~25 |
-acodec pcm_s16le | 音频编码为 16 位 PCM | ES8311 所需 |
-ar 16000 | 音频采样率 | 16000 Hz |
3.2 放置位置
将 output.avi 放入工程要求的目录:
- SD 卡:复制到 TF 卡根目录
- SPIFFS:放入
spiffs_image/(注意分区空间限制)
具体以 app_main.c 中的挂载路径为准。
4. 编译烧录
cd Korvo_Firmware\04.advanced.avi_player
idf.py set-target esp32s3
idf.py build flash monitor
接扬声器可听 AVI 内音频(若工程启用 ES8311 路径)。
5. 运行现象
| 阶段 | 屏幕表现 | 串口 | 声音 |
|---|---|---|---|
| 启动 | 初始化画面 | 存储挂载日志 | 静音 |
| 播放中 | 连续视频画面 | 帧率/解码信息 | 有声(若含 PCM) |
| 播放完毕 | 停在最后一帧或循环 | 文件结束 log | — |
6. 关键文件与代码解析
| 文件 | 作用 | 重点关注 |
|---|---|---|
main/app_main.c | 存储挂载、播放控制 | 文件路径、循环逻辑 |
main/app_jpeg_dec.c | JPEG 软解码 | 解码 → RGB565 → 刷屏 |
components/avi_player/ | AVI 容器解析 | 帧分离、音视频同步 |
核心播放流程
app_main
├── 挂载存储(SD 或 SPIFFS)
├── 打开 AVI 文件
├── 解析 AVI 头(宽高、帧率、编码)
│
└── while (有数据) {
AVI 解析器取出下一块数据:
├── 视频帧 → JPEG 软解码 → RGB565 → SPI 刷屏
└── 音频块 → ES8311 I2S 播放
}
JPEG 软解码流程
JPEG 压缩数据 (来自 AVI 帧)
→ JPEG 解码器(软件库)
→ 输出 RGB888 或 RGB565
→ 发送到 SPI LCD 的 draw_bitmap
7. Korvo vs P4C5 性能对比
| 对比项 | Korvo S3 | P4C5 |
|---|---|---|
| 屏幕 | SPI 240×280 | MIPI 480×800 |
| JPEG 解码 | 软解(CPU 计算) | 硬件解码器(专用硬件) |
| 缩放 | 无(需 ffmpeg 预缩放) | PPA 硬件缩放 |
| 实际帧率 | 10~15 fps | 25~30 fps |
| 分辨率上限 | 240×280(受 SPI 限制) | 480×800 |
| 刷屏方式 | SPI DMA | MIPI DSI(可 bypass LVGL) |
工程不可互烧——target 和屏幕完全不同。转码时分辨率需按各自屏幕调整 scale。
8. 常见问题与排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无画面 | AVI 不是 MJPEG 编码 | 用 ffprobe output.avi 确认 vcodec |
| 无画面 | 文件路径不对 | 检查 SD 卡/SPIFFS 挂载路径 |
| 画面卡顿 | 分辨率/帧率太高 | 降低 ffmpeg 的 scale 和 -r |
| 画面卡顿 | SPI 时钟低 | 提高 LCD_SPI_CLK_HZ |
| 有画面无声音 | AVI 中无 PCM 音频轨 | 转码时加 -acodec pcm_s16le |
| 有画面无声音 | ES8311 未初始化 | 检查 codec 初始化日志 |
| 色彩异常 | RGB565 字节序 | 检查解码输出格式是否与 LCD 一致 |
| SD 卡挂载失败 | 卡未格式化为 FAT32 | 格式化为 FAT32;检查 SPI/SDMMC 接线 |
9. 动手改造建议
- 视频列表:SD 卡放多个 AVI,自动扫描并循环播放
- 播放控制:触摸屏点击暂停/继续
- 帧率显示:统计并在串口打印实际 FPS
- 录制功能:参考同仓库
04.advanced.avi_recorder,用摄像头录制 AVI - 多文件播放器:结合 MP3 播放器 UI,做一个统一的多媒体播放器
10. 知识延伸
- MJPEG vs H.264:H.264 压缩比更高但解码需要大量计算和内存(参考帧),ESP32-S3 无法实时软解 H.264
- 音视频同步:AVI 中音频和视频数据交错排列,按顺序取出即可大致同步;精确同步需要时间戳对齐
- DMA 传输:SPI 刷屏时使用 DMA,CPU 不需要等待数据传输完成,可以同时解码下一帧
11. 下一步
| 方向 | 推荐例程 | 说明 |
|---|---|---|
| AVI 多文件播放 | 04.advanced.avi_multi_player | 连续播放多个视频 |
| AVI 录制 | 04.advanced.avi_recorder | 摄像头录制 AVI |
| MP3 播放器 | MP3 | 纯音频播放 |
| 通用 AVI 教程 | AVI 播放教程 | 深入原理 |
酷世DIY · Kevincoooool