working on avi parsers
This commit is contained in:
158
data/formats/avi/Demuxer.h
Normal file
158
data/formats/avi/Demuxer.h
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "structs.h"
|
||||||
|
|
||||||
|
// https://docs.microsoft.com/en-us/previous-versions//ms779636(v=vs.85)?redirectedfrom=MSDN
|
||||||
|
namespace AVI {
|
||||||
|
|
||||||
|
template <typename Source> class Demuxer {
|
||||||
|
|
||||||
|
Source& src;
|
||||||
|
|
||||||
|
bool valid = true;
|
||||||
|
AVITypeHeader riff;
|
||||||
|
AVITypeHeader hdrl;
|
||||||
|
AVICommonHeader avih;
|
||||||
|
AVIMainHeader main_hdr;
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
|
||||||
|
AVIStreamHeader streamHeaders[2];
|
||||||
|
|
||||||
|
struct Video {
|
||||||
|
uint32_t streamID;
|
||||||
|
BitMapInfoHeader fmt;
|
||||||
|
} video;
|
||||||
|
|
||||||
|
struct Audio {
|
||||||
|
uint32_t streamID;
|
||||||
|
WaveFormat fmt;
|
||||||
|
} audio;
|
||||||
|
|
||||||
|
ChunkInfo moviInfo;
|
||||||
|
ChunkInfo idxlInfo;
|
||||||
|
|
||||||
|
uint32_t totalSec;
|
||||||
|
|
||||||
|
} state;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Demuxer(Source& src) : src(src) {
|
||||||
|
|
||||||
|
read(riff);
|
||||||
|
if (memcmp(riff.fourcc, "RIFF", 4) != 0) {valid = false; return;}
|
||||||
|
|
||||||
|
read(hdrl);
|
||||||
|
if (memcmp(hdrl.fourcc, "LIST", 4) != 0) {valid = false; return;}
|
||||||
|
if (memcmp(hdrl.type, "hdrl", 4) != 0) {valid = false; return;}
|
||||||
|
|
||||||
|
read(avih);
|
||||||
|
if (memcmp(avih.fourcc, "avih", 4) != 0) {valid = false; return;}
|
||||||
|
if (avih.length != sizeof(main_hdr)) {valid = false; return;}
|
||||||
|
|
||||||
|
read(main_hdr);
|
||||||
|
|
||||||
|
uint32_t posOfStreamStart = pos;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < main_hdr.streams; ++i) {
|
||||||
|
|
||||||
|
bool curStreamIsVideo = false;
|
||||||
|
|
||||||
|
AVITypeHeader strl;
|
||||||
|
read(strl);
|
||||||
|
if (memcmp(strl.fourcc, "LIST", 4) != 0) {valid = false; return;}
|
||||||
|
if (memcmp(strl.type, "strl", 4) != 0) {valid = false; return;}
|
||||||
|
|
||||||
|
AVICommonHeader strh;
|
||||||
|
read(strh);
|
||||||
|
if (memcmp(strh.fourcc, "strh", 4) != 0) {valid = false; return;}
|
||||||
|
|
||||||
|
AVIStreamHeader stream_hdr;
|
||||||
|
read(stream_hdr);
|
||||||
|
if (memcmp(stream_hdr.type, "vids", 4) == 0) {
|
||||||
|
state.video.streamID = i;
|
||||||
|
state.streamHeaders[i] = stream_hdr;
|
||||||
|
curStreamIsVideo = true;
|
||||||
|
} else if (memcmp(stream_hdr.type, "auds", 4) == 0) {
|
||||||
|
state.audio.streamID = i;
|
||||||
|
state.streamHeaders[i] = stream_hdr;
|
||||||
|
} else {
|
||||||
|
valid = false; return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AVICommonHeader strf;
|
||||||
|
read(strf);
|
||||||
|
if (curStreamIsVideo) {
|
||||||
|
BitMapInfoHeader bmih;
|
||||||
|
read(bmih);
|
||||||
|
state.video.fmt = bmih;
|
||||||
|
} else {
|
||||||
|
WaveFormat wf;
|
||||||
|
read(state.audio.fmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// seek to the next stream
|
||||||
|
seek(posOfStreamStart + 8 + strl.length);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
AVITypeHeader movi;
|
||||||
|
state.moviInfo.offset = pos;
|
||||||
|
read(movi);
|
||||||
|
state.moviInfo.entry_offset = pos;
|
||||||
|
state.moviInfo.size = movi.length - 4;
|
||||||
|
|
||||||
|
seek(state.moviInfo.offset + 8 + movi.length);
|
||||||
|
|
||||||
|
AVITypeHeader idxl;
|
||||||
|
state.idxlInfo.offset = pos;
|
||||||
|
read(idxl);
|
||||||
|
state.idxlInfo.entry_offset = pos;
|
||||||
|
state.idxlInfo.size = idxl.length - 4;
|
||||||
|
|
||||||
|
// total length in seconds based on the video stream
|
||||||
|
// normally scale is 1 and rate = FPS
|
||||||
|
// for non-integer FPS, scale and rate vary accordingly
|
||||||
|
AVIStreamHeader& videoStreamHeader = state.streamHeaders[state.video.streamID];
|
||||||
|
state.totalSec = videoStreamHeader.length * videoStreamHeader.scale / videoStreamHeader.rate;
|
||||||
|
|
||||||
|
printf("nn");
|
||||||
|
// p->total_sec = avi_video_calc_seconds(avi_parser_get_video_header(p));
|
||||||
|
// goto end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//seek(state.streamHeaders[state.video.streamID].start);
|
||||||
|
AVICommonHeader chead;
|
||||||
|
read(chead);
|
||||||
|
|
||||||
|
printf("nn");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const {
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
uint32_t pos = 0;
|
||||||
|
|
||||||
|
void seek(uint32_t newPos) {
|
||||||
|
pos = newPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void read(T& dst) {
|
||||||
|
read(sizeof(T), &dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** read x bytes from the input into dst */
|
||||||
|
template <typename T> void read(uint32_t size, T* dst) {
|
||||||
|
src.read(pos, size, (uint8_t*)dst);
|
||||||
|
pos += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
104
data/formats/avi/structs.h
Normal file
104
data/formats/avi/structs.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef uint8_t FOURCC[4];
|
||||||
|
|
||||||
|
struct AVICommonHeader {
|
||||||
|
FOURCC fourcc;
|
||||||
|
uint32_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AVITypeHeader {
|
||||||
|
FOURCC fourcc;
|
||||||
|
uint32_t length;
|
||||||
|
FOURCC type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AVIMainHeader {
|
||||||
|
uint32_t ms_per_frame;
|
||||||
|
uint32_t max_bytes_per_sec;
|
||||||
|
uint32_t padding_granularity;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t total_frames;
|
||||||
|
uint32_t initial_frames;
|
||||||
|
uint32_t streams;
|
||||||
|
uint32_t suggested_buffer_size;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
uint32_t reserved[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AVIStreamHeader {
|
||||||
|
//FOURCC fourcc;
|
||||||
|
//uint32_t length;
|
||||||
|
FOURCC type;
|
||||||
|
FOURCC fcc_handler;
|
||||||
|
uint32_t flags;
|
||||||
|
uint16_t priority;
|
||||||
|
uint16_t language;
|
||||||
|
uint32_t initial_frames;
|
||||||
|
uint32_t scale;
|
||||||
|
uint32_t rate;
|
||||||
|
uint32_t start;
|
||||||
|
uint32_t length;
|
||||||
|
uint32_t suggested_buffer_size;
|
||||||
|
uint32_t quality;
|
||||||
|
uint32_t sample_size;
|
||||||
|
struct {
|
||||||
|
uint16_t left;
|
||||||
|
uint16_t top;
|
||||||
|
uint16_t right;
|
||||||
|
uint16_t bottom;
|
||||||
|
} rcFrame;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BitMapInfoHeader {
|
||||||
|
uint32_t biSize;
|
||||||
|
int32_t biWidth;
|
||||||
|
int32_t biHeight;
|
||||||
|
int16_t biPlanes;
|
||||||
|
uint16_t biBitCount;
|
||||||
|
uint32_t biCompression;
|
||||||
|
uint32_t biSizeImage;
|
||||||
|
int32_t biXPelsPerMeter;
|
||||||
|
int32_t biYPelsPerMeter;
|
||||||
|
uint32_t biClrUsed;
|
||||||
|
uint32_t biClrImportant;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RGBQUAD {
|
||||||
|
uint8_t rgbBlue;
|
||||||
|
uint8_t rgbGreen;
|
||||||
|
uint8_t rgbRed;
|
||||||
|
uint8_t rgbReserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BitMapInfo {
|
||||||
|
BitMapInfoHeader bmi_header;
|
||||||
|
RGBQUAD bmi_colors[1];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WaveFormat {
|
||||||
|
uint16_t format_tag;
|
||||||
|
uint16_t channels;
|
||||||
|
uint32_t samples_per_sec;
|
||||||
|
uint32_t avg_bytes_per_sec;
|
||||||
|
uint16_t block_align;
|
||||||
|
uint16_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AVIIndexEntry {
|
||||||
|
uint32_t ckid;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t chunk_offset;
|
||||||
|
uint32_t chunk_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct ChunkInfo {
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t entry_offset;
|
||||||
|
uint32_t size;
|
||||||
|
};
|
||||||
@@ -31,22 +31,21 @@ public:
|
|||||||
uint32_t written = 0;
|
uint32_t written = 0;
|
||||||
LBA512 addrLBA = addr / SEC_SIZE; // LBA address
|
LBA512 addrLBA = addr / SEC_SIZE; // LBA address
|
||||||
uint16_t offset = (addr - addrLBA*SEC_SIZE);// 0 when addr is SEC_SIZE-byte aligned
|
uint16_t offset = (addr - addrLBA*SEC_SIZE);// 0 when addr is SEC_SIZE-byte aligned
|
||||||
uint8_t buf[SEC_SIZE];
|
|
||||||
|
|
||||||
while(size) {
|
while(size) {
|
||||||
|
|
||||||
if (offset || size < SEC_SIZE) { // non-aligned / non-full-block write
|
if (offset || size < SEC_SIZE) { // non-aligned / non-full-block write
|
||||||
|
|
||||||
// read the whole sector
|
// read the whole sector
|
||||||
if (!readBlock(addrLBA, buf)) {return written;}
|
if (!readBlockToCache(addrLBA)) {return written;}
|
||||||
|
|
||||||
// merge in the new data
|
// merge in the new data
|
||||||
const uint32_t toModify = min(SEC_SIZE-offset, size);
|
const uint32_t toModify = min(SEC_SIZE-offset, size);
|
||||||
for (uint16_t i = 0; i < toModify; ++i) {buf[i+offset] = src[i+written];}
|
for (uint16_t i = 0; i < toModify; ++i) {cache.buf[i+offset] = src[i+written];}
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
|
||||||
// write back the modified sector
|
// write back the modified sector
|
||||||
if (!writeBlock(addrLBA, buf)) {return written;}
|
if (!writeBlock(addrLBA, cache.buf)) {return written;}
|
||||||
|
|
||||||
++addrLBA;
|
++addrLBA;
|
||||||
size -= toModify;
|
size -= toModify;
|
||||||
@@ -57,6 +56,9 @@ public:
|
|||||||
// write a full block
|
// write a full block
|
||||||
if (!writeBlock(addrLBA, &src[written])) {return written;}
|
if (!writeBlock(addrLBA, &src[written])) {return written;}
|
||||||
|
|
||||||
|
// written block was in cache? -> drop
|
||||||
|
if (addrLBA == cache.lba) {cache.lba = 0xFFFFFFFF;}
|
||||||
|
|
||||||
++addrLBA;
|
++addrLBA;
|
||||||
size -= SEC_SIZE;
|
size -= SEC_SIZE;
|
||||||
written += SEC_SIZE;
|
written += SEC_SIZE;
|
||||||
@@ -92,7 +94,9 @@ public:
|
|||||||
|
|
||||||
} else { // full block read
|
} else { // full block read
|
||||||
|
|
||||||
if (!readBlock(addrLBA, &dst[read])) {return read;}
|
//if (!readBlock(addrLBA, &dst[read])) {return read;}
|
||||||
|
if (!readBlockToCache(addrLBA)) {return read;}
|
||||||
|
memcpy(&dst[read], cache.buf, SEC_SIZE);
|
||||||
++addrLBA;
|
++addrLBA;
|
||||||
size -= SEC_SIZE;
|
size -= SEC_SIZE;
|
||||||
read += SEC_SIZE;
|
read += SEC_SIZE;
|
||||||
@@ -105,17 +109,27 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** read a single block of SEC_SIZE bytes. addr = byteAddr/512 */
|
struct Cache {
|
||||||
bool readBlock(LBA512 addr, uint8_t* dst) {
|
LBA512 lba = 0xFFFFFFFF;
|
||||||
return dev.readBlock(addr, dst);
|
uint8_t buf[SEC_SIZE];
|
||||||
|
} cache;
|
||||||
|
|
||||||
|
/** read a single block of SEC_SIZE bytes into the CACHE. addr = byteAddr/512 */
|
||||||
|
bool readBlockToCache(LBA512 addr) {
|
||||||
|
if (cache.lba == addr) {return true;} // already cached
|
||||||
|
if (dev.readBlock(addr, cache.buf)) {
|
||||||
|
cache.lba = addr;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** read a single block of SEC_SIZE bytes. addr = byteAddr/512, write only a fraction of the 512 bytes into dst (skip+len) */
|
/** read a single block of SEC_SIZE bytes. addr = byteAddr/512, write only a fraction of the 512 bytes into dst (skip+len) */
|
||||||
bool readBlock(LBA512 addr, uint8_t* dst, uint16_t skip, uint16_t len) {
|
bool readBlock(LBA512 addr, uint8_t* dst, uint16_t skip, uint16_t len) {
|
||||||
uint8_t buf[SEC_SIZE];
|
|
||||||
if (!dev.readBlock(addr, buf)) {return false;}
|
if (!readBlockToCache(addr)) {return false;}
|
||||||
for (int i = 0; i < len; ++i) {
|
for (int i = 0; i < len; ++i) {
|
||||||
*dst = buf[i+skip];
|
*dst = cache.buf[i+skip];
|
||||||
++dst;
|
++dst;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ INCLUDE_DIRECTORIES(
|
|||||||
FILE(GLOB HEADERS
|
FILE(GLOB HEADERS
|
||||||
./*.h
|
./*.h
|
||||||
./*/*.h
|
./*/*.h
|
||||||
|
|
||||||
|
/apps/ESP8266lib/data/formats/avi/Demuxer.h
|
||||||
|
/apps/ESP8266lib/data/formats/avi/structs.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -81,8 +81,25 @@ public:
|
|||||||
|
|
||||||
//#define logInfo(fmt, ...) std::string s = fmt::format(FMT_STRING(fmt), __VA_ARGS__);
|
//#define logInfo(fmt, ...) std::string s = fmt::format(FMT_STRING(fmt), __VA_ARGS__);
|
||||||
|
|
||||||
|
#include "/apps/ESP8266lib/data/formats/avi/Demuxer.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
// 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<Simu> ah(simu);
|
||||||
|
AVI::Demuxer demux(ah);
|
||||||
|
|
||||||
|
bool valid = demux.isValid();
|
||||||
|
std::cout << valid << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//logInfo("{:s}", "I am not a number")
|
//logInfo("{:s}", "I am not a number")
|
||||||
//std::string s = fmt::format(FMT_STRING("{:s}"), "I am not a number");
|
//std::string s = fmt::format(FMT_STRING("{:s}"), "I am not a number");
|
||||||
|
|||||||
Reference in New Issue
Block a user