Play AVI With ESP32

by 陳亮 in Circuits > Arduino

4471 Views, 34 Favorites, 0 Comments

Play AVI With ESP32

IMG_0883.jpg
T-Deck loop playing all AVI videos in folder
iBubly playing AVI
T-Display S3 Pro playing AVI

This instructables show how to play AVI video file with ESP32 and Arduino IDE.

Supplies

Any ESP32 dev device with display and I2S audio output should be ok. Dev devices that with SD/MicroSD card slot are preferred.

This instructables mainly test and develop with Lilygo T-Deck:

https://www.lilygo.cc/products/t-deck

And also further tested with some decent dev devices:

  1. https://www.aliexpress.com/item/1005006729377800.html
  2. https://www.aliexpress.com/item/1005007566332450.html
  3. https://www.aliexpress.com/item/1005007338742875.html

Note:

Since the arduino-esp32 upgrade from v2.x to v3.x has a big change of the interfaces supported. I highly recommend using SPI/QSPI display only during this period.

What Is AVI?

Audio Video Interleave (AVI) is a proprietary multimedia container format and Windows standard introduced by Microsoft in November 1992 as part of its Video for Windows software. AVI files can contain both audio and video data in a file container that allows synchronous audio-with-video playback.

AVI is a common video file format in last century. It is designed for playing video with the computer in that time. The disk reading speed and CPU processing power are very limited, the software engineer at that time use various techniques to optimize the reading, decoding and playing process.

Thanks to this thoughtful design, now we can use a ESP32 dev device to play AVI files.

Ref.:

https://en.wikipedia.org/wiki/Audio_Video_Interleave

Simple AVI Player Design

AVI Player flow chart.png

Above flow chart illustrate a simple AVI Player design. First read file list from a file system folder, loop each item in file list. If it is an AVI file, open, read, decode and play it.

  1. The file system can be SD card or built-in flash LittleFS or FATFS, most AVI video size requires SD card
  2. Decode MP3 audio also a CPU intensive task, so it is better offload to another EPS32 core

Codec

AVI file is a container, it can contains video and audio data encoded in various codec.

Decoding video and audio is always a CPU intensive task, ESP32 is not powerful enough to decode most recent codec e.g. H.264, H.265.

This project concentrate on the codecs developed for last century computer only, i.e. Cinepak and Motion JPEG(MJPEG) video codec; PCM and MP3 audio codec.

Ref.:

https://en.wikipedia.org/wiki/Codec

https://en.wikipedia.org/wiki/Cinepak

https://en.wikipedia.org/wiki/Motion_JPEG

https://en.wikipedia.org/wiki/Pulse-code_modulation

https://en.wikipedia.org/wiki/MP3

Arduino Libraries

AVI file data reading

"avilib" library is part of transcode, a linux video stream processing tool. And Github user lanyou1900 put it on Github. This project use avilib for reading avi file data:

https://github.com/lanyou1900/avilib.git

Cinepak Codec Decoder

ScummVM ported Cinepak decoder for decoding video in retro game. Now I further ported the decoder to Arduino, so we can decode Cinepak codec in Aduino.

MJPEG Codec Decoder

MJPEG is simply a sequence of JPEG image, so we can use normal JPEG decoder like JPEGDEC or ESP32_JPEG for decoding:

https://github.com/bitbank2/JPEGDEC.git

https://github.com/esp-arduino-libs/ESP32_JPEG.git

PCM Codec Decoder

Pulse-code modulation (PCM) is a method used to digitally represent analog signals.

PCM also the format feeding audio data to I2S audio module, so actually no further decoder is required. But it still requires some bit size conversion, audio gain manipulation and audio channel data duplication.

https://en.wikipedia.org/wiki/Pulse-code_modulation

https://en.wikipedia.org/wiki/I²S

MP3 Codec Decoder

Github user pschatzmann ported Helix MP3 decoder from RealNetworks as a simple Arduino Library. This decoder also can decode the MP3 audio stream in AVI file:

https://github.com/pschatzmann/arduino-libhelix.git

Cinepak Vs Motion JPEG

T-Deck playing MP3+Cinepak@30fps
T-Deck playing MP3+MJPEG@30fps
JC4827W543 playing MP3+Cinepak@30fps

Cinepak developed for early computer, so it requires relative low CPU power for decoding. But it tradeoff the encoding time, it is much higher than all the other codec. Moreover, the color space is also limited, so it only suitable for simple color anime video.

Motion JPEG(MJPEG) is simply a sequence of JPEG images, so the quality can be as good as JPEG image and capable decoded by ESP32. Since each frame is independent, no further compress between frames, so the size is relatively larger compare with other advanced video codec.

ESP32-S3 is able to decode:

  1. 320x240@30fps MJPEG video
  2. 480x272@15fps MJPEG video
  3. 480x272@30fps Cinepak video

You can test and select the suitable codec for you. T-Deck MP3+Cinepak:

Played avi_frames: 425
Skipped avi_frames: 26 (5.8 %)
Time used: 15034 ms
Expected FPS: 30.0
Actual FPS: 28.3
Read video: 2740 ms (18.2 %)
Decode video: 1398 ms (9.3 %)
Show video: 9352 ms (62.2 %)
Read audio: 655 ms (4.4 %)
Decode audio: 3172 ms (21.1 %)
Play audio: 9385 ms (62.4 %)

T-Deck MP3+MJPEG:

Played avi_frames: 334
Skipped avi_frames: 117 (25.9 %)
Time used: 15066 ms
Expected FPS: 30.0
Actual FPS: 22.2
Read video: 2161 ms (14.3 %)
Decode video: 4959 ms (32.9 %)
Show video: 7339 ms (48.7 %)
Read audio: 601 ms (4.0 %)
Decode audio: 3238 ms (21.5 %)
Play audio: 9134 ms (60.6 %)

JC4827W543 MP3+Cinepak:

Played avi_frames: 385
Skipped avi_frames: 66 (14.6 %)
Time used: 15042 ms
Expected FPS: 30.0
Actual FPS: 25.6
Read video: 1985 ms (13.2 %)
Decode video: 1893 ms (12.6 %)
Show video: 10651 ms (70.8 %)
Read audio: 389 ms (2.6 %)
Decode audio: 3354 ms (22.3 %)
Play audio: 9551 ms (63.5 %)

Note: Since read data from SD and feed audio may not well distributed in time, some frame skip is expected. The skipped frame should not notable in most case.

PCM Vs MP3

T-Deck playing PCM+Cinepak@30fps

T-Deck PCM+Cinepak:

Played avi_frames: 424
Skipped avi_frames: 26 (5.8 %)
Time used: 15001 ms
Expected FPS: 30.0
Actual FPS: 28.3
Read video: 2812 ms (18.7 %)
Decode video: 1204 ms (8.0 %)
Show video: 9146 ms (61.0 %)
Read audio: 1079 ms (7.2 %)
Decode audio: 0 ms (0.0 %)
Play audio: 10147 ms (67.6 %)

PCM audio format eliminated the decode time and should improve the frame rate. However, since we had offloaded the MP3 decode to another core so it did not have positive effect in ESP32-S3. PCM should help improve the frame rate for the single core device, e.g. ESP32-C3.

Software Preparation

Arduino IDE

Download and install Arduino IDE latest 1.x version if not yet:

https://www.arduino.cc/en/software

Arduino-ESP32

Follow installation step to add Arduino-ESP32 support if not yet:

https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html

Arduino_GFX Library

Open Arduino IDE Library Manager by selecting "Tools" menu -> "Manager Libraries...". Search "GFX for various displays" and press "install" button.

You may refer my previous instructables for more information about Arduino_GFX.

avilib

Download and import the avilib library to Arduino IDE:

https://github.com/lanyou1900/avilib.git

JPEGDEC

Open Arduino IDE Library Manager by selecting "Tools" menu -> "Manager Libraries...". Search "JPEGDEC" and press "install" button.

ESP32_JPEG

Download and import the ESP32_JPEG library to Arduino IDE:

https://github.com/esp-arduino-libs/ESP32_JPEG.git

arduino-libhelix

Download and import the arduino-libhelix library to Arduino IDE:

https://github.com/pschatzmann/arduino-libhelix.git


Note:

You may refer to Arduino Documentation for the details on how to import library to Arduino IDE.

Convert to AVI Format

We can use ffmpeg convert most video file to AVI format.

Convert to 320x240 dimension 30 FPS video with PCM audio and Cinepak video codec:

ffmpeg -i input.mp4 -ac 1 -c:a pcm_u8 -c:v cinepak -q:v 10 -vf "fps=30,scale=-1:240:flags=lanczos,crop=320:240:(in_w-320)/2:0" AviPcmu8Cinepak240p30fps.avi


Convert to 320x240 dimension 15 FPS video with MP3 audio and Motion JPEG video codec:

ffmpeg -i input.mp4 -c:a mp3 -c:v mjpeg -q:v 7 -vf "fps=15,scale=-1:240:flags=lanczos,crop=320:240:(in_w-320)/2:0" AviMp3Mjpeg240p15fps.avi


Then copy all converted AVI files to the SD card defined avi_folder.

Upload Program

  1. Please download the source code at Github: https://github.com/moononournation/aviPlayer.git
  2. Open AviPlayer/AviPlayer.ino in Arduino IDE
  3. The default pins settings is for T-Deck, you may comment out the code `#include "T_Deck.h"` and use your own
  4. Then compile and upload the program

Enjoy!

JC3636W518 playing MP3+MJPEG@30fps
JC4827W543 loop playing all AVI videos in folder

It's time to show off this fancy device on your desk!

Advanced Usage

JC3248W535 playing Olympics 2024 Youtube Shorts

Let's say during Olympics 2024, you may want to loop the related Youtube Shorts on your desk. You can prepare the video with:

yt-dlp --cookies-from-browser chrome --match-filters "like_count>?10000 & original_url*=/shorts/" --download-archive shorts.txt -o "shorts/%(title)s.%(ext)s" "https://www.youtube.com/results?search_query=olympics2024+shorts"

Or if you are a cat lover:

yt-dlp --cookies-from-browser chrome --match-filters "like_count>?1000000 & original_url*=/shorts/" --download-archive shorts.txt -o "shorts/%(title)s.%(ext)s" "https://www.youtube.com/results?search_query=catlover+shorts"

Then convert the video to AVI format:

find *.webm -exec sh -c 'ffmpeg -y -i "$1" -c:a mp3 -c:v mjpeg -q:v 7 -vf "fps=15,scale=320:-1:flags=lanczos,crop=320:480:0:(in_h-480)/2" "../output/${1%.*}.avi"' sh {} \;

And then copy the AVI files to the Micro SD card and play it.

Note:

Arduino file system do not recognize the file with emoji characters, so please rename the file before copy to the Micro SD card.