half-pixels, bugfix in sizes
[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 #ifdef MAIN
17 U16 totalframes = 0;
18 #endif
19 void swf_SetVideoStreamDefine(TAG*tag, VIDEOSTREAM*stream, U16 frames, U16 width, U16 height)
20 {
21     swf_SetU16(tag, frames);
22     swf_SetU16(tag, width);
23     swf_SetU16(tag, height);
24     //swf_SetU8(tag, 1); /* smoothing on */
25     swf_SetU8(tag, 0); /* smoothing off */
26     swf_SetU8(tag, 2); /* codec = h.263 sorenson spark */
27
28     totalframes = frames;
29
30     memset(stream, 0, sizeof(VIDEOSTREAM));
31     stream->olinex = width;
32     width+=15;width&=~15;
33     height+=15;height&=~15;
34     stream->linex = width;
35     stream->width = width;
36     stream->height = height;
37     stream->bbx = width/16;
38     stream->bby = height/16;
39     stream->current = (YUV*)malloc(width*height*sizeof(YUV));
40     stream->oldpic = (YUV*)malloc(width*height*sizeof(YUV));
41     stream->mvdx = (int*)malloc(stream->bbx*stream->bby*sizeof(int));
42     stream->mvdy = (int*)malloc(stream->bbx*stream->bby*sizeof(int));
43     stream->do_motion = 0;
44
45     memset(stream->oldpic, 0, width*height*sizeof(YUV));
46     memset(stream->current, 0, width*height*sizeof(YUV));
47 }
48 void swf_VideoStreamClear(VIDEOSTREAM*stream)
49 {
50     free(stream->oldpic);stream->oldpic = 0;
51     free(stream->current);stream->current = 0;
52     free(stream->mvdx);stream->mvdx=0;
53     free(stream->mvdy);stream->mvdy=0;
54 }
55
56 typedef struct _block_t
57 {
58     int y1[64];
59     int y2[64];
60     int y3[64];
61     int y4[64];
62     int u[64];
63     int v[64];
64 } block_t;
65
66 static int zigzagtable[64] = {
67     0, 1, 5, 6, 14, 15, 27, 28, 
68     2, 4, 7, 13, 16, 26, 29, 42, 
69     3, 8, 12, 17, 25, 30, 41, 43, 
70     9, 11, 18, 24, 31, 40, 44, 53, 
71     10, 19, 23, 32, 39, 45, 52, 54, 
72     20, 22, 33, 38, 46, 51, 55, 60, 
73     21, 34, 37, 47, 50, 56, 59, 61, 
74     35, 36, 48, 49, 57, 58, 62, 63};
75
76 static void zigzag(int*src) 
77 {
78     int tmp[64];
79     int t;
80     for(t=0;t<64;t++) {
81         tmp[zigzagtable[t]] = src[t];
82     }
83     memcpy(src, tmp, sizeof(int)*64);
84 }
85
86 #define PI 3.14159265358979
87 #define SQRT2 1.414214
88 #define RSQRT2 (1.0/1.414214)
89
90 static double table[8][8] =
91 {
92 {0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548,0.707106781186548},
93 {0.980785280403230,0.831469612302545,0.555570233019602,0.195090322016128,-0.195090322016128,-0.555570233019602,-0.831469612302545,-0.980785280403230},
94 {0.923879532511287,0.382683432365090,-0.382683432365090,-0.923879532511287,-0.923879532511287,-0.382683432365090,0.382683432365090,0.923879532511287},
95 {0.831469612302545,-0.195090322016128,-0.980785280403230,-0.555570233019602,0.555570233019602,0.980785280403230,0.195090322016129,-0.831469612302545},
96 {0.707106781186548,-0.707106781186547,-0.707106781186548,0.707106781186547,0.707106781186548,-0.707106781186547,-0.707106781186547,0.707106781186547},
97 {0.555570233019602,-0.980785280403230,0.195090322016128,0.831469612302545,-0.831469612302545,-0.195090322016128,0.980785280403231,-0.555570233019602},
98 {0.382683432365090,-0.923879532511287,0.923879532511287,-0.382683432365090,-0.382683432365091,0.923879532511287,-0.923879532511286,0.382683432365090},
99 {0.195090322016128,-0.555570233019602,0.831469612302545,-0.980785280403231,0.980785280403230,-0.831469612302545,0.555570233019602,-0.195090322016129}
100 };
101
102 static void dct(int*src)
103 {
104     double tmp[64];
105     int x,y,u,v,t;
106
107     for(v=0;v<8;v++)
108     for(u=0;u<8;u++)
109     {
110         double c = 0;
111         for(x=0;x<8;x++)
112         {
113             c+=table[u][x]*src[v*8+x];
114         }
115         tmp[v*8+u] = c;
116     }
117     for(u=0;u<8;u++)
118     for(v=0;v<8;v++)
119     {
120         double c = 0;
121         for(y=0;y<8;y++)
122         {
123             c+=table[v][y]*tmp[y*8+u];
124         }
125         src[v*8+u] = (int)(c*0.25+0.5);
126     }
127 }
128
129 static void idct(int*src)
130 {
131     double tmp[64];
132     int x,y,u,v;
133     for(y=0;y<8;y++)
134     for(x=0;x<8;x++)
135     {
136         double c = 0;
137         for(u=0;u<8;u++)
138         {
139             c+=table[u][x]*src[y*8+u];
140         }
141         tmp[y*8+x] = c;
142     }
143     for(y=0;y<8;y++)
144     for(x=0;x<8;x++)
145     {
146         double c = 0;
147         for(v=0;v<8;v++)
148         {
149             c+=table[v][y]*tmp[v*8+x];
150         }
151         src[y*8+x] = (int)(c*0.25+0.5);
152     }
153 }
154
155 static double c[8] = {1.0,
156 0.980785280403230, // cos(Pi*1/16), sin(Pi*7/16)
157 0.923879532511287, // cos(Pi*2/16), sin(Pi*6/16)
158 0.831469612302545, // cos(Pi*3/16), sin(Pi*5/16)
159 0.707106781186548, // cos(Pi*4/16), sin(Pi*4/16), 1/sqrt(2)
160 0.555570233019602, // cos(Pi*5/16), sin(Pi*3/16)
161 0.382683432365090, // cos(Pi*6/16), sin(Pi*2/16)
162 0.195090322016128 // cos(Pi*7/16), sin(Pi*1/16)
163 };
164
165 static double cc[8];
166 int ccquant = -1;
167
168 static void preparequant(int quant)
169 {
170     if(ccquant == quant)
171         return;
172     cc[0] = c[0]/(quant*2*4);
173     cc[1] = c[1]/(quant*2*4);
174     cc[2] = c[2]/(quant*2*4);
175     cc[3] = c[3]/(quant*2*4);
176     cc[4] = c[4]/(quant*2*4);
177     cc[5] = c[5]/(quant*2*4);
178     cc[6] = c[6]/(quant*2*4);
179     cc[7] = c[7]/(quant*2*4);
180     ccquant = quant;
181 }
182
183 inline static void innerdct(double*a,double*b, double*c)
184 {
185     // c1*c7*2 = c6
186     // c2*c6*2 = c4
187     // c3*c5*2 = c2
188     // c4*c4*2 = 1
189
190      //{  1,  3,  5,  7, -7, -5, -3, -1},
191      //{  3, -7, -1, -5,  5,  1,  7, -3},
192      //{  5, -1,  7,  3, -3, -7,  1, -5},
193      //{  7, -5,  3, -1,  1, -3,  5, -7}
194     double b0,b1,b2,b3,b4,b5;
195     b2 = (a[0]+a[7]);
196     b3 = (a[1]+a[6]);
197     b4 = (a[2]+a[5]);
198     b5 = (a[3]+a[4]);
199
200     b0 = (b2+b5)*c[4];
201     b1 = (b3+b4)*c[4];
202     b[0*8] = b0 + b1;
203     b[4*8] = b0 - b1;
204     b[2*8] = (b2-b5)*c[2] + (b3-b4)*c[6];
205     b[6*8] = (b2-b5)*c[6] + (b4-b3)*c[2];
206
207     b0 = (a[0]-a[7]);
208     b1 = (a[1]-a[6]);
209     b2 = (a[2]-a[5]);
210     b3 = (a[3]-a[4]);
211
212     b[1*8] = b0*c[1] + b1*c[3] + b2*c[5] + b3*c[7];
213     b[3*8] = b0*c[3] - b1*c[7] - b2*c[1] - b3*c[5];
214     b[5*8] = b0*c[5] - b1*c[1] + b2*c[7] + b3*c[3];
215     b[7*8] = b0*c[7] - b1*c[5] + b2*c[3] - b3*c[1];
216 }
217
218 static void dct2(int*src, int*dest)
219 {
220     double tmp[64], tmp2[64];
221     double*p;
222     int u,x,v,t;
223
224     for(t=0;t<64;t++)
225         tmp2[t] = src[t];
226
227     for(v=0;v<8;v++)
228     {
229         double* a=&tmp2[v*8];
230         double* b=&tmp[v];
231         innerdct(a,b,c);
232     }
233     for(v=0;v<8;v++)
234     {
235         double* a=&tmp[v*8];
236         double* b=&tmp2[v];
237         innerdct(a,b,cc);
238     }
239     for(t=0;t<64;t++) {
240         dest[zigzagtable[t]] = (int)(tmp2[t]);
241     }
242 }
243
244
245 static inline int truncate256(int a)
246 {
247     if(a>255) return 255;
248     if(a<0) return 0;
249     return a;
250 }
251
252 static void getregion(block_t* bb, YUV*pic, int posx, int posy, int linex)
253 {
254     YUV*p1;
255     YUV*p2;
256     int y1=0, y2=0, y3=0, y4=0;
257     int u=0,v=0;
258     int x,y;
259     posx*=16;
260     posy*=16;
261     p1 = &pic[posy*linex+posx];
262     p2 = p1;
263     for(y=0;y<8;y++) {
264         for(x=0;x<8;x++) {
265             bb->u[u++] = (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4;
266             bb->v[v++] = (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4;
267             bb->y1[y1++] = p1[x].y;
268             bb->y2[y2++] = p1[x+8].y;
269             bb->y3[y3++] = p1[linex*8+x].y;
270             bb->y4[y4++] = p1[linex*8+x+8].y;
271         }
272         p1+=linex;
273         p2+=linex*2;
274     }
275 }
276
277 static void getmvdregion(block_t* bb, YUV*pic, int posx, int posy, int mvdx, int mvdy, int linex)
278 {
279     YUV*p1;
280     YUV*p2;
281     int yy=0,uv=0;
282     int x,y;
283     int yhp = 0, uvhp=0;
284     int uvposx, uvposy;
285     posx = posx*16 + ((mvdx&~1)/2);
286     posy = posy*16 + ((mvdy&~1)/2);
287     p1 = &pic[posy*linex+posx];
288     p2 = &pic[(posy&~1)*linex+(posx&~1)];
289     uvhp = ((mvdx&1)|((mvdx>>1)&1))|((mvdy&2)|((mvdy&1)<<1));
290     yhp = ((mvdy&1)<<1|(mvdx&1));
291
292     /* y */
293     if(yhp==0 || yhp==2) {
294         for(y=0;y<8;y++) {
295             for(x=0;x<8;x++) {
296                 bb->y1[yy] = p1[x].y;
297                 bb->y2[yy] = p1[x+8].y;
298                 bb->y3[yy] = p1[linex*8+x].y;
299                 bb->y4[yy] = p1[linex*8+x+8].y;
300                 yy++;
301             }
302             p1+=linex;
303
304             if(yhp==2) {
305                 yy-=8;
306                 for(x=0;x<8;x++) {
307                     bb->y1[yy] += p1[x].y; bb->y1[yy] /= 2;
308                     bb->y2[yy] += p1[x+8].y; bb->y2[yy] /= 2;
309                     bb->y3[yy] += p1[linex*8+x].y; bb->y3[yy] /= 2;
310                     bb->y4[yy] += p1[linex*8+x+8].y; bb->y4[yy] /= 2;
311                     yy++;
312                 }
313             }
314         }
315         // todo: yhp==2
316     } else if(yhp==1 || yhp==3) {
317         for(y=0;y<8;y++) {
318             for(x=0;x<8;x++) {
319                 bb->y1[yy] = (p1[x].y + p1[x+1].y);
320                 bb->y2[yy] = (p1[x+8].y + p1[x+8+1].y);
321                 bb->y3[yy] = (p1[linex*8+x].y + p1[linex*8+x+1].y);
322                 bb->y4[yy] = (p1[linex*8+x+8].y + p1[linex*8+x+8+1].y);
323                 yy++;
324             }
325             yy-=8;
326             p1+=linex;
327             if(yhp==3) {
328                 for(x=0;x<8;x++) {
329                     bb->y1[yy] += (p1[x].y + p1[x+1].y); bb->y1[yy]/=4;
330                     bb->y2[yy] += (p1[x+8].y + p1[x+8+1].y); bb->y2[yy]/=4;
331                     bb->y3[yy] += (p1[linex*8+x].y + p1[linex*8+x+1].y); bb->y3[yy]/=4;
332                     bb->y4[yy] += (p1[linex*8+x+8].y + p1[linex*8+x+8+1].y); bb->y4[yy]/=4;
333                     yy++;
334                 }
335             } else {
336                 for(x=0;x<8;x++) {
337                     bb->y1[yy]/=2; bb->y2[yy]/=2; bb->y3[yy]/=2; bb->y4[yy]/=2;
338                     yy++;
339                 }
340             }
341         }
342         // todo: yhp==3
343     }
344
345     /* u,v */
346     if(uvhp==0 || uvhp==2) {
347         for(y=0;y<8;y++) {
348             for(x=0;x<8;x++) {
349                 bb->u[uv] = (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4;
350                 bb->v[uv] = (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4;
351                 uv++;
352             }
353             p2+=linex*2;
354             if(uvhp==2) {
355                 uv-=8;
356                 for(x=0;x<8;x++) {
357                     bb->u[uv] += (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4;
358                     bb->v[uv] += (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4;
359                     bb->u[uv] /= 2;
360                     bb->v[uv] /= 2;
361                     uv++;
362                 }
363             }
364         }
365     } else /* uvhp==1 || uvhp==3 */ {
366         for(y=0;y<8;y++) {
367             for(x=0;x<8;x++) {
368                 bb->u[uv] = ((p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4+
369                              (p2[x*2+2].u + p2[x*2+1+2].u + p2[linex+x*2+2].u + p2[linex+x*2+1+2].u)/4);
370                 bb->v[uv] = ((p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4+
371                              (p2[x*2+2].v + p2[x*2+1+2].v + p2[linex+x*2+2].v + p2[linex+x*2+1+2].v)/4);
372                 uv++;
373             }
374             uv-=8;
375             p2+=linex*2;
376             if(uvhp==3) {
377                 for(x=0;x<8;x++) {
378                     bb->u[uv] += ((p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4+
379                                   (p2[x*2+2].u + p2[x*2+1+2].u + p2[linex+x*2+2].u + p2[linex+x*2+1+2].u)/4);
380                     bb->v[uv] += ((p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4+
381                                   (p2[x*2+2].v + p2[x*2+1+2].v + p2[linex+x*2+2].v + p2[linex+x*2+1+2].v)/4);
382                     bb->u[uv] /= 4;
383                     bb->v[uv] /= 4;
384                     uv++;
385                 }
386             } else {
387                 for(x=0;x<8;x++) {
388                     bb->u[uv] /= 2;
389                     bb->v[uv] /= 2;
390                     uv++;
391                 }
392             }
393         }
394     }
395 }
396
397 static void rgb2yuv(YUV*dest, RGBA*src, int dlinex, int slinex, int width, int height)
398 {
399     int x,y;
400     for(y=0;y<height;y++) {
401         for(x=0;x<width;x++) {
402             int r,g,b;
403             r = src[y*slinex+x].r;
404             g = src[y*slinex+x].g;
405             b = src[y*slinex+x].b;
406             /*dest[y*dlinex+x].y = (r*0.299 + g*0.587 + b*0.114);
407             dest[y*dlinex+x].u = (r*-0.169 + g*-0.332 + b*0.500 + 128.0);
408             dest[y*dlinex+x].v = (r*0.500 + g*-0.419 + b*-0.0813 + 128.0);*/
409
410             //dest[y*dlinex+x].y = 128;//(r*((int)( 0.299*256)) + g*((int)( 0.587*256)) + b*((int)( 0.114 *256)))>>8;
411             dest[y*dlinex+x].y = (r*((int)( 0.299*256)) + g*((int)( 0.587*256)) + b*((int)( 0.114 *256)))>>8;
412             dest[y*dlinex+x].u = (r*((int)(-0.169*256)) + g*((int)(-0.332*256)) + b*((int)( 0.500 *256))+ 128*256)>>8;
413             dest[y*dlinex+x].v = (r*((int)( 0.500*256)) + g*((int)(-0.419*256)) + b*((int)(-0.0813*256))+ 128*256)>>8;
414         }
415     }
416 }
417 static void copyregion(VIDEOSTREAM*s, YUV*dest, YUV*src, int bx, int by)
418 {
419     YUV*p1 = &src[by*s->linex*16+bx*16];
420     YUV*p2 = &dest[by*s->linex*16+bx*16];
421     int y;
422     for(y=0;y<16;y++) {
423         memcpy(p1, p2, 16*sizeof(YUV));
424         p1+=s->linex;p2+=s->linex;
425     }
426 }
427
428 static void yuv2rgb(RGBA*dest, YUV*src, int linex, int width, int height)
429 {
430     int x,y;
431     for(y=0;y<height;y++) {
432         for(x=0;x<width;x++) {
433             int u,v,yy;
434             u = src[y*linex+x].u;
435             v = src[y*linex+x].v;
436             yy = src[y*linex+x].y;
437             dest[y*linex+x].r = truncate256(yy + ((360*(v-128))>>8));
438             dest[y*linex+x].g = truncate256(yy - ((88*(u-128)+183*(v-128))>>8));
439             dest[y*linex+x].b = truncate256(yy + ((455 * (u-128))>>8));
440         }
441     }
442 }
443 static void copyblock(VIDEOSTREAM*s, YUV*dest, block_t*b, int bx, int by)
444 {
445     YUV*p1 = &dest[(by*16)*s->linex+bx*16];
446     YUV*p2 = &dest[(by*16+8)*s->linex+bx*16];
447     int x,y;
448     for(y=0;y<8;y++) {
449         for(x=0;x<8;x++) {
450             int u,v,yy;
451             p1[x+0].u = b->u[(y/2)*8+(x/2)];
452             p1[x+0].v = b->v[(y/2)*8+(x/2)]; 
453             p1[x+0].y = b->y1[y*8+x];
454             p1[x+8].u = b->u[(y/2)*8+(x/2)+4];
455             p1[x+8].v = b->v[(y/2)*8+(x/2)+4]; 
456             p1[x+8].y = b->y2[y*8+x];
457             p2[x+0].u = b->u[(y/2+4)*8+(x/2)];
458             p2[x+0].v = b->v[(y/2+4)*8+(x/2)]; 
459             p2[x+0].y = b->y3[y*8+x];
460             p2[x+8].u = b->u[(y/2+4)*8+(x/2)+4];
461             p2[x+8].v = b->v[(y/2+4)*8+(x/2)+4]; 
462             p2[x+8].y = b->y4[y*8+x];
463         }
464         p1+=s->linex;
465         p2+=s->linex;
466     }
467 }
468
469 static int compareregions(VIDEOSTREAM*s, int bx, int by)
470 {
471     int linex = s->width;
472     YUV*p1 = &s->current[by*linex*16+bx*16];
473     YUV*p2 = &s->oldpic[by*linex*16+bx*16];
474     int diff = 0;
475     int x,y;
476     for(y=0;y<16;y++) {
477         for(x=0;x<16;x++) {
478             YUV*m = &p1[x];
479             YUV*n = &p2[x];
480             int y = m->y - n->y;
481             int u = m->u - n->u;
482             int v = m->v - n->v;
483             diff += y*y+(u*u+v*v)/4;
484         }
485         p1+=linex;
486         p2+=linex;
487     }
488     return diff/256;
489 }
490
491 static inline int valtodc(int val)
492 {
493     assert(val>=0);
494
495     /* table 12/h.263 */
496
497     //val+=4; //round
498     val/=8;
499     /* TODO: what to do for zero values? skip the block? */
500     if(val==0)
501         return 1;
502     if(val==128)
503         return 255;
504     if(val>254)
505         return 254;
506     return val;
507 }
508 static int dctoval(int dc)
509 {
510     int val;
511     assert(dc>0);
512     assert(dc!=128);
513     assert(dc<256);
514     /* table 12/h.263 */
515     val = dc*8;
516     if(val == 255*8)
517         val = 128*8;
518     return val;
519 }
520
521 static int codehuffman(TAG*tag, struct huffcode*table, int index)
522 {
523     /* TODO: !optimize! */
524     int i=0;
525     while(table[index].code[i]) {
526         if(table[index].code[i]=='0')
527             swf_SetBits(tag, 0, 1);
528         else
529             swf_SetBits(tag, 1, 1);
530         i++;
531     }
532     return i;
533 }
534
535 static void quantize8x8(int*src, int*dest, int has_dc, int quant)
536 {
537     int t,pos=0;
538     double q = 1.0/(quant*2);
539     if(has_dc) {
540         dest[0] = valtodc((int)src[0]); /*DC*/
541         pos++;
542     }
543     for(t=pos;t<64;t++)
544     {
545         //dest[t] = (int)src[t];
546     /* exact: if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;} */
547         //if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;}
548         //dest[t] = dest[t]/(quant*2);
549         dest[t] = (int)(src[t]*q);
550         /* TODO: warn if this happens- the video will be buggy */
551         if(dest[t]>127) dest[t]=127;
552         if(dest[t]<-127) dest[t]=-127;
553     }
554 }
555
556 static void dequantize8x8(int*b, int has_dc, int quant)
557 {
558     int t,pos=0;
559     if(has_dc) {
560         b[0] = dctoval(b[0]); //DC
561         pos++;
562     }
563     for(t=pos;t<64;t++) {
564         if(b[t]) {
565             int sign = 0;
566             if(b[t]<0) {
567                 b[t] = -b[t];
568                 sign = 1;
569             }
570
571             if(quant&1) {
572                 b[t] = quant*(2*b[t]+1); //-7,8,24,40
573             } else {
574                 b[t] = quant*(2*b[t]+1)-1; //-8,7,23,39
575             }
576
577             if(sign)
578                 b[t] = -b[t];
579         }
580
581         /* paragraph 6.2.2, "clipping of reconstruction levels": */
582         if(b[t]>2047) b[t]=2047;
583         if(b[t]<-2048) b[t]=-2048;
584     }
585 }
586
587 static int hascoef(int*b, int has_dc)
588 {
589     int t;
590     int pos=0;
591     if(has_dc)
592         pos++;
593     for(t=pos;t<64;t++) {
594         if(b[t])
595             return 1;
596     }
597     return 0;
598 }
599
600 static int coefbits8x8(int*bb, int has_dc)
601 {
602     int t;
603     int pos=0;
604     int bits=0;
605     int last;
606
607     if(has_dc) {
608         bits+=8;
609         pos++;
610     }
611     for(last=63;last>=pos;last--) {
612         if(bb[last])
613             break;
614     }
615     if(last < pos)
616         return bits;
617     while(1) {
618         int run=0, level=0, islast=0,t;
619         while(!bb[pos] && pos<last) {
620             pos++;
621             run++;
622         }
623         if(pos==last)
624             islast=1;
625         level=bb[pos];
626         if(level<0) level=-level;
627         assert(level);
628         for(t=0;t<RLE_ESCAPE;t++) {
629             if(rle_params[t].run == run &&
630                rle_params[t].level == level &&
631                rle_params[t].last == islast) {
632                 bits += rle[t].len + 1;
633                 break;
634             }
635         }
636         if(t==RLE_ESCAPE) {
637             bits += rle[RLE_ESCAPE].len + 1 + 6 + 8;
638         }
639         if(islast)
640             break;
641         pos++;
642     }
643     return bits;
644 }
645
646 static void encode8x8(TAG*tag, int*bb, int has_dc, int has_tcoef)
647 {
648     int t;
649     int pos=0;
650     int bits=0;
651
652     if(has_dc) {
653         swf_SetBits(tag, bb[0], 8);
654         pos++;
655     }
656
657     if(has_tcoef) {
658         int last;
659         /* determine last non-null coefficient */
660         for(last=63;last>=pos;last--) {
661             /* TODO: we could leave out small coefficients
662                      after a certain point (32?) */
663             if(bb[last])
664                 break;
665         }
666         /* blocks without coefficients should not be included
667            in the cbpy/cbpc patterns: */
668         assert(bb[last]);
669
670         while(1) {
671             int run=0;
672             int level=0;
673             int islast=0;
674             int sign=0;
675             int t;
676             while(!bb[pos] && pos<last) {
677                 pos++;
678                 run++;
679             }
680             if(pos==last)
681                 islast=1;
682             level=bb[pos];
683             assert(level);
684             if(level<0) {
685                 level = -level;
686                 sign = 1;
687             }
688             for(t=0;t<RLE_ESCAPE;t++) {
689                 /* TODO: lookup table */
690                 if(rle_params[t].run == run &&
691                    rle_params[t].level == level &&
692                    rle_params[t].last == islast) {
693                     codehuffman(tag, rle, t);
694                     swf_SetBits(tag, sign, 1);
695                     break;
696                 }
697             }
698             if(t==RLE_ESCAPE) {
699                 codehuffman(tag, rle, RLE_ESCAPE);
700                 level=bb[pos];
701                 /* table 14/h.263 */
702                 assert(level);
703                 assert(level>=-127);
704                 assert(level<=127);
705
706                 swf_SetBits(tag, islast, 1);
707                 swf_SetBits(tag, run, 6);
708                 swf_SetBits(tag, level, 8); //FIXME: fixme??
709             }
710
711             if(islast)
712                 break;
713             pos++;
714         }
715     }
716 }
717
718 static void quantize(block_t*fb, block_t*b, int has_dc, int quant)
719 {
720     quantize8x8(fb->y1, b->y1, has_dc, quant); 
721     quantize8x8(fb->y2, b->y2, has_dc, quant); 
722     quantize8x8(fb->y3, b->y3, has_dc, quant); 
723     quantize8x8(fb->y4, b->y4, has_dc, quant); 
724     quantize8x8(fb->u, b->u, has_dc, quant);   
725     quantize8x8(fb->v, b->v, has_dc, quant);   
726 }
727
728 static void dodct(block_t*fb)
729 {
730     dct(fb->y1); dct(fb->y2); dct(fb->y3); dct(fb->y4); 
731     dct(fb->u);  dct(fb->v);  
732     zigzag(fb->y1);
733     zigzag(fb->y2);
734     zigzag(fb->y3);
735     zigzag(fb->y4);
736     zigzag(fb->u);
737     zigzag(fb->v); 
738 }
739 static void dodctandquant(block_t*fb, block_t*b, int has_dc, int quant)
740 {
741     int t;
742     if(has_dc) {
743         dodct(fb);
744         quantize(fb,b,has_dc,quant);
745         return;
746     }
747     preparequant(quant);
748     dct2(fb->y1,b->y1); dct2(fb->y2,b->y2); dct2(fb->y3,b->y3); dct2(fb->y4,b->y4); 
749     dct2(fb->u,b->u);  dct2(fb->v,b->v);  
750 }
751
752 static void doidct(block_t*b)
753 {
754     block_t fb;
755     int t;
756     for(t=0;t<64;t++) {
757         fb.y1[t] = b->y1[zigzagtable[t]];
758         fb.y2[t] = b->y2[zigzagtable[t]];
759         fb.y3[t] = b->y3[zigzagtable[t]];
760         fb.y4[t] = b->y4[zigzagtable[t]];
761         fb.u[t] = b->u[zigzagtable[t]];
762         fb.v[t] = b->v[zigzagtable[t]];
763     }
764     idct(fb.y1); idct(fb.y2); idct(fb.y3); idct(fb.y4); 
765     idct(fb.u);  idct(fb.v);  
766     for(t=0;t<64;t++) {
767         b->y1[t] = fb.y1[t];
768         b->y2[t] = fb.y2[t];
769         b->y3[t] = fb.y3[t];
770         b->y4[t] = fb.y4[t];
771         b->u[t] = fb.u[t];
772         b->v[t] = fb.v[t];
773     }
774 }
775 static void truncateblock(block_t*b)
776 {
777     int t;
778     for(t=0;t<64;t++) {
779         b->y1[t] = truncate256(b->y1[t]);
780         b->y2[t] = truncate256(b->y2[t]);
781         b->y3[t] = truncate256(b->y3[t]);
782         b->y4[t] = truncate256(b->y4[t]);
783         b->u[t] = truncate256(b->u[t]);
784         b->v[t] = truncate256(b->v[t]);
785     }
786 }
787
788 static void dequantize(block_t*b, int has_dc, int quant)
789 {
790     dequantize8x8(b->y1, has_dc, quant); 
791     dequantize8x8(b->y2, has_dc, quant); 
792     dequantize8x8(b->y3, has_dc, quant); 
793     dequantize8x8(b->y4, has_dc, quant); 
794     dequantize8x8(b->u, has_dc, quant);   
795     dequantize8x8(b->v, has_dc, quant);   
796 }
797
798 static void getblockpatterns(block_t*b, int*cbpybits,int*cbpcbits, int has_dc)
799 {
800     *cbpybits = 0;
801     *cbpcbits = 0;
802
803     *cbpybits|=hascoef(b->y1, has_dc)*8;
804     *cbpybits|=hascoef(b->y2, has_dc)*4;
805     *cbpybits|=hascoef(b->y3, has_dc)*2;
806     *cbpybits|=hascoef(b->y4, has_dc)*1;
807
808     *cbpcbits|=hascoef(b->u, has_dc)*2;
809     *cbpcbits|=hascoef(b->v, has_dc)*1;
810 }
811
812 static void setQuant(TAG*tag, int dquant)
813 {
814     int code = 0;
815     /* 00 01 10 11
816        -1 -2 +1 +2
817     */
818     if(dquant == -1) {
819         swf_SetBits(tag, 0x0, 2);
820     } else if(dquant == -2) {
821         swf_SetBits(tag, 0x1, 2);
822     } else if(dquant == +1) {
823         swf_SetBits(tag, 0x2, 2);
824     } else if(dquant == +2) {
825         swf_SetBits(tag, 0x3, 2);
826     } else {
827         assert(0*strlen("invalid dquant"));
828     }
829 }
830
831 static void change_quant(int quant, int*dquant)
832 {
833     /* TODO */
834     *dquant = 0;
835 }
836
837 static void encode_blockI(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant)
838 {
839     block_t fb;
840     block_t b;
841     int dquant=0;
842     int cbpcbits = 0, cbpybits=0;
843
844     getregion(&fb, s->current, bx, by, s->width);
845     
846     change_quant(*quant, &dquant);
847     *quant+=dquant;
848
849     dodctandquant(&fb, &b, 1, *quant);
850     //quantize(&fb, &b, 1, *quant);
851
852     //decode_blockI(s, &b, bx, by);
853
854     getblockpatterns(&b, &cbpybits, &cbpcbits, 1);
855
856     if(dquant) {
857         codehuffman(tag, mcbpc_intra, 4+cbpcbits);
858     } else {
859         codehuffman(tag, mcbpc_intra, 0+cbpcbits);
860     }
861
862     codehuffman(tag, cbpy, cbpybits);
863
864     if(dquant) {
865         setQuant(tag, dquant);
866     }
867
868     /* luminance */
869     encode8x8(tag, b.y1, 1, cbpybits&8);
870     encode8x8(tag, b.y2, 1, cbpybits&4);
871     encode8x8(tag, b.y3, 1, cbpybits&2);
872     encode8x8(tag, b.y4, 1, cbpybits&1);
873
874     /* chrominance */
875     encode8x8(tag, b.u, 1, cbpcbits&2);
876     encode8x8(tag, b.v, 1, cbpcbits&1);
877
878     /* reconstruct */
879     dequantize(&b, 1, *quant);
880     doidct(&b);
881     truncateblock(&b);
882     copyblock(s, s->current, &b, bx, by);
883 }
884
885 static void yuvdiff(block_t*a, block_t*b)
886 {
887     int t;
888     for(t=0;t<64;t++) {
889         a->y1[t] = (a->y1[t] - b->y1[t]);
890         a->y2[t] = (a->y2[t] - b->y2[t]);
891         a->y3[t] = (a->y3[t] - b->y3[t]);
892         a->y4[t] = (a->y4[t] - b->y4[t]);
893         a->u[t]  = (a->u[t] - b->u[t]);
894         a->v[t]  = (a->v[t] - b->v[t]);
895     }
896 }
897
898 static void predictmvd(VIDEOSTREAM*s, int bx, int by, int*px, int*py)
899 {
900     int i1,i2;
901     int x1,y1,x2,y2,x3,y3;
902     int x4,y4,p;
903     if(bx) {x1=s->mvdx[by*s->bbx+bx-1];
904             y1=s->mvdy[by*s->bbx+bx-1];
905     } else {x1=y1=0;}
906
907     if(by) {x2=s->mvdx[(by-1)*s->bbx+bx];
908             y2=s->mvdy[(by-1)*s->bbx+bx];
909             if(bx<s->bbx-1) {
910                 x3=s->mvdx[(by-1)*s->bbx+bx+1];
911                 y3=s->mvdy[(by-1)*s->bbx+bx+1];         
912             } else {
913                 x3=y3=0;
914             }
915            }
916     else   {x2=x3=x1;y2=y3=y1;}
917
918            if((x1 <= x2 && x2 <= x3) || 
919               (x3 <= x2 && x2 <= x1)) {
920         x4=x2;
921     } else if((x2 <= x1 && x1 <= x3) ||
922               (x3 <= x1 && x1 <= x2)) {
923         x4=x1;
924     } else if((x1 <= x3 && x3 <= x2) ||
925               (x2 <= x3 && x3 <= x1)) {
926         x4=x3;
927     }
928
929            if((y1 <= y2 && y2 <= y3) || 
930               (y3 <= y2 && y2 <= y1)) {
931         y4=y2;
932     } else if((y2 <= y1 && y1 <= y3) ||
933               (y3 <= y1 && y1 <= y2)) {
934         y4=y1;
935     } else if((y1 <= y3 && y3 <= y2) ||
936               (y2 <= y3 && y3 <= y1)) {
937         y4=y3;
938     }
939
940     *px = x4;
941     *py = y4;
942     assert((x4>=-32 && x4<=31) && (y4>=-32 && y4<=31));
943 }
944
945 static inline int mvd2index(int px, int py, int x, int y, int xy)
946 {
947     assert((x>=-32 && x<=31) && (y>=-32 && y<=31));
948     //assert((x&1)==0 && (y&1)==0);//for now
949     //assert((x&2)==0 && (y&2)==0);//for now(2)
950     
951     x-=px;
952     y-=py;
953
954     if(xy)
955         x=y;
956     x+=32;
957
958     /* (x&63) */
959     if(x>63)
960         x-=64;
961     if(x<0)
962         x+=64;
963
964     assert(x>=0 && x<64);
965     return x;
966 }
967
968 static int encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant)
969 {
970     block_t fb;
971     block_t b;
972     int dquant=0;
973     int has_mvd=0;
974     int has_mvd24=0;
975     int has_dc=1;
976     int mode = 0;
977     int cbpcbits = 0, cbpybits=0;
978     int diff;
979     int predictmvdx;
980     int predictmvdy;
981
982     block_t b_i;
983     int bits_i;
984
985     block_t fbold_v00;
986     block_t b_v00;
987     int bits_v00 = 65535;
988     int x_v00=0;
989     int y_v00=0;
990
991     diff = compareregions(s, bx, by);
992     if(diff < 20 /*TODO: should be a parameter- good values are between 32 and 48 */) {
993         swf_SetBits(tag, 1,1); /* cod=1, block skipped */
994         /* copy the region from the last frame so that we have a complete reconstruction */
995         copyregion(s, s->current, s->oldpic, bx, by);
996         return 1;
997     }
998
999     predictmvd(s,bx,by,&predictmvdx,&predictmvdy);
1000     getregion(&fb, s->current, bx, by, s->width);
1001
1002     { /* consider I-block */
1003         block_t fb_i;
1004         int y,c;
1005         memcpy(&fb_i, &fb, sizeof(block_t));
1006         dodctandquant(&fb_i, &b_i, 1, *quant);
1007         //quantize(&fb_i, &b_i, 1, *quant);
1008         getblockpatterns(&b_i, &y, &c, 1);
1009         bits_i = 1; //cod
1010         bits_i += mcbpc_inter[3*4+c].len;
1011         bits_i += cbpy[y].len;
1012         bits_i += coefbits8x8(b_i.y1, 1);
1013         bits_i += coefbits8x8(b_i.y2, 1);
1014         bits_i += coefbits8x8(b_i.y3, 1);
1015         bits_i += coefbits8x8(b_i.y4, 1);
1016         bits_i += coefbits8x8(b_i.u, 1);
1017         bits_i += coefbits8x8(b_i.v, 1);
1018     }
1019
1020     { /* consider mvd(x,y)-block */
1021         block_t fbdiff;
1022         int y,c;
1023
1024         x_v00=0;
1025         y_v00=0;
1026
1027         if(s->do_motion) {
1028             int hx,hy;
1029             int bestx=0,besty=0,bestbits=65536;
1030             int startx=-2,endx=2;
1031             int starty=-2,endy=2;
1032
1033             if(!bx) startx=0;
1034             if(!by) starty=0;
1035             if(bx==s->bbx-1) endx=0;
1036             if(by==s->bby-1) endy=0;
1037
1038             for(hx=startx;hx<=endx;hx+=1)
1039             for(hy=starty;hy<=endy;hy+=1)
1040             {
1041                 block_t b;
1042                 block_t fbold;
1043                 int bits = 0;
1044                 memcpy(&fbdiff, &fb, sizeof(block_t));
1045                 getmvdregion(&fbold, s->oldpic, bx, by, hx, hy, s->linex);
1046                 yuvdiff(&fbdiff, &fbold);
1047                 dodctandquant(&fbdiff, &b, 0, *quant);
1048                 //quantize(&fbdiff, &b, 0, *quant);
1049                 bits += coefbits8x8(b.y1, 0);
1050                 bits += coefbits8x8(b.y2, 0);
1051                 bits += coefbits8x8(b.y3, 0);
1052                 bits += coefbits8x8(b.y4, 0);
1053                 bits += coefbits8x8(b.u, 0);
1054                 bits += coefbits8x8(b.v, 0);
1055                 if(bits<bestbits) {
1056                     bestbits = bits;
1057                     bestx = hx;
1058                     besty = hy;
1059                 }
1060             }
1061             x_v00 = bestx;
1062             y_v00 = besty;
1063         }
1064
1065         memcpy(&fbdiff, &fb, sizeof(block_t));
1066         getmvdregion(&fbold_v00, s->oldpic, bx, by, x_v00, y_v00, s->linex);
1067         yuvdiff(&fbdiff, &fbold_v00);
1068         dodctandquant(&fbdiff, &b_v00, 0, *quant);
1069         //quantize(&fbdiff, &b_v00, 0, *quant);
1070         getblockpatterns(&b_v00, &y, &c, 0);
1071
1072         bits_v00 = 1; //cod
1073         bits_v00 += mcbpc_inter[0*4+c].len;
1074         bits_v00 += cbpy[y^15].len;
1075         bits_v00 += mvd[mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 0)].len; // (0,0)
1076         bits_v00 += mvd[mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 1)].len;
1077         bits_v00 += coefbits8x8(b_v00.y1, 0);
1078         bits_v00 += coefbits8x8(b_v00.y2, 0);
1079         bits_v00 += coefbits8x8(b_v00.y3, 0);
1080         bits_v00 += coefbits8x8(b_v00.y4, 0);
1081         bits_v00 += coefbits8x8(b_v00.u, 0);
1082         bits_v00 += coefbits8x8(b_v00.v, 0);
1083     }
1084
1085     if(bits_i > bits_v00)
1086     { 
1087         /* mvd (0,0) block (mode=0) */
1088         int t;
1089         mode = 0; // mvd w/o mvd24
1090         has_dc = 0;
1091         memcpy(&b, &b_v00, sizeof(block_t));
1092
1093         getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
1094         swf_SetBits(tag,0,1); // COD
1095         codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
1096         codehuffman(tag, cbpy, cbpybits^15);
1097
1098         /* vector */
1099         codehuffman(tag, mvd, mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 0));
1100         codehuffman(tag, mvd, mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 1)); 
1101         s->mvdx[by*s->bbx+bx] = x_v00;
1102         s->mvdy[by*s->bbx+bx] = y_v00;
1103
1104         /* luminance */
1105         encode8x8(tag, b.y1, has_dc, cbpybits&8);
1106         encode8x8(tag, b.y2, has_dc, cbpybits&4);
1107         encode8x8(tag, b.y3, has_dc, cbpybits&2);
1108         encode8x8(tag, b.y4, has_dc, cbpybits&1);
1109
1110         /* chrominance */
1111         encode8x8(tag, b.u, has_dc, cbpcbits&2);
1112         encode8x8(tag, b.v, has_dc, cbpcbits&1);
1113         
1114         /* -- reconstruction -- */
1115         dequantize(&b, 0, *quant);
1116         doidct(&b);
1117         for(t=0;t<64;t++) {
1118             b.y1[t] = truncate256(b.y1[t] + (int)fbold_v00.y1[t]);
1119             b.y2[t] = truncate256(b.y2[t] + (int)fbold_v00.y2[t]);
1120             b.y3[t] = truncate256(b.y3[t] + (int)fbold_v00.y3[t]);
1121             b.y4[t] = truncate256(b.y4[t] + (int)fbold_v00.y4[t]);
1122             b.u[t] = truncate256(b.u[t] + (int)fbold_v00.u[t]);
1123             b.v[t] = truncate256(b.v[t] + (int)fbold_v00.v[t]);
1124         }
1125         copyblock(s, s->current, &b, bx, by);
1126         return bits_v00;
1127     } else {
1128         /* i block (mode=3) */
1129         mode = 3;
1130         has_dc = 1;
1131         memcpy(&b, &b_i, sizeof(block_t));
1132         getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
1133         swf_SetBits(tag,0,1); // COD
1134         codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
1135         codehuffman(tag, cbpy, cbpybits);
1136
1137         /* luminance */
1138         encode8x8(tag, b.y1, has_dc, cbpybits&8);
1139         encode8x8(tag, b.y2, has_dc, cbpybits&4);
1140         encode8x8(tag, b.y3, has_dc, cbpybits&2);
1141         encode8x8(tag, b.y4, has_dc, cbpybits&1);
1142
1143         /* chrominance */
1144         encode8x8(tag, b.u, has_dc, cbpcbits&2);
1145         encode8x8(tag, b.v, has_dc, cbpcbits&1);
1146
1147         /* -- reconstruction -- */
1148         dequantize(&b, 1, *quant);
1149         doidct(&b);
1150         truncateblock(&b);
1151         copyblock(s, s->current, &b, bx, by);
1152         return bits_i;
1153     }
1154
1155     exit(1);
1156 #if 0
1157     dodct(&fb);
1158     quantize(&fb, &b, has_dc, *quant);
1159     getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
1160
1161     if(!dquant && has_mvd && !has_mvd24 && !has_dc) mode = 0;
1162     else if(dquant && has_mvd && !has_mvd24 && !has_dc) mode = 1;
1163     else if(!dquant && has_mvd && has_mvd24 && !has_dc) mode = 2;
1164     else if(!dquant && !has_mvd && !has_mvd24 && has_dc) mode = 3;
1165     else if(dquant && !has_mvd && !has_mvd24 && has_dc) mode = 4;
1166     else exit(1);
1167
1168     swf_SetBits(tag,0,1); /* cod - 1 if we're not going to code this block*/
1169         
1170     codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
1171     codehuffman(tag, cbpy, (mode==3 || mode==4)?cbpybits:cbpybits^15);
1172
1173     if(dquant) {
1174         setQuant(tag, dquant);
1175     }
1176
1177     if(has_mvd) {
1178         /* 0,0 */
1179         codehuffman(tag, mvd, 32);
1180         codehuffman(tag, mvd, 32);
1181     }
1182     if(has_mvd24) {
1183     }
1184
1185     /* luminance */
1186     encode8x8(tag, b.y1, has_dc, cbpybits&8);
1187     encode8x8(tag, b.y2, has_dc, cbpybits&4);
1188     encode8x8(tag, b.y3, has_dc, cbpybits&2);
1189     encode8x8(tag, b.y4, has_dc, cbpybits&1);
1190
1191     /* chrominance */
1192     encode8x8(tag, b.u, has_dc, cbpcbits&2);
1193     encode8x8(tag, b.v, has_dc, cbpcbits&1);
1194 #endif
1195 }
1196
1197 static int bmid = 0;
1198 void setdbgpic(TAG*tag, RGBA*pic, int width, int height)
1199 {
1200     MATRIX m;
1201     tag = tag->prev;
1202     
1203     tag = swf_InsertTag(tag,ST_REMOVEOBJECT2);
1204     swf_SetU16(tag, 133);
1205
1206     tag = swf_InsertTag(tag, ST_DEFINEBITSLOSSLESS);
1207     swf_SetU16(tag, 1000+bmid);
1208     swf_SetLosslessBits(tag, width, height, (void*)pic, BMF_32BIT);
1209
1210     tag = swf_InsertTag(tag, ST_DEFINESHAPE);
1211     swf_SetU16(tag, 2000+bmid);
1212     swf_ShapeSetBitmapRect(tag, 1000+bmid, width, height);
1213
1214     tag = swf_InsertTag(tag,ST_PLACEOBJECT2);
1215     swf_GetMatrix(0,&m);
1216     m.tx = width*20;
1217     swf_ObjectPlace(tag, 2000+bmid, 133, &m, 0, 0);
1218
1219     bmid++;
1220 }
1221
1222 #define TYPE_IFRAME 0
1223 #define TYPE_PFRAME 1
1224
1225 static void writeHeader(TAG*tag, int width, int height, int frame, int quant, int type)
1226 {
1227     U32 i32;
1228     swf_SetU16(tag, frame);
1229     swf_SetBits(tag, 1, 17); /* picture start code*/
1230     swf_SetBits(tag, 0, 5); /* version=0, version 1 would optimize rle behaviour*/
1231     swf_SetBits(tag, frame, 8); /* time reference */
1232
1233     /* write dimensions, taking advantage of some predefined sizes
1234        if the opportunity presents itself */
1235     i32 = width<<16|height;
1236     switch(i32)
1237     {
1238         case 352<<16|288: swf_SetBits(tag, 2, 3);break;
1239         case 176<<16|144: swf_SetBits(tag, 3, 3);break;
1240         case 128<<16|96: swf_SetBits(tag, 4, 3);break;
1241         case 320<<16|240: swf_SetBits(tag, 5, 3);break;
1242         case 160<<16|120: swf_SetBits(tag, 6, 3);break;
1243         default:
1244             if(width>255 || height>255) {
1245                 swf_SetBits(tag, 1, 3);
1246                 swf_SetBits(tag, width, 16);
1247                 swf_SetBits(tag, height, 16);
1248             } else {
1249                 swf_SetBits(tag, 0, 3);
1250                 swf_SetBits(tag, width, 8);
1251                 swf_SetBits(tag, height, 8);
1252             }
1253     }
1254
1255     swf_SetBits(tag, type, 2); /* I-Frame or P-Frame */
1256     swf_SetBits(tag, 0, 1); /* No deblock filter */
1257     assert(quant>0);
1258     swf_SetBits(tag, quant, 5); /* quantizer (1-31), may be updated later on*/
1259     swf_SetBits(tag, 0, 1); /* No extra info */
1260 }
1261
1262 void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant)
1263 {
1264     int bx, by;
1265
1266     if(quant<1) quant=1;
1267     if(quant>31) quant=31;
1268
1269     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_IFRAME);
1270
1271     rgb2yuv(s->current, pic, s->linex, s->olinex, s->width, s->height);
1272
1273     //dostat(s);
1274
1275     for(by=0;by<s->bby;by++)
1276     {
1277         for(bx=0;bx<s->bbx;bx++)
1278         {
1279             encode_blockI(tag, s, bx, by, &quant);
1280         }
1281     }
1282     s->frame++;
1283     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
1284 }
1285
1286 void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant)
1287 {
1288     int bx, by;
1289
1290     if(quant<1) quant=1;
1291     if(quant>31) quant=31;
1292
1293     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME);
1294
1295     rgb2yuv(s->current, pic, s->linex, s->olinex, s->width, s->height);
1296     memset(s->mvdx, 0, s->bbx*s->bby*sizeof(int));
1297     memset(s->mvdy, 0, s->bbx*s->bby*sizeof(int));
1298
1299     for(by=0;by<s->bby;by++)
1300     {
1301         for(bx=0;bx<s->bbx;bx++)
1302         {
1303             encode_blockP(tag, s, bx, by, &quant);
1304         }
1305     }
1306     s->frame++;
1307     memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV));
1308
1309 //#define PNG
1310 #ifdef MAIN
1311 #ifdef PNG
1312     yuv2rgb(pic, s->current, s->linex, s->width, s->height);
1313     setdbgpic(tag, pic, s->width, s->height);
1314 #endif
1315     if(s->frame == (int)totalframes-1)
1316     {
1317         int t;
1318         FILE*fi = fopen("test.ppm", "wb");
1319         fprintf(fi, "P6\n%d %d\n255\n", s->width, s->height);
1320         for(t=0;t<s->width*s->height;t++)
1321         {
1322             fwrite(&pic[t].r, 1, 1, fi);
1323             fwrite(&pic[t].g, 1, 1, fi);
1324             fwrite(&pic[t].b, 1, 1, fi);
1325         }
1326         fclose(fi);
1327     }
1328 #endif
1329 }
1330
1331 int uline[64],vline[64],yline[64];
1332 void swf_SetVideoStreamMover(TAG*tag, VIDEOSTREAM*s, int quant)
1333 {
1334     int bx, by;
1335
1336     if(quant<1) quant=1;
1337     if(quant>31) quant=31;
1338
1339     writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME);
1340
1341     memset(s->mvdx, 0, s->bbx*s->bby*sizeof(int));
1342     memset(s->mvdy, 0, s->bbx*s->bby*sizeof(int));
1343
1344     for(by=0;by<s->bby;by++)
1345     {
1346         for(bx=0;bx<s->bbx;bx++)
1347         {
1348             //if((lrand48()&255) || !(bx>8 && bx<24 && by>8 && by<24)) {
1349             if(!(by==31)) {
1350                 /* mvd (0,0) block (mode=0) */
1351                 int t;
1352                 int mode = 0; // mvd w/o mvd24
1353                 int has_dc = 0;
1354                 int cbpybits=0,cbpcbits=0;
1355                 int predictmvdx, predictmvdy;
1356                 //int mvx=-1+(2*(s->frame&1));
1357                 //int mvy=-1+((s->frame&2));
1358                 int mvx=(lrand48()%4)-2;
1359                 int mvy=3;
1360
1361                 swf_SetBits(tag,0,1); // COD
1362                 codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
1363                 codehuffman(tag, cbpy, cbpybits^15);
1364
1365                 /* vector */
1366                 predictmvd(s,bx,by,&predictmvdx,&predictmvdy);
1367                 codehuffman(tag, mvd, mvd2index(predictmvdx, predictmvdy, mvx, mvy, 0));
1368                 codehuffman(tag, mvd, mvd2index(predictmvdx, predictmvdy, mvx, mvy, 1)); 
1369                 s->mvdx[by*s->bbx+bx] = mvx;
1370                 s->mvdy[by*s->bbx+bx] = mvy;
1371             } else {
1372                 /* i block (mode=3) */
1373                 int mode = 3;
1374                 int has_dc = 1;
1375                 int cbpybits,cbpcbits;
1376                 int t;
1377                 block_t b;
1378                 memset(&b, 0, sizeof(block_t));
1379                 b.y1[0] = b.y2[0] = b.y3[0] = b.y4[0] = yline[bx];
1380                 b.u[0] = uline[bx];
1381                 b.v[0] = vline[bx];
1382
1383                 getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc);
1384                 swf_SetBits(tag,0,1); // COD
1385                 codehuffman(tag, mcbpc_inter, mode*4+cbpcbits);
1386                 codehuffman(tag, cbpy, cbpybits);
1387
1388                 /* luminance */
1389                 encode8x8(tag, b.y1, has_dc, cbpybits&8);
1390                 encode8x8(tag, b.y2, has_dc, cbpybits&4);
1391                 encode8x8(tag, b.y3, has_dc, cbpybits&2);
1392                 encode8x8(tag, b.y4, has_dc, cbpybits&1);
1393
1394                 /* chrominance */
1395                 encode8x8(tag, b.u, has_dc, cbpcbits&2);
1396                 encode8x8(tag, b.v, has_dc, cbpcbits&1);
1397             }
1398         }
1399     }
1400 }
1401
1402 #ifdef MAIN
1403 #include "png.h"
1404 int main(int argn, char*argv[])
1405 {
1406     int fi;
1407     int t;
1408     SWF swf;
1409     TAG * tag;
1410     RGBA* pic, *pic2, rgb;
1411     SWFPLACEOBJECT obj;
1412     int width = 0;
1413     int height = 0;
1414     int frames = 20;
1415     int framerate = 29;
1416     unsigned char*data;
1417     char* fname = "/home/kramm/pics/peppers.png";
1418     VIDEOSTREAM stream;
1419     double d = 1.0;
1420
1421     memset(&stream, 0, sizeof(stream));
1422
1423     getPNG(fname, &width, &height, &data);
1424     pic = (RGBA*)malloc(width*height*sizeof(RGBA));
1425     pic2 = (RGBA*)malloc(width*height*sizeof(RGBA));
1426     memcpy(pic, data, width*height*sizeof(RGBA));
1427     free(data);
1428
1429     printf("Compressing %s, size %dx%d\n", fname, width, height);
1430
1431     memset(&swf,0,sizeof(SWF));
1432     memset(&obj,0,sizeof(obj));
1433
1434     swf.fileVersion    = 6;
1435     swf.frameRate      = framerate*256;
1436     swf.movieSize.xmax = 20*width*2;
1437     swf.movieSize.ymax = 20*height-20*64;
1438
1439     swf.firstTag = swf_InsertTag(NULL,ST_SETBACKGROUNDCOLOR);
1440     tag = swf.firstTag;
1441     rgb.r = 0x00;rgb.g = 0x00;rgb.b = 0x00;
1442     swf_SetRGB(tag,&rgb);
1443
1444     tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM);
1445     swf_SetU16(tag, 33);
1446     swf_SetVideoStreamDefine(tag, &stream, frames, width, height);
1447     stream.do_motion = 1;
1448
1449     for(t=0;t<frames;t++)
1450     {
1451         int x,y;
1452         double xx,yy;
1453         for(y=0,yy=0;y<height;y++,yy+=d)  {
1454             RGBA*line = &pic[((int)yy)*width];
1455             for(x=0,xx=0;x<width;x++,xx+=d) {
1456                 pic2[y*width+x] = line[((int)xx)];
1457             }
1458         }
1459         printf("frame:%d\n", t);fflush(stdout);
1460
1461         tag = swf_InsertTag(tag, ST_VIDEOFRAME);
1462         swf_SetU16(tag, 33);
1463         if(t==0)
1464             swf_SetVideoStreamIFrame(tag, &stream, pic2, 9);
1465         else {
1466             swf_SetVideoStreamPFrame(tag, &stream, pic2, 9);
1467         }
1468
1469         tag = swf_InsertTag(tag, ST_PLACEOBJECT2);
1470         swf_GetPlaceObject(0, &obj);
1471         if(t==0) {
1472             obj.depth = 1;
1473             obj.id = 33;
1474         } else {
1475             obj.move = 1;
1476             obj.depth = 1;
1477             obj.ratio = t;
1478         }
1479         swf_SetPlaceObject(tag,&obj);
1480
1481         tag = swf_InsertTag(tag, ST_SHOWFRAME);
1482         d-=0.015;
1483     }
1484     swf_VideoStreamClear(&stream);
1485    
1486     tag = swf_InsertTag(tag, ST_END);
1487
1488     fi = open("video3.swf", O_WRONLY|O_CREAT|O_TRUNC, 0644);
1489     if(swf_WriteSWC(fi,&swf)<0) {
1490         fprintf(stderr,"WriteSWF() failed.\n");
1491     }
1492     close(fi);
1493     swf_FreeTags(&swf);
1494 }
1495 #undef MAIN
1496 #endif