ESP32 Camera motion capture application to record JPEGs to SD card as AVI files and stream to browser as MJPEG. If a microphone is installed then a WAV file is also created. Files can be uploaded via FTP or downloaded to browser.
It appears that idxOffset[isTL] needs a value of 4 offset.
Now .avi plays in all windows apps including VLC player with no errors. Indexes now look like results obtained from ffmpeg.
Made a couple of changes in avi.cpp. Working for me but... over to you. :)
regards,
Alex
void prepAviIndex(bool isTL) {
// prep buffer to store index data, gets appended to end of file
if (idxBuf[isTL] == NULL) idxBuf[isTL] = (uint8_t)ps_malloc((maxFrames+1)IDX_ENTRY); // include some space for audio index
memcpy(idxBuf[isTL], idx1Buf, 4); // index header
idxPtr[isTL] = CHUNK_HDR; // leave 4 bytes for index size
moviSize[isTL] = indexLen[isTL] = 0;
idxOffset[isTL]=4; //value 4 offset
}
It appears that idxOffset[isTL] needs a value of 4 offset. Now .avi plays in all windows apps including VLC player with no errors. Indexes now look like results obtained from ffmpeg. Made a couple of changes in avi.cpp. Working for me but... over to you. :)
regards, Alex
void prepAviIndex(bool isTL) { // prep buffer to store index data, gets appended to end of file if (idxBuf[isTL] == NULL) idxBuf[isTL] = (uint8_t)ps_malloc((maxFrames+1)IDX_ENTRY); // include some space for audio index memcpy(idxBuf[isTL], idx1Buf, 4); // index header idxPtr[isTL] = CHUNK_HDR; // leave 4 bytes for index size moviSize[isTL] = indexLen[isTL] = 0; idxOffset[isTL]=4; //value 4 offset }
void buildAviHdr(uint8_t FPS, uint8_t frameType, uint16_t frameCnt, bool isTL) { // update AVI header template with file specific details size_t aviSize = moviSize[isTL] + AVI_HEADER_LEN + ((CHUNK_HDR+IDX_ENTRY) (frameCnt+(haveSoundFile?1:0))); // AVI content size // update aviHeader with relevant stats memcpy(aviHeader+4, &aviSize, 4); uint32_t usecs = (uint32_t)round(1000000.0f / FPS); // usecs_per_frame memcpy(aviHeader+0x20, &usecs, 4); memcpy(aviHeader+0x30, &frameCnt, 2); memcpy(aviHeader+0x8C, &frameCnt, 2); memcpy(aviHeader+0x84, &FPS, 1); uint32_t dataSize = moviSize[isTL] + ((frameCnt+(haveSoundFile?1:0)) CHUNK_HDR) + 4; memcpy(aviHeader+0x12E, &dataSize, 4); // data size
// apply video framesize to avi header memcpy(aviHeader+0x40, frameSizeData[frameType].frameWidth, 2); memcpy(aviHeader+0xA8, frameSizeData[frameType].frameWidth, 2); memcpy(aviHeader+0x44, frameSizeData[frameType].frameHeight, 2); memcpy(aviHeader+0xAC, frameSizeData[frameType].frameHeight, 2);
if INCLUDE_MIC
uint8_t withAudio = 2; // increase number of streams for audio if (isTL) memcpy(aviHeader+0x100, zeroBuf, 4); // no audio for timelapse else { if (haveSoundFile) memcpy(aviHeader+0x38, &withAudio, 1); memcpy(aviHeader+0x100, &audSize, 4); // audio data size } // apply audio details to avi header memcpy(aviHeader+0xF8, &SAMPLE_RATE, 4); uint32_t bytesPerSec = SAMPLE_RATE * 2; memcpy(aviHeader+0x104, &bytesPerSec, 4); // suggested buffer size memcpy(aviHeader+0x11C, &SAMPLE_RATE, 4); memcpy(aviHeader+0x120, &bytesPerSec, 4); // bytes per sec
else
memcpy(aviHeader+0x100, zeroBuf, 4);
endif
// reset state for next recording //moviSize[isTL] = idxOffset[isTL] = idxPtr[isTL] = 0;
moviSize[isTL] = idxPtr[isTL]=0; idxOffset[isTL]=4; //value 4 offset }