| @@ -4,6 +4,7 @@ · 3 unmodified lines |
| 4 | | 4 | |
| 5 | typedef struct Audio Audio; | 5 | typedef struct Audio Audio; |
| 6 | typedef struct Box Box; | 6 | typedef struct Box Box; |
| | 7 | typedef struct Moof Moof; |
| 7 | typedef struct RunSample RunSample; | 8 | typedef struct RunSample RunSample; |
| 8 | typedef struct SampleToChunk SampleToChunk; | 9 | typedef struct SampleToChunk SampleToChunk; |
| 9 | typedef struct Track Track; | 10 | typedef 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 | |
| 152 | struct SampleToChunk { | 159 | struct SampleToChunk { |
| @@ -155,30 +162,12 @@ struct SampleToChunk { · 2 unmodified lines |
| 155 | u32int sdt; | 162 | u32int sdt; |
| 156 | }; | 163 | }; |
| 157 | | 164 | |
| 158 | struct 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 | | | |
| 177 | enum { | 165 | enum { |
| 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 | |
| | 222 | struct Moof { |
| | 223 | Box; |
| | 224 | Box mfhd; |
| | 225 | Box tfhd; |
| | 226 | Box trun; |
| | 227 | }; |
| | 228 | |
| | 229 | struct 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 | |
| 233 | static int dflag; | 252 | static int dflag; |
| 234 | static int dind; | 253 | static int dind; |
| 235 | static u32int defsamplesize; | 254 | static u32int defsamplesize; |
| @@ -237,6 +256,9 @@ static u32int defsamplesize; · 1 unmodified line |
| 237 | static Track track; | 256 | static Track track; |
| 238 | static Track *tracks; | 257 | static Track *tracks; |
| 239 | static int ntracks; | 258 | static int ntracks; |
| | 259 | static Biobuf stderr; |
| | 260 | |
| | 261 | static Moof moof; |
| 240 | | 262 | |
| 241 | static int parsebox(Biobuf *f, Box *b, int *eof); | 263 | static 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 | |
| | 440 | static Track * |
| | 441 | gettrack(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 | |
| | 457 | static void |
| | 458 | addtrun(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 | |
| 418 | static int srate2mpeg4fi[] = { | 472 | static int srate2mpeg4fi[] = { |
| 419 | 96000, | 473 | 96000, |
| 420 | 88200, | 474 | 88200, |
| @@ -432,51 +486,14 @@ static int srate2mpeg4fi[] = { · 11 unmodified lines |
| 432 | }; | 486 | }; |
| 433 | | 487 | |
| 434 | static int | 488 | static int |
| 435 | dumptrack(Biobuf *f, int id) | 489 | dumpstc(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 | |
| | 557 | static int |
| | 558 | dumptrun(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 | |
| | 611 | static int |
| | 612 | dumptrack(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 | |
| 541 | int | 715 | int |
| @@ -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 | else | 945 | 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 |
| 950 | static void | 1154 | static void |
| 951 | usage(void) | 1155 | usage(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 | } |