ref: 1cd6fa1aa2cd7eb7fc2beebec6ae51eb25450971
parent: cb8864eb448c73bf5ade441f12b00ead0d0a86a1
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Mar 16 23:54:47 EDT 2020
extract raw streams
--- a/iso.c
+++ b/iso.c
@@ -4,6 +4,8 @@
typedef struct Box Box;
typedef struct RunSample RunSample;
+typedef struct Track Track;
+typedef struct SampleToChunk SampleToChunk;
struct Box {
vlong dsz;
@@ -88,11 +90,7 @@
struct {
u32int entrycount;
- struct {
- u32int firstchunk;
- u32int samplesperchunk;
- u32int sdt;
- }*entry;
+ SampleToChunk *entry;
}stsc;
struct {
@@ -129,6 +127,25 @@
vlong timeoffset;
};
+struct Track {
+ u64int *chunkoffset;
+ u32int numchunks;
+
+ u32int *samplesize;
+ u32int numsamples;
+
+ SampleToChunk *stc;
+ u32int numstc;
+
+ int id;
+};
+
+struct SampleToChunk {
+ u32int firstchunk;
+ u32int samplesperchunk;
+ u32int sdt;
+};
+
enum {
BoxUuid = 0x75756964u,
BoxFtyp = 0x66747970u,
@@ -146,6 +163,7 @@
BoxMinf = 0x6d696e66u,
BoxDinf = 0x64696e66u,
BoxStbl = 0x7374626cu,
+ BoxCtts = 0x63747473u,
BoxStsd = 0x73747364u,
BoxStts = 0x73747473u,
BoxStsc = 0x73747363u,
@@ -173,7 +191,7 @@
b->type == BoxMfhd || b->type == BoxTfhd || b->type == BoxTfdt || b->type == BoxTrun || \
b->type == BoxStsd || b->type == BoxStts || b->type == BoxStss || b->type == BoxTkhd || \
b->type == BoxElst || b->type == BoxStsc || b->type == BoxStco || b->type == BoxCo64 || \
- b->type == BoxStsz \
+ b->type == BoxStsz || b->type == BoxCtts \
)
#define eBread(sz, e) if(Bread(f, d, (sz)) != (sz)){ werrstr(e); goto err; }
@@ -180,8 +198,11 @@
static int dflag;
static int dind;
+static int trackdump = -1;
static u32int defsamplesize;
+static Track track;
+
static int parsebox(Biobuf *f, Box *b, int *eof);
#pragma varargck type "T" u32int
@@ -332,6 +353,47 @@
}
}
+static void
+dumptrack(Biobuf *f)
+{
+ SampleToChunk *stc;
+ u32int si, ch, lastch;
+ u32int samplelast, sample, rawsz;
+ vlong o;
+ u8int *raw;
+ Biobuf out;
+
+ Binit(&out, 1, OWRITE);
+ raw = nil;
+ rawsz = 0;
+ sample = samplelast = 0;
+ stc = track.stc;
+ for(si = 0; si < track.numstc; si++, stc++){
+ lastch = si+1 < track.numstc ? stc[1].firstchunk : track.numchunks;
+ for(ch = stc->firstchunk-1; ch < lastch && ch < track.numchunks; ch++){
+ o = track.chunkoffset[ch];
+ if(Bseek(f, o, 0) != o)
+ sysfatal("chunk %ud: %r", ch);
+ for(; sample < samplelast+stc->samplesperchunk && sample < track.numsamples; sample++){
+ if(track.samplesize[sample] == 0)
+ break;
+ if(rawsz < track.samplesize[sample]){
+ rawsz = track.samplesize[sample] * 2;
+ raw = realloc(raw, rawsz);
+ }
+ if(Bread(f, raw, track.samplesize[sample]) != track.samplesize[sample])
+ sysfatal("chunk %ud sample %ud size %ud: %r", ch, sample, track.samplesize[sample]);
+ if(Bwrite(&out, raw, track.samplesize[sample]) != track.samplesize[sample])
+ exits(nil);
+ }
+ samplelast = sample;
+ }
+ }
+ fprint(2, "%ud samples\n", sample);
+ Bterm(&out);
+ free(raw);
+};
+
static int
parseboxdata(Biobuf *f, Box *b)
{
@@ -369,6 +431,17 @@
if(inner.dstart+inner.dsz >= b->dstart+b->dsz)
break;
}
+ if(b->type == BoxTrak){
+ if(track.id == trackdump){
+ u = Boffset(f);
+ dumptrack(f);
+ Bseek(f, u, 0);
+ }
+ free(track.chunkoffset);
+ free(track.samplesize);
+ free(track.stc);
+ memset(&track, 0, sizeof(track));
+ }
dind--;
}else if(b->type == BoxMvhd){
n = b->version == 0 ? 96 : 108;
@@ -506,7 +579,7 @@
}else if(b->type == BoxStsc){
eBread(4, "entry_count");
b->stsc.entrycount = bu32(d);
- b->stsc.entry = calloc(b->stsc.entrycount, sizeof(*b->stsc.entry));
+ b->stsc.entry = calloc(b->stsc.entrycount, sizeof(SampleToChunk));
for(u = 0; u < b->stsc.entrycount; u++){
eBread(4, "first_chunk");
b->stsc.entry[u].firstchunk = bu32(d);
@@ -515,6 +588,8 @@
eBread(4, "sample_description_table");
b->stsc.entry[u].sdt = bu32(d);
}
+ track.numstc = b->stsc.entrycount;
+ track.stc = b->stsc.entry;
printbox(b);
}else if(b->type == BoxStco || b->type == BoxCo64){
eBread(4, "entry_count");
@@ -524,6 +599,8 @@
eBread(b->type == BoxStco ? 4 : 8, "chunk_offset");
b->stco_co64.chunkoffset[u] = b->type == BoxStco ? bu32(d) : bu64(d);
}
+ track.numchunks = b->stco_co64.entrycount;
+ track.chunkoffset = b->stco_co64.chunkoffset;
printbox(b);
}else if(b->type == BoxStsz){
eBread(4, "sample_size");
@@ -536,6 +613,8 @@
eBread(4, "chunk_offset");
b->stsz.entrysize[u] = bu32(d);
}
+ track.numsamples = b->stsz.samplecount;
+ track.samplesize = b->stsz.entrysize;
}
printbox(b);
}else if(b->type == BoxTkhd){
@@ -546,6 +625,7 @@
b->tkhd.modtime = bu64(d);
eBread(8, "track_id"); /* skipping 4 reserved as well */
b->tkhd.trackid = bu32(d);
+ track.id = b->tkhd.trackid;
eBread(8, "duration");
b->tkhd.duration = bu64(d);
}else if(b->version == 0){
@@ -555,6 +635,7 @@
b->tkhd.modtime = bu32(d);
eBread(8, "track_id"); /* skipping 4 reserved as well */
b->tkhd.trackid = bu32(d);
+ track.id = b->tkhd.trackid;
eBread(4, "duration");
b->tkhd.duration = bu32(d);
}else{
@@ -651,6 +732,13 @@
return -1;
}
+static void
+usage(void)
+{
+ fprint(2, "usage: iso [-d] [-t TRACK] FILE\n");
+ exits("usage");
+}
+
int
main(int argc, char **argv)
{
@@ -662,6 +750,9 @@
ARGBEGIN{
case 'd':
dflag = 1;
+ break;
+ case 't':
+ trackdump = atoi(EARGF(usage()));
break;
}ARGEND