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