2 Shows the structure of a swf file containing video
4 Part of the swftools package.
6 Copyright (c) 2003 Matthias Kramm <kramm@quiss.org> */
8 #include "../../config.h"
13 #include "../rfxswf.h"
15 #include "h263tables.c"
17 static char * filename = 0;
18 static char * indent = " ";
22 struct options_t options[] =
34 int args_callback_option(char*name,char*val)
36 if(!strcmp(name, "V")) {
37 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
40 else if(name[0]=='d') {
44 else if(name[0]=='v') {
49 printf("Unknown option: -%s\n", name);
55 int args_callback_longoption(char*name,char*val)
57 return args_long2shortoption(options, name, val);
59 void args_callback_usage(char*name)
61 printf("Usage: %s [-at] file.swf\n", name);
62 printf("\t-h , --help\t\t Print help and exit\n");
63 printf("\t-d , --hex\t\t Print hex output of tag data, too\n");
64 printf("\t-v , --verbose\t\t Print debugging information\n");
65 printf("\t-V , --version\t\t Print program version and exit\n");
67 int args_callback_command(char*name,char*val)
70 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
77 #define DEBUG if(debug)
79 void handleVideoStream(TAG*tag, char*prefix)
81 U16 id = swf_GetU16(tag);
82 U16 frames = swf_GetU16(tag);
83 U16 width = swf_GetU16(tag);
84 U16 height = swf_GetU16(tag);
85 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
86 U8 codec = swf_GetU8(tag);
87 printf(" (%d frames, %dx%d", frames, width, height);
91 printf(" sorenson h.263)");
93 printf(" codec 0x%02x)", codec);
96 int checkhufftable(struct huffcode*code, char*name)
101 if(strlen(code[t].code)!=code[t].len) {
102 printf("len mismatch in %s, index %d\n", name, t);
105 if(t != code[t].index) {
106 printf("index mismatch in %s, index %d\n", name, t);
109 while(code[s].code) {
110 char*a = code[s].code;
111 char*b = code[t].code;
114 if(s==t) {s++;continue;}
115 if(code[t].len < code[s].len) {
120 if(!strncmp(a,b,strlen(a))) {
121 printf("index %d (%s) is prefix of %d (%s)\n", ai, a, bi, b);
132 int gethuffvalue(TAG*tag, struct huffcode*code)
138 bits[len] = swf_GetBits(tag, 1)+0x30;
141 while(code[t].code) {
142 if(!strcmp(bits, code[t].code))
145 if(code[t].len >= len)
150 printf("error: %s\n", bits);
151 while(tag->pos < tag->len && nr<80) {
152 int b = swf_GetBits(tag, 1);
164 /*type = 0; // mb-type =3, cbpc = 00
166 printf("can't handle i-frame mcbpc bits %d yet\n", bit);
168 bit = swf_GetBits(tag, 1);
169 type = 0; // mb-type =0, cbpc = 00
171 bit = swf_GetBits(tag, 2);
172 type = 8; // mb-type =2, cbpc = 00
174 printf("can't handle p-frame mcbpc bits 0-%d yet\n", bit);
180 void get_DC_TCOEF(TAG*tag, int t, int has_dc, int has_tcoef)
183 int ac;// = swf_GetBits();
186 //printf("DC:%d\n", dc);
188 dc = swf_GetBits(tag, 8);
189 if(dc == 0 || dc == 128) {
190 printf("error: dc=%d\n", dc);
193 DEBUG printf(" %d ", dc);
203 index = gethuffvalue(tag, rle);
204 last = rle_params[index].last;
205 run = rle_params[index].run;
206 level = rle_params[index].level;
207 //DEBUG printf("index:%d\n", index);
208 if(index == RLE_ESCAPE) {
209 last = swf_GetBits(tag, 1);
210 run = swf_GetBits(tag, 6);
211 level = swf_GetBits(tag, 8);
213 DEBUG printf("(%d) E%d", run, level);
216 if(level == 0 || level == 128) {
217 printf("error: level=%d\n", level);
220 level = (int)((signed char)level);
222 int sign = swf_GetBits(tag, 1);
226 DEBUG printf("(%d) %s%d", run, level>0?"+":"",level);
228 DEBUG printf("%s%d", level>0?"+":"",level);
231 //DEBUG printf("run:%d level:%d\n", run, level);
233 DEBUG printf("] pos: %d", pos);
235 printf("\nerror:bad pos (%d)\n", pos);
244 void readMVD(TAG*tag)
246 int index = gethuffvalue(tag, mvd);
247 DEBUG printf("mvd index:%d\n", index);
250 char has_quant[] = {0,1,0,0,1};
251 char has_mvd[] = {1,1,3,0,0};
258 void decode_block(TAG*tag, int pictype)
261 int mb_type = -1, cbpc = -1;
263 int cbpy_index, cbpy_value;
266 if(pictype == TYPE_INTER) /* non-intra pictures have a cod flag */
268 int cod = swf_GetBits(tag, 1);
269 DEBUG printf("cod=%d\n",cod);
279 if(pictype == TYPE_INTRA) { /* I-frame */
280 type = gethuffvalue(tag, mcbpc_intra);
281 DEBUG printf("mcbpc=%d\n",type);
282 mb_type = mcbpc_intra_params[type].mb_type;
283 cbpc = mcbpc_intra_params[type].cbpc;
284 if(type == MCBPC_INTRA_STUFFING) {
285 printf("stuffing not supported yet!\n");
286 exit(1); //TODO: goto COD
289 else if(pictype == 1) { /* P-frame */
290 type = gethuffvalue(tag, mcbpc_inter);
291 DEBUG printf("mcbpc=%d\n",type);
292 mb_type = mcbpc_inter_params[type].mb_type;
293 cbpc = mcbpc_inter_params[type].cbpc;
294 if(type == MCBPC_INTER_STUFFING) {
295 printf("stuffing not supported yet!(2)\n");
296 exit(1); //TODO: goto COD
300 if(mb_type == 3 || mb_type == 4)
305 printf("%c", "vqVii"[mb_type]);
307 DEBUG printf("mcbpc type: %d mb_type:%d cbpc:%d\n", type, mb_type, cbpc);
311 cbpy_index = gethuffvalue(tag, cbpy);
312 cbpy_value = cbpy_index;
315 DEBUG printf("cbpy value:%d (%d)\n", cbpy_value, cbpy_index);
318 /* I 0: 00 mcbpc/cbpy
319 P 0: 00 cod/mcbpc/cbpy/mvd
320 P 6: 10 cod/mcbpc/cbpy/dquant/mvd
321 P 8: 00 cod/mcbpc/cbpy/mvd/mvd24
325 if(has_quant[mb_type]) {
326 dquant = swf_GetBits(tag, 2);
327 if(dquant == 0) dquant = -1;
328 else if(dquant == 1) dquant = -2;
329 else if(dquant == 2) dquant = +1;
330 else if(dquant == 3) dquant = +2;
331 DEBUG printf("dquant: %d\n", dquant);
334 if(has_mvd[mb_type]&1) {
335 readMVD(tag); //horizontal
336 readMVD(tag); //vertical
338 if(has_mvd[mb_type]&2) {
339 /* only in advanced prediction mode */
340 readMVD(tag); //horizontal
341 readMVD(tag); //vertical
342 readMVD(tag); //horizontal
343 readMVD(tag); //vertical
344 readMVD(tag); //horizontal
345 readMVD(tag); //vertical
349 int has_intradc = intrablock;
350 int has_tcoef = cbpy_value & (8>>t);
351 DEBUG printf("luminance%d ", t);
352 get_DC_TCOEF(tag, t, has_intradc, has_tcoef); /*luminance - affected by cbpy*/
356 int has_intradc = intrablock;
357 int has_tcoef = cbpc & (2>>t);
358 DEBUG printf("chrominance%d ", t);
359 get_DC_TCOEF(tag, t, has_intradc, has_tcoef); /*chrominance - affected by mcbc*/
364 void handleVideoFrame(TAG*tag, char*prefix)
366 U32 code, version, reference, sizeflags;
368 U8 blocktype, pictype;
369 U16 id = swf_GetU16(tag);
370 U16 frame = swf_GetU16(tag);
371 U8 deblock,flags, tmp, bit;
372 U32 quantizer, extrainfo;
379 char*types[] = {"intra- (I-)frame", "inter- (P-)frame", "disposable interframe", "<reserved>"};
380 printf("============================= frame %d ===================================", frame);
382 /* video packet follows */
384 code = swf_GetBits(tag, 17);
386 printf("code: %x (?)\n", code);
389 version = swf_GetBits(tag, 5); /*actually, part of the picture start code */
390 //printf("version: %x\n", version); /*usually 0*/
392 /* version 1 has some different transform coefficient coding which we
394 printf("spark version %d not supported yet\n", version);
397 reference = swf_GetBits(tag, 8);
398 DEBUG printf("reference: %d\n", reference); /*usually same as frame number (unless frames were skipped while encoding)*/
400 sizeflags = swf_GetBits(tag, 3);
403 case 0: width = swf_GetBits(tag,8); height = swf_GetBits(tag,8); break;
404 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
405 case 2: width = 352; height = 288; break;
406 case 3: width = 176; height = 144; break;
407 case 4: width = 128; height = 96; break;
408 case 5: width = 320; height = 240; break;
409 case 6: width = 160; height = 120; break;
410 case 7: width = -1; height = -1;/*reserved*/ break;
413 pictype = swf_GetBits(tag, 2);
415 printf("error: unknown pictype: %d\n", pictype);
419 pictype = TYPE_INTER;
422 if(pictype==TYPE_INTER)
423 printf("INTER P%s", disposable?" (disposeable)":"");
427 deblock = swf_GetBits(tag, 1); /*usually 0*/
428 DEBUG printf("deblock: %d\n", deblock);
429 quantizer = swf_GetBits(tag, 5); /*usually 9*/
430 DEBUG printf("quantizer: %d\n", quantizer);
432 extrainfo = swf_GetBits(tag, 1); /*usually none */
434 extrainfo = swf_GetBits(tag, 8);
435 printf("extrainfo: %02x\n", extrainfo);
436 extrainfo = swf_GetBits(tag, 1);
441 bby = (height+15)/16;
443 printf("%dx%d [blocks: %dx%d=%d]\n", width, height, bbx,bby, blocknum);
445 /*if(pictype == TYPE_INTER)
447 /*if(pictype == TYPE_INTRA)
455 for(by=0;by<bby;by++)
457 for(bx=0;bx<bbx;bx++)
459 decode_block(tag, pictype);
465 void hexdumpTag(TAG*tag, char* prefix)
468 printf(" %s-=> ",prefix);
469 for(t=0;t<tag->len;t++) {
470 printf("%02x ", tag->data[t]);
471 if((t && ((t&15)==15)) || (t==tag->len-1))
476 printf("\n %s-=> ",prefix);
481 int main (int argc,char ** argv)
490 checkhufftable(rle, "rle");
491 checkhufftable(mcbpc_intra, "intra");
492 checkhufftable(mcbpc_inter, "inter");
493 checkhufftable(cbpy, "cbpy");
494 checkhufftable(mvd, "mvd");
496 processargs(argc, argv);
498 fprintf(stderr, "You must supply a filename.\n");
502 f = open(filename,O_RDONLY);
505 perror("Couldn't open file: ");
508 if FAILED(swf_ReadSWF(f,&swf)) {
509 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
516 printf("[HEADER] File version: %d\n", swf.fileVersion);
518 printf("[HEADER] File is zlib compressed.");
519 if(filesize && swf.fileSize)
520 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
524 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
525 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
526 printf("[HEADER] Frame count: %d\n",swf.frameCount);
527 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
528 if(swf.movieSize.xmin)
529 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
532 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
533 if(swf.movieSize.ymin)
534 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
541 char*name = swf_TagGetName(tag);
543 //printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
545 if(swf_isDefiningTag(tag)) {
546 U16 id = swf_GetDefineID(tag);
547 //printf(" defines id %04d", id);
549 else if(swf_isPseudoDefiningTag(tag)) {
550 U16 id = swf_GetDefineID(tag);
551 //printf(" adds information to id %04d", id);
554 if(tag->id == ST_VIDEOFRAME) {
555 handleVideoFrame(tag, myprefix);
558 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
559 handleVideoStream(tag, myprefix);
566 sprintf(myprefix, " %s", prefix);
568 if(tag->len && hex) {
569 hexdumpTag(tag, prefix);