ebe859ab24a2569e9480109842e021f219bcbe0c
[swftools.git] / lib / h.263 / mkvideo.c
1 /* mkvideo.c
2    Create a video file.
3
4    Part of the swftools package.
5    
6    Copyright (c) 2003 Matthias Kramm <kramm@quiss.org> */
7
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <assert.h>
11 #include <math.h>
12 #include "../lib/rfxswf.h"
13 #include "png.h"
14 #include "h263tables.c"
15
16 typedef struct _YUV
17 {
18     unsigned char y,u,v;
19 } YUV;
20
21 typedef struct _VIDEOSTREAM
22 {
23     int width;
24     int height;
25     int frame;
26     int linex;
27     YUV*oldpic;
28     YUV*current;
29 } VIDEOSTREAM;
30
31 void swf_SetVideoStreamDefine(TAG*tag, VIDEOSTREAM*stream, U16 frames, U16 width, U16 height)
32 {
33     width=width&~15; height=height&~15;
34     swf_SetU16(tag, frames);
35     swf_SetU16(tag, width);
36     swf_SetU16(tag, height);
37     swf_SetU8(tag, 1); /* smoothing on */
38     swf_SetU8(tag, 2); /* codec = h.263 sorenson spark */
39
40     memset(stream, 0, sizeof(VIDEOSTREAM));
41     stream->linex = width;
42     width&=~15;
43     height&=~15;
44     stream->width = width;
45     stream->height = height;
46     stream->current = (YUV*)malloc(width*height*sizeof(YUV));
47     stream->oldpic = (YUV*)malloc(width*height*sizeof(YUV));
48
49     memset(stream->oldpic, 0, width*height*sizeof(YUV));
50 }
51
52 typedef struct _block_t
53 {
54     int y1[64];
55     int y2[64];
56     int y3[64];
57     int y4[64];
58     int u[64];
59     int v[64];
60 } block_t;
61
62 typedef struct _fblock_t
63 {
64     double y1[64];
65     double y2[64];
66     double y3[64];
67     double y4[64];
68     double u[64];
69     double v[64];
70 } fblock_t;
71
72 static int zigzagtable[64] = {
73     0, 1, 5, 6, 14, 15, 27, 28, 
74     2, 4, 7, 13, 16, 26, 29, 42, 
75     3, 8, 12, 17, 25, 30, 41, 43, 
76     9, 11, 18, 24, 31, 40, 44, 53, 
77     10, 19, 23, 32, 39, 45, 52, 54, 
78     20, 22, 33, 38, 46, 51, 55, 60, 
79     21, 34, 37, 47, 50, 56, 59, 61, 
80     35, 36, 48, 49, 57, 58, 62, 63};
81
82 static void fzigzag(double*src) 
83 {
84     double tmp[64];
85     int t;
86     for(t=0;t<64;t++) {
87         ((int*)&tmp[zigzagtable[t]])[0] = ((int*)&src[t])[0];
88         ((int*)&tmp[zigzagtable[t]])[1] = ((int*)&src[t])[1];
89     }
90     memcpy(src, tmp, sizeof(double)*64);
91 }
92
93 #define PI 3.14159265358979
94 #define SQRT2 1.414214
95 #define RSQRT2 (1.0/1.414214)
96
97 static double table[8][8] =
98 {
99 {0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548},
100 {0.980785280403230,0.831469612302545,0.555570233019602,0.195090322016128,-0.195090322016128,-0.555570233019602,-0.831469612302545,-0.980785280403230},
101 {0.923879532511287,0.382683432365090,-0.382683432365090,-0.923879532511287,-0.923879532511287,-0.382683432365090,0.382683432365090,0.923879532511287},
102 {0.831469612302545,-0.195090322016128,-0.980785280403230,-0.555570233019602,0.555570233019602,0.980785280403230,0.195090322016129,-0.831469612302545},
103 {0.707106781186548,-0.707106781186547,-0.707106781186548,0.707106781186547,0.707106781186548,-0.707106781186547,-0.707106781186547,0.707106781186547},
104 {0.555570233019602,-0.980785280403230,0.195090322016128,0.831469612302545,-0.831469612302545,-0.195090322016128,0.980785280403231,-0.555570233019602},
105 {0.382683432365090,-0.923879532511287,0.923879532511287,-0.382683432365090,-0.382683432365091,0.923879532511287,-0.923879532511286,0.382683432365090},
106 {0.195090322016128,-0.555570233019602,0.831469612302545,-0.980785280403231,0.980785280403230,-0.831469612302545,0.555570233019602,-0.195090322016129}
107 };
108
109 static void dct(double*src)
110 {
111     double tmp[64];
112     int x,y,u,v,t;
113
114     for(v=0;v<8;v++)
115     for(u=0;u<8;u++)
116     {
117         double c = 0;
118         for(x=0;x<8;x++)
119         {
120             c+=table[u][x]*src[v*8+x];
121         }
122         tmp[v*8+u] = c;
123     }
124     for(u=0;u<8;u++)
125     for(v=0;v<8;v++)
126     {
127         double c = 0;
128         for(y=0;y<8;y++)
129         {
130             c+=table[v][y]*tmp[y*8+u];
131         }
132         src[v*8+u] = c*0.25;
133     }
134 }
135
136 static void idct(double*src)
137 {
138     double tmp[64];
139     int x,y,u,v;
140     for(y=0;y<8;y++)
141     for(x=0;x<8;x++)
142     {
143         double c = 0;
144         for(u=0;u<8;u++)
145         {
146             c+=table[u][x]*src[y*8+u];
147         }
148         tmp[y*8+x] = c;
149     }
150     for(y=0;y<8;y++)
151     for(x=0;x<8;x++)
152     {
153         double c = 0;
154         for(v=0;v<8;v++)
155         {
156             c+=table[v][y]*tmp[v*8+x];
157         }
158         src[y*8+x] = c*0.25;
159     }
160 }
161
162 static inline int truncate256(int a)
163 {
164     if(a>255) return 255;
165     if(a<0) return 0;
166     return a;
167 }
168
169 static void getregion(fblock_t* bb, YUV*pic, int bx, int by, int linex)
170 {
171     YUV*p1 = &pic[by*linex*16+bx*16];
172     YUV*p2 = p1;
173     int y1=0, y2=0, y3=0, y4=0;
174     int u=0,v=0;
175     int x,y;
176     for(y=0;y<8;y++) {
177         for(x=0;x<8;x++) {
178             bb->u[u++] = (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4;
179             bb->v[v++] = (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4;
180             bb->y1[y1++] = p1[x].y;
181             bb->y2[y2++] = p1[x+8].y;
182             bb->y3[y3++] = p1[linex*8+x].y;
183             bb->y4[y4++] = p1[linex*8+x+8].y;
184         }
185         p1+=linex;
186         p2+=linex*2;
187     }
188 }
189 static void rgb2yuv(YUV*dest, RGBA*src, int linex, int width, int height)
190 {
191     int x,y;
192     for(y=0;y<height;y++) {
193         for(x=0;x<width;x++) {
194             double r,g,b;
195             r = src[y*linex+x].r;
196             g = src[y*linex+x].g;
197             b = src[y*linex+x].b;
198             dest[y*linex+x].y = (r*0.299 + g*0.587 + b*0.114);
199             dest[y*linex+x].u = (r*-0.169 + g*-0.332 + b*0.500 + 128.0);
200             dest[y*linex+x].v = (r*0.500 + g*-0.419 + b*-0.0813 + 128.0);
201         }
202     }
203 }
204 static void copyregion(VIDEOSTREAM*s, YUV*dest, YUV*src, int bx, int by)
205 {
206     YUV*p1 = &src[by*s->linex*16+bx*16];
207     YUV*p2 = &dest[by*s->linex*16+bx*16];
208     int y;
209     for(y=0;y<16;y++) {
210         memcpy(p1, p2, 16*sizeof(YUV));
211         p1+=s->linex;p2+=s->linex;
212     }
213 }
214
215 static void yuv2rgb(RGBA*dest, YUV*src, int linex, int width, int height)
216 {
217     int x,y;
218     for(y=0;y<height;y++) {
219         for(x=0;x<width;x++) {
220             int u,v,yy;
221             u = src[y*linex+x].u;
222             v = src[y*linex+x].v;
223             yy = src[y*linex+x].y;
224             dest[y*linex+x].r = truncate256(yy + ((360*(v-128))>>8));
225             dest[y*linex+x].g = truncate256(yy - ((88*(u-128)+183*(v-128))>>8));
226             dest[y*linex+x].b = truncate256(yy + ((455 * (u-128))>>8));
227         }
228     }
229 }
230 static void copyblock(VIDEOSTREAM*s, YUV*dest, block_t*b, int bx, int by)
231 {
232     YUV*p1 = &dest[(by*16)*s->linex+bx*16];
233     YUV*p2 = &dest[(by*16+8)*s->linex+bx*16];
234     int x,y;
235     for(y=0;y<8;y++) {
236         for(x=0;x<8;x++) {
237             int u,v,yy;
238             p1[x+0].u = b->u[(y/2)*8+(x/2)];
239             p1[x+0].v = b->v[(y/2)*8+(x/2)]; 
240             p1[x+0].y = b->y1[y*8+x];
241             p1[x+8].u = b->u[(y/2)*8+(x/2)+4];
242             p1[x+8].v = b->v[(y/2)*8+(x/2)+4]; 
243             p1[x+8].y = b->y2[y*8+x];
244             p2[x+0].u = b->u[(y/2+4)*8+(x/2)];
245             p2[x+0].v = b->v[(y/2+4)*8+(x/2)]; 
246             p2[x+0].y = b->y3[y*8+x];
247             p2[x+8].u = b->u[(y/2+4)*8+(x/2)+4];
248             p2[x+8].v = b->v[(y/2+4)*8+(x/2)+4]; 
249             p2[x+8].y = b->y4[y*8+x];
250         }
251         p1+=s->linex;
252         p2+=s->linex;
253     }
254 }
255
256 static int compareregions(VIDEOSTREAM*s, int bx, int by)
257 {
258     int linex = s->width;
259     YUV*p1 = &s->current[by*linex*16+bx*16];
260     YUV*p2 = &s->oldpic[by*linex*16+bx*16];
261     int diff = 0;
262     int x,y;
263     for(y=0;y<16;y++) {
264         for(x=0;x<16;x++) {
265             YUV*m = &p1[x];
266             YUV*n = &p2[x];
267             int y = m->y - n->y;
268             int u = m->u - n->u;
269             int v = m->v - n->v;
270             diff += y*y+(u*u+v*v)/4;
271         }
272         p1+=linex;
273         p2+=linex;
274     }
275     return diff/256;
276 }
277
278 static int valtodc(int val)
279 {
280     assert(val>=0);
281
282     /* table 12/h.263 */
283
284     //val+=4; //round
285     val/=8;
286     /* TODO: what to do for zero values? skip the block? */
287     if(val==0)
288         return 1;
289     if(val==128)
290         return 255;
291     if(val>254)
292         return 254;
293     return val;
294 }
295 static int dctoval(int dc)
296 {
297     int val;
298     assert(dc>0);
299     assert(dc!=128);
300     assert(dc<256);
301     /* table 12/h.263 */
302     val = dc*8;
303     if(val == 255*8)
304         val = 128*8;
305     return val;
306 }
307
308 static int codehuffman(TAG*tag, struct huffcode*table, int index)
309 {
310     /* TODO: !optimize! */
311     int i=0;
312     while(table[index].code[i]) {
313         if(table[index].code[i]=='0')
314             swf_SetBits(tag, 0, 1);
315         else
316             swf_SetBits(tag, 1, 1);
317         i++;
318     }
319     return i;
320 }
321
322 static void quantize8x8(double*src, int*dest, int has_dc, int quant)
323 {
324     int t,pos=0;
325     if(has_dc) {
326         dest[0] = valtodc((int)src[0]); /*DC*/
327         pos++;
328     }
329     for(t=pos;t<64;t++)
330     {
331         dest[t] = (int)src[t];
332     /* exact: if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;} */
333         //if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;}
334         dest[t] = dest[t]/(quant*2);
335     }
336 }
337
338 static void dequantize8x8(int*b, int has_dc, int quant)
339 {
340     int t,pos=0;
341     if(has_dc) {
342         b[0] = dctoval(b[0]); //DC
343         pos++;
344     }
345     for(t=pos;t<64;t++) {
346         if(b[t]) {
347             int sign = 0;
348             if(b[t]<0) {
349                 b[t] = -b[t];
350                 sign = 1;
351             }
352
353             if(quant&1) {
354                 b[t] = quant*(2*b[t]+1); //-7,8,24,40
355             } else {
356                 b[t] = quant*(2*b[t]+1)-1; //-8,7,23,39
357             }
358
359             if(sign)
360                 b[t] = -b[t];
361         }
362
363         /* paragraph 6.2.2, "clipping of reconstruction levels": */
364         if(b[t]>2047) b[t]=2047;
365         if(b[t]<-2048) b[t]=-2048;
366     }
367 }
368
369 static int hascoef(int*b, int has_dc)
370 {
371     int t;
372     int pos=0;
373     if(has_dc)
374         pos++;
375     for(t=pos;t<64;t++) {
376         if(b[t])
377             return 1;
378     }
379     return 0;
380 }
381
382 static void encode8x8(TAG*tag, int*bb, int has_dc, int has_tcoef)
383 {
384     int t;
385     int pos=0;
386
387     if(has_dc) {
388         swf_SetBits(tag, bb[0], 8);
389         pos++;
390     }
391
392     if(has_tcoef) {
393         int last;
394         /* determine last non-null coefficient */
395         for(last=63;last>=pos;last--) {
396             /* TODO: we could leave out small coefficients
397                      after a certain point (32?) */
398             if(bb[last])
399                 break;
400         }
401         /* blocks without coefficients should not be included
402            in the cbpy/cbpc patterns: */
403         assert(bb[last]);
404
405         while(1) {
406             int run=0;
407             int level=0;
408             int islast=0;
409             int sign=0;
410             int t;
411             while(!bb[pos] && pos<last) {
412                 pos++;
413                 run++;
414             }
415             if(pos==last)
416                 islast=1;
417             level=bb[pos];
418             assert(level);
419             if(level<0) {
420                 level = -level;
421                 sign = 1;
422             }
423             for(t=0;t<RLE_ESCAPE;t++) {
424                 if(rle_params[t].run == run &&
425                    rle_params[t].level == level &&
426                    rle_params[t].last == islast) {
427                     codehuffman(tag, rle, t);
428                     swf_SetBits(tag, sign, 1);
429                     break;
430                 }
431             }
432             if(t==RLE_ESCAPE) {
433                 codehuffman(tag, rle, RLE_ESCAPE);
434                 level=bb[pos];
435                 /* table 14/h.263 */
436                 assert(level);
437                 assert(level>=-127);
438                 assert(level<=127);
439
440                 swf_SetBits(tag, islast, 1);
441                 swf_SetBits(tag, run, 6);
442                 swf_SetBits(tag, level, 8); //FIXME: fixme??
443             }
444
445             if(islast)
446                 break;
447             pos++;
448         }
449     }
450 }
451
452 static void dodct(fblock_t*fb)
453 {
454     int t;
455     dct(fb->y1); dct(fb->y2); dct(fb->y3); dct(fb->y4); 
456     dct(fb->u);  dct(fb->v);  
457     fzigzag(fb->y1);
458     fzigzag(fb->y2);
459     fzigzag(fb->y3);
460     fzigzag(fb->y4);
461     fzigzag(fb->u);
462     fzigzag(fb->v); 
463 }
464
465 static void doidct(block_t*b)
466 {
467     fblock_t fb;
468     int t;
469     for(t=0;t<64;t++) {
470         fb.y1[t] = b->y1[zigzagtable[t]];
471         fb.y2[t] = b->y2[zigzagtable[t]];
472         fb.y3[t] = b->y3[zigzagtable[t]];
473         fb.y4[t] = b->y4[zigzagtable[t]];
474         fb.u[t] = b->u[zigzagtable[t]];
475         fb.v[t] = b->v[zigzagtable[t]];
476     }
477     idct(fb.y1); idct(fb.y2); idct(fb.y3); idct(fb.y4); 
478     idct(fb.u);  idct(fb.v);  
479     for(t=0;t<64;t++) {
480         b->y1[t] = fb.y1[t];
481         b->y2[t] = fb.y2[t];
482         b->y3[t] = fb.y3[t];
483         b->y4[t] = fb.y4[t];
484         b->u[t] = fb.u[t];
485         b->v[t] = fb.v[t];
486     }
487 }
488 static void truncateblock(block_t*b)
489 {
490     int t;
491     for(t=0;t<64;t++) {
492         b->y1[t] = truncate256(b->y1[t]);
493         b->y2[t] = truncate256(b->y2[t]);
494         b->y3[t] = truncate256(b->y3[t]);
495         b->y4[t] = truncate256(b->y4[t]);
496         b->u[t] = truncate256(b->u[t]);
497         b->v[t] = truncate256(b->v[t]);
498     }
499 }
500
501 static void quantize(fblock_t*fb, block_t*b, int has_dc, int quant)
502 {
503     quantize8x8(fb->y1, b->y1, has_dc, quant); 
504     quantize8x8(fb->y2, b->y2, has_dc, quant); 
505     quantize8x8(fb->y3, b->y3, has_dc, quant); 
506     quantize8x8(fb->y4, b->y4, has_dc, quant); 
507     quantize8x8(fb->u, b->u, has_dc, quant);   
508     quantize8x8(fb->v, b->v, has_dc, quant);   
509 }
510 static void dequantize(block_t*b, int has_dc, int quant)
511 {
512     dequantize8x8(b->y1, has_dc, quant); 
513     dequantize8x8(b->y2, has_dc, quant); 
514     dequantize8x8(b->y3, has_dc, quant); 
515     dequantize8x8(b->y4, has_dc, quant); 
516     dequantize8x8(b->u, has_dc, quant);   
517     dequantize8x8(b->v, has_dc, quant);   
518 }
519
520 static void getblockpatterns(block_t*b, int*cbpybits,int*cbpcbits, int has_dc)
521 {
522     *cbpybits = 0;
523     *cbpcbits = 0;
524
525     *cbpybits|=hascoef(b->y1, has_dc)*8;
526     *cbpybits|=hascoef(b->y2, has_dc)*4;
527     *cbpybits|=hascoef(b->y3, has_dc)*2;
528     *cbpybits|=hascoef(b->y4, has_dc)*1;
529
530     *cbpcbits|=hascoef(b->u, has_dc)*2;
531     *cbpcbits|=hascoef(b->v, has_dc)*1;
532 }
533
534 static void setQuant(TAG*tag, int dquant)
535 {
536     int code = 0;
537     /* 00 01 10 11
538        -1 -2 +1 +2
539     */
540     if(dquant == -1) {
541         swf_SetBits(tag, 0x0, 2);
542     } else if(dquant == -2) {
543         swf_SetBits(tag, 0x1, 2);
544     } else if(dquant == +1) {
545         swf_SetBits(tag, 0x2, 2);
546     } else if(dquant == +2) {
547         swf_SetBits(tag, 0x3, 2);
548     } else {
549         assert(0*strlen("invalid dquant"));
550     }
551 }
552
553 static void change_quant(int quant, int*dquant)
554 {
555     /* TODO */
556     *dquant = 0;
557 }
558
559 static void encode_blockI(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant)
560 {
561     fblock_t fb;
562     block_t b;
563     int dquant=0;
564     int cbpcbits = 0, cbpybits=0;
565
566     getregion(&fb, s->current, bx, by, s->width);
567     dodct(&fb);
568     
569     change_quant(*quant, &dquant);
570     *quant+=dquant;
571     quantize(&fb, &b, 1, *quant);
572
573     //decode_blockI(s, &b, bx, by);
574
575     getblockpatterns(&b, &cbpybits, &cbpcbits, 1);
576
577     if(dquant) {
578         codehuffman(tag, mcbpc_intra, 4+cbpcbits);
579     } else {
580         codehuffman(tag, mcbpc_intra, 0+cbpcbits);
581     }
582
583     codehuffman(tag, cbpy, cbpybits);
584
585     if(dquant) {
586         setQuant(tag, dquant);
587     }
588
589     /* luminance */
590     encode8x8(tag, b.y1, 1, cbpybits&8);
591     encode8x8(tag, b.y2, 1, cbpybits&4);
592     encode8x8(tag, b.y3, 1, cbpybits&2);
593     encode8x8(tag, b.y4, 1, cbpybits&1);
594
595     /* chrominance */
596     encode8x8(tag, b.u, 1, cbpcbits&2);
597     encode8x8(tag, b.v, 1, cbpcbits&1);
598
599     /* reconstruct */
600     dequantize(&b, 1, *quant);
601     doidct(&b);
602     truncateblock(&b);
603     copyblock(s, s->current, &b, bx, by);
604 }
605
606 static void yuvdiff(fblock_t*a, fblock_t*b)
607 {
608     int t;
609     for(t=0;t<64;t++) {
610         a->y1[t] = (a->y1[t] - b->y1[t]);
611         a->y2[t] = (a->y2[t] - b->y2[t]);
612         a->y3[t] = (a->y3[t] - b->y3[t]);
613         a->y4[t] = (a->y4[t] - b->y4[t]);
614         a->u[t]  = (a->u[t] - b->u[t]);
615         a->v[t]  = (a->v[t] - b->v[t]);
616     }
617 }
618
619 static void encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant)
620 {
621     fblock_t fb,fbdiff, fbold;
622     block_t b;
623     int dquant=0;
624     int has_mvd=0;
625     int has_mvd24=0;
626     int has_dc=1;
627     int mode = 0;
628     int cbpcbits = 0, cbpybits=0;
629     int diff;
630
631     diff = compareregions(s, bx, by);
632     if(diff < 24 /*TODO: should be a parameter- good values are between 32 and 48 */) {
633         swf_SetBits(tag, 1,1); /* cod=1, block skipped */
634         copyregion(s, s->current, s->oldpic, bx, by);
635         return;
636     }
637
638     getregion(&fb, s->current, bx, by, s->width);
639
640     //if(diff < 128)
641     if(1)
642     { 
643         /* mvd (0,0) block (mode=0) */
644         int t;
645         memcpy(&fbdiff, &fb, sizeof(fblock_t));
646         getregion(&fbold, s->oldpic, bx, by, s->linex);
647         yuvdiff(&fbdiff, &fbold);
648         //getregiondiff(&fbdiff, s->oldpic, s->current, bx, by, s->linex);
649         dodct(&fbdiff);
650         has_dc = 0;
651
652         quantize(&fbdiff, &b, has_dc, *quant);
653         getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
654         mode = 0; // mvd w/o mvd24
655         swf_SetBits(tag,0,1); // COD
656         codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
657         codehuffman(tag, cbpy, cbpybits^15);
658
659         /* 0,0 */
660         codehuffman(tag, mvd, 32);
661         codehuffman(tag, mvd, 32);
662
663         /* luminance */
664         encode8x8(tag, b.y1, has_dc, cbpybits&8);
665         encode8x8(tag, b.y2, has_dc, cbpybits&4);
666         encode8x8(tag, b.y3, has_dc, cbpybits&2);
667         encode8x8(tag, b.y4, has_dc, cbpybits&1);
668
669         /* chrominance */
670         encode8x8(tag, b.u, has_dc, cbpcbits&2);
671         encode8x8(tag, b.v, has_dc, cbpcbits&1);
672
673         /* -- reconstruction -- */
674         dequantize(&b, 0, *quant);
675         
676         doidct(&b);
677         for(t=0;t<64;t++) {
678             b.y1[t] = truncate256(b.y1[t] + (int)fbold.y1[t]);
679             b.y2[t] = truncate256(b.y2[t] + (int)fbold.y2[t]);
680             b.y3[t] = truncate256(b.y3[t] + (int)fbold.y3[t]);
681             b.y4[t] = truncate256(b.y4[t] + (int)fbold.y4[t]);
682             b.u[t] = truncate256(b.u[t] + (int)fbold.u[t]);
683             b.v[t] = truncate256(b.v[t] + (int)fbold.v[t]);
684         }
685         copyblock(s, s->current, &b, bx, by);
686         return;
687     } else {
688         /* i block (mode=3) */
689         mode = 3;
690         has_dc = 1;
691         dodct(&fb);
692         quantize(&fb, &b, has_dc, *quant);
693         getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
694         swf_SetBits(tag,0,1); // COD
695         codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
696         codehuffman(tag, cbpy, cbpybits);
697
698         /* luminance */
699         encode8x8(tag, b.y1, has_dc, cbpybits&8);
700         encode8x8(tag, b.y2, has_dc, cbpybits&4);
701         encode8x8(tag, b.y3, has_dc, cbpybits&2);
702         encode8x8(tag, b.y4, has_dc, cbpybits&1);
703
704         /* chrominance */
705         encode8x8(tag, b.u, has_dc, cbpcbits&2);
706         encode8x8(tag, b.v, has_dc, cbpcbits&1);
707     
708         dequantize(&b, 1, *quant);
709         doidct(&b);
710         truncateblock(&b);
711         copyblock(s, s->current, &b, bx, by);
712         return;
713     }
714
715     exit(1);
716 #if 0
717     dodct(&fb);
718     quantize(&fb, &b, has_dc, *quant);
719     getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
720
721     if(!dquant && has_mvd && !has_mvd24 && !has_dc) mode = 0;
722     else if(dquant && has_mvd && !has_mvd24 && !has_dc) mode = 1;
723     else if(!dquant && has_mvd && has_mvd24 && !has_dc) mode = 2;
724     else if(!dquant && !has_mvd && !has_mvd24 && has_dc) mode = 3;
725     else if(dquant && !has_mvd && !has_mvd24 && has_dc) mode = 4;
726     else exit(1);
727
728     swf_SetBits(tag,0,1); /* cod - 1 if we're not going to code this block*/
729         
730     codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
731     codehuffman(tag, cbpy, (mode==3 || mode==4)?cbpybits:cbpybits^15);
732
733     if(dquant) {
734         setQuant(tag, dquant);
735     }
736
737     if(has_mvd) {
738         /* 0,0 */
739         codehuffman(tag, mvd, 32);
740         codehuffman(tag, mvd, 32);
741     }
742     if(has_mvd24) {
743     }
744
745     /* luminance */
746     encode8x8(tag, b.y1, has_dc, cbpybits&8);
747     encode8x8(tag, b.y2, has_dc, cbpybits&4);
748     encode8x8(tag, b.y3, has_dc, cbpybits&2);
749     encode8x8(tag, b.y4, has_dc, cbpybits&1);
750
751     /* chrominance */
752     encode8x8(tag, b.u, has_dc, cbpcbits&2);
753     encode8x8(tag, b.v, has_dc, cbpcbits&1);
754 #endif
755 }
756
757 #define TYPE_IFRAME 0
758 #define TYPE_PFRAME 1
759
760 static void writeHeader(TAG*tag, int width, int height, int frame, int quant, int type)
761 {
762     U32 i32;
763     swf_SetU16(tag, frame);
764     swf_SetBits(tag, 1, 17); /* picture start code*/
765     swf_SetBits(tag, 0, 5); /* version=0, version 1 would optimize rle behaviour*/
766     swf_SetBits(tag, frame, 8); /* time reference */
767
768     /* write dimensions, taking advantage of some predefined sizes
769        if the opportunity presents itself */
770     i32 = width<<16|height;
771     switch(i32)
772     {
773         case 352<<16|288: swf_SetBits(tag, 2, 3);break;
774         case 176<<16|144: swf_SetBits(tag, 3, 3);break;
775         case 128<<16|96: swf_SetBits(tag, 4, 3);break;
776         case 320<<16|240: swf_SetBits(tag, 5, 3);break;
777         case 160<<16|120: swf_SetBits(tag, 6, 3);break;
778         default:
779             if(width>255 || height>255) {
780                 swf_SetBits(tag, 1, 3);
781                 swf_SetBits(tag, width, 16);
782                 swf_SetBits(tag, height, 16);
783             } else {
784                 swf_SetBits(tag, 0, 3);
785                 swf_SetBits(tag, width, 8);
786                 swf_SetBits(tag, height, 8);
787             }
788     }
789
790     swf_SetBits(tag, type, 2); /* I-Frame or P-Frame */
791     swf_SetBits(tag, 0, 1); /* No deblock filter */
792     assert(quant>0);
793     swf_SetBits(tag, quant, 5); /* quantizer (1-31), may be updated later on*/
794     swf_SetBits(tag, 0, 1); /* No extra info */
795 }
796
797 void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic)
798 {
799     int bx, by, bbx, bby;
800     int quant = 3;
801
802     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_IFRAME);
803
804     bbx = (s->width+15)/16; //TODO: move bbx,bby into VIDEOSTREAM
805     bby = (s->height+15)/16;
806
807     rgb2yuv(s->current, pic, s->linex, s->width, s->height);
808
809     for(by=0;by<bby;by++)
810     {
811         for(bx=0;bx<bbx;bx++)
812         {
813             encode_blockI(tag, s, bx, by, &quant);
814         }
815     }
816     s->frame++;
817     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
818 }
819
820 void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic)
821 {
822     int bx, by, bbx, bby;
823     int quant = 3;
824
825     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME);
826
827     bbx = (s->width+15)/16;
828     bby = (s->height+15)/16;
829
830     rgb2yuv(s->current, pic, s->linex, s->width, s->height);
831
832     for(by=0;by<bby;by++)
833     {
834         for(bx=0;bx<bbx;bx++)
835         {
836             encode_blockP(tag, s, bx, by, &quant);
837         }
838     }
839     s->frame++;
840     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
841
842     {
843         int t;
844         FILE*fi = fopen("test.ppm", "wb");
845         yuv2rgb(pic, s->current, s->linex, s->width, s->height);
846         fprintf(fi, "P6\n%d %d\n255\n", s->width, s->height);
847         for(t=0;t<s->width*s->height;t++)
848         {
849             fwrite(&pic[t].r, 1, 1, fi);
850             fwrite(&pic[t].g, 1, 1, fi);
851             fwrite(&pic[t].b, 1, 1, fi);
852         }
853         fclose(fi);
854     }
855 }
856
857 int main(int argn, char*argv[])
858 {
859     int fi;
860     int t;
861     SWF swf;
862     TAG * tag;
863     RGBA* pic, *pic2, rgb;
864     SWFPLACEOBJECT obj;
865     int width = 0;
866     int height = 0;
867     int frames = 50;
868     int framerate = 29;
869     unsigned char*data;
870     char* fname = "/home/kramm/pics/peppers.png";
871     VIDEOSTREAM stream;
872     double d = 1.0;
873
874     memset(&stream, 0, sizeof(stream));
875
876     getPNG(fname, &width, &height, &data);
877     pic = (RGBA*)malloc(width*height*sizeof(RGBA));
878     pic2 = (RGBA*)malloc(width*height*sizeof(RGBA));
879     memcpy(pic, data, width*height*sizeof(RGBA));
880     free(data);
881
882     printf("Compressing %s, size %dx%d\n", fname, width, height);
883
884     memset(&swf,0,sizeof(SWF));
885     memset(&obj,0,sizeof(obj));
886
887     swf.fileVersion    = 6;
888     swf.frameRate      = framerate*256;
889     swf.movieSize.xmax = 20*width;
890     swf.movieSize.ymax = 20*height;
891
892     swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
893     tag = swf.firstTag;
894     rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
895     swf_SetRGB(tag,&rgb);
896
897     tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
898     swf_SetU16(tag, 33);
899     swf_SetVideoStreamDefine(tag, &stream, frames, width, height);
900     
901     for(t=0;t<frames;t++)
902     {
903         int x,y;
904         double xx,yy;
905         for(y=0,yy=0;y<height;y++,yy+=d)  {
906             RGBA*line = &pic[((int)yy)*width];
907             for(x=0,xx=0;x<width;x++,xx+=d) {
908                 pic2[y*width+x] = line[((int)xx)];
909             }
910         }
911         printf("frame:%d\n", t);fflush(stdout);
912
913         tag = swf_InsertTag(tag, ST_VIDEOFRAME);
914         swf_SetU16(tag, 33);
915         if(t==0)
916             swf_SetVideoStreamIFrame(tag, &stream, pic2);
917         else
918             swf_SetVideoStreamPFrame(tag, &stream, pic2);
919
920         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
921         swf_GetPlaceObject(0, &obj);
922         if(t==0) {
923             obj.depth = 1;
924             obj.id = 33;
925         } else {
926             obj.move = 1;
927             obj.depth = 1;
928             obj.ratio = t;
929         }
930         swf_SetPlaceObject(tag,&obj);
931
932         tag = swf_InsertTag(tag, ST_SHOWFRAME);
933         d-=0.005;
934     }
935    
936     tag = swf_InsertTag(tag, ST_END);
937
938     fi = open("video3.swf", O_WRONLY|O_CREAT|O_TRUNC, 0644);
939     if(swf_WriteSWC(fi,&swf)<0) {
940         fprintf(stderr,"WriteSWF() failed.\n");
941     }
942     close(fi);
943     swf_FreeTags(&swf);
944 }