From 78235556f27a7dc3928cc88aef6fba0a5f4b03d9 Mon Sep 17 00:00:00 2001 From: kramm Date: Mon, 7 Apr 2003 18:27:58 +0000 Subject: [PATCH] initial revision --- lib/h.263/mkvideo.c | 447 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 447 insertions(+) create mode 100644 lib/h.263/mkvideo.c diff --git a/lib/h.263/mkvideo.c b/lib/h.263/mkvideo.c new file mode 100644 index 0000000..88a482a --- /dev/null +++ b/lib/h.263/mkvideo.c @@ -0,0 +1,447 @@ +/* mkvideo.c + Create a video file. + + Part of the swftools package. + + Copyright (c) 2003 Matthias Kramm */ + +#include +#include +#include +#include +#include "../lib/rfxswf.h" +#include "png.h" +#include "h263tables.c" + + +void swf_SetVideoStreamDefine(TAG*tag, U16 frames, U16 width, U16 height) +{ + width=width&~15; height=height&~15; + swf_SetU16(tag, frames); + swf_SetU16(tag, width); + swf_SetU16(tag, height); + swf_SetU8(tag, 1); /* smoothing on */ + swf_SetU8(tag, 2); /* codec = h.263 sorenson spark */ +} + +struct block_t +{ + int y1[64]; + int y2[64]; + int y3[64]; + int y4[64]; + int u[64]; + int v[64]; +}; + +struct fblock_t +{ + double y1[64]; + double y2[64]; + double y3[64]; + double y4[64]; + double u[64]; + double v[64]; +}; + +void zigzag(int*src) +{ + int table[64] = { + 0, 1, 5, 6, 14, 15, 27, 28, + 2, 4, 7, 13, 16, 26, 29, 42, + 3, 8, 12, 17, 25, 30, 41, 43, + 9, 11, 18, 24, 31, 40, 44, 53, + 10, 19, 23, 32, 39, 45, 52, 54, + 20, 22, 33, 38, 46, 51, 55, 60, + 21, 34, 37, 47, 50, 56, 59, 61, + 35, 36, 48, 49, 57, 58, 62, 63}; + int tmp[64]; + int t; + for(t=0;t<64;t++) { + tmp[table[t]] = src[t]; + } + memcpy(src, tmp, sizeof(int)*64); +} + +#define PI 3.14159265358979 +#define SQRT2 1.414214 +#define RSQRT2 (1.0/1.414214) + +void dct(double*src) +{ + double tmp[64]; + int x,y,u,v; + for(y=0;y<8;y++) + for(x=0;x<8;x++) + { + double c = 0; + for(v=0;v<8;v++) + for(u=0;u<8;u++) + { + double f = 0.25*cos(PI*(2.0*x+1.0)*u/16.0)*cos(PI*(2.0*y+1.0)*v/16.0); + if(!u) f *= RSQRT2; + if(!v) f *= RSQRT2; + c+=f*src[v*8+u]; + } + tmp[y*8+x] = c; + } + memcpy(src, tmp, sizeof(double)*64); +} + +void idct(double*src) +{ + double tmp[64]; + int x,y,u,v; + for(v=0;v<8;v++) + for(u=0;u<8;u++) + { + double c = 0; + for(y=0;y<8;y++) + for(x=0;x<8;x++) + { + double f = 0.25*cos(PI*(2.0*x+1.0)*u/16.0)*cos(PI*(2.0*y+1.0)*v/16.0); + if(!u) f *= RSQRT2; + if(!v) f *= RSQRT2; + c+=f*src[y*8+x]; + } + tmp[v*8+u] = c; + } + memcpy(src, tmp, sizeof(double)*64); +} + +void getregion(struct fblock_t* bb, RGBA*pic, int bx, int by, int width, int height) +{ + RGBA*p1 = &pic[by*width*16+bx*16]; + RGBA*p2 = p1; + int linex = width; + int y1=0, y2=0, y3=0, y4=0; + int u=0,v=0; + int x,y; + for(y=0;y<8;y++) { + for(x=0;x<8;x++) { + double r,g,b; + r = (p2[x*2].r + p2[x*2+1].r + p2[linex+x*2].r + p2[linex+x*2+1].r)/4.0; + g = (p2[x*2].g + p2[x*2+1].g + p2[linex+x*2].g + p2[linex+x*2+1].g)/4.0; + b = (p2[x*2].b + p2[x*2+1].b + p2[linex+x*2].b + p2[linex+x*2+1].b)/4.0; + bb->u[u++] = (r*-0.169 + g*-0.332 + b*0.500 + 128.0); + bb->v[v++] = (r*0.500 + g*-0.419 + b*-0.0813 + 128.0); + + r = p1[x].r; g = p1[x].g; b = p1[x].b; + bb->y1[y1++] = (r*0.299 + g*0.587 + b*0.114); + r = p1[x+8].r; g = p1[x+8].g; b = p1[x+8].b; + bb->y2[y2++] = (r*0.299 + g*0.587 + b*0.114); + r = p1[linex*8+x].r; g = p1[linex*8+x].g; b = p1[linex*8+x].b; + bb->y3[y3++] = (r*0.299 + g*0.587 + b*0.114); + r = p1[linex*8+x+8].r; g = p1[linex*8+x+8].g; b = p1[linex*8+x+8].b; + bb->y4[y4++] = (r*0.299 + g*0.587 + b*0.114); + } + p1+=linex; + p2+=linex*2; + } +} + +int valtodc(int val) +{ + assert(val>=0); + + /* table 12/h.263 */ + val/=8; + /* TODO: what to do for zero values? skip the block? */ + if(val==0) + return 1; + if(val==128) + return 255; + if(val>254) + return 254; + return val; +} + +void codehuffman(TAG*tag, struct huffcode*table, int index) +{ + /* TODO: !optimize! */ + int i=0; + while(table[index].code[i]) { + if(table[index].code[i]=='0') + swf_SetBits(tag, 0, 1); + else + swf_SetBits(tag, 1, 1); + i++; + } +} + +int see=0; + +void quantize(double*src, int*dest, int quant, int has_dc) +{ + int t,pos=0; + if(has_dc) { + dest[0] = (int)src[0]; /*DC*/ + dest[0] = valtodc(dest[0]); + pos++; + } + for(t=pos;t<64;t++) + { + dest[t] = (int)src[t]; + //val = (quant*(2*level+1)-1)+quant&1 + if(quant&1) { + dest[t] = (dest[t]/quant - 1)/2; + } else { + dest[t] = ((dest[t]+1)/quant - 1)/2; + } + } +} + +int hascoef(int*b, int has_dc) +{ + int t; + int pos=0; + int range=2; + if(has_dc) + pos++; + for(t=pos;t<64;t++) { + if(b[t]<=-range || b[t]>=range) + return 1; + } + return 0; +} + +void encode8x8(TAG*tag, int*bb, int has_dc, int has_tcoef) +{ + int t; + int pos=0; + + if(has_dc) { + swf_SetBits(tag, bb[0], 8); + pos++; + } + + if(has_tcoef) { + int last; + /* determine last non-null coefficient */ + for(last=63;last>=pos;last--) { + if(bb[last]) + break; + } + assert(bb[last]); + /* blocks without coefficients should not be included + in the cbpy/cbpc patterns */ + while(1) { + int run=0; + int level=0; + int islast=0; + int sign=0; + int t; + while(!bb[pos] && pos127) level = 127; + + swf_SetBits(tag, islast, 1); + swf_SetBits(tag, run, 6); + swf_SetBits(tag, level, 8); //fixme + } + + if(islast) + break; + pos++; + } + + //codehuffman(tag, rle, 58); + //swf_SetBits(tag, 1, 1); //sign + } + see++; +} + +void encode_blockI(TAG*tag, RGBA*pic, int bx, int by, int width, int height, int*quant) +{ + struct fblock_t b; + int dquant=0; /* TODO: should we take advantage of the dquant feature?*/ + //int cbpcbits = 3; + //int cbpybits = 15; + int cbpcbits = 0; + int cbpybits = 0; + int y1[64],y2[64],y3[64],y4[64],u[64],v[64]; + + getregion(&b, pic, bx, by, width, height); + dct(b.y1); quantize(b.y1,y1,1,*quant); zigzag(y1); cbpybits|=hascoef(y1, 1)*8; + dct(b.y2); quantize(b.y2,y2,1,*quant); zigzag(y2); cbpybits|=hascoef(y2, 1)*4; + dct(b.y3); quantize(b.y3,y3,1,*quant); zigzag(y3); cbpybits|=hascoef(y3, 1)*2; + dct(b.y4); quantize(b.y4,y4,1,*quant); zigzag(y4); cbpybits|=hascoef(y4, 1)*1; + dct(b.u); quantize(b.u,u,1,*quant); zigzag(u); cbpcbits|=hascoef(u, 1)*2; + dct(b.v); quantize(b.v,v,1,*quant); zigzag(v); cbpcbits|=hascoef(v, 1)*1; + + if(dquant) { + codehuffman(tag, mcbpc_intra, 4+cbpcbits); + } else { + codehuffman(tag, mcbpc_intra, 0+cbpcbits); + } + //swf_SetBits(tag, 1, 1); /*cbpc-00 mb_type=3 (no bquant), cbc=0*/ + + /* if this was an intra frame, we'd need to code (cbpybits^15) */ + codehuffman(tag, cbpy, cbpybits); + + if(dquant) { + /* 00 01 10 11 + -1 -2 +1 +2 + */ + swf_SetBits(tag, 0x3, 2); + } + + /* luminance */ + encode8x8(tag, y1, 1, cbpybits&8); + encode8x8(tag, y2, 1, cbpybits&4); + encode8x8(tag, y3, 1, cbpybits&2); + encode8x8(tag, y4, 1, cbpybits&1); + /*swf_SetBits(tag, 0x1, 8); + swf_SetBits(tag, 0xfe, 8); + swf_SetBits(tag, 0x1, 8); + swf_SetBits(tag, 0x1, 8);*/ + + /* chrominance */ + encode8x8(tag, u, 1, cbpcbits&2); + encode8x8(tag, v, 1, cbpcbits&1); + /*swf_SetBits(tag, 0xfe, 8); + swf_SetBits(tag, 0xfe, 8);*/ +} + +void swf_SetVideoStreamIFrame(TAG*tag, RGBA*pic, U16 width, U16 height, int frame) +{ + U32 i32; + int bx, by, bbx, bby; + int quant = 9; + + width=width&~15; height=height&~15; + + swf_SetU16(tag, frame); + swf_SetBits(tag, 1, 17); /* picture start code*/ + swf_SetBits(tag, 0, 5); /* version=0, version 1 would optimize rle behaviour*/ + swf_SetBits(tag, frame, 8); /* time reference */ + + /* write dimensions, taking advantage of some predefined sizes + if the opportunity presents itself */ + i32 = width<<16|height; + switch(i32) + { + case 352<<16|288: swf_SetBits(tag, 2, 3);break; + case 176<<16|144: swf_SetBits(tag, 3, 3);break; + case 128<<16|96: swf_SetBits(tag, 4, 3);break; + case 320<<16|240: swf_SetBits(tag, 5, 3);break; + case 160<<16|120: swf_SetBits(tag, 6, 3);break; + default: + if(width>255 || height>255) { + swf_SetBits(tag, 1, 3); + swf_SetBits(tag, width, 16); + swf_SetBits(tag, height, 16); + } else { + swf_SetBits(tag, 0, 3); + swf_SetBits(tag, width, 8); + swf_SetBits(tag, height, 8); + } + } + + swf_SetBits(tag, 0, 2); /* I-Frame */ + swf_SetBits(tag, 0, 1); /* No deblock filter */ + swf_SetBits(tag, quant, 5); /* quantizer (1-31), may be updated later on*/ + swf_SetBits(tag, 0, 1); /* No extra info */ + + bbx = (width+15)/16; + bby = (height+15)/16; + + for(by=0;by