diff --git a/player/platformio.ini b/player/platformio.ini index c3ab644..51c4afc 100644 --- a/player/platformio.ini +++ b/player/platformio.ini @@ -168,6 +168,8 @@ build_flags = -DSD_CARD_MOSI=GPIO_NUM_23 -DSD_CARD_CLK=GPIO_NUM_18 -DSD_CARD_CS=GPIO_NUM_5 + ; increase file buffer size to prevent playback stalling on SD Card read + -DFILE_BUFFER_SIZE=16384 [env:touch-down] extends = esp32_common @@ -235,6 +237,8 @@ build_flags = -DSD_CARD_MOSI=GPIO_NUM_15 -DSD_CARD_CLK=GPIO_NUM_13 -DSD_CARD_CS=GPIO_NUM_2 + ; increase file buffer size to prevent playback stalling on SD Card read + -DFILE_BUFFER_SIZE=16384 [env:m5core2] extends = esp32_common diff --git a/player/src/AVIParser/AVIParser.cpp b/player/src/AVIParser/AVIParser.cpp index 798b9dd..bec86dc 100644 --- a/player/src/AVIParser/AVIParser.cpp +++ b/player/src/AVIParser/AVIParser.cpp @@ -65,6 +65,11 @@ bool AVIParser::open() Serial.printf("Failed to open file.\n"); return false; } + #ifdef FILE_BUFFER_SIZE + // Increase size of file buffer if needed. + Serial.printf("Setting file buffer size to %d bytes.\n", FILE_BUFFER_SIZE); + setvbuf(mFile, NULL, _IOFBF, FILE_BUFFER_SIZE); + #endif // check the file is valid ChunkHeader header; // Read RIFF header @@ -129,7 +134,7 @@ bool AVIParser::open() return true; } -size_t AVIParser::getNextChunk(uint8_t **buffer, size_t &bufferLength) +size_t AVIParser::getNextChunk(uint8_t **buffer, size_t &bufferLength, bool skipRead) { // check if the file is open if (!mFile) @@ -153,14 +158,22 @@ size_t AVIParser::getNextChunk(uint8_t **buffer, size_t &bufferLength) if (mRequiredChunkType == AVIChunkType::VIDEO && isVideoChunk || mRequiredChunkType == AVIChunkType::AUDIO && isAudioChunk) { - // we've got the required chunk - copy it into the provided buffer - // reallocate the buffer if necessary - if (header.chunkSize > bufferLength) - { - *buffer = (uint8_t *)realloc(*buffer, header.chunkSize); + // we've got the required chunk + if (skipRead) + { // skip over this chunk + fseek(mFile, header.chunkSize, SEEK_CUR); + } + else + { // copy this chunk into the provided buffer + // reallocate the buffer if necessary + if (header.chunkSize > bufferLength) + { + *buffer = (uint8_t *)realloc(*buffer, header.chunkSize); + bufferLength = header.chunkSize; + } + // copy the chunk data + fread(*buffer, header.chunkSize, 1, mFile); } - // copy the chunk data - fread(*buffer, header.chunkSize, 1, mFile); mMoviListLength -= header.chunkSize; // handle any padding bytes if (header.chunkSize % 2 != 0) diff --git a/player/src/AVIParser/AVIParser.h b/player/src/AVIParser/AVIParser.h index 5aef56f..cb21c91 100644 --- a/player/src/AVIParser/AVIParser.h +++ b/player/src/AVIParser/AVIParser.h @@ -20,5 +20,5 @@ class AVIParser AVIParser(std::string fname, AVIChunkType requiredChunkType); ~AVIParser(); bool open(); - size_t getNextChunk(uint8_t **buffer, size_t &bufferLength); + size_t getNextChunk(uint8_t **buffer, size_t &bufferLength, bool skipRead=false); }; \ No newline at end of file diff --git a/player/src/VideoSource/SDCardVideoSource.cpp b/player/src/VideoSource/SDCardVideoSource.cpp index 9d8ae38..a8860b0 100644 --- a/player/src/VideoSource/SDCardVideoSource.cpp +++ b/player/src/VideoSource/SDCardVideoSource.cpp @@ -38,15 +38,25 @@ bool SDCardVideoSource::getVideoFrame(uint8_t **buffer, size_t &bufferLength, si // work out the video time from a combination of the currentAudioSample and the elapsed time int elapsedTime = millis() - mLastAudioTimeUpdateMs; int videoTime = mAudioTimeMs + elapsedTime; - int frameTime = 1000 * mFrameCount / DEFAULT_FPS; - if (videoTime <= frameTime) - { + int targetFrame = videoTime * DEFAULT_FPS / 1000; + if (mFrameCount >= targetFrame){ return false; } - while (videoTime > 1000 * mFrameCount / DEFAULT_FPS) - { + // Skip some number of frames if we have fallen behind + while (targetFrame - mFrameCount > 1){ + size_t skipped = parser->getNextChunk(buffer, bufferLength, true); + if (skipped == 0) { + // No more data or error — bail without advancing the frame counter. + return false; + } mFrameCount++; - frameLength = parser->getNextChunk((uint8_t **)buffer, bufferLength); } + // We are caught up to targetFrame-1, so load the next frame to show. + frameLength = parser->getNextChunk(buffer, bufferLength); + if (frameLength == 0){ + return false; + } + mFrameCount++; + return true; }