#include <u.h>#include <libc.h>#include <bio.h>#include <ctype.h>#include "common.h" typedef struct Audio Audio;typedef struct Box Box;typedef struct Moof Moof;typedef struct ParamSet ParamSet;typedef struct RunSample RunSample;typedef struct SampleEntry SampleEntry;typedef struct SampleToChunk SampleToChunk;typedef struct TimeToSample TimeToSample;typedef struct Track Track;typedef struct Video Video; struct Audio { u32int format; int objtype; int channels; int bps; int samplerate;}; struct ParamSet { int len; u8int *data;}; struct Video { u32int format; int width; int height; u32int hres; u32int vres; int framecount; char compressor[32]; struct { u8int profile; u8int compat; u8int level; u8int nallen; /* in bytes (1, 2, 4), ie with 1 already added to it */ int nsps; ParamSet *sps; int npps; ParamSet *pps; }avc;}; struct SampleEntry { u32int format; u16int datarefid; Video video; Audio audio;}; struct Box { vlong dsz; vlong offset; vlong dstart; char extended[16]; u32int type; /* full box */ u8int version; u32int flags; union { struct { u32int brand; u32int version; u32int *compat; int ncompat; }ftyp; struct { u64int creation; u64int modification; u64int duration; u32int timescale; }mdhd; struct { u64int creation; u64int modification; u64int duration; u32int timescale; u32int rate; u32int matrix[9]; u32int nexttrack; u16int volume; }mvhd; struct { u32int trackid; struct { u32int descrindex; u32int duration; u32int size; u32int flags; }defsample; }trex; struct { u32int seqnumber; }mfhd; struct { u64int decodetime; }tfdt; struct { u32int trackid; u64int baseoffset; struct { u32int descrindex; u32int duration; u32int size; u32int flags; }defsample; }tfhd; struct { u32int samplecount; s32int dataoffset; u32int firstsampleflags; RunSample *samples; }trun; struct { u16int id; u32int entrycount; SampleEntry *entry; }stsd; struct { u32int entrycount; TimeToSample *entry; }stts; struct { u32int entrycount; /* FIXME entries */ }stss; struct { u32int entrycount; SampleToChunk *entry; }stsc; struct { u32int entrycount; u64int *chunkoffset; }stco_co64; struct { u32int samplesizeeach; u32int samplecount; u32int *samplesize; }stsz; /* FIXME need stz2 as well */ struct { u64int creattime; u64int modtime; u32int trackid; u64int duration; u32int width; u32int height; }tkhd; struct { u32int handlertype; char *name; }hdlr; };}; struct RunSample { u32int duration; u32int size; u32int flags; vlong timeoffset; vlong offset;}; struct SampleToChunk { u32int firstchunk; u32int samplesperchunk; u32int sdt;}; struct TimeToSample { u32int samplecount; u32int sampledelta;}; enum { HandlerVideo = 0x76696465u, HandlerAudio = 0x736f756eu, BoxUuid = 0x75756964u, BoxFtyp = 0x66747970u, BoxMoov = 0x6d6f6f76u, BoxUdta = 0x75647461u, BoxMvhd = 0x6d766864u, BoxMvex = 0x6d766578u, BoxTrex = 0x74726578u, BoxTrak = 0x7472616bu, BoxEdts = 0x65647473u, BoxElst = 0x656c7374u, BoxTkhd = 0x746b6864u, BoxMdia = 0x6d646961u, BoxMdhd = 0x6d646864u, BoxHdlr = 0x68646c72u, BoxMinf = 0x6d696e66u, BoxDinf = 0x64696e66u, BoxStbl = 0x7374626cu, BoxCtts = 0x63747473u, BoxStsd = 0x73747364u, BoxAvcc = 0x61766343u, BoxEsds = 0x65736473u, BoxStts = 0x73747473u, BoxStsc = 0x73747363u, BoxStco = 0x7374636fu, BoxCo64 = 0x636f3634u, BoxStsz = 0x7374737au, BoxStss = 0x73747373u, BoxVmhd = 0x766d6864u, BoxSidx = 0x73696478u, BoxMoof = 0x6d6f6f66u, BoxMfhd = 0x6d666864u, BoxTraf = 0x74726166u, BoxTfdt = 0x74666474u, BoxTfhd = 0x74666864u, BoxTrun = 0x7472756eu, BoxMdat = 0x6d646174u,}; #define bu16(x) ((x)[0]<<8 | (x)[1])#define bu32(x) ((x)[0]<<24 | (x)[1]<<16 | (x)[2]<<8 | (x)[3])#define bu64(x) ((u64int)(x)[0]<<56 | (u64int)(x)[1]<<48 | (u64int)(x)[2]<<40 | (u64int)(x)[3]<<32 | (x)[4]<<24 | (x)[5]<<16 | (x)[6]<<8 | (x)[7]) #define isfullbox(b) ( \ b->type == BoxMvhd || b->type == BoxTrex || b->type == BoxMdhd || b->type == BoxHdlr || \ 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 == BoxCtts || b->type == BoxEsds \) #define eBread(sz, e) if(Bread(f, d, (sz)) != (sz)){ werrstr(e); goto err; } struct Moof { Box; Box mfhd; Box tfhd; Box trun;}; struct Track { u32int handlertype; u32int timescale; u64int *chunkoffset; u32int numchunks; u32int samplesizeeach; u32int *samplesize; u32int numsamples; SampleToChunk *stc; u32int numstc; TimeToSample *tts; u32int numtts; Moof *moof; int nmoof; Audio audio; Video video; int id;}; static int dind;static u32int defsamplesize; static Track track;static Track *tracks;static int ntracks; 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); intisotypefmt(Fmt *f){ char t[5]; int x; x = va_arg(f->args, int); t[0] = x>>24; t[1] = x>>16; t[2] = x>>8; t[3] = x; t[4] = 0; return fmtstrcpy(f, t);} static u32inttts(Track *t, u32int s){ u32int dt, n, e; dt = 0; for(e = 0; e < t->numtts && s > 0; e++){ n = min(t->tts[e].samplecount, s); dt += t->tts[e].sampledelta * n; s -= n; } return dt;} static voidprintbox(Box *b){ int i; uvlong u; if(dflag == 0) return; Bprint(&stderr, "%.*s%T\n", dind, ind, b->type); /* full box */ if(isfullbox(b)){ Bprint(&stderr, "\t%.*sversion\t%d\n", dind, ind, b->version); Bprint(&stderr, "\t%.*sflags\t0x%ux\n", dind, ind, b->flags); } if(dflag > 1){ Bprint(&stderr, "\t%.*soffset\t%lld\n", dind, ind, b->offset); Bprint(&stderr, "\t%.*sdstart\t%lld\n", dind, ind, b->dstart); Bprint(&stderr, "\t%.*sdsize\t%lld\n", dind, ind, b->dsz); } if(b->type == BoxFtyp){ Bprint(&stderr, "\t%.*sbrand\t%T\n", dind, ind, b->ftyp.brand); Bprint(&stderr, "\t%.*sversion\t%d\n", dind, ind, b->ftyp.version); Bprint(&stderr, "\t%.*scompat", dind, ind); for(i = 0; i < b->ftyp.ncompat; i++) Bprint(&stderr, "\t%.*s%T", dind, ind, b->ftyp.compat[i]); Bprint(&stderr, "\n"); }else if(b->type == BoxMdhd){ Bprint(&stderr, "\t%.*screation\t%llud\n", dind, ind, b->mdhd.creation); Bprint(&stderr, "\t%.*smodification\t%llud\n", dind, ind, b->mdhd.modification); Bprint(&stderr, "\t%.*stimescale\t%ud\n", dind, ind, b->mdhd.timescale); Bprint(&stderr, "\t%.*sduration\t%llud\n", dind, ind, b->mdhd.duration); }else if(b->type == BoxMvhd){ Bprint(&stderr, "\t%.*screation\t%llud\n", dind, ind, b->mvhd.creation); Bprint(&stderr, "\t%.*smodification\t%llud\n", dind, ind, b->mvhd.modification); Bprint(&stderr, "\t%.*stimescale\t%ud\n", dind, ind, b->mvhd.timescale); Bprint(&stderr, "\t%.*sduration\t%llud\n", dind, ind, b->mvhd.duration); Bprint(&stderr, "\t%.*srate\t0x%ux\n", dind, ind, b->mvhd.rate); Bprint(&stderr, "\t%.*svolume\t0x%ux\n", dind, ind, b->mvhd.volume); Bprint(&stderr, "\t%.*snexttrack\t0x%ux\n", dind, ind, b->mvhd.nexttrack); Bprint(&stderr, "\t%.*smatrix\t0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux\n", dind, ind, b->mvhd.matrix[0], b->mvhd.matrix[1], b->mvhd.matrix[2], b->mvhd.matrix[3], b->mvhd.matrix[4], b->mvhd.matrix[5], b->mvhd.matrix[6], b->mvhd.matrix[7], b->mvhd.matrix[8] ); }else if(b->type == BoxTrex){ Bprint(&stderr, "\t%.*strackid\t0x%ux\n", dind, ind, b->trex.trackid); Bprint(&stderr, "\t%.*sdefsample\n", dind, ind); Bprint(&stderr, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->trex.defsample.descrindex); Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->trex.defsample.duration); Bprint(&stderr, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->trex.defsample.size); Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trex.defsample.flags); }else if(b->type == BoxMfhd){ Bprint(&stderr, "\t%.*sseqnumber\t%ud\n", dind, ind, b->mfhd.seqnumber); }else if(b->type == BoxTfhd){ Bprint(&stderr, "\t%.*strackid\t%d\n", dind, ind, b->tfhd.trackid); if(b->flags & 1) Bprint(&stderr, "\t%.*sbaseoffset\t%llud\n", dind, ind, b->tfhd.baseoffset); Bprint(&stderr, "\t%.*sdefsample\n", dind, ind); if(b->flags & 2) Bprint(&stderr, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->tfhd.defsample.descrindex); if(b->flags & 8) Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->tfhd.defsample.duration); if(b->flags & 16) Bprint(&stderr, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->tfhd.defsample.size); if(b->flags & 32) Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->tfhd.defsample.flags); if(b->flags & 0x10000) Bprint(&stderr, "\t%.*sduration is empty\n", dind, ind); if(b->flags & 0x20000) Bprint(&stderr, "\t%.*sdefault base is moof\n", dind, ind); }else if(b->type == BoxTfdt){ Bprint(&stderr, "\t%.*sdecodetime\t%llud\n", dind, ind, b->tfdt.decodetime); }else if(b->type == BoxTrun){ Bprint(&stderr, "\t%.*ssamplecount\t%ud\n", dind, ind, b->trun.samplecount); if(b->flags & 1) Bprint(&stderr, "\t%.*sdataoffset\t%d\n", dind, ind, b->trun.dataoffset); if(b->flags & 2) Bprint(&stderr, "\t%.*sfirstsampleflags\t0x%ux\n", dind, ind, b->trun.firstsampleflags); for(u = 0; dflag > 1 && u < b->trun.samplecount; u++){ Bprint(&stderr, "\t%.*ssamples[%llud]\n", dind, ind, u); Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->trun.samples[u].duration); Bprint(&stderr, "\t\t%.*ssize\t%ud\n", dind, ind, b->trun.samples[u].size); Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trun.samples[u].flags); if(b->flags & 0x800) Bprint(&stderr, "\t\t%.*stimeoffset\t%lld\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); for(u = 0; u < b->stsd.entrycount; u++){ Bprint(&stderr, "\t%.*sentry[%llud]\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, b->stsd.entry[u].video.compressor); if(b->stsd.entry[u].video.format == FmtAvc1){ Bprint(&stderr, "\t\t\t%.*sprofile\t%d\n", dind, ind, b->stsd.entry[u].video.avc.profile); Bprint(&stderr, "\t\t\t%.*scompat\t%d\n", dind, ind, b->stsd.entry[u].video.avc.compat); Bprint(&stderr, "\t\t\t%.*slevel\t%d\n", dind, ind, b->stsd.entry[u].video.avc.level); Bprint(&stderr, "\t\t\t%.*snallen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.nallen); Bprint(&stderr, "\t\t\t%.*snsps\t%d\n", dind, ind, b->stsd.entry[u].video.avc.nsps); for(i = 0; i < b->stsd.entry[u].video.avc.nsps; i++){ Bprint(&stderr, "\t\t\t\t%.*ssps[%d]\n", dind, ind, i); Bprint(&stderr, "\t\t\t\t\t%.*slen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.sps[i].len); Bprint(&stderr, "\t\t\t\t\t%.*sdata\t%.*H\n", dind, ind, b->stsd.entry[u].video.avc.sps[i].len, b->stsd.entry[u].video.avc.sps[i].data); } Bprint(&stderr, "\t\t\t%.*snpps\t%d\n", dind, ind, b->stsd.entry[u].video.avc.npps); for(i = 0; i < b->stsd.entry[u].video.avc.npps; i++){ Bprint(&stderr, "\t\t\t\t%.*spps[%d]\n", dind, ind, i); Bprint(&stderr, "\t\t\t\t\t%.*slen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.pps[i].len); Bprint(&stderr, "\t\t\t\t\t%.*sdata\t%.*H\n", dind, ind, b->stsd.entry[u].video.avc.pps[i].len, b->stsd.entry[u].video.avc.pps[i].data); } } } 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); } } }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++){ Bprint(&stderr, "\t%.*sentry[%llud]\n", dind, ind, u); Bprint(&stderr, "\t\t%.*ssample_count\t%ud\n", dind, ind, b->stts.entry[u].samplecount); Bprint(&stderr, "\t\t%.*ssamples_delta\t%ud\n", dind, ind, b->stts.entry[u].sampledelta); } }else if(b->type == BoxStss){ Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount); }else if(b->type == BoxStsc){ Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount); for(u = 0; dflag > 1 && u < b->stsc.entrycount; u++){ Bprint(&stderr, "\t%.*sentry[%llud]\n", dind, ind, u); Bprint(&stderr, "\t\t%.*sfirst_chunk\t%ud\n", dind, ind, b->stsc.entry[u].firstchunk); Bprint(&stderr, "\t\t%.*ssamples_per_chunk\t%ud\n", dind, ind, b->stsc.entry[u].samplesperchunk); Bprint(&stderr, "\t\t%.*ssample_description_table\t%ud\n", dind, ind, b->stsc.entry[u].sdt); } }else if(b->type == BoxStsz){ Bprint(&stderr, "\t%.*ssample_size\t%ud\n", dind, ind, b->stsz.samplesizeeach); Bprint(&stderr, "\t%.*ssample_count\t%ud\n", dind, ind, b->stsz.samplecount); if(dflag > 1 && b->stsz.samplesizeeach == 0){ for(u = 0; u < b->stsz.samplecount; u++) Bprint(&stderr, "\t%.*ssamplesize[%llud]\t%ud\n", dind, ind, u, b->stsz.samplesize[u]); } }else if(b->type == BoxTkhd){ Bprint(&stderr, "\t%.*screation_time\t%llud\n", dind, ind, b->tkhd.creattime); Bprint(&stderr, "\t%.*smodification_time\t%llud\n", dind, ind, b->tkhd.modtime); Bprint(&stderr, "\t%.*strack_id\t%ud\n", dind, ind, b->tkhd.trackid); Bprint(&stderr, "\t%.*sduration\t%llud\n", dind, ind, b->tkhd.duration); Bprint(&stderr, "\t%.*swidth\t%ud\n", dind, ind, b->tkhd.width); Bprint(&stderr, "\t%.*sheight\t%ud\n", dind, ind, b->tkhd.height); }else if(b->type == BoxHdlr){ Bprint(&stderr, "\t%.*shandler_type\t%T\n", dind, ind, b->hdlr.handlertype); Bprint(&stderr, "\t%.*sname\t%s\n", dind, ind, b->hdlr.name);Lines 1–500 of 1589. Load more
#include <u.h> #include <libc.h> #include <bio.h> #include <ctype.h> #include "common.h" typedef struct Audio Audio; typedef struct Box Box; typedef struct Moof Moof; typedef struct ParamSet ParamSet; typedef struct RunSample RunSample; typedef struct SampleEntry SampleEntry; typedef struct SampleToChunk SampleToChunk; typedef struct TimeToSample TimeToSample; typedef struct Track Track; typedef struct Video Video; struct Audio { u32int format; int objtype; int channels; int bps; int samplerate; }; struct ParamSet { int len; u8int *data; }; struct Video { u32int format; int width; int height; u32int hres; u32int vres; int framecount; char compressor[32]; struct { u8int profile; u8int compat; u8int level; u8int nallen; /* in bytes (1, 2, 4), ie with 1 already added to it */ int nsps; ParamSet *sps; int npps; ParamSet *pps; }avc; }; struct SampleEntry { u32int format; u16int datarefid; Video video; Audio audio; }; struct Box { vlong dsz; vlong offset; vlong dstart; char extended[16]; u32int type; /* full box */ u8int version; u32int flags; union { struct { u32int brand; u32int version; u32int *compat; int ncompat; }ftyp; struct { u64int creation; u64int modification; u64int duration; u32int timescale; }mdhd; struct { u64int creation; u64int modification; u64int duration; u32int timescale; u32int rate; u32int matrix[9]; u32int nexttrack; u16int volume; }mvhd; struct { u32int trackid; struct { u32int descrindex; u32int duration; u32int size; u32int flags; }defsample; }trex; struct { u32int seqnumber; }mfhd; struct { u64int decodetime; }tfdt; struct { u32int trackid; u64int baseoffset; struct { u32int descrindex; u32int duration; u32int size; u32int flags; }defsample; }tfhd; struct { u32int samplecount; s32int dataoffset; u32int firstsampleflags; RunSample *samples; }trun; struct { u16int id; u32int entrycount; SampleEntry *entry; }stsd; struct { u32int entrycount; TimeToSample *entry; }stts; struct { u32int entrycount; /* FIXME entries */ }stss; struct { u32int entrycount; SampleToChunk *entry; }stsc; struct { u32int entrycount; u64int *chunkoffset; }stco_co64; struct { u32int samplesizeeach; u32int samplecount; u32int *samplesize; }stsz; /* FIXME need stz2 as well */ struct { u64int creattime; u64int modtime; u32int trackid; u64int duration; u32int width; u32int height; }tkhd; struct { u32int handlertype; char *name; }hdlr; }; }; struct RunSample { u32int duration; u32int size; u32int flags; vlong timeoffset; vlong offset; }; struct SampleToChunk { u32int firstchunk; u32int samplesperchunk; u32int sdt; }; struct TimeToSample { u32int samplecount; u32int sampledelta; }; enum { HandlerVideo = 0x76696465u, HandlerAudio = 0x736f756eu, BoxUuid = 0x75756964u, BoxFtyp = 0x66747970u, BoxMoov = 0x6d6f6f76u, BoxUdta = 0x75647461u, BoxMvhd = 0x6d766864u, BoxMvex = 0x6d766578u, BoxTrex = 0x74726578u, BoxTrak = 0x7472616bu, BoxEdts = 0x65647473u, BoxElst = 0x656c7374u, BoxTkhd = 0x746b6864u, BoxMdia = 0x6d646961u, BoxMdhd = 0x6d646864u, BoxHdlr = 0x68646c72u, BoxMinf = 0x6d696e66u, BoxDinf = 0x64696e66u, BoxStbl = 0x7374626cu, BoxCtts = 0x63747473u, BoxStsd = 0x73747364u, BoxAvcc = 0x61766343u, BoxEsds = 0x65736473u, BoxStts = 0x73747473u, BoxStsc = 0x73747363u, BoxStco = 0x7374636fu, BoxCo64 = 0x636f3634u, BoxStsz = 0x7374737au, BoxStss = 0x73747373u, BoxVmhd = 0x766d6864u, BoxSidx = 0x73696478u, BoxMoof = 0x6d6f6f66u, BoxMfhd = 0x6d666864u, BoxTraf = 0x74726166u, BoxTfdt = 0x74666474u, BoxTfhd = 0x74666864u, BoxTrun = 0x7472756eu, BoxMdat = 0x6d646174u, }; #define bu16(x) ((x)[0]<<8 | (x)[1]) #define bu32(x) ((x)[0]<<24 | (x)[1]<<16 | (x)[2]<<8 | (x)[3]) #define bu64(x) ((u64int)(x)[0]<<56 | (u64int)(x)[1]<<48 | (u64int)(x)[2]<<40 | (u64int)(x)[3]<<32 | (x)[4]<<24 | (x)[5]<<16 | (x)[6]<<8 | (x)[7]) #define isfullbox(b) ( \ b->type == BoxMvhd || b->type == BoxTrex || b->type == BoxMdhd || b->type == BoxHdlr || \ 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 == BoxCtts || b->type == BoxEsds \ ) #define eBread(sz, e) if(Bread(f, d, (sz)) != (sz)){ werrstr(e); goto err; } struct Moof { Box; Box mfhd; Box tfhd; Box trun; }; struct Track { u32int handlertype; u32int timescale; u64int *chunkoffset; u32int numchunks; u32int samplesizeeach; u32int *samplesize; u32int numsamples; SampleToChunk *stc; u32int numstc; TimeToSample *tts; u32int numtts; Moof *moof; int nmoof; Audio audio; Video video; int id; }; static int dind; static u32int defsamplesize; static Track track; static Track *tracks; static int ntracks; 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); int isotypefmt(Fmt *f) { char t[5]; int x; x = va_arg(f->args, int); t[0] = x>>24; t[1] = x>>16; t[2] = x>>8; t[3] = x; t[4] = 0; return fmtstrcpy(f, t); } static u32int tts(Track *t, u32int s) { u32int dt, n, e; dt = 0; for(e = 0; e < t->numtts && s > 0; e++){ n = min(t->tts[e].samplecount, s); dt += t->tts[e].sampledelta * n; s -= n; } return dt; } static void printbox(Box *b) { int i; uvlong u; if(dflag == 0) return; Bprint(&stderr, "%.*s%T\n", dind, ind, b->type); /* full box */ if(isfullbox(b)){ Bprint(&stderr, "\t%.*sversion\t%d\n", dind, ind, b->version); Bprint(&stderr, "\t%.*sflags\t0x%ux\n", dind, ind, b->flags); } if(dflag > 1){ Bprint(&stderr, "\t%.*soffset\t%lld\n", dind, ind, b->offset); Bprint(&stderr, "\t%.*sdstart\t%lld\n", dind, ind, b->dstart); Bprint(&stderr, "\t%.*sdsize\t%lld\n", dind, ind, b->dsz); } if(b->type == BoxFtyp){ Bprint(&stderr, "\t%.*sbrand\t%T\n", dind, ind, b->ftyp.brand); Bprint(&stderr, "\t%.*sversion\t%d\n", dind, ind, b->ftyp.version); Bprint(&stderr, "\t%.*scompat", dind, ind); for(i = 0; i < b->ftyp.ncompat; i++) Bprint(&stderr, "\t%.*s%T", dind, ind, b->ftyp.compat[i]); Bprint(&stderr, "\n"); }else if(b->type == BoxMdhd){ Bprint(&stderr, "\t%.*screation\t%llud\n", dind, ind, b->mdhd.creation); Bprint(&stderr, "\t%.*smodification\t%llud\n", dind, ind, b->mdhd.modification); Bprint(&stderr, "\t%.*stimescale\t%ud\n", dind, ind, b->mdhd.timescale); Bprint(&stderr, "\t%.*sduration\t%llud\n", dind, ind, b->mdhd.duration); }else if(b->type == BoxMvhd){ Bprint(&stderr, "\t%.*screation\t%llud\n", dind, ind, b->mvhd.creation); Bprint(&stderr, "\t%.*smodification\t%llud\n", dind, ind, b->mvhd.modification); Bprint(&stderr, "\t%.*stimescale\t%ud\n", dind, ind, b->mvhd.timescale); Bprint(&stderr, "\t%.*sduration\t%llud\n", dind, ind, b->mvhd.duration); Bprint(&stderr, "\t%.*srate\t0x%ux\n", dind, ind, b->mvhd.rate); Bprint(&stderr, "\t%.*svolume\t0x%ux\n", dind, ind, b->mvhd.volume); Bprint(&stderr, "\t%.*snexttrack\t0x%ux\n", dind, ind, b->mvhd.nexttrack); Bprint(&stderr, "\t%.*smatrix\t0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux\n", dind, ind, b->mvhd.matrix[0], b->mvhd.matrix[1], b->mvhd.matrix[2], b->mvhd.matrix[3], b->mvhd.matrix[4], b->mvhd.matrix[5], b->mvhd.matrix[6], b->mvhd.matrix[7], b->mvhd.matrix[8] ); }else if(b->type == BoxTrex){ Bprint(&stderr, "\t%.*strackid\t0x%ux\n", dind, ind, b->trex.trackid); Bprint(&stderr, "\t%.*sdefsample\n", dind, ind); Bprint(&stderr, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->trex.defsample.descrindex); Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->trex.defsample.duration); Bprint(&stderr, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->trex.defsample.size); Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trex.defsample.flags); }else if(b->type == BoxMfhd){ Bprint(&stderr, "\t%.*sseqnumber\t%ud\n", dind, ind, b->mfhd.seqnumber); }else if(b->type == BoxTfhd){ Bprint(&stderr, "\t%.*strackid\t%d\n", dind, ind, b->tfhd.trackid); if(b->flags & 1) Bprint(&stderr, "\t%.*sbaseoffset\t%llud\n", dind, ind, b->tfhd.baseoffset); Bprint(&stderr, "\t%.*sdefsample\n", dind, ind); if(b->flags & 2) Bprint(&stderr, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->tfhd.defsample.descrindex); if(b->flags & 8) Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->tfhd.defsample.duration); if(b->flags & 16) Bprint(&stderr, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->tfhd.defsample.size); if(b->flags & 32) Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->tfhd.defsample.flags); if(b->flags & 0x10000) Bprint(&stderr, "\t%.*sduration is empty\n", dind, ind); if(b->flags & 0x20000) Bprint(&stderr, "\t%.*sdefault base is moof\n", dind, ind); }else if(b->type == BoxTfdt){ Bprint(&stderr, "\t%.*sdecodetime\t%llud\n", dind, ind, b->tfdt.decodetime); }else if(b->type == BoxTrun){ Bprint(&stderr, "\t%.*ssamplecount\t%ud\n", dind, ind, b->trun.samplecount); if(b->flags & 1) Bprint(&stderr, "\t%.*sdataoffset\t%d\n", dind, ind, b->trun.dataoffset); if(b->flags & 2) Bprint(&stderr, "\t%.*sfirstsampleflags\t0x%ux\n", dind, ind, b->trun.firstsampleflags); for(u = 0; dflag > 1 && u < b->trun.samplecount; u++){ Bprint(&stderr, "\t%.*ssamples[%llud]\n", dind, ind, u); Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->trun.samples[u].duration); Bprint(&stderr, "\t\t%.*ssize\t%ud\n", dind, ind, b->trun.samples[u].size); Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trun.samples[u].flags); if(b->flags & 0x800) Bprint(&stderr, "\t\t%.*stimeoffset\t%lld\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); for(u = 0; u < b->stsd.entrycount; u++){ Bprint(&stderr, "\t%.*sentry[%llud]\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, b->stsd.entry[u].video.compressor); if(b->stsd.entry[u].video.format == FmtAvc1){ Bprint(&stderr, "\t\t\t%.*sprofile\t%d\n", dind, ind, b->stsd.entry[u].video.avc.profile); Bprint(&stderr, "\t\t\t%.*scompat\t%d\n", dind, ind, b->stsd.entry[u].video.avc.compat); Bprint(&stderr, "\t\t\t%.*slevel\t%d\n", dind, ind, b->stsd.entry[u].video.avc.level); Bprint(&stderr, "\t\t\t%.*snallen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.nallen); Bprint(&stderr, "\t\t\t%.*snsps\t%d\n", dind, ind, b->stsd.entry[u].video.avc.nsps); for(i = 0; i < b->stsd.entry[u].video.avc.nsps; i++){ Bprint(&stderr, "\t\t\t\t%.*ssps[%d]\n", dind, ind, i); Bprint(&stderr, "\t\t\t\t\t%.*slen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.sps[i].len); Bprint(&stderr, "\t\t\t\t\t%.*sdata\t%.*H\n", dind, ind, b->stsd.entry[u].video.avc.sps[i].len, b->stsd.entry[u].video.avc.sps[i].data); } Bprint(&stderr, "\t\t\t%.*snpps\t%d\n", dind, ind, b->stsd.entry[u].video.avc.npps); for(i = 0; i < b->stsd.entry[u].video.avc.npps; i++){ Bprint(&stderr, "\t\t\t\t%.*spps[%d]\n", dind, ind, i); Bprint(&stderr, "\t\t\t\t\t%.*slen\t%d\n", dind, ind, b->stsd.entry[u].video.avc.pps[i].len); Bprint(&stderr, "\t\t\t\t\t%.*sdata\t%.*H\n", dind, ind, b->stsd.entry[u].video.avc.pps[i].len, b->stsd.entry[u].video.avc.pps[i].data); } } } 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); } } }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++){ Bprint(&stderr, "\t%.*sentry[%llud]\n", dind, ind, u); Bprint(&stderr, "\t\t%.*ssample_count\t%ud\n", dind, ind, b->stts.entry[u].samplecount); Bprint(&stderr, "\t\t%.*ssamples_delta\t%ud\n", dind, ind, b->stts.entry[u].sampledelta); } }else if(b->type == BoxStss){ Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount); }else if(b->type == BoxStsc){ Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount); for(u = 0; dflag > 1 && u < b->stsc.entrycount; u++){ Bprint(&stderr, "\t%.*sentry[%llud]\n", dind, ind, u); Bprint(&stderr, "\t\t%.*sfirst_chunk\t%ud\n", dind, ind, b->stsc.entry[u].firstchunk); Bprint(&stderr, "\t\t%.*ssamples_per_chunk\t%ud\n", dind, ind, b->stsc.entry[u].samplesperchunk); Bprint(&stderr, "\t\t%.*ssample_description_table\t%ud\n", dind, ind, b->stsc.entry[u].sdt); } }else if(b->type == BoxStsz){ Bprint(&stderr, "\t%.*ssample_size\t%ud\n", dind, ind, b->stsz.samplesizeeach); Bprint(&stderr, "\t%.*ssample_count\t%ud\n", dind, ind, b->stsz.samplecount); if(dflag > 1 && b->stsz.samplesizeeach == 0){ for(u = 0; u < b->stsz.samplecount; u++) Bprint(&stderr, "\t%.*ssamplesize[%llud]\t%ud\n", dind, ind, u, b->stsz.samplesize[u]); } }else if(b->type == BoxTkhd){ Bprint(&stderr, "\t%.*screation_time\t%llud\n", dind, ind, b->tkhd.creattime); Bprint(&stderr, "\t%.*smodification_time\t%llud\n", dind, ind, b->tkhd.modtime); Bprint(&stderr, "\t%.*strack_id\t%ud\n", dind, ind, b->tkhd.trackid); Bprint(&stderr, "\t%.*sduration\t%llud\n", dind, ind, b->tkhd.duration); Bprint(&stderr, "\t%.*swidth\t%ud\n", dind, ind, b->tkhd.width); Bprint(&stderr, "\t%.*sheight\t%ud\n", dind, ind, b->tkhd.height); }else if(b->type == BoxHdlr){ Bprint(&stderr, "\t%.*shandler_type\t%T\n", dind, ind, b->hdlr.handlertype); Bprint(&stderr, "\t%.*sname\t%s\n", dind, ind, b->hdlr.name);