|
| 1 | +/******************************************************************************* |
| 2 | + * ESP32 SIMD Motion JPEG Image Viewer |
| 3 | + * This is a simple Motion JPEG image viewer example using ESP32 SIMD |
| 4 | + * Image Source: https://www.pexels.com/video/earth-rotating-video-856356/ |
| 5 | + * cropped: x: 598 y: 178 width: 720 height: 720 resized: 240x240 |
| 6 | + * ffmpeg -i "Pexels Videos 3931.mp4" -ss 0 -t 20.4s -vf "reverse,setpts=0.5*PTS,fps=10,vflip,hflip,rotate=90,crop=720:720:178:598,scale=240:240:flags=lanczos" -q:v 11 earth.mjpeg |
| 7 | + * |
| 8 | + * Dependent libraries: |
| 9 | + * ESP32_JPEG: https://github.com/esp-arduino-libs/ESP32_JPEG.git |
| 10 | + * |
| 11 | + * Setup steps: |
| 12 | + * 1. Change your LCD parameters in Arduino_GFX setting |
| 13 | + * 2. Upload Motion JPEG file |
| 14 | + * FFat/LittleFS: |
| 15 | + * upload FFat (FatFS) data with ESP32 Sketch Data Upload: |
| 16 | + * ESP32: https://github.com/lorol/arduino-esp32fs-plugin |
| 17 | + * SD: |
| 18 | + * Most Arduino system built-in support SD file system. |
| 19 | + ******************************************************************************/ |
| 20 | +#define ROOT "/root" |
| 21 | +#define MJPEG_FILENAME ROOT "/earth.mjpeg" |
| 22 | +#define MJPEG_OUTPUT_SIZE (240 * 240 * 2) // memory for a output image frame |
| 23 | +#define MJPEG_BUFFER_SIZE (MJPEG_OUTPUT_SIZE / 10) // memory for a single JPEG frame |
| 24 | + |
| 25 | +/******************************************************************************* |
| 26 | + * Start of Arduino_GFX setting |
| 27 | + ******************************************************************************/ |
| 28 | +#include <Arduino_GFX_Library.h> |
| 29 | + |
| 30 | +#define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin |
| 31 | + |
| 32 | +/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */ |
| 33 | +#if defined(DISPLAY_DEV_KIT) |
| 34 | +Arduino_GFX *gfx = create_default_Arduino_GFX(); |
| 35 | +#else /* !defined(DISPLAY_DEV_KIT) */ |
| 36 | + |
| 37 | +/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */ |
| 38 | +Arduino_DataBus *bus = create_default_Arduino_DataBus(); |
| 39 | + |
| 40 | +/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */ |
| 41 | +Arduino_GFX *gfx = new Arduino_ILI9341(bus, DF_GFX_RST, 3 /* rotation */, false /* IPS */); |
| 42 | + |
| 43 | +#endif /* !defined(DISPLAY_DEV_KIT) */ |
| 44 | +/******************************************************************************* |
| 45 | + * End of Arduino_GFX setting |
| 46 | + ******************************************************************************/ |
| 47 | + |
| 48 | +#include <FFat.h> |
| 49 | +#include <LittleFS.h> |
| 50 | +#include <SPIFFS.h> |
| 51 | +#include <SD.h> |
| 52 | +#include <SD_MMC.h> |
| 53 | + |
| 54 | +#include "MjpegClass.h" |
| 55 | +static MjpegClass mjpeg; |
| 56 | + |
| 57 | +/* variables */ |
| 58 | +static int total_frames = 0; |
| 59 | +static unsigned long total_read_video = 0; |
| 60 | +static unsigned long total_decode_video = 0; |
| 61 | +static unsigned long total_show_video = 0; |
| 62 | +static unsigned long start_ms, curr_ms; |
| 63 | +static int16_t x = -1, y = -1, w = -1, h = -1; |
| 64 | + |
| 65 | +void setup() |
| 66 | +{ |
| 67 | +#ifdef DEV_DEVICE_INIT |
| 68 | + DEV_DEVICE_INIT(); |
| 69 | +#endif |
| 70 | + |
| 71 | + Serial.begin(115200); |
| 72 | + // Serial.setDebugOutput(true); |
| 73 | + // while(!Serial); |
| 74 | + Serial.println("Arduino_GFX Motion JPEG ESP32P4 Decoder Image Viewer example"); |
| 75 | + |
| 76 | + // Init Display |
| 77 | + if (!gfx->begin()) |
| 78 | + { |
| 79 | + Serial.println("gfx->begin() failed!"); |
| 80 | + } |
| 81 | + gfx->fillScreen(RGB565_BLACK); |
| 82 | + |
| 83 | +#ifdef GFX_BL |
| 84 | + pinMode(GFX_BL, OUTPUT); |
| 85 | + digitalWrite(GFX_BL, HIGH); |
| 86 | +#endif |
| 87 | + |
| 88 | + // if (!FFat.begin(false, ROOT)) |
| 89 | + if (!LittleFS.begin(false, ROOT)) |
| 90 | + // if (!SPIFFS.begin(false, ROOT)) |
| 91 | + // SPI.begin(12 /* CLK */, 13 /* D0/MISO */, 11 /* CMD/MOSI */); |
| 92 | + // if (!SD.begin(10 /* CS */, SPI, 80000000L, ROOT)) |
| 93 | + // pinMode(10 /* CS */, OUTPUT); |
| 94 | + // digitalWrite(SD_CS, HIGH); |
| 95 | + // SD_MMC.setPins(12 /* CLK */, 11 /* CMD/MOSI */, 13 /* D0/MISO */); |
| 96 | + // if (!SD_MMC.begin(ROOT, true /* mode1bit */, false /* format_if_mount_failed */, SDMMC_FREQ_DEFAULT)) |
| 97 | + // SD_MMC.setPins(12 /* CLK */, 11 /* CMD/MOSI */, 13 /* D0/MISO */, 14 /* D1 */, 15 /* D2 */, 10 /* D3/CS */); |
| 98 | + // if (!SD_MMC.begin(ROOT, false /* mode1bit */, false /* format_if_mount_failed */, SDMMC_FREQ_HIGHSPEED)) |
| 99 | + { |
| 100 | + Serial.println(F("ERROR: File System Mount Failed!")); |
| 101 | + gfx->println(F("ERROR: File System Mount Failed!")); |
| 102 | + } |
| 103 | + else |
| 104 | + { |
| 105 | + Serial.println(F("MJPEG start")); |
| 106 | + |
| 107 | + start_ms = millis(); |
| 108 | + curr_ms = millis(); |
| 109 | + if (!mjpeg.setup(MJPEG_FILENAME)) |
| 110 | + { |
| 111 | + Serial.println(F("mjpeg.setup() failed!")); |
| 112 | + } |
| 113 | + else |
| 114 | + { |
| 115 | + while (mjpeg.readMjpegBuf()) |
| 116 | + { |
| 117 | + // Read video |
| 118 | + total_read_video += millis() - curr_ms; |
| 119 | + curr_ms = millis(); |
| 120 | + |
| 121 | + // Play video |
| 122 | + mjpeg.decodeJpg(); |
| 123 | + total_decode_video += millis() - curr_ms; |
| 124 | + curr_ms = millis(); |
| 125 | + |
| 126 | + if (x == -1) |
| 127 | + { |
| 128 | + w = mjpeg.getWidth(); |
| 129 | + h = mjpeg.getHeight(); |
| 130 | + x = (w > gfx->width()) ? 0 : ((gfx->width() - w) / 2); |
| 131 | + y = (h > gfx->height()) ? 0 : ((gfx->height() - h) / 2); |
| 132 | + } |
| 133 | + gfx->draw16bitRGBBitmap(x, y, mjpeg.getOutBuf(), w, h); |
| 134 | + total_show_video += millis() - curr_ms; |
| 135 | + |
| 136 | + curr_ms = millis(); |
| 137 | + total_frames++; |
| 138 | + } |
| 139 | + int time_used = millis() - start_ms; |
| 140 | + Serial.println(F("MJPEG end")); |
| 141 | + |
| 142 | + float fps = 1000.0 * total_frames / time_used; |
| 143 | + Serial.printf("Arduino_GFX ESP32 SIMD MJPEG decoder\n\n"); |
| 144 | + Serial.printf("Frame size: %d x %d\n", mjpeg.getWidth(), mjpeg.getHeight()); |
| 145 | + Serial.printf("Total frames: %d\n", total_frames); |
| 146 | + Serial.printf("Time used: %d ms\n", time_used); |
| 147 | + Serial.printf("Average FPS: %0.1f\n", fps); |
| 148 | + Serial.printf("Read MJPEG: %lu ms (%0.1f %%)\n", total_read_video, 100.0 * total_read_video / time_used); |
| 149 | + Serial.printf("Decode video: %lu ms (%0.1f %%)\n", total_decode_video, 100.0 * total_decode_video / time_used); |
| 150 | + Serial.printf("Show video: %lu ms (%0.1f %%)\n", total_show_video, 100.0 * total_show_video / time_used); |
| 151 | + |
| 152 | + gfx->setCursor(0, 0); |
| 153 | + gfx->printf("Arduino_GFX ESP32 SIMD MJPEG decoder\n\n"); |
| 154 | + gfx->printf("Frame size: %d x %d\n", mjpeg.getWidth(), mjpeg.getHeight()); |
| 155 | + gfx->printf("Total frames: %d\n", total_frames); |
| 156 | + gfx->printf("Time used: %d ms\n", time_used); |
| 157 | + gfx->printf("Average FPS: %0.1f\n", fps); |
| 158 | + gfx->printf("Read MJPEG: %lu ms (%0.1f %%)\n", total_read_video, 100.0 * total_read_video / time_used); |
| 159 | + gfx->printf("Decode video: %lu ms (%0.1f %%)\n", total_decode_video, 100.0 * total_decode_video / time_used); |
| 160 | + gfx->printf("Show video: %lu ms (%0.1f %%)\n", total_show_video, 100.0 * total_show_video / time_used); |
| 161 | + |
| 162 | + mjpeg.close(); |
| 163 | + } |
| 164 | + } |
| 165 | +} |
| 166 | + |
| 167 | +void loop() |
| 168 | +{ |
| 169 | +} |
0 commit comments