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