GIGA Display Shield - Display Jpegs from USB or SD, play Mjpeg Video from SD

Been working on this off and on for a while. KurtE posted some code that was a big help on getting this to work. It stores decoded jpeg to SDRAM GFX Canvas, then writes to screen. Configured Mjpeg to use a large SDRAM buffer which seemed to help considerably.

Haven't been able to play Mjpegs from USB yet, code fails because of incompatibility between USB Mbed5 file class and Stream class. Maybe someone can help out with this.

Edit: I solved this problem today, see post #2.

Download Zip, it has all the code and media.

Giga_Display_SDFat_USB_SDRAMGFXCanvas.zip (7.6 MB)

You can touch screen to toggle SD - USB devices.
Here's the main .ino

#include <Arduino_GigaDisplay_GFX.h>
#include <Arduino_USBHostMbed5.h>
#include <DigitalOut.h>
#include <FATFileSystem.h>
#include <SdFat.h>
#include "Arduino_GigaDisplayTouch.h"
#include <elapsedMillis.h>
#include "WrapperFile.h"
#include "SDRAMGFXcanvas.h"
#include "JPEGDEC.h"
#include "MjpegClass.h"
static MjpegClass mjpeg;

REDIRECT_STDOUT_TO(Serial)

GigaDisplay_GFX tft;
Adafruit_GFX *pgfx = &tft;
SDRAMGFXcanvas16 canvas(800, 480); // Allocate canvas in SDRAM

#define sd_chipSelect 53 // Card select for shield use
#define ENABLE_DEDICATED_SPI 1

#define SD_FAT_TYPE 3                   
//SdFat SD; File file; File dirFile;              //SD_FAT_TYPE 0 
//SdFat32 SD; File32 file;                        //SD_FAT_TYPE 1
//SdExFat SD; ExFile file; ExFile dirFile;        //SD_FAT_TYPE 2 
SdFs SD; FsFile file; FsFile dirFile;             //SD_FAT_TYPE 3 

USBHostMSD msd;
mbed::FATFileSystem usb("usb"); 
DIR *root_USB = nullptr;

#define USB_DRIVE 0x01
#define SD_DRIVE 0x04
uint8_t g_current_device = 0;
int g_display_image_time = 2000;
int g_tft_width = 0;
int g_tft_height = 0;

JPEGDEC jpeg;

Arduino_GigaDisplayTouch touchDetector;
bool changedDevice = false;
void gigaTouchHandler(uint8_t contacts, GDTpoint_t* points) {
  //Serial.print("Contacts: ");  Serial.println(contacts);
  if (contacts > 0) {
    //Serial.print(points[0].x); Serial.print(" "); Serial.println(points[0].y);
    if (g_current_device == SD_DRIVE) {
      g_current_device = USB_DRIVE;
      Serial.print("Switched to USB_DRIVE: ");
    }
    else {  
      g_current_device = SD_DRIVE;
      Serial.print("Switched to SD_DRIVE: ");
    }
   Serial.println(g_current_device, HEX);
   changedDevice = true;
   delay(200); 
  }
 else changedDevice = false;
}


void setup() {

  Serial.begin(115200);

  SDRAM.begin(); 

  tft.begin();          // start the display
  tft.setRotation(1);   // set up text to display horizonal in the display
  tft.fillScreen(0);

  if (touchDetector.begin()) {
    Serial.println("Touch controller init - OK");
  } else {
    Serial.println("Touch controller init - FAILED");
    while(1) ;
  }
  touchDetector.onDetect(gigaTouchHandler);
 
  Serial.print("Initializing SD card...");
  //if (!SD.begin()) {
  if (!SD.begin(sd_chipSelect, SD_SCK_MHZ(160))) {
  Serial.println("initialization failed!");
  tft.setCursor(10,  tft.height()-180);
  tft.print(" SD INIT. FAILED...");
  delay(2000);
  }
  else Serial.println("initialization done.");

  while (!msd.connect()) {
        //while (!port.connected()) {
        delay(100);
  }
  Serial.print("Mounting USB device... ");
  int err = usb.mount(&msd);
  if (err) {
    Serial.print("Error mounting USB device ");
    Serial.println(err);
    //while (1);
  }

  canvas.begin();
  Serial.print("Canvas buffer: ");
  Serial.println((uint32_t)canvas.getBuffer(), HEX);
  pgfx = &canvas;
  g_tft_width = tft.width();
  g_tft_height = tft.height();

  //g_current_device = USB_DRIVE;
  g_current_device = SD_DRIVE;
  Serial.println("Current Device: SD_DRIVE");
  Serial.println("Touch screen to toggle SD USB devices...");

} 


void loop() {

tft.fillScreen(0); 
tft.setRotation(1);

int x = tft.width ()/2 - 320/2; // Center mjpeg width
int y = tft.height()/2 - 320/2; // Center mjpeg height
drawMjpeg("/Mjpeg/Drone.mjpeg", x, y); //This mjpeg is 320x320

for (int i = 0; i < 5; i++) {
drawJpeg("TheyLive1.jpg", 0, 0);
drawJpeg("TheyLive2.jpg", 0, 0);
}

fetchDirFiles("/Jpg800x480L", 0, 0, 0, 0); 
}


void drawJpeg(char* jpegName, int x, int y) {
  elapsedMillis em;
  char fullPath[512];
  File jpegFile;
  FILE* jFile;
  WrapperFile wpfImage;

  if(changedDevice){changedDevice=0;return;}

  if (g_current_device == SD_DRIVE) {
    strcpy(fullPath, "/");
    strcat(fullPath, jpegName); 
    jpegFile = SD.open(fullPath, FILE_READ);
    wpfImage.setFile(jpegFile);
  }

  if (g_current_device == USB_DRIVE)  {
    strcpy(fullPath, "/usb/");
    strcat(fullPath, jpegName); 
    jFile = fopen(fullPath, "rb");
    if (!jFile) Serial.println("USB file not found!");
    wpfImage.setFile(jFile);
   }

  Serial.println(" "); Serial.println(fullPath);
  processJPGFile(wpfImage, fullPath, true); 
  tft.drawRGBBitmap(0, 0, canvas.getBuffer(), tft.width(), tft.height());
  Serial.print("Draw Time: "); Serial.println(em, DEC); Serial.print(" ");
  if (g_current_device == SD_DRIVE) file.close();
  if (g_current_device == USB_DRIVE) fclose(jFile);
}


void fetchDirFiles(char *dirName, int x, int y, int w, int h) {
  int fCount = 1; 
  char filename[256];
  char fullPath[512];
  char   dirUSB[512];
  WrapperFile wpfImage;
  FsFile imageFile;
  FILE *jFile;
  DIR* d;
  struct dirent *dir_entry;
  bool dirEnd = false;

  if (g_current_device == SD_DRIVE) { 
     if (!dirFile.open(dirName, O_READ)) {  
        SD.errorHalt("Open directory failed");
    }
  }

  if (g_current_device == USB_DRIVE) {  
     strcpy(dirUSB, "/usb");
     strcat(dirUSB, dirName); 
     //Serial.println(dirUSB);
     d = opendir(dirUSB);
  }

 while (!dirEnd) {
    elapsedMillis drawTime;

   if(changedDevice){changedDevice=0;return;}

   if (g_current_device == SD_DRIVE) { 
      imageFile = dirFile.openNextFile();
      if (!imageFile.isSubDir()) { 
        if (!imageFile) {dirEnd = true; break;}
        sprintf(fullPath, "%s/", dirName);
        imageFile.getName(filename, sizeof(filename));
        strcat( fullPath, filename );
        wpfImage.setFile(imageFile);
        file.close();
      }   
    }

    if (g_current_device == USB_DRIVE) {  
        dir_entry = readdir(d);
        if (!dir_entry) dirEnd = true;
        strcpy(fullPath, dirUSB);
        strcat(fullPath, "/");
        strcat(fullPath, dir_entry->d_name);
        jFile = fopen(fullPath, "r+");
        wpfImage.setFile(jFile);
    }

      String strname = String(fullPath); 
      Serial.print("Image Filepath: "); Serial.println(fullPath);
      
      if (strname.endsWith(".raw")) {
         //drawRAW (fullPath, x, y, w, h);
        }

      if (strname.endsWith(".bin")) {
         //drawRAW (fullPath, x, y, w, h);
        }   

      if (strname.endsWith(".jpg")) {
         processJPGFile(wpfImage, fullPath, true);
         //drawJpeg(wpfImage, fullPath);
        }
   
    fCount++;
    tft.drawRGBBitmap(0, 0, canvas.getBuffer(), tft.width(), tft.height());
    Serial.print("Draw Time: "); Serial.println(drawTime, DEC);
    if (g_current_device == SD_DRIVE) file.close();
    if (g_current_device == USB_DRIVE) fclose(jFile);
  }
  Serial.println("End of Directory");
  Serial.println(" ");
}  


.

This one is a sketch that only needs the USB port on the Giga R1. Had to make changes to Mjpeg.Class.h to use USB Mbed5 file functions, and trimmed out all the SD calls in the other tabbed files.

320x320 Mjpeg plays @ 10.80 fps, almost 2x as fast as reading from SD card. I can disconnect my SD module now.

Some of the tabbed files changed, so make sure to use the ones in this zip file. The media files are in the zip at my first post above. Add the required libraries from IDE.

Giga_USB_JPG_MJPEG_SDRAM.zip (8.5 KB)

Here's the main .ino:

#include <Arduino_GigaDisplay_GFX.h>
#include <Arduino_USBHostMbed5.h>
#include <DigitalOut.h>
#include <FATFileSystem.h>
//#include "Arduino_GigaDisplayTouch.h"
#include <elapsedMillis.h>
#include "WrapperFile.h"
#include "SDRAMGFXcanvas.h"
#include "JPEGDEC.h"
#include "MjpegClass.h"
static MjpegClass mjpeg;

REDIRECT_STDOUT_TO(Serial)

GigaDisplay_GFX tft;
Adafruit_GFX *pgfx = &tft;
SDRAMGFXcanvas16 canvas(800, 480); // Allocate canvas in SDRAM

USBHostMSD msd;
mbed::FATFileSystem usb("usb"); 
DIR *root_USB = nullptr;

int g_tft_width = 0;
int g_tft_height = 0;

JPEGDEC jpeg;


void setup() {

  Serial.begin(115200);

  SDRAM.begin(); 

  tft.begin();          // start the display
  tft.setRotation(1);   // set up text to display horizonal in the display
  tft.fillScreen(0);
  
  while (!msd.connect()) {
     //while (!port.connected()) {
     delay(100);
  }
  Serial.print("Mounting USB device... ");
  int err = usb.mount(&msd);
  if (err) {
    Serial.print("Error mounting USB device ");
    Serial.println(err);
    //while (1);
  }

  canvas.begin();
  Serial.print("Canvas buffer: ");
  Serial.println((uint32_t)canvas.getBuffer(), HEX);
  pgfx = &canvas;
  g_tft_width = tft.width();
  g_tft_height = tft.height();
} 


void loop() {
int x, y;
tft.setRotation(1);

for (int i = 0; i <3; i++) {
drawJpeg("TheyLive1.jpg", 0, 0);
drawJpeg("TheyLive2.jpg", 0, 0);
}

x = tft.width ()/2 - 320/2; // Center mjpeg width
y = tft.height()/2 - 320/2; // Center mjpeg height
drawMjpeg("/Mjpeg/Drone.mjpeg", x, y);

fetchDirFiles("/Jpg800x480L", 0, 0, 0, 0); 

}


void drawJpeg(char* jpegName, int x, int y) {
  elapsedMillis em;
  char fullPath[512];
  //File jpegFile;
  FILE* jFile;
  WrapperFile wpfImage;

  strcpy(fullPath, "/usb/");
  strcat(fullPath, jpegName); 
  jFile = fopen(fullPath, "rb");
  if (!jFile) Serial.println("USB file not found!");
  wpfImage.setFile(jFile);

  Serial.println(" "); Serial.println(fullPath);
  processJPGFile(wpfImage, fullPath, true); 
  tft.drawRGBBitmap(0, 0, canvas.getBuffer(), tft.width(), tft.height());
  Serial.print("Draw Time: "); Serial.println(em, DEC); Serial.print(" ");
  fclose(jFile);
}


void fetchDirFiles(char *dirName, int x, int y, int w, int h) {
  int fCount = 1; 
//  char filename[256];
  char fullPath[512];
  char   dirUSB[512];
  WrapperFile wpfImage;
  FILE *jFile;
  DIR* d;
  struct dirent *dir_entry;
  bool dirEnd = false;

  strcpy(dirUSB, "/usb");
  strcat(dirUSB, dirName); 
  Serial.println(dirUSB);
  d = opendir(dirUSB);

 while (!dirEnd) {
    elapsedMillis drawTime;
    dir_entry = readdir(d);
    if (!dir_entry) {dirEnd = true; return;}
    strcpy(fullPath, dirUSB);
    strcat(fullPath, "/");
    strcat(fullPath, dir_entry->d_name);
    jFile = fopen(fullPath, "r+");
    wpfImage.setFile(jFile);
  
    String strname = String(fullPath); 
    Serial.print("Image Filepath: "); Serial.println(fullPath);
      
    if (strname.endsWith(".raw")) {
       //drawRAW (fullPath, x, y, w, h);
      }
    if (strname.endsWith(".bin")) {
       //drawRAW (fullPath, x, y, w, h);
      }      
    if (strname.endsWith(".rwv")) {
       //drawRawVidAutoSize (fullPath);
      }
    if (strname.endsWith(".jpg")) {
       processJPGFile(wpfImage, fullPath, true);
       //drawJpeg(wpfImage, fullPath);
      }
 
    fCount++;
    tft.drawRGBBitmap(0, 0, canvas.getBuffer(), tft.width(), tft.height());
    Serial.print("Draw Time: "); Serial.println(drawTime, DEC);
    fclose(jFile);
   }

  Serial.println("End of Directory");
  Serial.println(" ");
}  


A little extra. Media files in zip below. Add your own movie clip using FFMpeg.
ffmpeg -i input.mp4 -ss 0 -pix_fmt yuv420p -q:v 15 output.mjpeg

300Spartans.zip (2.3 MB)

Add these lines to loop() in post #2.

drawJpeg("MovieTheater.jpg", 0, 0);

x = tft.width ()/2 - 544/2;
y = tft.height()/2 - 208/2;
drawMjpeg("/Mjpeg/300-Spartans.mjpeg", x, y); // 544x208

1 Like

nice code, on my giga little bit strange color

Follow these directions, see if that helps.

The temporary fix Bitbank2 posted at git works for Giga if you change jpeg.inl (JPEGDEC lib) to

#if !defined(NO_SIMD) && (defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7))
//#define HAS_SIMD
#endif

it has solved the problem! thank you

1 Like

@JGordonJones Thank you for sharing this out! Got stalled while back trying to use LVGL.

Did NOT have to apply Bitbank2 fix mentioned in post #5.