moved to lib/h.263, quant is now a parameter, added swf_VideoStreamClear.
[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 "../rfxswf.h"
13 #include "h263tables.c"
14 #include "swfvideo.h"
15
16 void swf_SetVideoStreamDefine(TAG*tag, VIDEOSTREAM*stream, U16 frames, U16 width, U16 height)
17 {
18     width=width&~15; height=height&~15;
19     swf_SetU16(tag, frames);
20     swf_SetU16(tag, width);
21     swf_SetU16(tag, height);
22     swf_SetU8(tag, 1); /* smoothing on */
23     swf_SetU8(tag, 2); /* codec = h.263 sorenson spark */
24
25     memset(stream, 0, sizeof(VIDEOSTREAM));
26     stream->olinex = width;
27     width+=15;width&=~15;
28     height+=15;height&=~15;
29     stream->linex = width;
30     stream->width = width;
31     stream->height = height;
32     stream->current = (YUV*)malloc(width*height*sizeof(YUV));
33     stream->oldpic = (YUV*)malloc(width*height*sizeof(YUV));
34
35     memset(stream->oldpic, 0, width*height*sizeof(YUV));
36     memset(stream->current, 0, width*height*sizeof(YUV));
37 }
38 void swf_VideoStreamClear(VIDEOSTREAM*stream)
39 {
40     free(stream->oldpic);stream->oldpic = 0;
41     free(stream->current);stream->current = 0;
42 }
43
44 typedef struct _block_t
45 {
46     int y1[64];
47     int y2[64];
48     int y3[64];
49     int y4[64];
50     int u[64];
51     int v[64];
52 } block_t;
53
54 typedef struct _fblock_t
55 {
56     double y1[64];
57     double y2[64];
58     double y3[64];
59     double y4[64];
60     double u[64];
61     double v[64];
62 } fblock_t;
63
64 static int zigzagtable[64] = {
65     0, 1, 5, 6, 14, 15, 27, 28, 
66     2, 4, 7, 13, 16, 26, 29, 42, 
67     3, 8, 12, 17, 25, 30, 41, 43, 
68     9, 11, 18, 24, 31, 40, 44, 53, 
69     10, 19, 23, 32, 39, 45, 52, 54, 
70     20, 22, 33, 38, 46, 51, 55, 60, 
71     21, 34, 37, 47, 50, 56, 59, 61, 
72     35, 36, 48, 49, 57, 58, 62, 63};
73
74 static void fzigzag(double*src) 
75 {
76     double tmp[64];
77     int t;
78     for(t=0;t<64;t++) {
79         ((int*)&tmp[zigzagtable[t]])[0] = ((int*)&src[t])[0];
80         ((int*)&tmp[zigzagtable[t]])[1] = ((int*)&src[t])[1];
81     }
82     memcpy(src, tmp, sizeof(double)*64);
83 }
84
85 #define PI 3.14159265358979
86 #define SQRT2 1.414214
87 #define RSQRT2 (1.0/1.414214)
88
89 static double table[8][8] =
90 {
91 {0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548},
92 {0.980785280403230,0.831469612302545,0.555570233019602,0.195090322016128,-0.195090322016128,-0.555570233019602,-0.831469612302545,-0.980785280403230},
93 {0.923879532511287,0.382683432365090,-0.382683432365090,-0.923879532511287,-0.923879532511287,-0.382683432365090,0.382683432365090,0.923879532511287},
94 {0.831469612302545,-0.195090322016128,-0.980785280403230,-0.555570233019602,0.555570233019602,0.980785280403230,0.195090322016129,-0.831469612302545},
95 {0.707106781186548,-0.707106781186547,-0.707106781186548,0.707106781186547,0.707106781186548,-0.707106781186547,-0.707106781186547,0.707106781186547},
96 {0.555570233019602,-0.980785280403230,0.195090322016128,0.831469612302545,-0.831469612302545,-0.195090322016128,0.980785280403231,-0.555570233019602},
97 {0.382683432365090,-0.923879532511287,0.923879532511287,-0.382683432365090,-0.382683432365091,0.923879532511287,-0.923879532511286,0.382683432365090},
98 {0.195090322016128,-0.555570233019602,0.831469612302545,-0.980785280403231,0.980785280403230,-0.831469612302545,0.555570233019602,-0.195090322016129}
99 };
100
101 static void dct(double*src)
102 {
103     double tmp[64];
104     int x,y,u,v,t;
105
106     for(v=0;v<8;v++)
107     for(u=0;u<8;u++)
108     {
109         double c = 0;
110         for(x=0;x<8;x++)
111         {
112             c+=table[u][x]*src[v*8+x];
113         }
114         tmp[v*8+u] = c;
115     }
116     for(u=0;u<8;u++)
117     for(v=0;v<8;v++)
118     {
119         double c = 0;
120         for(y=0;y<8;y++)
121         {
122             c+=table[v][y]*tmp[y*8+u];
123         }
124         src[v*8+u] = c*0.25;
125     }
126 }
127
128 static void idct(double*src)
129 {
130     double tmp[64];
131     int x,y,u,v;
132     for(y=0;y<8;y++)
133     for(x=0;x<8;x++)
134     {
135         double c = 0;
136         for(u=0;u<8;u++)
137         {
138             c+=table[u][x]*src[y*8+u];
139         }
140         tmp[y*8+x] = c;
141     }
142     for(y=0;y<8;y++)
143     for(x=0;x<8;x++)
144     {
145         double c = 0;
146         for(v=0;v<8;v++)
147         {
148             c+=table[v][y]*tmp[v*8+x];
149         }
150         src[y*8+x] = c*0.25;
151     }
152 }
153
154 static inline int truncate256(int a)
155 {
156     if(a>255) return 255;
157     if(a<0) return 0;
158     return a;
159 }
160
161 static void getregion(fblock_t* bb, YUV*pic, int bx, int by, int linex)
162 {
163     YUV*p1 = &pic[by*linex*16+bx*16];
164     YUV*p2 = p1;
165     int y1=0, y2=0, y3=0, y4=0;
166     int u=0,v=0;
167     int x,y;
168     for(y=0;y<8;y++) {
169         for(x=0;x<8;x++) {
170             bb->u[u++] = (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4;
171             bb->v[v++] = (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4;
172             bb->y1[y1++] = p1[x].y;
173             bb->y2[y2++] = p1[x+8].y;
174             bb->y3[y3++] = p1[linex*8+x].y;
175             bb->y4[y4++] = p1[linex*8+x+8].y;
176         }
177         p1+=linex;
178         p2+=linex*2;
179     }
180 }
181 static void rgb2yuv(YUV*dest, RGBA*src, int dlinex, int slinex, int width, int height)
182 {
183     int x,y;
184     for(y=0;y<height;y++) {
185         for(x=0;x<width;x++) {
186             int r,g,b;
187             r = src[y*slinex+x].r;
188             g = src[y*slinex+x].g;
189             b = src[y*slinex+x].b;
190             /*dest[y*dlinex+x].y = (r*0.299 + g*0.587 + b*0.114);
191             dest[y*dlinex+x].u = (r*-0.169 + g*-0.332 + b*0.500 + 128.0);
192             dest[y*dlinex+x].v = (r*0.500 + g*-0.419 + b*-0.0813 + 128.0);*/
193             dest[y*dlinex+x].y = (r*((int)( 0.299*256)) + g*((int)( 0.587*256)) + b*((int)( 0.114 *256)))>>8;
194             dest[y*dlinex+x].u = (r*((int)(-0.169*256)) + g*((int)(-0.332*256)) + b*((int)( 0.500 *256))+ 128*256)>>8;
195             dest[y*dlinex+x].v = (r*((int)( 0.500*256)) + g*((int)(-0.419*256)) + b*((int)(-0.0813*256))+ 128*256)>>8;
196         }
197     }
198 }
199 static void copyregion(VIDEOSTREAM*s, YUV*dest, YUV*src, int bx, int by)
200 {
201     YUV*p1 = &src[by*s->linex*16+bx*16];
202     YUV*p2 = &dest[by*s->linex*16+bx*16];
203     int y;
204     for(y=0;y<16;y++) {
205         memcpy(p1, p2, 16*sizeof(YUV));
206         p1+=s->linex;p2+=s->linex;
207     }
208 }
209
210 static void yuv2rgb(RGBA*dest, YUV*src, int linex, int width, int height)
211 {
212     int x,y;
213     for(y=0;y<height;y++) {
214         for(x=0;x<width;x++) {
215             int u,v,yy;
216             u = src[y*linex+x].u;
217             v = src[y*linex+x].v;
218             yy = src[y*linex+x].y;
219             dest[y*linex+x].r = truncate256(yy + ((360*(v-128))>>8));
220             dest[y*linex+x].g = truncate256(yy - ((88*(u-128)+183*(v-128))>>8));
221             dest[y*linex+x].b = truncate256(yy + ((455 * (u-128))>>8));
222         }
223     }
224 }
225 static void copyblock(VIDEOSTREAM*s, YUV*dest, block_t*b, int bx, int by)
226 {
227     YUV*p1 = &dest[(by*16)*s->linex+bx*16];
228     YUV*p2 = &dest[(by*16+8)*s->linex+bx*16];
229     int x,y;
230     for(y=0;y<8;y++) {
231         for(x=0;x<8;x++) {
232             int u,v,yy;
233             p1[x+0].u = b->u[(y/2)*8+(x/2)];
234             p1[x+0].v = b->v[(y/2)*8+(x/2)]; 
235             p1[x+0].y = b->y1[y*8+x];
236             p1[x+8].u = b->u[(y/2)*8+(x/2)+4];
237             p1[x+8].v = b->v[(y/2)*8+(x/2)+4]; 
238             p1[x+8].y = b->y2[y*8+x];
239             p2[x+0].u = b->u[(y/2+4)*8+(x/2)];
240             p2[x+0].v = b->v[(y/2+4)*8+(x/2)]; 
241             p2[x+0].y = b->y3[y*8+x];
242             p2[x+8].u = b->u[(y/2+4)*8+(x/2)+4];
243             p2[x+8].v = b->v[(y/2+4)*8+(x/2)+4]; 
244             p2[x+8].y = b->y4[y*8+x];
245         }
246         p1+=s->linex;
247         p2+=s->linex;
248     }
249 }
250
251 static int compareregions(VIDEOSTREAM*s, int bx, int by)
252 {
253     int linex = s->width;
254     YUV*p1 = &s->current[by*linex*16+bx*16];
255     YUV*p2 = &s->oldpic[by*linex*16+bx*16];
256     int diff = 0;
257     int x,y;
258     for(y=0;y<16;y++) {
259         for(x=0;x<16;x++) {
260             YUV*m = &p1[x];
261             YUV*n = &p2[x];
262             int y = m->y - n->y;
263             int u = m->u - n->u;
264             int v = m->v - n->v;
265             diff += y*y+(u*u+v*v)/4;
266         }
267         p1+=linex;
268         p2+=linex;
269     }
270     return diff/256;
271 }
272
273 static inline int valtodc(int val)
274 {
275     assert(val>=0);
276
277     /* table 12/h.263 */
278
279     //val+=4; //round
280     val/=8;
281     /* TODO: what to do for zero values? skip the block? */
282     if(val==0)
283         return 1;
284     if(val==128)
285         return 255;
286     if(val>254)
287         return 254;
288     return val;
289 }
290 static int dctoval(int dc)
291 {
292     int val;
293     assert(dc>0);
294     assert(dc!=128);
295     assert(dc<256);
296     /* table 12/h.263 */
297     val = dc*8;
298     if(val == 255*8)
299         val = 128*8;
300     return val;
301 }
302
303 static int codehuffman(TAG*tag, struct huffcode*table, int index)
304 {
305     /* TODO: !optimize! */
306     int i=0;
307     while(table[index].code[i]) {
308         if(table[index].code[i]=='0')
309             swf_SetBits(tag, 0, 1);
310         else
311             swf_SetBits(tag, 1, 1);
312         i++;
313     }
314     return i;
315 }
316
317 static void quantize8x8(double*src, int*dest, int has_dc, int quant)
318 {
319     int t,pos=0;
320     double q = 1.0/(quant*2);
321     if(has_dc) {
322         dest[0] = valtodc((int)src[0]); /*DC*/
323         pos++;
324     }
325     for(t=pos;t<64;t++)
326     {
327         //dest[t] = (int)src[t];
328     /* exact: if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;} */
329         //if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;}
330         //dest[t] = dest[t]/(quant*2);
331         dest[t] = (int)(src[t]*q);
332         /* TODO: warn if this happens- the video will be buggy */
333         if(dest[t]>127) dest[t]=127;
334         if(dest[t]<-127) dest[t]=-127;
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 < 16 /*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 1;
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, int quant)
888 {
889     int bx, by, bbx, bby;
890
891     if(quant<1) quant=1;
892     if(quant>31) quant=31;
893
894     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_IFRAME);
895
896     bbx = (s->width+15)/16; //TODO: move bbx,bby into VIDEOSTREAM
897     bby = (s->height+15)/16;
898
899     rgb2yuv(s->current, pic, s->linex, s->olinex, s->width, s->height);
900
901     for(by=0;by<bby;by++)
902     {
903         for(bx=0;bx<bbx;bx++)
904         {
905             encode_blockI(tag, s, bx, by, &quant);
906         }
907     }
908     s->frame++;
909     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
910 }
911
912 void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant)
913 {
914     int bx, by, bbx, bby;
915
916     if(quant<1) quant=1;
917     if(quant>31) quant=31;
918
919     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME);
920
921     bbx = (s->width+15)/16;
922     bby = (s->height+15)/16;
923
924     rgb2yuv(s->current, pic, s->linex, s->olinex, s->width, s->height);
925
926     for(by=0;by<bby;by++)
927     {
928         for(bx=0;bx<bbx;bx++)
929         {
930             encode_blockP(tag, s, bx, by, &quant);
931         }
932     }
933     s->frame++;
934     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
935
936     {
937         int t;
938         FILE*fi = fopen("test.ppm", "wb");
939         yuv2rgb(pic, s->current, s->linex, s->width, s->height);
940         fprintf(fi, "P6\n%d %d\n255\n", s->width, s->height);
941         for(t=0;t<s->width*s->height;t++)
942         {
943             fwrite(&pic[t].r, 1, 1, fi);
944             fwrite(&pic[t].g, 1, 1, fi);
945             fwrite(&pic[t].b, 1, 1, fi);
946         }
947         fclose(fi);
948     }
949 }
950
951 #ifdef MAIN
952 #include "png.h"
953 int main(int argn, char*argv[])
954 {
955     int fi;
956     int t;
957     SWF swf;
958     TAG * tag;
959     RGBA* pic, *pic2, rgb;
960     SWFPLACEOBJECT obj;
961     int width = 0;
962     int height = 0;
963     int frames = 10;
964     int framerate = 29;
965     unsigned char*data;
966     char* fname = "/home/kramm/pics/lena.png";
967     VIDEOSTREAM stream;
968     double d = 1.0;
969
970     memset(&stream, 0, sizeof(stream));
971
972     getPNG(fname, &width, &height, &data);
973     pic = (RGBA*)malloc(width*height*sizeof(RGBA));
974     pic2 = (RGBA*)malloc(width*height*sizeof(RGBA));
975     memcpy(pic, data, width*height*sizeof(RGBA));
976     free(data);
977
978     printf("Compressing %s, size %dx%d\n", fname, width, height);
979
980     memset(&swf,0,sizeof(SWF));
981     memset(&obj,0,sizeof(obj));
982
983     swf.fileVersion    = 6;
984     swf.frameRate      = framerate*256;
985     swf.movieSize.xmax = 20*width;
986     swf.movieSize.ymax = 20*height;
987
988     swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
989     tag = swf.firstTag;
990     rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
991     swf_SetRGB(tag,&rgb);
992
993     tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
994     swf_SetU16(tag, 33);
995     swf_SetVideoStreamDefine(tag, &stream, frames, width, height);
996     
997     for(t=0;t<frames;t++)
998     {
999         int x,y;
1000         double xx,yy;
1001         for(y=0,yy=0;y<height;y++,yy+=d)  {
1002             RGBA*line = &pic[((int)yy)*width];
1003             for(x=0,xx=0;x<width;x++,xx+=d) {
1004                 pic2[y*width+x] = line[((int)xx)];
1005             }
1006         }
1007         printf("frame:%d\n", t);fflush(stdout);
1008
1009         tag = swf_InsertTag(tag, ST_VIDEOFRAME);
1010         swf_SetU16(tag, 33);
1011         if(t==0)
1012             swf_SetVideoStreamIFrame(tag, &stream, pic2, 9);
1013         else
1014             swf_SetVideoStreamPFrame(tag, &stream, pic2, 9);
1015
1016         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1017         swf_GetPlaceObject(0, &obj);
1018         if(t==0) {
1019             obj.depth = 1;
1020             obj.id = 33;
1021         } else {
1022             obj.move = 1;
1023             obj.depth = 1;
1024             obj.ratio = t;
1025         }
1026         swf_SetPlaceObject(tag,&obj);
1027
1028         tag = swf_InsertTag(tag, ST_SHOWFRAME);
1029         d-=0.005;
1030     }
1031
1032     swf_VideoStreamClear(&stream);
1033    
1034     tag = swf_InsertTag(tag, ST_END);
1035
1036     fi = open("video3.swf", O_WRONLY|O_CREAT|O_TRUNC, 0644);
1037     if(swf_WriteSWC(fi,&swf)<0) {
1038         fprintf(stderr,"WriteSWF() failed.\n");
1039     }
1040     close(fi);
1041     swf_FreeTags(&swf);
1042 }
1043 #undef MAIN
1044 #endif