History

remux video streams as IVF

Sigrid Haflínudóttir committed 6 years ago

Commit ed803b21 parent f8e5a164 files · +371 −162Browse files

Unified · Split

4 files
  1. .gitignore +2 −0
  2. README.md +3 −1
  3. iso.c +364 −156
  4. mkfile +2 −5
.gitignore+2−0
@@ -0,0 +1,2 @@
1[a0125678vqki].out
2*.[o0125678vqki]
README.md+3−1
@@ -1,4 +1,6 @@
1# mp41# mcfs
2
3Multimedia container file system.
2 4
3Someday this might end up as a 9p filesystem for various video5Someday this might end up as a 9p filesystem for various video
4container formats so other programs (vidya players) can identify6container formats so other programs (vidya players) can identify
iso.c+364−156
@@ -4,6 +4,7 @@ · 3 unmodified lines
4 4
5typedef struct Audio Audio;5typedef struct Audio Audio;
6typedef struct Box Box;6typedef struct Box Box;
7typedef struct Moof Moof;
7typedef struct RunSample RunSample;8typedef struct RunSample RunSample;
8typedef struct SampleToChunk SampleToChunk;9typedef struct SampleToChunk SampleToChunk;
9typedef struct Track Track;10typedef struct Track Track;
@@ -139,6 +140,11 @@ struct Box { · 129 unmodified lines
139 u32int handlertype;140 u32int handlertype;
140 char *name;141 char *name;
141 }hdlr;142 }hdlr;
143
144 struct {
145 int id;
146 int flags;
147 }esds;
142 };148 };
143};149};
144 150
@@ -147,6 +153,7 @@ struct RunSample { · 2 unmodified lines
147 u32int size;153 u32int size;
148 u32int flags;154 u32int flags;
149 vlong timeoffset;155 vlong timeoffset;
156 vlong offset;
150};157};
151 158
152struct SampleToChunk {159struct SampleToChunk {
@@ -155,30 +162,12 @@ struct SampleToChunk { · 2 unmodified lines
155 u32int sdt;162 u32int sdt;
156};163};
157 164
158struct Track {
159 u32int handlertype;
160
161 u64int *chunkoffset;
162 u32int numchunks;
163
164 u32int samplesizeeach;
165 u32int *samplesize;
166 u32int numsamples;
167
168 SampleToChunk *stc;
169 u32int numstc;
170
171 Audio audio;
172 Video video;
173
174 int id;
175};
176
177enum {165enum {
178 HandlerVideo = 0x76696465u,166 HandlerVideo = 0x76696465u,
179 HandlerAudio = 0x736f756eu,167 HandlerAudio = 0x736f756eu,
180 168
181 FmtMp4a = 0x6d703461u,169 FmtMp4a = 0x6d703461u,
170 FmtAv01 = 0x61763031u,
182 171
183 BoxUuid = 0x75756964u,172 BoxUuid = 0x75756964u,
184 BoxFtyp = 0x66747970u,173 BoxFtyp = 0x66747970u,
@@ -230,6 +219,36 @@ enum { · 45 unmodified lines
230 219
231#define eBread(sz, e) if(Bread(f, d, (sz)) != (sz)){ werrstr(e); goto err; }220#define eBread(sz, e) if(Bread(f, d, (sz)) != (sz)){ werrstr(e); goto err; }
232 221
222struct Moof {
223 Box;
224 Box mfhd;
225 Box tfhd;
226 Box trun;
227};
228
229struct Track {
230 u32int handlertype;
231 u32int timescale;
232
233 u64int *chunkoffset;
234 u32int numchunks;
235
236 u32int samplesizeeach;
237 u32int *samplesize;
238 u32int numsamples;
239
240 SampleToChunk *stc;
241 u32int numstc;
242
243 Moof *moof;
244 int nmoof;
245
246 Audio audio;
247 Video video;
248
249 int id;
250};
251
233static int dflag;252static int dflag;
234static int dind;253static int dind;
235static u32int defsamplesize;254static u32int defsamplesize;
@@ -237,6 +256,9 @@ static u32int defsamplesize; · 1 unmodified line
237static Track track;256static Track track;
238static Track *tracks;257static Track *tracks;
239static int ntracks;258static int ntracks;
259static Biobuf stderr;
260
261static Moof moof;
240 262
241static int parsebox(Biobuf *f, Box *b, int *eof);263static int parsebox(Biobuf *f, Box *b, int *eof);
242 264
@@ -267,40 +289,40 @@ printbox(Box *b) · 24 unmodified lines
267 if(dflag == 0)289 if(dflag == 0)
268 return;290 return;
269 291
270 fprint(2, "%.*s%T\n", dind, ind, b->type);292 Bprint(&stderr, "%.*s%T\n", dind, ind, b->type);
271 293
272 /* full box */294 /* full box */
273 if(isfullbox(b)){295 if(isfullbox(b)){
274 fprint(2, "\t%.*sversion\t%d\n", dind, ind, b->version);296 Bprint(&stderr, "\t%.*sversion\t%d\n", dind, ind, b->version);
275 fprint(2, "\t%.*sflags\t0x%ux\n", dind, ind, b->flags);297 Bprint(&stderr, "\t%.*sflags\t0x%ux\n", dind, ind, b->flags);
276 }298 }
277 if(dflag > 1){299 if(dflag > 1){
278 fprint(2, "\t%.*soffset\t%zd\n", dind, ind, b->offset);300 Bprint(&stderr, "\t%.*soffset\t%zd\n", dind, ind, b->offset);
279 fprint(2, "\t%.*sdstart\t%zd\n", dind, ind, b->dstart);301 Bprint(&stderr, "\t%.*sdstart\t%zd\n", dind, ind, b->dstart);
280 fprint(2, "\t%.*sdsize\t%zd\n", dind, ind, b->dsz);302 Bprint(&stderr, "\t%.*sdsize\t%zd\n", dind, ind, b->dsz);
281 }303 }
282 304
283 if(b->type == BoxFtyp){305 if(b->type == BoxFtyp){
284 fprint(2, "\t%.*sbrand\t%T\n", dind, ind, b->ftyp.brand);306 Bprint(&stderr, "\t%.*sbrand\t%T\n", dind, ind, b->ftyp.brand);
285 fprint(2, "\t%.*sversion\t%d\n", dind, ind, b->ftyp.version);307 Bprint(&stderr, "\t%.*sversion\t%d\n", dind, ind, b->ftyp.version);
286 fprint(2, "\t%.*scompat", dind, ind);308 Bprint(&stderr, "\t%.*scompat", dind, ind);
287 for(i = 0; i < b->ftyp.ncompat; i++)309 for(i = 0; i < b->ftyp.ncompat; i++)
288 fprint(2, "\t%.*s%T", dind, ind, b->ftyp.compat[i]);310 Bprint(&stderr, "\t%.*s%T", dind, ind, b->ftyp.compat[i]);
289 fprint(2, "\n");311 Bprint(&stderr, "\n");
290 }else if(b->type == BoxMdhd){312 }else if(b->type == BoxMdhd){
291 fprint(2, "\t%.*screation\t%zd\n", dind, ind, b->mdhd.creation);313 Bprint(&stderr, "\t%.*screation\t%zd\n", dind, ind, b->mdhd.creation);
292 fprint(2, "\t%.*smodification\t%zd\n", dind, ind, b->mdhd.modification);314 Bprint(&stderr, "\t%.*smodification\t%zd\n", dind, ind, b->mdhd.modification);
293 fprint(2, "\t%.*stimescale\t%ud\n", dind, ind, b->mdhd.timescale);315 Bprint(&stderr, "\t%.*stimescale\t%ud\n", dind, ind, b->mdhd.timescale);
294 fprint(2, "\t%.*sduration\t%zd\n", dind, ind, b->mdhd.duration);316 Bprint(&stderr, "\t%.*sduration\t%zd\n", dind, ind, b->mdhd.duration);
295 }else if(b->type == BoxMvhd){317 }else if(b->type == BoxMvhd){
296 fprint(2, "\t%.*screation\t%zd\n", dind, ind, b->mvhd.creation);318 Bprint(&stderr, "\t%.*screation\t%zd\n", dind, ind, b->mvhd.creation);
297 fprint(2, "\t%.*smodification\t%zd\n", dind, ind, b->mvhd.modification);319 Bprint(&stderr, "\t%.*smodification\t%zd\n", dind, ind, b->mvhd.modification);
298 fprint(2, "\t%.*stimescale\t%ud\n", dind, ind, b->mvhd.timescale);320 Bprint(&stderr, "\t%.*stimescale\t%ud\n", dind, ind, b->mvhd.timescale);
299 fprint(2, "\t%.*sduration\t%zd\n", dind, ind, b->mvhd.duration);321 Bprint(&stderr, "\t%.*sduration\t%zd\n", dind, ind, b->mvhd.duration);
300 fprint(2, "\t%.*srate\t0x%ux\n", dind, ind, b->mvhd.rate);322 Bprint(&stderr, "\t%.*srate\t0x%ux\n", dind, ind, b->mvhd.rate);
301 fprint(2, "\t%.*svolume\t0x%ux\n", dind, ind, b->mvhd.volume);323 Bprint(&stderr, "\t%.*svolume\t0x%ux\n", dind, ind, b->mvhd.volume);
302 fprint(2, "\t%.*snexttrack\t0x%ux\n", dind, ind, b->mvhd.nexttrack);324 Bprint(&stderr, "\t%.*snexttrack\t0x%ux\n", dind, ind, b->mvhd.nexttrack);
303 fprint(2, "\t%.*smatrix\t0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux\n", dind, ind,325 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,
304 b->mvhd.matrix[0],326 b->mvhd.matrix[0],
305 b->mvhd.matrix[1],327 b->mvhd.matrix[1],
306 b->mvhd.matrix[2],328 b->mvhd.matrix[2],
@@ -312,99 +334,99 @@ printbox(Box *b) · 5 unmodified lines
312 b->mvhd.matrix[8]334 b->mvhd.matrix[8]
313 );335 );
314 }else if(b->type == BoxTrex){336 }else if(b->type == BoxTrex){
315 fprint(2, "\t%.*strackid\t0x%ux\n", dind, ind, b->trex.trackid);337 Bprint(&stderr, "\t%.*strackid\t0x%ux\n", dind, ind, b->trex.trackid);
316 fprint(2, "\t%.*sdefsample\n", dind, ind);338 Bprint(&stderr, "\t%.*sdefsample\n", dind, ind);
317 fprint(2, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->trex.defsample.descrindex);339 Bprint(&stderr, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->trex.defsample.descrindex);
318 fprint(2, "\t\t%.*sduration\t%ud\n", dind, ind, b->trex.defsample.duration);340 Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->trex.defsample.duration);
319 fprint(2, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->trex.defsample.size);341 Bprint(&stderr, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->trex.defsample.size);
320 fprint(2, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trex.defsample.flags);342 Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trex.defsample.flags);
321 }else if(b->type == BoxMfhd){343 }else if(b->type == BoxMfhd){
322 fprint(2, "\t%.*sseqnumber\t%ud\n", dind, ind, b->mfhd.seqnumber);344 Bprint(&stderr, "\t%.*sseqnumber\t%ud\n", dind, ind, b->mfhd.seqnumber);
323 }else if(b->type == BoxTfhd){345 }else if(b->type == BoxTfhd){
324 fprint(2, "\t%.*strackid\t0x%ux\n", dind, ind, b->tfhd.trackid);346 Bprint(&stderr, "\t%.*strackid\t%d\n", dind, ind, b->tfhd.trackid);
325 if(b->flags & 1)347 if(b->flags & 1)
326 fprint(2, "\t%.*sbaseoffset\t%zd\n", dind, ind, b->tfhd.baseoffset);348 Bprint(&stderr, "\t%.*sbaseoffset\t%zd\n", dind, ind, b->tfhd.baseoffset);
327 fprint(2, "\t%.*sdefsample\n", dind, ind);349 Bprint(&stderr, "\t%.*sdefsample\n", dind, ind);
328 if(b->flags & 2)350 if(b->flags & 2)
329 fprint(2, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->tfhd.defsample.descrindex);351 Bprint(&stderr, "\t\t%.*sdescrindex\t0x%ux\n", dind, ind, b->tfhd.defsample.descrindex);
330 if(b->flags & 8)352 if(b->flags & 8)
331 fprint(2, "\t\t%.*sduration\t%ud\n", dind, ind, b->tfhd.defsample.duration);353 Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->tfhd.defsample.duration);
332 if(b->flags & 16)354 if(b->flags & 16)
333 fprint(2, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->tfhd.defsample.size);355 Bprint(&stderr, "\t\t%.*ssize\t0x%ux\n", dind, ind, b->tfhd.defsample.size);
334 if(b->flags & 32)356 if(b->flags & 32)
335 fprint(2, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->tfhd.defsample.flags);357 Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->tfhd.defsample.flags);
336 if(b->flags & 0x10000)358 if(b->flags & 0x10000)
337 fprint(2, "\t%.*sduration is empty\n", dind, ind);359 Bprint(&stderr, "\t%.*sduration is empty\n", dind, ind);
338 if(b->flags & 0x20000)360 if(b->flags & 0x20000)
339 fprint(2, "\t%.*sdefault base is moof\n", dind, ind);361 Bprint(&stderr, "\t%.*sdefault base is moof\n", dind, ind);
340 }else if(b->type == BoxTfdt){362 }else if(b->type == BoxTfdt){
341 fprint(2, "\t%.*sdecodetime\t%zd\n", dind, ind, b->tfdt.decodetime);363 Bprint(&stderr, "\t%.*sdecodetime\t%zd\n", dind, ind, b->tfdt.decodetime);
342 }else if(b->type == BoxTrun){364 }else if(b->type == BoxTrun){
343 fprint(2, "\t%.*ssamplecount\t%ud\n", dind, ind, b->trun.samplecount);365 Bprint(&stderr, "\t%.*ssamplecount\t%ud\n", dind, ind, b->trun.samplecount);
344 if(b->flags & 1)366 if(b->flags & 1)
345 fprint(2, "\t%.*sdataoffset\t%d\n", dind, ind, b->trun.dataoffset);367 Bprint(&stderr, "\t%.*sdataoffset\t%d\n", dind, ind, b->trun.dataoffset);
346 if(b->flags & 2)368 if(b->flags & 2)
347 fprint(2, "\t%.*sfirstsampleflags\t0x%ux\n", dind, ind, b->trun.firstsampleflags);369 Bprint(&stderr, "\t%.*sfirstsampleflags\t0x%ux\n", dind, ind, b->trun.firstsampleflags);
348 for(u = 0; dflag > 1 && u < b->trun.samplecount; u++){370 for(u = 0; dflag > 1 && u < b->trun.samplecount; u++){
349 fprint(2, "\t%.*ssamples[%zd]\n", dind, ind, u);371 Bprint(&stderr, "\t%.*ssamples[%zd]\n", dind, ind, u);
350 if(b->flags & 0x100)372 Bprint(&stderr, "\t\t%.*sduration\t%ud\n", dind, ind, b->trun.samples[u].duration);
351 fprint(2, "\t\t%.*sduration\t%ud\n", dind, ind, b->trun.samples[u].duration);373 Bprint(&stderr, "\t\t%.*ssize\t%ud\n", dind, ind, b->trun.samples[u].size);
352 if(b->flags & 0x200)374 Bprint(&stderr, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trun.samples[u].flags);
353 fprint(2, "\t\t%.*ssize\t%ud\n", dind, ind, b->trun.samples[u].size);
354 if(b->flags & 0x400)
355 fprint(2, "\t\t%.*sflags\t0x%ux\n", dind, ind, b->trun.samples[u].flags);
356 if(b->flags & 0x800)375 if(b->flags & 0x800)
357 fprint(2, "\t\t%.*stimeoffset\t%zd\n", dind, ind, b->trun.samples[u].timeoffset);376 Bprint(&stderr, "\t\t%.*stimeoffset\t%zd\n", dind, ind, b->trun.samples[u].timeoffset);
358 }377 }
359 }else if(b->type == BoxStsd){378 }else if(b->type == BoxStsd){
360 fprint(2, "\t%.*sentry_count\t%ud\n", dind, ind, b->stsd.entrycount);379 Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stsd.entrycount);
361 if(b->stsd.video.format != 0){380 if(b->stsd.video.format != 0){
362 fprint(2, "\t\t%.*svideo\t%T\n", dind, ind, b->stsd.video.format);381 Bprint(&stderr, "\t\t%.*svideo\t%T\n", dind, ind, b->stsd.video.format);
363 fprint(2, "\t\t\t%.*swidth\t%d\n", dind, ind, b->stsd.video.width);382 Bprint(&stderr, "\t\t\t%.*swidth\t%d\n", dind, ind, b->stsd.video.width);
364 fprint(2, "\t\t\t%.*sheight\t%d\n", dind, ind, b->stsd.video.height);383 Bprint(&stderr, "\t\t\t%.*sheight\t%d\n", dind, ind, b->stsd.video.height);
365 }384 }
366 if(b->stsd.audio.format != 0){385 if(b->stsd.audio.format != 0){
367 fprint(2, "\t\t%.*saudio\t%T\n", dind, ind, b->stsd.audio.format);386 Bprint(&stderr, "\t\t%.*saudio\t%T\n", dind, ind, b->stsd.audio.format);
368 fprint(2, "\t\t\t%.*schannels\t%d\n", dind, ind, b->stsd.audio.channels);387 Bprint(&stderr, "\t\t\t%.*schannels\t%d\n", dind, ind, b->stsd.audio.channels);
369 fprint(2, "\t\t\t%.*ssample_rate\t%d\n", dind, ind, b->stsd.audio.samplerate);388 Bprint(&stderr, "\t\t\t%.*ssample_rate\t%d\n", dind, ind, b->stsd.audio.samplerate);
370 }389 }
371 }else if(b->type == BoxStts){390 }else if(b->type == BoxStts){
372 fprint(2, "\t%.*sentry_count\t%ud\n", dind, ind, b->stts.entrycount);391 Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stts.entrycount);
373 }else if(b->type == BoxStss){392 }else if(b->type == BoxStss){
374 fprint(2, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount);393 Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount);
375 }else if(b->type == BoxStsc){394 }else if(b->type == BoxStsc){
376 fprint(2, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount);395 Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount);
377 for(u = 0; dflag > 1 && u < b->stsc.entrycount; u++){396 for(u = 0; dflag > 1 && u < b->stsc.entrycount; u++){
378 fprint(2, "\t%.*sentry[%zd]\n", dind, ind, u);397 Bprint(&stderr, "\t%.*sentry[%zd]\n", dind, ind, u);
379 fprint(2, "\t\t%.*sfirst_chunk\t%ud\n", dind, ind, b->stsc.entry[u].firstchunk);398 Bprint(&stderr, "\t\t%.*sfirst_chunk\t%ud\n", dind, ind, b->stsc.entry[u].firstchunk);
380 fprint(2, "\t\t%.*ssamples_per_chunk\t%ud\n", dind, ind, b->stsc.entry[u].samplesperchunk);399 Bprint(&stderr, "\t\t%.*ssamples_per_chunk\t%ud\n", dind, ind, b->stsc.entry[u].samplesperchunk);
381 fprint(2, "\t\t%.*ssample_description_table\t%ud\n", dind, ind, b->stsc.entry[u].sdt);400 Bprint(&stderr, "\t\t%.*ssample_description_table\t%ud\n", dind, ind, b->stsc.entry[u].sdt);
382 }401 }
383 }else if(b->type == BoxStsz){402 }else if(b->type == BoxStsz){
384 fprint(2, "\t%.*ssample_size\t%ud\n", dind, ind, b->stsz.samplesizeeach);403 Bprint(&stderr, "\t%.*ssample_size\t%ud\n", dind, ind, b->stsz.samplesizeeach);
385 fprint(2, "\t%.*ssample_count\t%ud\n", dind, ind, b->stsz.samplecount);404 Bprint(&stderr, "\t%.*ssample_count\t%ud\n", dind, ind, b->stsz.samplecount);
386 if(dflag > 1 && b->stsz.samplesizeeach == 0){405 if(dflag > 1 && b->stsz.samplesizeeach == 0){
387 for(u = 0; u < b->stsz.samplecount; u++)406 for(u = 0; u < b->stsz.samplecount; u++)
388 fprint(2, "\t%.*ssamplesize[%zd]\t%ud\n", dind, ind, u, b->stsz.samplesize[u]);407 Bprint(&stderr, "\t%.*ssamplesize[%zd]\t%ud\n", dind, ind, u, b->stsz.samplesize[u]);
389 }408 }
390 }else if(b->type == BoxTkhd){409 }else if(b->type == BoxTkhd){
391 fprint(2, "\t%.*screation_time\t%zd\n", dind, ind, b->tkhd.creattime);410 Bprint(&stderr, "\t%.*screation_time\t%zd\n", dind, ind, b->tkhd.creattime);
392 fprint(2, "\t%.*smodification_timetime\t%zd\n", dind, ind, b->tkhd.modtime);411 Bprint(&stderr, "\t%.*smodification_time\t%zd\n", dind, ind, b->tkhd.modtime);
393 fprint(2, "\t%.*strack_id\t%ud\n", dind, ind, b->tkhd.trackid);412 Bprint(&stderr, "\t%.*strack_id\t%ud\n", dind, ind, b->tkhd.trackid);
394 fprint(2, "\t%.*sduration\t%zd\n", dind, ind, b->tkhd.duration);413 Bprint(&stderr, "\t%.*sduration\t%zd\n", dind, ind, b->tkhd.duration);
395 fprint(2, "\t%.*swidth\t%ud\n", dind, ind, b->tkhd.width);414 Bprint(&stderr, "\t%.*swidth\t%ud\n", dind, ind, b->tkhd.width);
396 fprint(2, "\t%.*sheight\t%ud\n", dind, ind, b->tkhd.height);415 Bprint(&stderr, "\t%.*sheight\t%ud\n", dind, ind, b->tkhd.height);
397 }else if(b->type == BoxHdlr){416 }else if(b->type == BoxHdlr){
398 fprint(2, "\t%.*shandler_type\t%T\n", dind, ind, b->hdlr.handlertype);417 Bprint(&stderr, "\t%.*shandler_type\t%T\n", dind, ind, b->hdlr.handlertype);
399 fprint(2, "\t%.*sname\t%s\n", dind, ind, b->hdlr.name);418 Bprint(&stderr, "\t%.*sname\t%s\n", dind, ind, b->hdlr.name);
400 }else if(b->type == BoxStco || b->type == BoxCo64){419 }else if(b->type == BoxStco || b->type == BoxCo64){
401 fprint(2, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount);420 Bprint(&stderr, "\t%.*sentry_count\t%ud\n", dind, ind, b->stss.entrycount);
402 for(u = 0; dflag > 1 && u < b->stco_co64.entrycount; u++)421 for(u = 0; dflag > 1 && u < b->stco_co64.entrycount; u++)
403 fprint(2, "\t%.*schunkoffset[%zd]\t%zd\n", dind, ind, u, b->stco_co64.chunkoffset[u]);422 Bprint(&stderr, "\t%.*schunkoffset[%zd]\t%zd\n", dind, ind, u, b->stco_co64.chunkoffset[u]);
423 }else if(b->type == BoxEsds){
424 Bprint(&stderr, "\t%.*sid\t%d\n", dind, ind, b->esds.id);
425 Bprint(&stderr, "\t%.*sflags\t0x%x\n", dind, ind, b->esds.flags);
404 }else if(dflag < 2){426 }else if(dflag < 2){
405 fprint(2, "\t%.*soffset\t%zd\n", dind, ind, b->offset);427 Bprint(&stderr, "\t%.*soffset\t%zd\n", dind, ind, b->offset);
406 fprint(2, "\t%.*sdstart\t%zd\n", dind, ind, b->dstart);428 Bprint(&stderr, "\t%.*sdstart\t%zd\n", dind, ind, b->dstart);
407 fprint(2, "\t%.*sdsize\t%zd\n", dind, ind, b->dsz);429 Bprint(&stderr, "\t%.*sdsize\t%zd\n", dind, ind, b->dsz);
408 }430 }
409}431}
410 432
@@ -415,6 +437,38 @@ addtrack(void) · 4 unmodified lines
415 memmove(&tracks[ntracks++], &track, sizeof(track));437 memmove(&tracks[ntracks++], &track, sizeof(track));
416}438}
417 439
440static Track *
441gettrack(int id)
442{
443 Track *t;
444 int i;
445
446 for(t = tracks, i = 0; i < ntracks && t->id != id; i++, t++){
447 fprint(2, "%d != %d\n", t->id, id);
448 }
449 if(i >= ntracks){
450 werrstr("no track %d", id);
451 t = nil;
452 }
453
454 return t;
455}
456
457static void
458addtrun(Box *trun)
459{
460 Track *t;
461 Moof *m;
462
463 if((t = gettrack(moof.tfhd.tfhd.trackid)) == nil)
464 sysfatal("trun without a track");
465
466 t->moof = realloc(t->moof, (t->nmoof+1)*sizeof(Moof));
467 m = &t->moof[t->nmoof++];
468 memmove(&moof.trun, trun, sizeof(moof.trun));
469 memmove(m, &moof, sizeof(moof));
470}
471
418static int srate2mpeg4fi[] = {472static int srate2mpeg4fi[] = {
419 96000,473 96000,
420 88200,474 88200,
@@ -432,51 +486,14 @@ static int srate2mpeg4fi[] = { · 11 unmodified lines
432};486};
433 487
434static int488static int
435dumptrack(Biobuf *f, int id)489dumpstc(Biobuf *f, Biobuf *out, Track *t, u8int *frame)
436{490{
437 SampleToChunk *stc;491 SampleToChunk *stc;
438 u32int si, ch, nextch;492 u32int si, ch, nextch;
439 u32int samplelast, sample, rawsz, samplesz;493 u32int samplelast, sample, rawsz, samplesz;
440 u64int o, wo;494 u64int o, wo;
441 int i;
442 u8int *raw;495 u8int *raw;
443 Biobuf out;
444 Track *t;
445 u8int frame[7];
446
447 for(t = tracks, i = 0; i < ntracks && t->id != id; i++, t++);
448 if(i >= ntracks){
449 werrstr("no track %d", id);
450 return -1;
451 }
452 496
453 fprint(
454 2,
455 "track %d: handler=%T numstc=%ud chunks=%ud samples=%ud\n", t->id, t->handlertype, t->numstc, t->numchunks, t->numsamples
456 );
457 if(t->audio.format != 0){
458 fprint(2, "audio: format=%T channels=%d samplerate=%d\n", t->audio.format, t->audio.channels, t->audio.samplerate);
459 if(t->audio.format == FmtMp4a){
460 for(i = 0; i < nelem(srate2mpeg4fi) && srate2mpeg4fi[i] != t->audio.samplerate; i++);
461 if(i >= nelem(srate2mpeg4fi)){
462 werrstr("audio: mpeg4: invalid sample rate %d", t->audio.samplerate);
463 return -1;
464 }
465 frame[0] = 0xff; /* syncword */
466 frame[1] = 0xf1; /* syncword, mpeg4, no crc */
467 frame[2] = 1<<6 | i<<2 | t->audio.channels>>2; /* AAC(LC)??? FIXME, frequency index, channels */
468 }else{
469 werrstr("audio: unknown format %T\n", t->audio.format);
470 return -1;
471 }
472 }
473 if(t->video.format != 0){
474 fprint(2, "video: format=%T resolution=%dx%d\n", t->video.format, t->video.width, t->video.height);
475 //werrstr("video: unknown format %T", t->video.format);
476 //return -1;
477 }
478
479 Binit(&out, 1, OWRITE);
480 raw = nil;497 raw = nil;
481 rawsz = 0;498 rawsz = 0;
482 sample = samplelast = 0;499 sample = samplelast = 0;
@@ -515,14 +532,14 @@ dumptrack(Biobuf *f, int id) · 32 unmodified lines
515 frame[5] = (samplesz&7)<<5 | 0x1f; /* frame length, fullness */532 frame[5] = (samplesz&7)<<5 | 0x1f; /* frame length, fullness */
516 frame[6] = 0xfc; /* fullness, number of frames */533 frame[6] = 0xfc; /* fullness, number of frames */
517 samplesz -= 7;534 samplesz -= 7;
518 if(Bwrite(&out, frame, 7) != 7){ /* EOF */535 if(Bwrite(out, frame, 7) != 7){ /* EOF */
519 werrstr("eof");536 werrstr("eof");
520 break;537 break;
521 }538 }
522 wo += 7;539 wo += 7;
523 o += 7;540 o += 7;
524 }541 }
525 if(Bwrite(&out, raw, samplesz) != samplesz){ /* EOF? */542 if(Bwrite(out, raw, samplesz) != samplesz){ /* EOF? */
526 werrstr("eof");543 werrstr("eof");
527 break;544 break;
528 }545 }
@@ -532,10 +549,167 @@ dumptrack(Biobuf *f, int id) · 3 unmodified lines
532 samplelast = sample;549 samplelast = sample;
533 }550 }
534 }551 }
535 Bterm(&out);
536 free(raw);552 free(raw);
537 553
538 return 0;554 return 0;
555}
556
557static int
558dumptrun(Biobuf *f, Biobuf *out, Track *t, u8int *frame)
559{
560 int i, j;
561 u64int ts;
562 u8int *raw;
563 int maxsz;
564 RunSample *s;
565 Moof *m;
566
567 USED(frame);
568
569 if(t->video.format == 0)
570 sysfatal("trun dump only works with IVF atm"); /* FIXME */
571
572 ts = 0;
573 maxsz = 0;
574 raw = nil;
575 for(i = 0, m = t->moof; i < t->nmoof; i++, m++){
576 for(j = 0; j < m->trun.trun.samplecount; j++){
577 s = &m->trun.trun.samples[j];
578 if(12 + s->size > maxsz){
579 maxsz = 12 + s->size;
580 raw = realloc(raw, maxsz);
581 }
582 raw[0] = s->size;
583 raw[1] = s->size >> 8;
584 raw[2] = s->size >> 16;
585 raw[3] = s->size >> 24;
586 raw[4] = ts;
587 raw[5] = ts >> 8;
588 raw[6] = ts >> 16;
589 raw[7] = ts >> 24;
590 raw[8] = ts >> 32;
591 raw[9] = ts >> 40;
592 raw[10] = ts >> 48;
593 raw[11] = ts >> 56;
594 if(Bseek(f, s->offset, 0) != s->offset){
595 werrstr("couldn't seek to offset %zd", s->offset);
596 return -1;
597 }
598 if(Bread(f, raw+12, s->size) != s->size){
599 werrstr("couldn't read sample (%d bytes)", s->size);
600 return -1;
601 }
602 if(Bwrite(out, raw, 12 + s->size) != 12 + s->size) /* eof? */
603 break;
604 ts += s->duration; /* sample's "time offset" is ignored here */
605 }
606 }
607
608 return 0;
609}
610
611static int
612dumptrack(Biobuf *f, int id)
613{
614 int i, j, res;
615 Biobuf out;
616 u64int dur;
617 Track *t;
618 Moof *m;
619 u8int frame[0x20];
620
621 if((t = gettrack(id)) == nil)
622 return -1;
623
624 if(dflag)
625 Bprint(&stderr, "track %d: handler=%T ", t->id, t->handlertype);
626 if(t->numstc > 0){
627 if(dflag)
628 Bprint(&stderr, "numstc=%ud chunks=%ud samples=%ud\n", t->numstc, t->numchunks, t->numsamples);
629 }else if(t->nmoof > 0){
630 if(dflag)
631 Bprint(&stderr, "numtrun: %d\n", t->nmoof);
632 }else{
633 if(dflag)
634 Bprint(&stderr, "no samples\n");
635 werrstr("track %d has no samples", t->id);
636 return -1;
637 }
638
639 Binit(&out, 1, OWRITE);
640
641 if(t->audio.format != 0){
642 Bprint(&stderr, "audio: format=%T channels=%d samplerate=%d\n", t->audio.format, t->audio.channels, t->audio.samplerate);
643 if(t->audio.format == FmtMp4a){
644 for(i = 0; i < nelem(srate2mpeg4fi) && srate2mpeg4fi[i] != t->audio.samplerate; i++);
645 if(i >= nelem(srate2mpeg4fi)){
646 werrstr("audio: mpeg4: invalid sample rate %d", t->audio.samplerate);
647 return -1;
648 }
649 frame[0] = 0xff; /* syncword */
650 frame[1] = 0xf1; /* syncword, mpeg4, no crc */
651 frame[2] = 1<<6 | i<<2 | t->audio.channels>>2; /* AAC(LC)??? FIXME, frequency index, channels */
652 }else{
653 werrstr("audio: unknown format %T\n", t->audio.format);
654 return -1;
655 }
656 }else if(t->video.format != 0){
657 Bprint(&stderr, "video: format=%T resolution=%dx%d\n", t->video.format, t->video.width, t->video.height);
658 /* video is remuxed into IVF */
659 memset(frame, 0, 0x20);
660 memmove(frame, "DKIF", 4);
661 frame[4] = 0;
662 frame[5] = 0;
663 frame[6] = 0x20;
664 frame[7] = 0;
665 if(t->video.format == FmtAv01){
666 memmove(frame+8, "AV01", 4);
667 frame[12] = t->video.width;
668 frame[13] = t->video.width >> 8;
669 frame[14] = t->video.height;
670 frame[15] = t->video.height >> 8;
671 /* timebase denum */
672 frame[16] = t->timescale;
673 frame[17] = t->timescale >> 8;
674 frame[18] = t->timescale >> 16;
675 frame[19] = t->timescale >> 24;
676 /* timebase num */
677 frame[20] = 1;
678 frame[21] = 0;
679 frame[22] = 0;
680 frame[23] = 0;
681 /* FIXME is it a "number of frames" or "total duration?" */
682 dur = 0;
683 for(i = 0, m = t->moof; i < t->nmoof; i++, m++){
684 for(j = 0; j < m->trun.trun.samplecount; j++){
685 dur += m->trun.trun.samples[j].duration;
686 }
687 }
688 frame[24] = dur;
689 frame[25] = dur >> 8;
690 frame[26] = dur >> 16;
691 frame[27] = dur >> 24;
692 frame[28] = dur >> 32; /* FIXME is it 64 bits? */
693 frame[29] = dur >> 40;
694 frame[30] = dur >> 48;
695 frame[31] = dur >> 56;
696
697 Bwrite(&out, frame, 0x20);
698 }else{
699 werrstr("video: unknown format %T", t->video.format);
700 return -1;
701 }
702 }
703
704 res = -1;
705 if(t->numstc > 0)
706 res = dumpstc(f, &out, t, frame);
707 else if(t->nmoof > 0)
708 res = dumptrun(f, &out, t, frame);
709
710 Bterm(&out);
711
712 return res;
539};713};
540 714
541int715int
@@ -565,7 +739,7 @@ sampleentry(Biobuf *f, Box *b, u32int fmt, int n) · 23 unmodified lines
565 memmove(&track.audio, &b->stsd.audio, sizeof(Audio));739 memmove(&track.audio, &b->stsd.audio, sizeof(Audio));
566 /* FIXME do we care about the rest? */740 /* FIXME do we care about the rest? */
567 }else{741 }else{
568 fprint(2, "SampleEntry: unknown handler type %T\n", track.handlertype);742 Bprint(&stderr, "SampleEntry: unknown handler type %T\n", track.handlertype);
569 }743 }
570 744
571 return n;745 return n;
@@ -579,8 +753,8 @@ parseboxdata(Biobuf *f, Box *b) · 7 unmodified lines
579 u8int d[128], *p;753 u8int d[128], *p;
580 Box inner;754 Box inner;
581 int i, n, eof;755 int i, n, eof;
582 s32int s32i;756 u64int u, off;
583 u64int u;757 RunSample *s;
584 758
585 if(b->type == BoxFtyp){759 if(b->type == BoxFtyp){
586 eBread(8, "brand and version");760 eBread(8, "brand and version");
@@ -601,6 +775,10 @@ parseboxdata(Biobuf *f, Box *b) · 14 unmodified lines
601 b->type == BoxMdia || b->type == BoxMinf || b->type == BoxStbl ||775 b->type == BoxMdia || b->type == BoxMinf || b->type == BoxStbl ||
602 b->type == BoxMoof || b->type == BoxTraf || b->type == BoxEdts ||776 b->type == BoxMoof || b->type == BoxTraf || b->type == BoxEdts ||
603 b->type == BoxDinf){777 b->type == BoxDinf){
778 if(b->type == BoxMoof){
779 memset(&moof, 0, sizeof(moof));
780 memmove(&moof, b, sizeof(Box));
781 }
604 printbox(b);782 printbox(b);
605 dind++;783 dind++;
606 for(;;){784 for(;;){
@@ -616,6 +794,8 @@ parseboxdata(Biobuf *f, Box *b) · 9 unmodified lines
616 memset(&track, 0, sizeof(track));794 memset(&track, 0, sizeof(track));
617 }795 }
618 dind--;796 dind--;
797 if(b->type == BoxMoof)
798 memset(&moof, 0, sizeof(moof));
619 }else if(b->type == BoxMdhd){799 }else if(b->type == BoxMdhd){
620 n = b->version == 0 ? 16 : 28;800 n = b->version == 0 ? 16 : 28;
621 eBread(n, "short read");801 eBread(n, "short read");
@@ -632,6 +812,7 @@ parseboxdata(Biobuf *f, Box *b) · 10 unmodified lines
632 }812 }
633 813
634 b->mdhd.timescale = bu32(p); p += 4;814 b->mdhd.timescale = bu32(p); p += 4;
815 track.timescale = b->mdhd.timescale; /* it's used for IVF timebase */
635 816
636 b->mdhd.duration = bu32(p); p += 4;817 b->mdhd.duration = bu32(p); p += 4;
637 if(b->version == 1){818 if(b->version == 1){
@@ -683,6 +864,7 @@ parseboxdata(Biobuf *f, Box *b) · 45 unmodified lines
683 }else if(b->type == BoxMfhd){864 }else if(b->type == BoxMfhd){
684 eBread(4, "short read");865 eBread(4, "short read");
685 b->mfhd.seqnumber = bu32(d);866 b->mfhd.seqnumber = bu32(d);
867 memmove(&moof.mfhd, b, sizeof(*b));
686 printbox(b);868 printbox(b);
687 }else if(b->type == BoxTfhd){869 }else if(b->type == BoxTfhd){
688 eBread(4, "track_id");870 eBread(4, "track_id");
@@ -708,6 +890,7 @@ parseboxdata(Biobuf *f, Box *b) · 19 unmodified lines
708 eBread(4, "default_sample_flags");890 eBread(4, "default_sample_flags");
709 b->tfhd.defsample.flags = bu32(d);891 b->tfhd.defsample.flags = bu32(d);
710 }892 }
893 memmove(&moof.tfhd, b, sizeof(*b));
711 printbox(b);894 printbox(b);
712 }else if(b->type == BoxTfdt){895 }else if(b->type == BoxTfdt){
713 if(b->version == 1){896 if(b->version == 1){
@@ -731,32 +914,53 @@ parseboxdata(Biobuf *f, Box *b) · 17 unmodified lines
731 }914 }
732 /* FIXME free those */915 /* FIXME free those */
733 b->trun.samples = calloc(b->trun.samplecount, sizeof(RunSample));916 b->trun.samples = calloc(b->trun.samplecount, sizeof(RunSample));
917 off = 0;
734 for(u = 0; u < b->trun.samplecount; u++){918 for(u = 0; u < b->trun.samplecount; u++){
919 s = &b->trun.samples[u];
735 if(b->flags & 0x100){920 if(b->flags & 0x100){
736 eBread(4, "sample_duration");921 eBread(4, "sample_duration");
737 b->trun.samples[u].duration = bu32(d);922 s->duration = bu32(d);
738 }923 }else if(moof.tfhd.flags & 8)
924 s->duration = moof.tfhd.tfhd.defsample.duration;
925
739 if(b->flags & 0x200){926 if(b->flags & 0x200){
740 eBread(4, "sample_size");927 eBread(4, "sample_size");
741 b->trun.samples[u].size = bu32(d);928 s->size = bu32(d);
742 }929 }else if(moof.tfhd.flags & 16)
930 s->size = moof.tfhd.tfhd.defsample.size;
931
743 if(b->flags & 0x400){932 if(b->flags & 0x400){
744 eBread(4, "sample_flags");933 eBread(4, "sample_flags");
745 b->trun.samples[u].flags = bu32(d);934 s->flags = bu32(d);
746 }935 }else if((b->flags & 4) && u == 0){
936 // FIXME default flags???
937 s->flags = b->trun.firstsampleflags;
938 }else if(moof.tfhd.flags & 32)
939 s->flags = moof.tfhd.tfhd.defsample.flags;
940
747 if(b->flags & 0x800){941 if(b->flags & 0x800){
748 eBread(4, "sample_composition_time_offset");942 eBread(4, "sample_composition_time_offset");
749 s32i = bu32(d);
750 if(b->version == 0)943 if(b->version == 0)
751 b->trun.samples[u].timeoffset = bu32(d);944 s->timeoffset = bu32(d);
752 else945 else
753 b->trun.samples[u].timeoffset = s32i;946 s->timeoffset = (s32int)bu32(d);
754 }947 }
948
949 s->offset = b->trun.dataoffset + off;
950 if(moof.tfhd.flags & 1)
951 Bprint(&stderr, "tfhd has base-data-offset-present set, this isn't supported atm\n");
952 else if(moof.tfhd.flags & 0x20000)
953 s->offset += moof.offset + moof.tfhd.tfhd.baseoffset;
954 else
955 Bprint(&stderr, "couldn't calculate sample offset\n");
956 off += s->size;
755 }957 }
958 addtrun(b);
756 printbox(b);959 printbox(b);
757 }else if(b->type == BoxEsds){960 }else if(b->type == BoxEsds){
758 eBread(3, "es id");961 eBread(3, "es id");
759 fprint(2, "# es id: %ud\n# es flags: 0x%02x\n", bu16(d+1), d[3]);962 b->esds.id = bu16(d+1);
963 b->esds.flags = d[3];
760 printbox(b);964 printbox(b);
761 }else if(b->type == BoxStsd){965 }else if(b->type == BoxStsd){
762 eBread(4, "entry_count");966 eBread(4, "entry_count");
@@ -950,7 +1154,7 @@ err: · 187 unmodified lines
950static void1154static void
951usage(void)1155usage(void)
952{1156{
953 fprint(2, "usage: iso [-d] [-t TRACK] FILE\n");1157 Bprint(&stderr, "usage: iso [-d] [-t TRACK] FILE\n");
954 exits("usage");1158 exits("usage");
955}1159}
956 1160
@@ -975,6 +1179,8 @@ main(int argc, char **argv) · 18 unmodified lines
975 1179
976 fmtinstall('T', typefmt);1180 fmtinstall('T', typefmt);
977 1181
1182 Binit(&stderr, 2, OWRITE);
1183
978 status = nil;1184 status = nil;
979 for(; *argv && status == nil; argv++){1185 for(; *argv && status == nil; argv++){
980 if((f = Bopen(*argv, OREAD)) == nil)1186 if((f = Bopen(*argv, OREAD)) == nil)
@@ -992,12 +1198,14 @@ main(int argc, char **argv) · 11 unmodified lines
992 }1198 }
993 1199
994 if(trackdump >= 0 && dumptrack(f, trackdump) != 0){1200 if(trackdump >= 0 && dumptrack(f, trackdump) != 0){
995 fprint(2, "%s: %r\n", *argv);1201 Bprint(&stderr, "%s: %r\n", *argv);
996 status = "dump";1202 status = "dump";
997 }1203 }
998 1204
999 Bterm(f);1205 Bterm(f);
1000 }1206 }
1001 1207
1208 Bterm(&stderr);
1209
1002 exits(status);1210 exits(status);
1003}1211}
mkfile+2−5
@@ -1,8 +1,7 @@
1</$objtype/mkfile1</$objtype/mkfile
2MAN=/sys/man/12MAN=/sys/man/1
3 3
4TARG=\4TARG=mcfs
5 iso\
6 5
7BIN=/$objtype/bin6BIN=/$objtype/bin
8 7
@@ -13,6 +12,4 @@ HFILES=\ · 4 unmodified lines
13 12
14default:V: all13default:V: all
15 14
16</sys/src/cmd/mkmany15</sys/src/cmd/mkone
17
18install:

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t