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 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
22 #include "../../config.h"
28 #include "../rfxswf.h"
30 #include "h263tables.h"
32 static char * filename = 0;
33 static char * indent = " ";
37 struct options_t options[] =
49 int args_callback_option(char*name,char*val)
51 if(!strcmp(name, "V")) {
52 printf("swfdump - part of %s %s\n", PACKAGE, VERSION);
55 else if(name[0]=='d') {
59 else if(name[0]=='v') {
64 printf("Unknown option: -%s\n", name);
70 int args_callback_longoption(char*name,char*val)
72 return args_long2shortoption(options, name, val);
74 void args_callback_usage(char*name)
76 printf("Usage: %s [-at] file.swf\n", name);
77 printf("\t-h , --help\t\t Print help and exit\n");
78 printf("\t-d , --hex\t\t Print hex output of tag data, too\n");
79 printf("\t-v , --verbose\t\t Print debugging information\n");
80 printf("\t-V , --version\t\t Print program version and exit\n");
82 int args_callback_command(char*name,char*val)
85 fprintf(stderr, "Only one file allowed. You supplied at least two. (%s and %s)\n",
92 #define DEBUG if(debug)
94 void handleVideoStream(TAG*tag, char*prefix)
96 U16 id = swf_GetU16(tag);
97 U16 frames = swf_GetU16(tag);
98 U16 width = swf_GetU16(tag);
99 U16 height = swf_GetU16(tag);
100 U8 flags = swf_GetU8(tag); //5-2(videopacket 01=off 10=on)-1(smoothing 1=on)
101 U8 codec = swf_GetU8(tag);
102 printf(" (%d frames, %dx%d", frames, width, height);
106 printf(" sorenson h.263)");
108 printf(" codec 0x%02x)", codec);
111 int checkhufftable(struct huffcode*code, char*name)
114 while(code[t].code) {
116 if(strlen(code[t].code)!=code[t].len) {
117 printf("len mismatch in %s, index %d\n", name, t);
120 if(t != code[t].index) {
121 printf("index mismatch in %s, index %d\n", name, t);
124 while(code[s].code) {
125 char*a = code[s].code;
126 char*b = code[t].code;
129 if(s==t) {s++;continue;}
130 if(code[t].len < code[s].len) {
135 if(!strncmp(a,b,strlen(a))) {
136 printf("index %d (%s) is prefix of %d (%s)\n", ai, a, bi, b);
150 struct hufftree*left;//0
151 struct hufftree*right;//1
155 struct hufftree * rle_tree;
156 struct hufftree * mcbpc_intra_tree;
157 struct hufftree * mcbpc_inter_tree;
158 struct hufftree * cbpy_tree;
159 struct hufftree * mvd_tree;
161 static void insert(struct hufftree*tree, char*code, int index)
164 assert(!tree->left); //shannon conditional
165 assert(!tree->right);
173 tree->left = (struct hufftree*)malloc(sizeof(struct hufftree));
174 memset(tree->left, 0, sizeof(struct hufftree));
175 tree->left->index = -1;
177 insert(tree->left, code+1, index);
180 assert(code[0] == '1');
182 tree->right = (struct hufftree*)malloc(sizeof(struct hufftree));
183 memset(tree->right, 0, sizeof(struct hufftree));
184 tree->right->index = -1;
186 insert(tree->right, code+1, index);
191 struct hufftree* huffcode2tree(struct huffcode*code)
193 struct hufftree* t = malloc(sizeof(struct hufftree));
194 memset(t, 0, sizeof(struct hufftree));
197 insert(t, code->code, code->index);
203 int gethuffvalue(TAG*tag, struct huffcode*code)
209 bits[len] = swf_GetBits(tag, 1)+0x30;
212 while(code[t].code) {
213 if(!strcmp(bits, code[t].code))
216 if(code[t].len >= len)
221 printf("error: %s\n", bits);
222 while(tag->pos < tag->len && nr<80) {
223 int b = swf_GetBits(tag, 1);
235 /*type = 0; // mb-type =3, cbpc = 00
237 printf("can't handle i-frame mcbpc bits %d yet\n", bit);
239 bit = swf_GetBits(tag, 1);
240 type = 0; // mb-type =0, cbpc = 00
242 bit = swf_GetBits(tag, 2);
243 type = 8; // mb-type =2, cbpc = 00
245 printf("can't handle p-frame mcbpc bits 0-%d yet\n", bit);
251 int gethuffvalue2(TAG*tag, struct huffcode*code, struct hufftree*tree)
257 if(!swf_GetBits(tag, 1)) {
267 void get_DC_TCOEF(TAG*tag, int t, int has_dc, int has_tcoef)
270 int ac;// = swf_GetBits();
275 memset(line, 0, sizeof(line));
277 //printf("DC:%d\n", dc);
279 dc = swf_GetBits(tag, 8);
280 if(dc == 0 || dc == 128) {
281 printf("error: dc=%d\n", dc);
284 DEBUG if(show_rle_code) printf(" %d ", dc);
290 DEBUG if(show_rle_code) printf("[");
295 index = gethuffvalue2(tag, rle, rle_tree);
296 last = rle_params[index].last;
297 run = rle_params[index].run;
298 level = rle_params[index].level;
299 //DEBUG printf("index:%d\n", index);
300 if(index == RLE_ESCAPE) {
301 last = swf_GetBits(tag, 1);
302 run = swf_GetBits(tag, 6);
303 level = swf_GetBits(tag, 8);
305 DEBUG if(show_rle_code) printf(" (%d) E%d", run, level);
307 DEBUG if(show_rle_code) printf("E");
309 if(level == 0 || level == 128) {
310 printf("error: level=%d\n", level);
313 level = (int)((signed char)level);
315 int sign = swf_GetBits(tag, 1);
320 DEBUG if(show_rle_code) printf(" (%d) %s%d", run, level>0?"+":"",level);
322 DEBUG if(show_rle_code) printf(" %s%d", level>0?"+":"",level);
327 printf("\nerror:bad pos: %d\n", pos);
331 //DEBUG printf("run:%d level:%d\n", run, level);
333 DEBUG if(show_rle_code) printf("] pos: %d", pos);
335 printf("\nerror:bad pos (%d)\n", pos);
342 DEBUG if(show_rle_code) printf("\n");
346 DEBUG printf("%d", line[t]);
347 DEBUG if(t<pos-1) printf(" ");
354 int index = gethuffvalue2(tag, mvd, mvd_tree);
355 DEBUG printf("mvd index:%d\n", index);
359 char has_quant[] = {0,1,0,0,1};
360 char has_mvd[] = {1,1,3,0,0};
367 void decode_block(TAG*tag, int pictype)
370 int mb_type = -1, cbpc = -1;
372 int cbpy_index, cbpy_value;
375 if(pictype == TYPE_INTER) /* non-intra pictures have a cod flag */
377 int cod = swf_GetBits(tag, 1);
378 DEBUG printf("cod=%d\n",cod);
388 if(pictype == TYPE_INTRA) { /* I-frame */
389 type = gethuffvalue2(tag, mcbpc_intra, mcbpc_intra_tree);
390 DEBUG printf("mcbpc=%d\n",type);
391 mb_type = mcbpc_intra_params[type].mb_type;
392 cbpc = mcbpc_intra_params[type].cbpc;
393 if(type == MCBPC_INTRA_STUFFING) {
394 printf("stuffing not supported yet!\n");
395 exit(1); //TODO: goto COD
398 else if(pictype == 1) { /* P-frame */
399 type = gethuffvalue2(tag, mcbpc_inter, mcbpc_inter_tree);
400 DEBUG printf("mcbpc=%d\n",type);
401 mb_type = mcbpc_inter_params[type].mb_type;
402 cbpc = mcbpc_inter_params[type].cbpc;
403 if(type == MCBPC_INTER_STUFFING) {
404 printf("stuffing not supported yet!(2)\n");
405 exit(1); //TODO: goto COD
409 if(mb_type == 3 || mb_type == 4)
414 printf("%c", "vqVii"[mb_type]);
416 DEBUG printf("mcbpc type: %d mb_type:%d cbpc:%d\n", type, mb_type, cbpc);
420 cbpy_index = gethuffvalue2(tag, cbpy, cbpy_tree);
421 cbpy_value = cbpy_index;
424 DEBUG printf("cbpy value:%d (%d)\n", cbpy_value, cbpy_index);
427 /* I 0: 00 mcbpc/cbpy
428 P 0: 00 cod/mcbpc/cbpy/mvd
429 P 6: 10 cod/mcbpc/cbpy/dquant/mvd
430 P 8: 00 cod/mcbpc/cbpy/mvd/mvd24
434 if(has_quant[mb_type]) {
435 dquant = swf_GetBits(tag, 2);
436 if(dquant == 0) dquant = -1;
437 else if(dquant == 1) dquant = -2;
438 else if(dquant == 2) dquant = +1;
439 else if(dquant == 3) dquant = +2;
440 DEBUG printf("dquant: %d\n", dquant);
443 if(has_mvd[mb_type]&1) {
445 x = readMVD(tag); //horizontal
446 y = readMVD(tag); //vertical
448 printf("
\b0"); // prediction was 100% match
451 if(has_mvd[mb_type]&2) {
452 /* only in advanced prediction mode */
453 readMVD(tag); //horizontal
454 readMVD(tag); //vertical
455 readMVD(tag); //horizontal
456 readMVD(tag); //vertical
457 readMVD(tag); //horizontal
458 readMVD(tag); //vertical
462 int has_intradc = intrablock;
463 int has_tcoef = cbpy_value & (8>>t);
464 DEBUG printf("luminance%d ", t);
465 get_DC_TCOEF(tag, t, has_intradc, has_tcoef); /*luminance - affected by cbpy*/
468 int has_intradc = intrablock;
469 int has_tcoef = cbpc & (2>>t);
470 DEBUG printf("chrominance%d ", t);
471 get_DC_TCOEF(tag, t, has_intradc, has_tcoef); /*chrominance - affected by mcbc*/
475 void handleVideoFrame(TAG*tag, char*prefix)
477 U32 code, version, reference, sizeflags;
479 U8 blocktype, pictype;
480 U16 id = swf_GetU16(tag);
481 U16 frame = swf_GetU16(tag);
482 U8 deblock,flags, tmp, bit;
483 U32 quantizer, extrainfo;
490 char*types[] = {"intra- (I-)frame", "inter- (P-)frame", "disposable interframe", "<reserved>"};
491 printf("============================= frame %d ===================================", frame);
493 /* video packet follows */
495 code = swf_GetBits(tag, 17);
497 printf("code: %x (?)\n", code);
500 version = swf_GetBits(tag, 5); /*actually, part of the picture start code */
501 //printf("version: %x\n", version); /*usually 0*/
503 /* version 1 has some different transform coefficient coding which we
505 printf("spark version %d not supported yet\n", version);
508 reference = swf_GetBits(tag, 8);
509 DEBUG printf("reference: %d\n", reference); /*usually same as frame number (unless frames were skipped while encoding)*/
511 sizeflags = swf_GetBits(tag, 3);
514 case 0: width = swf_GetBits(tag,8); height = swf_GetBits(tag,8); break;
515 case 1: width = swf_GetBits(tag, 16); height = swf_GetBits(tag, 16); break;
516 case 2: width = 352; height = 288; break;
517 case 3: width = 176; height = 144; break;
518 case 4: width = 128; height = 96; break;
519 case 5: width = 320; height = 240; break;
520 case 6: width = 160; height = 120; break;
521 case 7: width = -1; height = -1;/*reserved*/ break;
524 pictype = swf_GetBits(tag, 2);
526 printf("error: unknown pictype: %d\n", pictype);
530 pictype = TYPE_INTER;
533 if(pictype==TYPE_INTER)
534 printf("INTER P%s", disposable?" (disposeable)":"");
538 deblock = swf_GetBits(tag, 1); /*usually 0*/
539 DEBUG printf("deblock: %d\n", deblock);
540 quantizer = swf_GetBits(tag, 5); /*usually 9*/
541 DEBUG printf("quantizer: %d\n", quantizer);
543 extrainfo = swf_GetBits(tag, 1); /*usually none */
545 extrainfo = swf_GetBits(tag, 8);
546 printf("extrainfo: %02x\n", extrainfo);
547 extrainfo = swf_GetBits(tag, 1);
552 bby = (height+15)/16;
554 printf("%dx%d [blocks: %dx%d=%d]\n", width, height, bbx,bby, blocknum);
556 /*if(pictype == TYPE_INTER)
558 /*if(pictype == TYPE_INTRA)
566 for(by=0;by<bby;by++)
568 for(bx=0;bx<bbx;bx++)
570 decode_block(tag, pictype);
576 void hexdumpTag(TAG*tag, char* prefix)
579 printf(" %s-=> ",prefix);
580 for(t=0;t<tag->len;t++) {
581 printf("%02x ", tag->data[t]);
582 if((t && ((t&15)==15)) || (t==tag->len-1))
587 printf("\n %s-=> ",prefix);
592 int main (int argc,char ** argv)
601 checkhufftable(rle, "rle");
602 checkhufftable(mcbpc_intra, "intra");
603 checkhufftable(mcbpc_inter, "inter");
604 checkhufftable(cbpy, "cbpy");
605 checkhufftable(mvd, "mvd");
607 rle_tree = huffcode2tree(rle);
608 mcbpc_intra_tree = huffcode2tree(mcbpc_intra);
609 mcbpc_inter_tree = huffcode2tree(mcbpc_inter);
610 cbpy_tree = huffcode2tree(cbpy);
611 mvd_tree = huffcode2tree(mvd);
613 processargs(argc, argv);
615 fprintf(stderr, "You must supply a filename.\n");
619 f = open(filename,O_RDONLY);
622 perror("Couldn't open file: ");
625 if FAILED(swf_ReadSWF(f,&swf)) {
626 fprintf(stderr, "%s is not a valid SWF file or contains errors.\n",filename);
633 printf("[HEADER] File version: %d\n", swf.fileVersion);
635 printf("[HEADER] File is zlib compressed.");
636 if(filesize && swf.fileSize)
637 printf(" Ratio: %02d%%\n", filesize*100/(swf.fileSize));
641 printf("[HEADER] File size: %ld%s\n", swf.fileSize, swf.compressed?" (Depacked)":"");
642 printf("[HEADER] Frame rate: %f\n",swf.frameRate/256.0);
643 printf("[HEADER] Frame count: %d\n",swf.frameCount);
644 printf("[HEADER] Movie width: %.2f",(swf.movieSize.xmax-swf.movieSize.xmin)/20.0);
645 if(swf.movieSize.xmin)
646 printf(" (left offset: %.2f)\n", swf.movieSize.xmin/20.0);
649 printf("[HEADER] Movie height: %.2f",(swf.movieSize.ymax-swf.movieSize.ymin)/20.0);
650 if(swf.movieSize.ymin)
651 printf(" (top offset: %.2f)\n", swf.movieSize.ymin/20.0);
658 char*name = swf_TagGetName(tag);
660 //printf("[%03x] %9ld %s%s", tag->id, tag->len, prefix, swf_TagGetName(tag));
662 if(swf_isDefiningTag(tag)) {
663 U16 id = swf_GetDefineID(tag);
664 //printf(" defines id %04d", id);
666 else if(swf_isPseudoDefiningTag(tag)) {
667 U16 id = swf_GetDefineID(tag);
668 //printf(" adds information to id %04d", id);
671 if(tag->id == ST_VIDEOFRAME) {
672 handleVideoFrame(tag, myprefix);
675 else if(tag->id == ST_DEFINEVIDEOSTREAM) {
676 handleVideoStream(tag, myprefix);
683 sprintf(myprefix, " %s", prefix);
685 if(tag->len && hex) {
686 hexdumpTag(tag, prefix);