worked on avi, working now? :P

This commit is contained in:
2021-02-25 07:11:56 +01:00
parent 851631e79d
commit f04742a1b0
2 changed files with 208 additions and 96 deletions

View File

@@ -4,16 +4,30 @@
#include <iostream>
// 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)
namespace AVI {
enum class NextChunkType {
INVALID,
AUDIO,
VIDEO,
};
struct NextChunk {
NextChunkType type;
uint32_t size;
NextChunk() {}
NextChunk(NextChunkType type, uint32_t size) : type(type), size(size) {}
};
template <typename Source> class Demuxer {
Source& src;
bool valid = true;
AVITypeHeader riff;
AVITypeHeader hdrl;
AVIMainHeader avih;
//AVITypeHeader riff;
//AVITypeHeader hdrl;
//AVIMainHeader avih;
struct State {
@@ -40,98 +54,106 @@ namespace AVI {
Demuxer(Source& src) : src(src) {
RIFFHeader riff;
read(riff);
if (memcmp(riff.fourcc, "RIFF", 4) != 0) {valid = false; return;}
if (riff.type != FOURCC("RIFF") || riff.content != FOURCC("AVI ")) {return;}
read(hdrl);
if (memcmp(hdrl.fourcc, "LIST", 4) != 0) {valid = false; return;}
if (memcmp(hdrl.type, "hdrl", 4) != 0) {valid = false; return;}
AVIList hdrl;
read(hdrl);
if (hdrl.type != FOURCC("LIST") || hdrl.content != FOURCC("hdrl")) {return;}
uint32_t posAfterStreams = pos + (hdrl.size - 4);
read(avih);
if (memcmp(avih.fourcc, "avih", 4) != 0) {valid = false; return;}
if (avih.cb != 56) {valid = false; return;}
AVIMainHeader avih;
read(avih);
if (avih.type != FOURCC("avih") || avih.size != 56) {return;}
// parse all streams
for (uint32_t streamID = 0; streamID < avih.streams; ++streamID) {
AVIList strl;
read(strl);
if (strl.type != "LIST" || strl.content != FOURCC("strl")) {return;}
// determine where the next entry will start
const uint32_t startOfNextStream = pos + (strl.size - 4);
AVIStreamHeader strh;
read(strh);
if (strh.type != FOURCC("strh")) {return;}
// remember
state.streamHeaders[streamID] = strh;
// read the type-specific stream format: strf
if (strh.isVideo()) {
state.video.streamID = streamID;
read(state.video.fmt);
if (state.video.fmt.type != FOURCC("strf")) {return;}
} else if (strh.isAudio()) {
state.audio.streamID = streamID;
read(state.audio.fmt);
if (state.video.fmt.type != FOURCC("strf")) {return;}
for (uint32_t i = 0; i < avih.streams; ++i) {
}
uint32_t posOfStreamStart = pos;
bool curStreamIsVideo = false;
// seek to next
seek(startOfNextStream);
AVITypeHeader strl;
read(strl);
if (memcmp(strl.fourcc, "LIST", 4) != 0) {valid = false; return;}
if (memcmp(strl.type, "strl", 4) != 0) {valid = false; return;}
}
AVIStreamHeader strh;
read(strh);
if (memcmp(strh.fourcc, "strh", 4) != 0) {valid = false; return;}
dumpState();
if (memcmp(strh.type, "vids", 4) == 0) {
state.video.streamID = i;
state.streamHeaders[i] = strh;
curStreamIsVideo = true;
} else if (memcmp(strh.type, "auds", 4) == 0) {
state.audio.streamID = i;
state.streamHeaders[i] = strh;
} else {
valid = false; return;
// continue reading after hdrl
seek(posAfterStreams);
// there might be an INFO list before the movi list
AVIList movi = readUntilList("movi");
std::cout << "movi data: " << movi.size << " bytes" << std::endl;
printf("nn");
}
/** determine the next (usable) Chunk in the data stream */
NextChunk getNextChunk() {
while(true) {
AVIChunk chunk;
read(chunk);
if (chunk.isAudioData()) {
return NextChunk(NextChunkType::AUDIO, chunk.size);
}
if (chunk.isVideoData()) {
return NextChunk(NextChunkType::VIDEO, chunk.size);
}
// ????
uint8_t xx[8];
read(xx);
// strf, depends on type (audio/video)
if (curStreamIsVideo) {
read(state.video.fmt); // BitmapInfoHeader
} else {
read(state.audio.fmt); // WaveFormatEx
// 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));
continue;
}
// seek to the next stream
seek(posOfStreamStart + 8 + strl.length);
// just ignore unknown chunks
seek(pos + chunk.size);
continue;
}
dumpState();
uint8_t tmp[128];
read(tmp);
seek(pos-4);
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);
}
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");
}
bool isValid() const {
@@ -140,10 +162,11 @@ namespace AVI {
private:
uint32_t pos = 0;
//uint32_t pos = 0;
void seek(uint32_t newPos) {
pos = newPos;
//pos = newPos;
src.seekTo(newPos);
}
template <typename T> void read(T& dst) {
@@ -152,16 +175,46 @@ namespace AVI {
/** 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;
src.read(size, (uint8_t*)dst);
//pos += size;
}
void dumpState() {
std::cout << "video @" << state.video.streamID << ": " << state.video.fmt.bmi_header.biWidth << "x" << state.video.fmt.bmi_header.biHeight << " Format: " << state.streamHeaders[state.video.streamID].fccHandler.chars << std::endl;
std::cout << "audio @" << state.audio.streamID << ": " << state.audio.fmt.channels << " channels @ " << state.audio.fmt.samples_per_sec << " Hz" << " Format: " << state.audio.fmt.format_tag << std::endl;
}
std::cout << "video @" << state.video.streamID << ": " << state.video.fmt.bmi_header.biWidth << "x" << state.video.fmt.bmi_header.biHeight << std::endl;
std::cout << "audio @" << state.audio.streamID << ": " << state.audio.fmt.channels << " channels @ " << state.audio.fmt.samples_per_sec << " Hz" << std::endl;
AVIList readUntilList(const char* content) {
AVIChunk chunk;
while(true) {
const uint32_t startOfChunk = pos;
read(chunk);
// skip non-list chunks
if (chunk.type != FOURCC("LIST")) {
seek(pos + chunk.size);
continue;
}
// is a list. seek back, before the chunk, to read it again, this time as LIST
seek(startOfChunk);
AVIList list;
read(list);
// found!
if (list.content == FOURCC(content)) {
return list;
}
// skip this list
seek(pos + list.getPayloadSize());
}
}