VideoSDCard Teensy 3.2 +octows2811 flickering + format questions

Status
Not open for further replies.

eyemac2011

New member
Hi, I have teensy 3.2 w/ octows2811 and an arduino sd module (https://www.amazon.com/Storage-Memory-Shield-Module-Arduino/dp/B01IPCAP72)
I am trying to do a simple test of of the videosdcard sketch with a single 50 led strip. I tried rendering the video at different resolutions and with different codecs, but cannot seem to get it to work. I am able to generate a BIN file from Processing and successfully run the addaudio commands (though I do not need audio). Com port says "File Opened / error: unable to read 5-byte header", but the lights flicker for a bit and stop before flickering again, so it seems to be reading something. Here is my code
Code:
/*

#include <OctoWS2811.h>
#include <SPI.h>
#include <SD.h>
#include <Audio.h>
#include <Wire.h>

#define LED_WIDTH    50   // number of LEDs horizontally
#define LED_HEIGHT   8   // number of LEDs vertically (must be multiple of 8)

#define FILENAME     "VIDEO.BIN"

const int ledsPerStrip = LED_WIDTH * LED_HEIGHT / 8;
DMAMEM int displayMemory[ledsPerStrip*6];
int drawingMemory[ledsPerStrip*6];
elapsedMicros elapsedSinceLastFrame = 0;
bool playing = false;

OctoWS2811 leds(ledsPerStrip, displayMemory, drawingMemory, WS2811_800kHz);
File videofile;

AudioPlayQueue     audio;
AudioOutputAnalog  dac;
AudioConnection    patchCord1(audio, dac);


void setup() {
  AudioMemory(40);
  //while (!Serial) ;
  delay(50);
  Serial.println("VideoSDcard");
  leds.begin();
  leds.show();
  if (!SD.begin(3)) stopWithErrorMessage("Could not access SD card");
  Serial.println("SD card ok");
  videofile = SD.open(FILENAME, FILE_READ);
  if (!videofile) stopWithErrorMessage("Could not read " FILENAME);
  Serial.println("File opened");
  playing = true;
  elapsedSinceLastFrame = 0;
}

// read from the SD card, true=ok, false=unable to read
// the SD library is much faster if all reads are 512 bytes
// this function lets us easily read any size, but always
// requests data from the SD library in 512 byte blocks.
//
bool sd_card_read(void *ptr, unsigned int len)
{
  static unsigned char buffer[512];
  static unsigned int bufpos = 0;
  static unsigned int buflen = 0;
  unsigned char *dest = (unsigned char *)ptr;
  unsigned int n;

  while (len > 0) {
    if (buflen == 0) {
      n = videofile.read(buffer, 512);
      if (n == 0) return false;		
      buflen = n;
      bufpos = 0;
    }
    unsigned int n = buflen;
    if (n > len) n = len;
    memcpy(dest, buffer + bufpos, n);
    dest += n;
    bufpos += n;
    buflen -= n;
    len -= n;
  }
  return true;
}

// skip past data from the SD card
void sd_card_skip(unsigned int len)
{
  unsigned char buf[256];

  while (len > 0) {
    unsigned int n = len;
    if (n > sizeof(buf)) n = sizeof(buf);
    sd_card_read(buf, n);
    len -= n;
  }
}


void loop()
{
  unsigned char header[5];

  if (playing) {
    if (sd_card_read(header, 5)) {
      if (header[0] == '*') {
        // found an image frame
        unsigned int size = (header[1] | (header[2] << 8)) * 3;
        unsigned int usec = header[3] | (header[4] << 8);
        unsigned int readsize = size;
	// Serial.printf("v: %u %u", size, usec);
        if (readsize > sizeof(drawingMemory)) {
          readsize = sizeof(drawingMemory);
        }
        if (sd_card_read(drawingMemory, readsize)) {
           //Serial.printf(", us = %u", (unsigned int)elapsedSinceLastFrame);
          // Serial.println();
          while (elapsedSinceLastFrame < usec) ; // wait
          elapsedSinceLastFrame -= usec;
          leds.show();
        } else {
          error("unable to read video frame data");
          return;
        }
        if (readsize < size) {
          sd_card_skip(size - readsize);
        }
      } else if (header[0] == '%') {
        // found a chunk of audio data
        unsigned int size = (header[1] | (header[2] << 8)) * 2;
        // Serial.printf("a: %u", size);
	// Serial.println();
	while (size > 0) {
	  unsigned int len = size;
	  if (len > 256) len = 256;
	  int16_t *p = audio.getBuffer();
	  if (!sd_card_read(p, len)) {
	    error("unable to read audio frame data");
            return;
	  }
	  if (len < 256) {
            for (int i=len; i < 256; i++) {
              *((char *)p + i) = 0;  // fill rest of buffer with zero
            }
	  }
          audio.playBuffer();
	  size -= len;
	}
      } else {
        error("unknown header");
        return;
      }
    } else {
      error("unable to read 5-byte header");
      return;
    }
  } else {
    delay(2000);
    videofile = SD.open(FILENAME, FILE_READ);
    if (videofile) {
      Serial.println("File opened");
      playing = true;
      elapsedSinceLastFrame = 0;
    }
  }
}

// when any error happens during playback, close the file and restart
void error(const char *str)
{
  Serial.print("error: ");
  Serial.println(str);
  videofile.close();
  playing = false;
}

// when an error happens during setup, give up and print a message
// to the serial monitor.
void stopWithErrorMessage(const char *str)
{
  while (1) {
    Serial.println(str);
    delay(1000);
  }
}

All I did was change width and height. I rendered a MJPEG MOV at 50x8 and 30 fps to fit. I cant seem to get it to work. Is there a specific format the video must be? Am I going about "fitting" the video the wrong way? Is it possible to use the BIN generated by processing without adding audio? I added audio because I thought it would fix the header error, but it did not. Thanks

Here is my processing code
Code:
import processing.video.*;
import processing.serial.*;
import java.io.*;

int ledWidth =  50;          // size of LED panel
int ledHeight = 8;
boolean ledLayout = true;    // layout of rows, true = even is left->right

double framerate = 30;    // You MUST set this to the movie's frame rate
                             // Processing does not seem to have a way to detect it.

Movie myMovie = new Movie(this, "D:/Videos/myvideo.mov");
FileOutputStream myFile;     // edit output filename below...

float gamma = 1.8;
PImage ledImage;
int[] gammatable = new int[256];
long elapsed_picoseconds=0L;
long elapsed_microseconds=0L;
long picoseconds_per_frame = (long)(1e12 / framerate + 0.5);
boolean fileopen=true;

void setup() {
  for (int i=0; i < 256; i++) {
    gammatable[i] = (int)(pow((float)i / 255.0, gamma) * 255.0 + 0.5);
  }
  try {
    myFile = new FileOutputStream("D:/Videos/myvideo.bin");
  } catch (Exception e) {
    exit();
  }
  ledImage = createImage(ledWidth, ledHeight, RGB);
  size(720, 560);  // create the window
  myMovie.play();  // start the movie :-)
}
 
// movieEvent runs for each new frame of movie data
void movieEvent(Movie m) {
  // read the movie's next frame
  m.read();

  elapsed_picoseconds += picoseconds_per_frame;
  int usec = (int)((elapsed_picoseconds / 1000000L) - elapsed_microseconds);
  elapsed_microseconds += (long)usec;
  println("usec = " + usec);
  
  
  // copy the movie's image to the LED image
  ledImage.copy(m, 0, 0, m.width, m.height, 0, 0, ledWidth, ledHeight);
  // convert the LED image to raw data
  byte[] ledData =  new byte[(ledWidth * ledHeight * 3) + 5];
  image2data(ledImage, ledData, ledLayout);
  ledData[0] = '*';  // first Teensy is the frame sync master
  
  ledData[1] = (byte)(ledWidth * ledHeight);
  ledData[2] = (byte)((ledWidth * ledHeight) >> 8);
  ledData[3] = (byte)(usec);   // request the frame sync pulse
  ledData[4] = (byte)(usec >> 8); // at 75% of the frame time
  // send the raw data to the LEDs  :-)
  //ledSerial[i].write(ledData); 
  try {
    myFile.write(ledData);
  } catch (Exception e) {    
    exit();
  }
}

// image2data converts an image to OctoWS2811's raw data format.
// The number of vertical pixels in the image must be a multiple
// of 8.  The data array must be the proper size for the image.
void image2data(PImage image, byte[] data, boolean layout) {
  int offset = 5;
  int x, y, xbegin, xend, xinc, mask;
  int linesPerPin = image.height / 8;
  int pixel[] = new int[8];
  
  for (y = 0; y < linesPerPin; y++) {
    if ((y & 1) == (layout ? 0 : 1)) {
      // even numbered rows are left to right
      xbegin = 0;
      xend = image.width;
      xinc = 1;
    } else {
      // odd numbered rows are right to left
      xbegin = image.width - 1;
      xend = -1;
      xinc = -1;
    }
    for (x = xbegin; x != xend; x += xinc) {
      for (int i=0; i < 8; i++) {
        // fetch 8 pixels from the image, 1 for each pin
        pixel[i] = image.pixels[x + (y + linesPerPin * i) * image.width];
        pixel[i] = colorWiring(pixel[i]);
      }
      // convert 8 pixels to 24 bytes
      for (mask = 0x800000; mask != 0; mask >>= 1) {
        byte b = 0;
        for (int i=0; i < 8; i++) {
          if ((pixel[i] & mask) != 0) b |= (1 << i);
        }
        data[offset++] = b;
      }
    }
  } 
}

// translate the 24 bit color from RGB to the actual
// order used by the LED wiring.  GRB is the most common.
int colorWiring(int c) {
  int red = (c & 0xFF0000) >> 16;
  int green = (c & 0x00FF00) >> 8;
  int blue = (c & 0x0000FF);
  red = gammatable[red];
  green = gammatable[green];
  blue = gammatable[blue];
  return (green << 16) | (red << 8) | (blue); // GRB - most common wiring
}

// draw runs every time the screen is redrawn - show the movie...
void draw() {
  if (myMovie.time() < myMovie.duration()) {
    image(myMovie, 0, 80);
    image(ledImage, 240 - ledWidth / 2, 10);
  } else {
    if (fileopen) {
      println("movie stop, closing output file");
      try {
        myFile.close();
      } catch (Exception e) {    
        exit();
      }
      fileopen = false;
    }
  }
}

// respond to mouse clicks as pause/play
boolean isPlaying = true;
void mousePressed() {
  if (isPlaying) {
    myMovie.pause();
    isPlaying = false;
  } else {
    myMovie.play();
    isPlaying = true;
  }
}
 
Status
Not open for further replies.
Back
Top