ref: 0c272ab00fe0275858ab03a1bccf5d04ae7e631b
parent: f11e1423cd3f0caba30be0c539694107dbf5ad52
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Sun Sep 13 06:46:39 EDT 2020
correctly parse esds
--- a/iso.c
+++ b/iso.c
@@ -8,6 +8,7 @@
typedef struct Box Box;
typedef struct Moof Moof;
typedef struct RunSample RunSample;
+typedef struct SampleEntry SampleEntry;
typedef struct SampleToChunk SampleToChunk;
typedef struct TimeToSample TimeToSample;
typedef struct Track Track;
@@ -16,6 +17,7 @@
struct Audio {
u32int format;
int channels;
+ int bps;
int samplerate;
};
@@ -23,8 +25,19 @@
u32int format;
int width;
int height;
+ u32int hres;
+ u32int vres;
+ int framecount;
+ uchar compressor[32];
};
+struct SampleEntry {
+ u32int format;
+ u16int datarefid;
+ Video video;
+ Audio audio;
+};
+
struct Box {
vlong dsz;
vlong offset;
@@ -99,9 +112,9 @@
}trun;
struct {
+ u16int id;
u32int entrycount;
- Video video;
- Audio audio;
+ SampleEntry *entry;
}stsd;
struct {
@@ -273,7 +286,10 @@
static Biobuf stderr;
static Moof moof;
+static SampleEntry *sampleentry;
+static char ind[16] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
static int parsebox(Biobuf *f, Box *b, int *eof);
#pragma varargck type "T" u32int
@@ -312,7 +328,6 @@
printbox(Box *b)
{
int i;
- char ind[16] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
uvlong u;
if(dflag == 0)
@@ -405,17 +420,26 @@
Bprint(&stderr, "\t\t%.*stimeoffset\t%zd\n", dind, ind, b->trun.samples[u].timeoffset);
}
}else if(b->type == BoxStsd){
+ Bprint(&stderr, "\t%.*sid\t%d\n", dind, ind, b->stsd.id);
Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stsd.entrycount);
- if(b->stsd.video.format != 0){
- Bprint(&stderr, "\t\t%.*svideo\t%T\n", dind, ind, b->stsd.video.format);
- Bprint(&stderr, "\t\t\t%.*swidth\t%d\n", dind, ind, b->stsd.video.width);
- Bprint(&stderr, "\t\t\t%.*sheight\t%d\n", dind, ind, b->stsd.video.height);
+ for(u = 0; u < b->stsd.entrycount; u++){
+ Bprint(&stderr, "\t%.*sentry[%zd]\n", dind, ind, u);
+ Bprint(&stderr, "\t\t%.*sdatarefid\t%d\n", dind, ind, b->stsd.entry[u].datarefid);
+ Bprint(&stderr, "\t\t%.*sformat\t%T\n", dind, ind, b->stsd.entry[u].format);
+ if(b->stsd.entry[u].video.format != 0){
+ Bprint(&stderr, "\t\t\t%.*swidth\t%d\n", dind, ind, b->stsd.entry[u].video.width);
+ Bprint(&stderr, "\t\t\t%.*sheight\t%d\n", dind, ind, b->stsd.entry[u].video.height);
+ Bprint(&stderr, "\t\t\t%.*shres\t%d\n", dind, ind, b->stsd.entry[u].video.hres);
+ Bprint(&stderr, "\t\t\t%.*svres\t%d\n", dind, ind, b->stsd.entry[u].video.vres);
+ Bprint(&stderr, "\t\t\t%.*sframecount\t%d\n", dind, ind, b->stsd.entry[u].video.framecount);
+ Bprint(&stderr, "\t\t\t%.*scompressor\t%.*s\n", dind, ind, 32, (char*)b->stsd.entry[u].video.compressor);
+ }
+ if(b->stsd.entry[u].audio.format != 0){
+ Bprint(&stderr, "\t\t\t%.*schannels\t%d\n", dind, ind, b->stsd.entry[u].audio.channels);
+ Bprint(&stderr, "\t\t\t%.*sbps\t%d\n", dind, ind, b->stsd.entry[u].audio.bps);
+ Bprint(&stderr, "\t\t\t%.*ssample_rate\t%d\n", dind, ind, b->stsd.entry[u].audio.samplerate);
+ }
}
- if(b->stsd.audio.format != 0){
- Bprint(&stderr, "\t\t%.*saudio\t%T\n", dind, ind, b->stsd.audio.format);
- Bprint(&stderr, "\t\t\t%.*schannels\t%d\n", dind, ind, b->stsd.audio.channels);
- Bprint(&stderr, "\t\t\t%.*ssample_rate\t%d\n", dind, ind, b->stsd.audio.samplerate);
- }
}else if(b->type == BoxStts){
Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stts.entrycount);
for(u = 0; dflag > 1 && u < b->stts.entrycount; u++){
@@ -457,7 +481,7 @@
}else if(b->type == BoxEsds){
Bprint(&stderr, "\t%.*sid\t%d\n", dind, ind, b->esds.id);
Bprint(&stderr, "\t%.*sflags\t0x%x\n", dind, ind, b->esds.flags);
- }else if(dflag < 2){
+ }else{
Bprint(&stderr, "\t%.*soffset\t%zd\n", dind, ind, b->offset);
Bprint(&stderr, "\t%.*sdstart\t%zd\n", dind, ind, b->dstart);
Bprint(&stderr, "\t%.*sdsize\t%zd\n", dind, ind, b->dsz);
@@ -755,30 +779,64 @@
};
int
-sampleentry(Biobuf *f, Box *b, u32int fmt, int n)
+parsesampleentry(Biobuf *f, SampleEntry *e, int n)
{
u8int d[96];
+ int sz, eof;
+ vlong off;
+ Box b;
if(track.handlertype == HandlerVideo){
- b->stsd.video.format = fmt;
+ e->video.format = e->format;
/* predefined+reserved+predefined, width+height, hres+vres, reserved, framecount, compressor */
- eBread(2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32, "SampleEntry: video");
- b->stsd.video.width = bu16(d+16);
- b->stsd.video.height = bu16(d+18);
- n -= 2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32;
+ sz = 2+2+4*3 + 2+2 + 4+4 + 4 + 2 + 32;
+ eBread(sz, "SampleEntry: video");
+ e->video.width = bu16(d+16);
+ e->video.height = bu16(d+18);
+ e->video.hres = bu32(d+20);
+ e->video.vres = bu32(d+24);
+ e->video.framecount = bu16(d+32);
+ memmove(e->video.compressor, d+34, 32);
+ n -= sz;
- memmove(&track.video, &b->stsd.video, sizeof(Video));
+ sampleentry = e;
+ while(n > 8){
+ off = Boffset(f);
+ if(parsebox(f, &b, &eof) != 0)
+ return -1;
+ Bseek(f, b.dstart+b.dsz, 0);
+ n -= b.dstart+b.dsz - off;
+ }
+ sampleentry = nil;
+
+ memmove(&track.video, &e->video, sizeof(Video));
}else if(track.handlertype == HandlerAudio){
- b->stsd.audio.format = fmt;
+ e->audio.format = e->format;
- /* ver+rev+vendor, channels+bps, ?+?, sample rate */
- eBread(2+4+2 + 2+2 + 2+2 + 4, "SampleEntry: audio");
- b->stsd.audio.channels = bu16(d+8);
- b->stsd.audio.samplerate = bu32(d+16)>>16;
- n -= 2+4+2 + 2+2 + 2+2 + 4;
+ /* <depends on the version>, channels+bps, predefined+reserved, samplerate */
+ sz = 8 + 2+2 + 2+2 + 4;
+ eBread(sz, "SampleEntry: audio");
+ if(bu16(d) == 0){ /* version */
+ e->audio.channels = bu16(d+8);
+ e->audio.bps = bu16(d+10);
+ e->audio.samplerate = bu32(d+16)>>16;
+ }else{
+ sysfatal("AudioSampleEntryV1 unsupported");
+ }
+ n -= sz;
- memmove(&track.audio, &b->stsd.audio, sizeof(Audio));
+ sampleentry = e;
+ while(n > 8){
+ off = Boffset(f);
+ if(parsebox(f, &b, &eof) != 0)
+ return -1;
+ Bseek(f, b.dstart+b.dsz, 0);
+ n -= b.dstart+b.dsz - off;
+ }
+ sampleentry = nil;
+
+ memmove(&track.audio, &e->audio, sizeof(Audio));
/* FIXME do we care about the rest? */
}else{
Bprint(&stderr, "SampleEntry: unknown handler type %T\n", track.handlertype);
@@ -790,6 +848,91 @@
}
static int
+descrlen(Biobuf *f, int *len)
+{
+ int i, c;
+
+ *len = 0;
+ for(i = 1; i <= 4; i++){
+ c = Bgetc(f);
+ *len = *len << 7 | c & 0x7f;
+ if((c & 0x80) == 0)
+ break;
+ }
+
+ return i;
+}
+
+static int aacchans[] = {0, 1, 2, 3, 4, 5, 6, 8};
+
+static int
+parseesds(Biobuf *f, SampleEntry *e, int n)
+{
+ int tag, len, o, x, srate;
+
+ o = -1;
+ while(n > 1){
+ tag = Bgetc(f);
+ n -= 1 + descrlen(f, &len);
+
+ if(tag == 3){ /* es descriptor */
+ Bseek(f, 2, 1); /* id */
+ n -= 2;
+
+ x = Bgetc(f);
+ n--;
+
+ if(x & 0x80){
+ Bseek(f, 2, 1); /* dep id */
+ n -= 2;
+ }
+ if(x & 0x40){ /* skip URL */
+ x = Bgetc(f);
+ Bseek(f, x, 1);
+ n -= x;
+ }
+ if(x & 0x20){ /* OCR */
+ Bseek(f, 2, 1);
+ n -= 2;
+ }
+ }else if(tag == 4){ /* decoder config descriptor */
+ o = Bgetc(f); /* object type id */
+ n--;
+
+ Bgetc(f); /* stream type (6 bits) */
+ n--;
+
+ Bseek(f, 3, 1); /* buffer size */
+ n -= 3;
+
+ Bseek(f, 4, 1); /* max bitrate */
+ n -= 4;
+
+ Bseek(f, 4, 1); /* avg bitrate */
+ n -= 4;
+ }else if(tag == 5){ /* decoder specific descriptor */
+ x = Bgetc(f)<<8;
+ x |= Bgetc(f);
+ n -= 2;
+
+ if(o == 0x40){ /* AAC */
+ if((x >> 11) == 0x1f)
+ sysfatal("extended object type not supported");
+
+ srate = (x >> 7) & 0xf;
+ if(srate == 0xf)
+ sysfatal("extended sample rate not supported");
+ e->audio.samplerate = srate2mpeg4fi[srate];
+ e->audio.channels = aacchans[(x >> 3) & 0xf];
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int
parseboxdata(Biobuf *f, Box *b)
{
u8int d[128], *p;
@@ -999,32 +1142,34 @@
}
addtrun(b);
printbox(b);
- }else if(b->type == BoxEsds){
- eBread(3, "es id");
- b->esds.id = bu16(d+1);
- b->esds.flags = d[3];
- printbox(b);
}else if(b->type == BoxStsd){
eBread(4, "entry_count");
b->stsd.entrycount = bu32(d);
- eBread(4, "size");
- n = bu32(d);
- eBread(4, "format");
- Bseek(f, 6+2, 1); /* skip reserved+id */
- n -= 8 + 6+2;
- n = sampleentry(f, b, bu32(d), n);
- printbox(b);
+ b->stsd.entry = calloc(b->stsd.entrycount, sizeof(SampleEntry));
+ for(u = 0; u < b->stsd.entrycount; u++){
+ eBread(4, "size");
+ n = bu32(d);
+ n -= 4;
- dind += 2;
- for(; n > 0;){
- memset(&inner, 0, sizeof(inner));
- if(parsebox(f, &inner, &eof) != 0)
- goto err;
- Bseek(f, inner.dstart+inner.dsz, 0);
- if(inner.dstart+inner.dsz >= b->dstart+b->dsz)
- break;
+ eBread(4, "format");
+ b->stsd.entry[u].format = bu32(d);
+ n -= 4;
+
+ Bseek(f, 6, 1); /* skip reserved */
+ n -= 6;
+
+ eBread(2, "id");
+ b->stsd.entry[u].datarefid = bu16(d);
+ n -= 2;
+
+ n = parsesampleentry(f, &b->stsd.entry[u], n);
+ Bseek(f, n, 1);
}
- dind -= 2;
+ printbox(b);
+ }else if(b->type == BoxEsds){
+ assert(sampleentry != nil);
+ parseesds(f, sampleentry, b->dsz);
+ /* print it with the sample entry */
}else if(b->type == BoxStts){
eBread(4, "entry_count");
b->stts.entrycount = bu32(d);