implemented bit comparison.
[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 int coefbits8x8(int*bb, int has_dc)
383 {
384     int t;
385     int pos=0;
386     int bits=0;
387     int last;
388
389     if(has_dc) {
390         bits+=8;
391         pos++;
392     }
393     for(last=63;last>=pos;last--) {
394         if(bb[last])
395             break;
396     }
397     if(last < pos)
398         return bits;
399     while(1) {
400         int run=0, level=0, islast=0,t;
401         while(!bb[pos] && pos<last) {
402             pos++;
403             run++;
404         }
405         if(pos==last)
406             islast=1;
407         level=bb[pos];
408         if(level<0) level=-level;
409         assert(level);
410         for(t=0;t<RLE_ESCAPE;t++) {
411             if(rle_params[t].run == run &&
412                rle_params[t].level == level &&
413                rle_params[t].last == islast) {
414                 bits += rle[t].len + 1;
415                 break;
416             }
417         }
418         if(t==RLE_ESCAPE) {
419             bits += rle[RLE_ESCAPE].len + 1 + 6 + 8;
420         }
421         if(islast)
422             break;
423         pos++;
424     }
425     return bits;
426 }
427
428 static void encode8x8(TAG*tag, int*bb, int has_dc, int has_tcoef)
429 {
430     int t;
431     int pos=0;
432     int bits=0;
433
434     if(has_dc) {
435         swf_SetBits(tag, bb[0], 8);
436         pos++;
437     }
438
439     if(has_tcoef) {
440         int last;
441         /* determine last non-null coefficient */
442         for(last=63;last>=pos;last--) {
443             /* TODO: we could leave out small coefficients
444                      after a certain point (32?) */
445             if(bb[last])
446                 break;
447         }
448         /* blocks without coefficients should not be included
449            in the cbpy/cbpc patterns: */
450         assert(bb[last]);
451
452         while(1) {
453             int run=0;
454             int level=0;
455             int islast=0;
456             int sign=0;
457             int t;
458             while(!bb[pos] && pos<last) {
459                 pos++;
460                 run++;
461             }
462             if(pos==last)
463                 islast=1;
464             level=bb[pos];
465             assert(level);
466             if(level<0) {
467                 level = -level;
468                 sign = 1;
469             }
470             for(t=0;t<RLE_ESCAPE;t++) {
471                 /* TODO: lookup table */
472                 if(rle_params[t].run == run &&
473                    rle_params[t].level == level &&
474                    rle_params[t].last == islast) {
475                     codehuffman(tag, rle, t);
476                     swf_SetBits(tag, sign, 1);
477                     break;
478                 }
479             }
480             if(t==RLE_ESCAPE) {
481                 codehuffman(tag, rle, RLE_ESCAPE);
482                 level=bb[pos];
483                 /* table 14/h.263 */
484                 assert(level);
485                 assert(level>=-127);
486                 assert(level<=127);
487
488                 swf_SetBits(tag, islast, 1);
489                 swf_SetBits(tag, run, 6);
490                 swf_SetBits(tag, level, 8); //FIXME: fixme??
491             }
492
493             if(islast)
494                 break;
495             pos++;
496         }
497     }
498 }
499
500 static void dodct(fblock_t*fb)
501 {
502     int t;
503     dct(fb->y1); dct(fb->y2); dct(fb->y3); dct(fb->y4); 
504     dct(fb->u);  dct(fb->v);  
505     fzigzag(fb->y1);
506     fzigzag(fb->y2);
507     fzigzag(fb->y3);
508     fzigzag(fb->y4);
509     fzigzag(fb->u);
510     fzigzag(fb->v); 
511 }
512
513 static void doidct(block_t*b)
514 {
515     fblock_t fb;
516     int t;
517     for(t=0;t<64;t++) {
518         fb.y1[t] = b->y1[zigzagtable[t]];
519         fb.y2[t] = b->y2[zigzagtable[t]];
520         fb.y3[t] = b->y3[zigzagtable[t]];
521         fb.y4[t] = b->y4[zigzagtable[t]];
522         fb.u[t] = b->u[zigzagtable[t]];
523         fb.v[t] = b->v[zigzagtable[t]];
524     }
525     idct(fb.y1); idct(fb.y2); idct(fb.y3); idct(fb.y4); 
526     idct(fb.u);  idct(fb.v);  
527     for(t=0;t<64;t++) {
528         b->y1[t] = fb.y1[t];
529         b->y2[t] = fb.y2[t];
530         b->y3[t] = fb.y3[t];
531         b->y4[t] = fb.y4[t];
532         b->u[t] = fb.u[t];
533         b->v[t] = fb.v[t];
534     }
535 }
536 static void truncateblock(block_t*b)
537 {
538     int t;
539     for(t=0;t<64;t++) {
540         b->y1[t] = truncate256(b->y1[t]);
541         b->y2[t] = truncate256(b->y2[t]);
542         b->y3[t] = truncate256(b->y3[t]);
543         b->y4[t] = truncate256(b->y4[t]);
544         b->u[t] = truncate256(b->u[t]);
545         b->v[t] = truncate256(b->v[t]);
546     }
547 }
548
549 static void quantize(fblock_t*fb, block_t*b, int has_dc, int quant)
550 {
551     quantize8x8(fb->y1, b->y1, has_dc, quant); 
552     quantize8x8(fb->y2, b->y2, has_dc, quant); 
553     quantize8x8(fb->y3, b->y3, has_dc, quant); 
554     quantize8x8(fb->y4, b->y4, has_dc, quant); 
555     quantize8x8(fb->u, b->u, has_dc, quant);   
556     quantize8x8(fb->v, b->v, has_dc, quant);   
557 }
558 static void dequantize(block_t*b, int has_dc, int quant)
559 {
560     dequantize8x8(b->y1, has_dc, quant); 
561     dequantize8x8(b->y2, has_dc, quant); 
562     dequantize8x8(b->y3, has_dc, quant); 
563     dequantize8x8(b->y4, has_dc, quant); 
564     dequantize8x8(b->u, has_dc, quant);   
565     dequantize8x8(b->v, has_dc, quant);   
566 }
567
568 static void getblockpatterns(block_t*b, int*cbpybits,int*cbpcbits, int has_dc)
569 {
570     *cbpybits = 0;
571     *cbpcbits = 0;
572
573     *cbpybits|=hascoef(b->y1, has_dc)*8;
574     *cbpybits|=hascoef(b->y2, has_dc)*4;
575     *cbpybits|=hascoef(b->y3, has_dc)*2;
576     *cbpybits|=hascoef(b->y4, has_dc)*1;
577
578     *cbpcbits|=hascoef(b->u, has_dc)*2;
579     *cbpcbits|=hascoef(b->v, has_dc)*1;
580 }
581
582 static void setQuant(TAG*tag, int dquant)
583 {
584     int code = 0;
585     /* 00 01 10 11
586        -1 -2 +1 +2
587     */
588     if(dquant == -1) {
589         swf_SetBits(tag, 0x0, 2);
590     } else if(dquant == -2) {
591         swf_SetBits(tag, 0x1, 2);
592     } else if(dquant == +1) {
593         swf_SetBits(tag, 0x2, 2);
594     } else if(dquant == +2) {
595         swf_SetBits(tag, 0x3, 2);
596     } else {
597         assert(0*strlen("invalid dquant"));
598     }
599 }
600
601 static void change_quant(int quant, int*dquant)
602 {
603     /* TODO */
604     *dquant = 0;
605 }
606
607 static void encode_blockI(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant)
608 {
609     fblock_t fb;
610     block_t b;
611     int dquant=0;
612     int cbpcbits = 0, cbpybits=0;
613
614     getregion(&fb, s->current, bx, by, s->width);
615     dodct(&fb);
616     
617     change_quant(*quant, &dquant);
618     *quant+=dquant;
619     quantize(&fb, &b, 1, *quant);
620
621     //decode_blockI(s, &b, bx, by);
622
623     getblockpatterns(&b, &cbpybits, &cbpcbits, 1);
624
625     if(dquant) {
626         codehuffman(tag, mcbpc_intra, 4+cbpcbits);
627     } else {
628         codehuffman(tag, mcbpc_intra, 0+cbpcbits);
629     }
630
631     codehuffman(tag, cbpy, cbpybits);
632
633     if(dquant) {
634         setQuant(tag, dquant);
635     }
636
637     /* luminance */
638     encode8x8(tag, b.y1, 1, cbpybits&8);
639     encode8x8(tag, b.y2, 1, cbpybits&4);
640     encode8x8(tag, b.y3, 1, cbpybits&2);
641     encode8x8(tag, b.y4, 1, cbpybits&1);
642
643     /* chrominance */
644     encode8x8(tag, b.u, 1, cbpcbits&2);
645     encode8x8(tag, b.v, 1, cbpcbits&1);
646
647     /* reconstruct */
648     dequantize(&b, 1, *quant);
649     doidct(&b);
650     truncateblock(&b);
651     copyblock(s, s->current, &b, bx, by);
652 }
653
654 static void yuvdiff(fblock_t*a, fblock_t*b)
655 {
656     int t;
657     for(t=0;t<64;t++) {
658         a->y1[t] = (a->y1[t] - b->y1[t]);
659         a->y2[t] = (a->y2[t] - b->y2[t]);
660         a->y3[t] = (a->y3[t] - b->y3[t]);
661         a->y4[t] = (a->y4[t] - b->y4[t]);
662         a->u[t]  = (a->u[t] - b->u[t]);
663         a->v[t]  = (a->v[t] - b->v[t]);
664     }
665 }
666
667 static int encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant)
668 {
669     fblock_t fb;
670     block_t b;
671     int dquant=0;
672     int has_mvd=0;
673     int has_mvd24=0;
674     int has_dc=1;
675     int mode = 0;
676     int cbpcbits = 0, cbpybits=0;
677     int diff;
678
679     block_t b_i;
680     int bits_i;
681
682     fblock_t fbold_v00;
683     block_t b_v00;
684     int bits_v00;
685
686     diff = compareregions(s, bx, by);
687     if(diff < 24 /*TODO: should be a parameter- good values are between 32 and 48 */) {
688         swf_SetBits(tag, 1,1); /* cod=1, block skipped */
689         copyregion(s, s->current, s->oldpic, bx, by);
690         return;
691     }
692
693     getregion(&fb, s->current, bx, by, s->width);
694
695     { /* consider I-block */
696         fblock_t fb_i;
697         int y,c;
698         memcpy(&fb_i, &fb, sizeof(fblock_t));
699         dodct(&fb_i);
700         quantize(&fb_i, &b_i, 1, *quant);
701         getblockpatterns(&b_i, &y, &c, 1);
702         bits_i = 1; //cod
703         bits_i += mcbpc_inter[3*4+c].len;
704         bits_i += cbpy[y].len;
705         bits_i += coefbits8x8(b_i.y1, 1);
706         bits_i += coefbits8x8(b_i.y2, 1);
707         bits_i += coefbits8x8(b_i.y3, 1);
708         bits_i += coefbits8x8(b_i.y4, 1);
709         bits_i += coefbits8x8(b_i.u, 1);
710         bits_i += coefbits8x8(b_i.v, 1);
711     }
712
713     { /* consider mvd(0,0)-block */
714         fblock_t fbdiff;
715         int y,c;
716         memcpy(&fbdiff, &fb, sizeof(fblock_t));
717         getregion(&fbold_v00, s->oldpic, bx, by, s->linex);
718         yuvdiff(&fbdiff, &fbold_v00);
719         dodct(&fbdiff);
720         quantize(&fbdiff, &b_v00, 0, *quant);
721         getblockpatterns(&b_v00, &y, &c, 0);
722         bits_v00 = 1; //cod
723         bits_v00 += mcbpc_inter[0*4+c].len;
724         bits_v00 += cbpy[y^15].len;
725         bits_v00 += mvd[32].len; // (0,0)
726         bits_v00 += mvd[32].len;
727         bits_v00 += coefbits8x8(b_v00.y1, 0);
728         bits_v00 += coefbits8x8(b_v00.y2, 0);
729         bits_v00 += coefbits8x8(b_v00.y3, 0);
730         bits_v00 += coefbits8x8(b_v00.y4, 0);
731         bits_v00 += coefbits8x8(b_v00.u, 0);
732         bits_v00 += coefbits8x8(b_v00.v, 0);
733     }
734
735     if(bits_i > bits_v00)
736     { 
737         /* mvd (0,0) block (mode=0) */
738         int t;
739         mode = 0; // mvd w/o mvd24
740         has_dc = 0;
741         memcpy(&b, &b_v00, sizeof(block_t));
742
743         getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
744         swf_SetBits(tag,0,1); // COD
745         codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
746         codehuffman(tag, cbpy, cbpybits^15);
747
748         /* 0,0 */
749         codehuffman(tag, mvd, 32);
750         codehuffman(tag, mvd, 32);
751
752         /* luminance */
753         encode8x8(tag, b.y1, has_dc, cbpybits&8);
754         encode8x8(tag, b.y2, has_dc, cbpybits&4);
755         encode8x8(tag, b.y3, has_dc, cbpybits&2);
756         encode8x8(tag, b.y4, has_dc, cbpybits&1);
757
758         /* chrominance */
759         encode8x8(tag, b.u, has_dc, cbpcbits&2);
760         encode8x8(tag, b.v, has_dc, cbpcbits&1);
761         
762         /* -- reconstruction -- */
763         dequantize(&b, 0, *quant);
764         doidct(&b);
765         for(t=0;t<64;t++) {
766             b.y1[t] = truncate256(b.y1[t] + (int)fbold_v00.y1[t]);
767             b.y2[t] = truncate256(b.y2[t] + (int)fbold_v00.y2[t]);
768             b.y3[t] = truncate256(b.y3[t] + (int)fbold_v00.y3[t]);
769             b.y4[t] = truncate256(b.y4[t] + (int)fbold_v00.y4[t]);
770             b.u[t] = truncate256(b.u[t] + (int)fbold_v00.u[t]);
771             b.v[t] = truncate256(b.v[t] + (int)fbold_v00.v[t]);
772         }
773         copyblock(s, s->current, &b, bx, by);
774         return bits_v00;
775     } else {
776         /* i block (mode=3) */
777         mode = 3;
778         has_dc = 1;
779         memcpy(&b, &b_i, sizeof(block_t));
780         //dodct(&fb);
781         //quantize(&fb, &b, has_dc, *quant);
782         getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
783         swf_SetBits(tag,0,1); // COD
784         codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
785         codehuffman(tag, cbpy, cbpybits);
786
787         /* luminance */
788         encode8x8(tag, b.y1, has_dc, cbpybits&8);
789         encode8x8(tag, b.y2, has_dc, cbpybits&4);
790         encode8x8(tag, b.y3, has_dc, cbpybits&2);
791         encode8x8(tag, b.y4, has_dc, cbpybits&1);
792
793         /* chrominance */
794         encode8x8(tag, b.u, has_dc, cbpcbits&2);
795         encode8x8(tag, b.v, has_dc, cbpcbits&1);
796
797         /* -- reconstruction -- */
798         dequantize(&b, 1, *quant);
799         doidct(&b);
800         truncateblock(&b);
801         copyblock(s, s->current, &b, bx, by);
802         return bits_i;
803     }
804
805     exit(1);
806 #if 0
807     dodct(&fb);
808     quantize(&fb, &b, has_dc, *quant);
809     getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
810
811     if(!dquant && has_mvd && !has_mvd24 && !has_dc) mode = 0;
812     else if(dquant && has_mvd && !has_mvd24 && !has_dc) mode = 1;
813     else if(!dquant && has_mvd && has_mvd24 && !has_dc) mode = 2;
814     else if(!dquant && !has_mvd && !has_mvd24 && has_dc) mode = 3;
815     else if(dquant && !has_mvd && !has_mvd24 && has_dc) mode = 4;
816     else exit(1);
817
818     swf_SetBits(tag,0,1); /* cod - 1 if we're not going to code this block*/
819         
820     codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
821     codehuffman(tag, cbpy, (mode==3 || mode==4)?cbpybits:cbpybits^15);
822
823     if(dquant) {
824         setQuant(tag, dquant);
825     }
826
827     if(has_mvd) {
828         /* 0,0 */
829         codehuffman(tag, mvd, 32);
830         codehuffman(tag, mvd, 32);
831     }
832     if(has_mvd24) {
833     }
834
835     /* luminance */
836     encode8x8(tag, b.y1, has_dc, cbpybits&8);
837     encode8x8(tag, b.y2, has_dc, cbpybits&4);
838     encode8x8(tag, b.y3, has_dc, cbpybits&2);
839     encode8x8(tag, b.y4, has_dc, cbpybits&1);
840
841     /* chrominance */
842     encode8x8(tag, b.u, has_dc, cbpcbits&2);
843     encode8x8(tag, b.v, has_dc, cbpcbits&1);
844 #endif
845 }
846
847 #define TYPE_IFRAME 0
848 #define TYPE_PFRAME 1
849
850 static void writeHeader(TAG*tag, int width, int height, int frame, int quant, int type)
851 {
852     U32 i32;
853     swf_SetU16(tag, frame);
854     swf_SetBits(tag, 1, 17); /* picture start code*/
855     swf_SetBits(tag, 0, 5); /* version=0, version 1 would optimize rle behaviour*/
856     swf_SetBits(tag, frame, 8); /* time reference */
857
858     /* write dimensions, taking advantage of some predefined sizes
859        if the opportunity presents itself */
860     i32 = width<<16|height;
861     switch(i32)
862     {
863         case 352<<16|288: swf_SetBits(tag, 2, 3);break;
864         case 176<<16|144: swf_SetBits(tag, 3, 3);break;
865         case 128<<16|96: swf_SetBits(tag, 4, 3);break;
866         case 320<<16|240: swf_SetBits(tag, 5, 3);break;
867         case 160<<16|120: swf_SetBits(tag, 6, 3);break;
868         default:
869             if(width>255 || height>255) {
870                 swf_SetBits(tag, 1, 3);
871                 swf_SetBits(tag, width, 16);
872                 swf_SetBits(tag, height, 16);
873             } else {
874                 swf_SetBits(tag, 0, 3);
875                 swf_SetBits(tag, width, 8);
876                 swf_SetBits(tag, height, 8);
877             }
878     }
879
880     swf_SetBits(tag, type, 2); /* I-Frame or P-Frame */
881     swf_SetBits(tag, 0, 1); /* No deblock filter */
882     assert(quant>0);
883     swf_SetBits(tag, quant, 5); /* quantizer (1-31), may be updated later on*/
884     swf_SetBits(tag, 0, 1); /* No extra info */
885 }
886
887 void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic)
888 {
889     int bx, by, bbx, bby;
890     int quant = 31;
891
892     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_IFRAME);
893
894     bbx = (s->width+15)/16; //TODO: move bbx,bby into VIDEOSTREAM
895     bby = (s->height+15)/16;
896
897     rgb2yuv(s->current, pic, s->linex, s->width, s->height);
898
899     for(by=0;by<bby;by++)
900     {
901         for(bx=0;bx<bbx;bx++)
902         {
903             encode_blockI(tag, s, bx, by, &quant);
904         }
905     }
906     s->frame++;
907     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
908 }
909
910 void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic)
911 {
912     int bx, by, bbx, bby;
913     int quant = 31;
914
915     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME);
916
917     bbx = (s->width+15)/16;
918     bby = (s->height+15)/16;
919
920     rgb2yuv(s->current, pic, s->linex, s->width, s->height);
921
922     for(by=0;by<bby;by++)
923     {
924         for(bx=0;bx<bbx;bx++)
925         {
926             encode_blockP(tag, s, bx, by, &quant);
927         }
928     }
929     s->frame++;
930     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
931
932     {
933         int t;
934         FILE*fi = fopen("test.ppm", "wb");
935         yuv2rgb(pic, s->current, s->linex, s->width, s->height);
936         fprintf(fi, "P6\n%d %d\n255\n", s->width, s->height);
937         for(t=0;t<s->width*s->height;t++)
938         {
939             fwrite(&pic[t].r, 1, 1, fi);
940             fwrite(&pic[t].g, 1, 1, fi);
941             fwrite(&pic[t].b, 1, 1, fi);
942         }
943         fclose(fi);
944     }
945 }
946
947 int main(int argn, char*argv[])
948 {
949     int fi;
950     int t;
951     SWF swf;
952     TAG * tag;
953     RGBA* pic, *pic2, rgb;
954     SWFPLACEOBJECT obj;
955     int width = 0;
956     int height = 0;
957     int frames = 2;
958     int framerate = 1;
959     unsigned char*data;
960     char* fname = "/home/kramm/pics/peppers.png";
961     VIDEOSTREAM stream;
962     double d = 1.0;
963
964     memset(&stream, 0, sizeof(stream));
965
966     getPNG(fname, &width, &height, &data);
967     pic = (RGBA*)malloc(width*height*sizeof(RGBA));
968     pic2 = (RGBA*)malloc(width*height*sizeof(RGBA));
969     memcpy(pic, data, width*height*sizeof(RGBA));
970     free(data);
971
972     printf("Compressing %s, size %dx%d\n", fname, width, height);
973
974     memset(&swf,0,sizeof(SWF));
975     memset(&obj,0,sizeof(obj));
976
977     swf.fileVersion    = 6;
978     swf.frameRate      = framerate*256;
979     swf.movieSize.xmax = 20*width;
980     swf.movieSize.ymax = 20*height;
981
982     swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
983     tag = swf.firstTag;
984     rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
985     swf_SetRGB(tag,&rgb);
986
987     tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
988     swf_SetU16(tag, 33);
989     swf_SetVideoStreamDefine(tag, &stream, frames, width, height);
990     
991     for(t=0;t<frames;t++)
992     {
993         int x,y;
994         double xx,yy;
995         for(y=0,yy=0;y<height;y++,yy+=d)  {
996             RGBA*line = &pic[((int)yy)*width];
997             for(x=0,xx=0;x<width;x++,xx+=d) {
998                 pic2[y*width+x] = line[((int)xx)];
999             }
1000         }
1001         printf("frame:%d\n", t);fflush(stdout);
1002
1003         tag = swf_InsertTag(tag, ST_VIDEOFRAME);
1004         swf_SetU16(tag, 33);
1005         if(t==0)
1006             swf_SetVideoStreamIFrame(tag, &stream, pic2);
1007         else
1008             swf_SetVideoStreamPFrame(tag, &stream, pic2);
1009
1010         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1011         swf_GetPlaceObject(0, &obj);
1012         if(t==0) {
1013             obj.depth = 1;
1014             obj.id = 33;
1015         } else {
1016             obj.move = 1;
1017             obj.depth = 1;
1018             obj.ratio = t;
1019         }
1020         swf_SetPlaceObject(tag,&obj);
1021
1022         tag = swf_InsertTag(tag, ST_SHOWFRAME);
1023         d-=0.005;
1024     }
1025    
1026     tag = swf_InsertTag(tag, ST_END);
1027
1028     fi = open("video3.swf", O_WRONLY|O_CREAT|O_TRUNC, 0644);
1029     if(swf_WriteSWC(fi,&swf)<0) {
1030         fprintf(stderr,"WriteSWF() failed.\n");
1031     }
1032     close(fi);
1033     swf_FreeTags(&swf);
1034 }