diff --git a/data/formats/avi/Demuxer.h b/data/formats/avi/Demuxer.h index 673f7fd..79ddd63 100644 --- a/data/formats/avi/Demuxer.h +++ b/data/formats/avi/Demuxer.h @@ -1,7 +1,7 @@ #pragma once #include "structs.h" -#include +//#include // https://docs.microsoft.com/en-us/previous-versions//ms779636(v=vs.85)?redirectedfrom=MSDN // basically, everything is a CHUNK and a chunk has a type (4 bytes) and a length (4 bytes) @@ -61,7 +61,7 @@ namespace AVI { AVIList hdrl; read(hdrl); if (hdrl.type != FOURCC("LIST") || hdrl.content != FOURCC("hdrl")) {return;} - uint32_t posAfterStreams = pos + (hdrl.size - 4); + uint32_t posAfterStreams = curPos() + (hdrl.size - 4); AVIMainHeader avih; read(avih); @@ -75,7 +75,7 @@ namespace AVI { if (strl.type != "LIST" || strl.content != FOURCC("strl")) {return;} // determine where the next entry will start - const uint32_t startOfNextStream = pos + (strl.size - 4); + const uint32_t startOfNextStream = curPos() + (strl.size - 4); AVIStreamHeader strh; read(strh); @@ -103,7 +103,7 @@ namespace AVI { } - dumpState(); + //dumpState(); // continue reading after hdrl seek(posAfterStreams); @@ -112,10 +112,7 @@ namespace AVI { AVIList movi = readUntilList("movi"); - std::cout << "movi data: " << movi.size << " bytes" << std::endl; - - - printf("nn"); + //std::cout << "movi data: " << movi.size << " bytes" << std::endl; } @@ -136,12 +133,12 @@ namespace AVI { // if this is a list, dive INTO it (do not skip it! it has meaningful content!) if (chunk.type == "LIST") { - seek(pos + sizeof(AVIList) - sizeof(AVIChunk)); + seek(curPos() + sizeof(AVIList) - sizeof(AVIChunk)); continue; } // just ignore unknown chunks - seek(pos + chunk.size); + seek(curPos() + chunk.size); continue; } @@ -151,9 +148,7 @@ namespace AVI { void read(NextChunk nc, uint8_t* dst) { //seek(pos + nc.size); read(nc.size, dst); - if ((nc.size % 2) != 0) {seek(pos+1);} - - printf("xx"); + if ((nc.size % 2) != 0) {seek(curPos()+1);} } bool isValid() const { @@ -164,6 +159,10 @@ namespace AVI { //uint32_t pos = 0; + uint32_t curPos() const { + return src.curPos(); + } + void seek(uint32_t newPos) { //pos = newPos; src.seekTo(newPos); @@ -191,13 +190,13 @@ namespace AVI { while(true) { - const uint32_t startOfChunk = pos; + const uint32_t startOfChunk = curPos(); read(chunk); // skip non-list chunks if (chunk.type != FOURCC("LIST")) { - seek(pos + chunk.size); + seek(curPos() + chunk.size); continue; } @@ -212,7 +211,7 @@ namespace AVI { } // skip this list - seek(pos + list.getPayloadSize()); + seek(curPos() + list.getPayloadSize()); } diff --git a/data/formats/avi/structs.h b/data/formats/avi/structs.h index 6cdf4be..60f1cbe 100644 --- a/data/formats/avi/structs.h +++ b/data/formats/avi/structs.h @@ -79,14 +79,14 @@ struct AVIMainHeader : AVIChunk { uint32_t height; uint32_t reserved[4]; -}; +} __attribute__((__packed__)); struct AVIRect { uint16_t left; uint16_t top; uint16_t right; uint16_t bottom; -}; +} __attribute__((__packed__)); struct AVIStreamHeader : AVIChunk { @@ -110,9 +110,10 @@ struct AVIStreamHeader : AVIChunk { bool isVideo() const {return fccType == FOURCC("vids");} bool isAudio() const {return fccType == FOURCC("auds");} -}; +} __attribute__((__packed__)); struct BitMapInfoHeader { + uint32_t biSize; int32_t biWidth; int32_t biHeight; @@ -124,22 +125,28 @@ struct BitMapInfoHeader { int32_t biYPelsPerMeter; uint32_t biClrUsed; uint32_t biClrImportant; -}; + +} __attribute__((__packed__)); struct RGBQUAD { + uint8_t rgbBlue; uint8_t rgbGreen; uint8_t rgbRed; uint8_t rgbReserved; -}; + +} __attribute__((__packed__)); struct BitMapInfo : AVIChunk { + // BitMapInfoHeader bmi_header; RGBQUAD bmi_colors[1]; + }; struct WaveFormat : AVIChunk { + // uint16_t format_tag; uint16_t channels; @@ -147,21 +154,25 @@ struct WaveFormat : AVIChunk { uint32_t avg_bytes_per_sec; uint16_t block_align; uint16_t size; -}; + +} __attribute__((__packed__)); struct AVIIndexEntry { + uint32_t ckid; uint32_t flags; uint32_t chunk_offset; uint32_t chunk_length; -}; +} __attribute__((__packed__)); struct ChunkInfo { + uint32_t offset; uint32_t entry_offset; uint32_t size; -}; + +} __attribute__((__packed__)); diff --git a/ext/sd/fat32/File.h b/ext/sd/fat32/File.h index 1949eec..e89dd50 100644 --- a/ext/sd/fat32/File.h +++ b/ext/sd/fat32/File.h @@ -32,6 +32,16 @@ public: std::string getName() const {return h.getName();} + /** current position within the file */ + uint32_t curPos() const { + return curAbsPos; + } + + /** seek to a new position within the file */ + void seekTo(uint32_t pos) { + _seekTo(pos); + } + /** read x bytes from the file */ uint32_t read(uint32_t size, uint8_t* dst) { @@ -105,6 +115,12 @@ private: } + void _seekTo(uint32_t pos) { + this->curAbsPos = pos; + this->iCurCluster = pos / fs.tmp.bytesPerCluster; + this->posInCluster = pos - (this->iCurCluster * fs.tmp.bytesPerCluster); + } + int32_t _read(uint32_t readSize, uint8_t* dst) { // EOF reached? diff --git a/ext/sd/main.cpp b/ext/sd/main.cpp index 92456b2..4a39919 100644 --- a/ext/sd/main.cpp +++ b/ext/sd/main.cpp @@ -45,13 +45,13 @@ //}; -class Simu { +class SimuBlockDev { uint8_t* data; public: - Simu(const char* image) { + SimuBlockDev(const char* image) { FILE* f = fopen(image, "rw"); if (!f) {throw std::runtime_error("failed to open");} fseek(f, 0L, SEEK_END); @@ -76,26 +76,96 @@ public: }; +class SimuFile { + + FILE* f; + +public: + + SimuFile(const char* image) { + f = fopen(image, "rw"); + if (!f) {throw std::runtime_error("failed to open");} + } + + uint32_t curPos() const { + return ftell(f); + } + + void seekTo(uint32_t pos) { + fseek(f, pos, SEEK_SET); + } + + uint32_t read(uint32_t bytes, uint8_t* dst) { + return fread(dst, bytes, 1, f) * bytes; + } + + uint32_t write(uint32_t bytes, const uint8_t* src) { + return fwrite(src, bytes, 1, f) * bytes; + } + +}; + #include //#define logInfo(fmt, ...) std::string s = fmt::format(FMT_STRING(fmt), __VA_ARGS__); + #include "/apps/ESP8266lib/data/formats/avi/Demuxer.h" +#define __LINUX__ +#include "/apps/ESP8266lib/data/formats/jpeg/JPEGDEC.h" +#include "/apps/ESP8266lib/data/formats/jpeg/JPEGDEC.cpp" +//#include "/apps/ESP8266lib/data/formats/jpeg/jpeg.c" + +int drawJPEG(JPEGDRAW* pDraw) { + return 1; +} int main(int argc, char** argv) { - { + if (1==0) { // ffmpeg -i '/mnt/ssss/anime/Toaru Majutsu no Index/[Eclipse] Toaru Majutsu no Index - 07 (1280x720 h264) [0255D83A].mkv' -r 15 -ss 30 -vf scale=480x320 -c:v mjpeg -c:a mp3 -ar 44100 /tmp/ram/1.avi - Simu simu("/tmp/ram/1.avi"); - AccessHelper ah(simu); - AVI::Demuxer demux(ah); + SimuFile simu("/tmp/ram/1.avi"); + AVI::Demuxer demux(simu); bool valid = demux.isValid(); std::cout << "valid: " << valid << std::endl; + uint8_t buf[64*1024]; + + std::ofstream outV("/tmp/ram/1.mjpeg"); + std::ofstream outA("/tmp/ram/1.mp3"); + + JPEGDEC jpeg; + + for (int i = 0; i < 1024; ++i) { + + AVI::NextChunk nc = demux.getNextChunk(); + std::cout << (int)nc.type << " : " << nc.size << std::endl; + + demux.read(nc, buf); + + if (nc.type == AVI::NextChunkType::VIDEO) { + outV.write((const char*)buf, nc.size); + + int res = jpeg.openRAM(buf, nc.size, drawJPEG); + std::cout << "jpeg: " << res << std::endl; + if (res) { + jpeg.setPixelType(RGB565_BIG_ENDIAN); + jpeg.decode(0, 0, 0);//40, 100, JPEG_SCALE_QUARTER | JPEG_EXIF_THUMBNAIL); + jpeg.close(); + } + + } else if (nc.type == AVI::NextChunkType::AUDIO) { + outA.write((const char*)buf, nc.size); + } + + + + } + return 0; } @@ -106,15 +176,15 @@ int main(int argc, char** argv) { //std::string s = fmt::format(FMT_STRING("{:s}"), "I am not a number"); ::testing::InitGoogleTest(&argc, argv); - ::testing::GTEST_FLAG(filter) = "*TestCreate*"; + ::testing::GTEST_FLAG(filter) = "*TestSeek*"; return RUN_ALL_TESTS(); // diff /tmp/ram/TETRIS.GB /apps/workspace/gbemu/tests/tetris.gb - Simu simu("/tmp/ram/1.dat"); - AccessHelper ah(simu); + SimuBlockDev simu("/tmp/ram/1.dat"); + AccessHelper ah(simu); - MBR> mbr(ah); + MBR> mbr(ah); if (mbr.isPresent() && mbr.isValid()) { @@ -122,7 +192,7 @@ int main(int argc, char** argv) { std::cout << (int) mbr.getPartition(i).getType() << " - " << mbr.getPartition(i).getFirstSector() << " - " << mbr.getPartition(i).getNumSectors() << std::endl; } - using FAT32FS = FAT32::FS>; + using FAT32FS = FAT32::FS>; FAT32FS fat(ah, mbr.getPartition(0).getFirstSector() * 512); diff --git a/ext/sd/tests/TestCreate.cpp b/ext/sd/tests/TestCreate.cpp index 7091c3b..77074b8 100644 --- a/ext/sd/tests/TestCreate.cpp +++ b/ext/sd/tests/TestCreate.cpp @@ -26,7 +26,7 @@ TEST(TestCreate, structure) { } -TEST (TestCreat, writeRead) { +TEST (TestCreate, writeRead) { using BlockDev = AccessHelper; using FS = FAT32::FS; @@ -96,7 +96,7 @@ TEST (TestCreat, writeRead) { } -TEST (TestCreat, init) { +TEST (TestCreate, init) { using BlockDev = AccessHelper; using FS = FAT32::FS; @@ -135,7 +135,7 @@ TEST (TestCreat, init) { } -TEST (TestCreat, getOrCreateFile) { +TEST (TestCreate, getOrCreateFile) { using BlockDev = AccessHelper; using FS = FAT32::FS; diff --git a/ext/sd/tests/TestSeek.cpp b/ext/sd/tests/TestSeek.cpp new file mode 100644 index 0000000..15eaf7b --- /dev/null +++ b/ext/sd/tests/TestSeek.cpp @@ -0,0 +1,55 @@ +#include + +#include "Helper.h" + +#include "../AccessHelper.h" +#include "../fat32/FS.h" + + +TEST (TestSeek, seek1) { + + using BlockDev = AccessHelper; + using FS = FAT32::FS; + + size_t size = 32*1024*1024; + TestDevice dev(size); + BlockDev bDev(dev); + + FS fs(bDev, 0); + ASSERT_FALSE(fs.isValid()); // filesystem must not be considered valid, header contains only zeros + fs.setup(size, true); // initialize the filesystem + ASSERT_TRUE(fs.isValid()); // must be considered valid now + + auto testData = [] (const uint32_t pos) { + return (uint8_t) (pos * 21 + 13); + }; + + // create a file + FS::File f1 = fs.getOrCreateFile("test.txt"); + static constexpr uint32_t testSize = 16*1024; + uint8_t d1[testSize]; + for (int i = 0; i < testSize; ++i) { + d1[i] = testData(i); + } + ASSERT_EQ(testSize, f1.write(testSize, d1)); + + // re-open the file + FS::File f2 = fs.getOrCreateFile("test.txt"); + + + for (int i = 0; i < 1024; ++i) { + uint8_t tmp = 0; + f2.read(1, &tmp); + ASSERT_EQ(testData(i), tmp); + } + + for (int i = 0; i < 100; ++i) { + uint32_t pos = rand() % testSize; + f2.seekTo(pos); + uint8_t tmp = 0; + f2.read(1, &tmp); + uint8_t expected = testData(pos); + ASSERT_EQ(expected, tmp); + } + +}