X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fh.263%2Fmkvideo.c;h=20e58339491766f2e708caf51099d5499a5cf166;hb=d6ae22a11779055f9b4cb417b5f93562da99aaec;hp=db8d5278b24826aeb69f0debafb761abcb363070;hpb=a7a60c127b70f891c5bb1ecf58b9e90dfbfb1e41;p=swftools.git diff --git a/lib/h.263/mkvideo.c b/lib/h.263/mkvideo.c index db8d527..20e5833 100644 --- a/lib/h.263/mkvideo.c +++ b/lib/h.263/mkvideo.c @@ -29,8 +29,13 @@ void swf_SetVideoStreamDefine(TAG*tag, VIDEOSTREAM*stream, U16 frames, U16 width stream->linex = width; stream->width = width; stream->height = height; + stream->bbx = width/16; + stream->bby = height/16; stream->current = (YUV*)malloc(width*height*sizeof(YUV)); stream->oldpic = (YUV*)malloc(width*height*sizeof(YUV)); + stream->mvdx = (int*)malloc(stream->bbx*stream->bby*sizeof(int)); + stream->mvdy = (int*)malloc(stream->bbx*stream->bby*sizeof(int)); + stream->do_motion = 0; memset(stream->oldpic, 0, width*height*sizeof(YUV)); memset(stream->current, 0, width*height*sizeof(YUV)); @@ -39,6 +44,8 @@ void swf_VideoStreamClear(VIDEOSTREAM*stream) { free(stream->oldpic);stream->oldpic = 0; free(stream->current);stream->current = 0; + free(stream->mvdx);stream->mvdx=0; + free(stream->mvdy);stream->mvdy=0; } typedef struct _block_t @@ -51,16 +58,6 @@ typedef struct _block_t int v[64]; } block_t; -typedef struct _fblock_t -{ - double y1[64]; - double y2[64]; - double y3[64]; - double y4[64]; - double u[64]; - double v[64]; -} fblock_t; - static int zigzagtable[64] = { 0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, @@ -71,15 +68,14 @@ static int zigzagtable[64] = { 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63}; -static void fzigzag(double*src) +static void zigzag(int*src) { - double tmp[64]; + int tmp[64]; int t; for(t=0;t<64;t++) { - ((int*)&tmp[zigzagtable[t]])[0] = ((int*)&src[t])[0]; - ((int*)&tmp[zigzagtable[t]])[1] = ((int*)&src[t])[1]; + tmp[zigzagtable[t]] = src[t]; } - memcpy(src, tmp, sizeof(double)*64); + memcpy(src, tmp, sizeof(int)*64); } #define PI 3.14159265358979 @@ -98,7 +94,7 @@ static double table[8][8] = {0.195090322016128,-0.555570233019602,0.831469612302545,-0.980785280403231,0.980785280403230,-0.831469612302545,0.555570233019602,-0.195090322016129} }; -static void dct(double*src) +static void dct(int*src) { double tmp[64]; int x,y,u,v,t; @@ -121,11 +117,11 @@ static void dct(double*src) { c+=table[v][y]*tmp[y*8+u]; } - src[v*8+u] = c*0.25; + src[v*8+u] = (int)(c*0.25); } } -static void idct(double*src) +static void idct(int*src) { double tmp[64]; int x,y,u,v; @@ -147,10 +143,100 @@ static void idct(double*src) { c+=table[v][y]*tmp[v*8+x]; } - src[y*8+x] = c*0.25; + src[y*8+x] = (int)(c*0.25); } } +static double c[8] = {1.0, +0.980785280403230, // cos(Pi*1/16), sin(Pi*7/16) +0.923879532511287, // cos(Pi*2/16), sin(Pi*6/16) +0.831469612302545, // cos(Pi*3/16), sin(Pi*5/16) +0.707106781186548, // cos(Pi*4/16), sin(Pi*4/16), 1/sqrt(2) +0.555570233019602, // cos(Pi*5/16), sin(Pi*3/16) +0.382683432365090, // cos(Pi*6/16), sin(Pi*2/16) +0.195090322016128 // cos(Pi*7/16), sin(Pi*1/16) +}; + +static double cc[8]; +int ccquant = -1; + +static void preparequant(int quant) +{ + if(ccquant == quant) + return; + cc[0] = c[0]/(quant*2*4); + cc[1] = c[1]/(quant*2*4); + cc[2] = c[2]/(quant*2*4); + cc[3] = c[3]/(quant*2*4); + cc[4] = c[4]/(quant*2*4); + cc[5] = c[5]/(quant*2*4); + cc[6] = c[6]/(quant*2*4); + cc[7] = c[7]/(quant*2*4); + ccquant = quant; +} + +inline static void innerdct(double*a,double*b, double*c) +{ + // c1*c7*2 = c6 + // c2*c6*2 = c4 + // c3*c5*2 = c2 + // c4*c4*2 = 1 + + //{ 1, 3, 5, 7, -7, -5, -3, -1}, + //{ 3, -7, -1, -5, 5, 1, 7, -3}, + //{ 5, -1, 7, 3, -3, -7, 1, -5}, + //{ 7, -5, 3, -1, 1, -3, 5, -7} + double b0,b1,b2,b3,b4,b5; + b2 = (a[0]+a[7]); + b3 = (a[1]+a[6]); + b4 = (a[2]+a[5]); + b5 = (a[3]+a[4]); + + b0 = (b2+b5)*c[4]; + b1 = (b3+b4)*c[4]; + b[0*8] = b0 + b1; + b[4*8] = b0 - b1; + b[2*8] = (b2-b5)*c[2] + (b3-b4)*c[6]; + b[6*8] = (b2-b5)*c[6] + (b4-b3)*c[2]; + + b0 = (a[0]-a[7]); + b1 = (a[1]-a[6]); + b2 = (a[2]-a[5]); + b3 = (a[3]-a[4]); + + b[1*8] = b0*c[1] + b1*c[3] + b2*c[5] + b3*c[7]; + b[3*8] = b0*c[3] - b1*c[7] - b2*c[1] - b3*c[5]; + b[5*8] = b0*c[5] - b1*c[1] + b2*c[7] + b3*c[3]; + b[7*8] = b0*c[7] - b1*c[5] + b2*c[3] - b3*c[1]; +} + +static void dct2(int*src, int*dest) +{ + double tmp[64], tmp2[64]; + double*p; + int u,x,v,t; + + for(t=0;t<64;t++) + tmp2[t] = src[t]; + + for(v=0;v<8;v++) + { + double* a=&tmp2[v*8]; + double* b=&tmp[v]; + innerdct(a,b,c); + } + for(v=0;v<8;v++) + { + double* a=&tmp[v*8]; + double* b=&tmp2[v]; + innerdct(a,b,cc); + } + for(t=0;t<64;t++) { + dest[zigzagtable[t]] = (int)(tmp2[t]); + } +} + + static inline int truncate256(int a) { if(a>255) return 255; @@ -158,25 +244,47 @@ static inline int truncate256(int a) return a; } -static void getregion(fblock_t* bb, YUV*pic, int bx, int by, int linex) +static void getregion(block_t* bb, YUV*pic, int posx, int posy, int linex) { - YUV*p1 = &pic[by*linex*16+bx*16]; - YUV*p2 = p1; + YUV*p1; + YUV*p2; 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++) { - bb->u[u++] = (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4; - bb->v[v++] = (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4; - bb->y1[y1++] = p1[x].y; - bb->y2[y2++] = p1[x+8].y; - bb->y3[y3++] = p1[linex*8+x].y; - bb->y4[y4++] = p1[linex*8+x+8].y; + int hp = (posy&1)<<1|(posx&1); + posx>>=1; + posy>>=1; + p1 = &pic[posy*linex+posx]; + p2 = p1; + if(hp==0x0) { + for(y=0;y<8;y++) { + for(x=0;x<8;x++) { + bb->u[u++] = (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4; + bb->v[v++] = (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4; + bb->y1[y1++] = p1[x].y; + bb->y2[y2++] = p1[x+8].y; + bb->y3[y3++] = p1[linex*8+x].y; + bb->y4[y4++] = p1[linex*8+x+8].y; + } + p1+=linex; + p2+=linex*2; + } + } else if(hp==0x1) { + for(y=0;y<8;y++) { + for(x=0;x<8;x++) { + bb->u[u++] = (p2[x*2].u + p2[x*2+1].u + p2[linex+x*2].u + p2[linex+x*2+1].u)/4; + bb->v[v++] = (p2[x*2].v + p2[x*2+1].v + p2[linex+x*2].v + p2[linex+x*2+1].v)/4; + bb->y1[y1++] = (p1[x].y + p1[x+1].y)/2; + bb->y2[y2++] = (p1[x+8].y + p1[x+8+1].y)/2; + bb->y3[y3++] = (p1[linex*8+x].y + p1[linex*8+x+1].y)/2; + bb->y4[y4++] = (p1[linex*8+x+8].y + p1[linex*8+x+8+1].y)/2; + } + p1+=linex; + p2+=linex*2; } - p1+=linex; - p2+=linex*2; } + else + assert(0); } static void rgb2yuv(YUV*dest, RGBA*src, int dlinex, int slinex, int width, int height) { @@ -314,7 +422,7 @@ static int codehuffman(TAG*tag, struct huffcode*table, int index) return i; } -static void quantize8x8(double*src, int*dest, int has_dc, int quant) +static void quantize8x8(int*src, int*dest, int has_dc, int quant) { int t,pos=0; double q = 1.0/(quant*2); @@ -497,22 +605,43 @@ static void encode8x8(TAG*tag, int*bb, int has_dc, int has_tcoef) } } -static void dodct(fblock_t*fb) +static void quantize(block_t*fb, block_t*b, int has_dc, int quant) +{ + quantize8x8(fb->y1, b->y1, has_dc, quant); + quantize8x8(fb->y2, b->y2, has_dc, quant); + quantize8x8(fb->y3, b->y3, has_dc, quant); + quantize8x8(fb->y4, b->y4, has_dc, quant); + quantize8x8(fb->u, b->u, has_dc, quant); + quantize8x8(fb->v, b->v, has_dc, quant); +} + +static void dodct(block_t*fb) { - int t; dct(fb->y1); dct(fb->y2); dct(fb->y3); dct(fb->y4); dct(fb->u); dct(fb->v); - fzigzag(fb->y1); - fzigzag(fb->y2); - fzigzag(fb->y3); - fzigzag(fb->y4); - fzigzag(fb->u); - fzigzag(fb->v); + zigzag(fb->y1); + zigzag(fb->y2); + zigzag(fb->y3); + zigzag(fb->y4); + zigzag(fb->u); + zigzag(fb->v); +} +static void dodctandquant(block_t*fb, block_t*b, int has_dc, int quant) +{ + int t; + if(has_dc) { + dodct(fb); + quantize(fb,b,has_dc,quant); + return; + } + preparequant(quant); + dct2(fb->y1,b->y1); dct2(fb->y2,b->y2); dct2(fb->y3,b->y3); dct2(fb->y4,b->y4); + dct2(fb->u,b->u); dct2(fb->v,b->v); } static void doidct(block_t*b) { - fblock_t fb; + block_t fb; int t; for(t=0;t<64;t++) { fb.y1[t] = b->y1[zigzagtable[t]]; @@ -546,15 +675,6 @@ static void truncateblock(block_t*b) } } -static void quantize(fblock_t*fb, block_t*b, int has_dc, int quant) -{ - quantize8x8(fb->y1, b->y1, has_dc, quant); - quantize8x8(fb->y2, b->y2, has_dc, quant); - quantize8x8(fb->y3, b->y3, has_dc, quant); - quantize8x8(fb->y4, b->y4, has_dc, quant); - quantize8x8(fb->u, b->u, has_dc, quant); - quantize8x8(fb->v, b->v, has_dc, quant); -} static void dequantize(block_t*b, int has_dc, int quant) { dequantize8x8(b->y1, has_dc, quant); @@ -606,17 +726,18 @@ static void change_quant(int quant, int*dquant) static void encode_blockI(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) { - fblock_t fb; + block_t fb; block_t b; int dquant=0; int cbpcbits = 0, cbpybits=0; - getregion(&fb, s->current, bx, by, s->width); - dodct(&fb); + getregion(&fb, s->current, bx*2*16, by*2*16, s->width); change_quant(*quant, &dquant); *quant+=dquant; - quantize(&fb, &b, 1, *quant); + + dodctandquant(&fb, &b, 1, *quant); + //quantize(&fb, &b, 1, *quant); //decode_blockI(s, &b, bx, by); @@ -651,7 +772,7 @@ static void encode_blockI(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) copyblock(s, s->current, &b, bx, by); } -static void yuvdiff(fblock_t*a, fblock_t*b) +static void yuvdiff(block_t*a, block_t*b) { int t; for(t=0;t<64;t++) { @@ -664,9 +785,79 @@ static void yuvdiff(fblock_t*a, fblock_t*b) } } +static void predictmvd(VIDEOSTREAM*s, int bx, int by, int*px, int*py) +{ + int i1,i2; + int x1,y1,x2,y2,x3,y3; + int x4,y4,p; + if(bx) {x1=s->mvdx[by*s->bbx+bx-1]; + y1=s->mvdy[by*s->bbx+bx-1]; + } else {x1=y1=0;} + + if(by) {x2=s->mvdx[(by-1)*s->bbx+bx]; + y2=s->mvdy[(by-1)*s->bbx+bx]; + if(bxbbx-1) { + x3=s->mvdx[(by-1)*s->bbx+bx+1]; + y3=s->mvdy[(by-1)*s->bbx+bx+1]; + } else { + x3=y3=0; + } + } + else {x2=x3=x1;y2=y3=y1;} + + if((x1 <= x2 && x2 <= x3) || + (x3 <= x2 && x2 <= x1)) { + x4=x2; + } else if((x2 <= x1 && x1 <= x3) || + (x3 <= x1 && x1 <= x2)) { + x4=x1; + } else if((x1 <= x3 && x3 <= x2) || + (x2 <= x3 && x3 <= x1)) { + x4=x3; + } + + if((y1 <= y2 && y2 <= y3) || + (y3 <= y2 && y2 <= y1)) { + y4=y2; + } else if((y2 <= y1 && y1 <= y3) || + (y3 <= y1 && y1 <= y2)) { + y4=y1; + } else if((y1 <= y3 && y3 <= y2) || + (y2 <= y3 && y3 <= y1)) { + y4=y3; + } + + *px = x4; + *py = y4; + assert((x4>=-32 && x4<=31) && (y4>=-32 && y4<=31)); +} + +static inline int mvd2index(int px, int py, int x, int y, int xy) +{ + assert((x>=-32 && x<=31) && (y>=-32 && y<=31)); + assert((x&1)==0 && (y&1)==0);//for now + assert((x&2)==0 && (y&2)==0);//for now(2) + + x-=px; + y-=py; + + if(xy) + x=y; + x+=32; + + /* (x&63) */ + if(x>63) + x-=64; + if(x<0) + x+=64; + + assert(x>=0 && x<64); + return x; +} + static int encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) { - fblock_t fb; + block_t fb; block_t b; int dquant=0; int has_mvd=0; @@ -675,29 +866,35 @@ static int encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) int mode = 0; int cbpcbits = 0, cbpybits=0; int diff; + int predictmvdx; + int predictmvdy; block_t b_i; int bits_i; - fblock_t fbold_v00; + block_t fbold_v00; block_t b_v00; - int bits_v00; + int bits_v00 = 65535; + int x_v00=0; + int y_v00=0; diff = compareregions(s, bx, by); - if(diff < 16 /*TODO: should be a parameter- good values are between 32 and 48 */) { + if(diff < 20 /*TODO: should be a parameter- good values are between 32 and 48 */) { swf_SetBits(tag, 1,1); /* cod=1, block skipped */ + /* copy the region from the last frame so that we have a complete reconstruction */ copyregion(s, s->current, s->oldpic, bx, by); return 1; } - getregion(&fb, s->current, bx, by, s->width); + predictmvd(s,bx,by,&predictmvdx,&predictmvdy); + getregion(&fb, s->current, bx*2*16, by*2*16, s->width); { /* consider I-block */ - fblock_t fb_i; + block_t fb_i; int y,c; - memcpy(&fb_i, &fb, sizeof(fblock_t)); - dodct(&fb_i); - quantize(&fb_i, &b_i, 1, *quant); + memcpy(&fb_i, &fb, sizeof(block_t)); + dodctandquant(&fb_i, &b_i, 1, *quant); + //quantize(&fb_i, &b_i, 1, *quant); getblockpatterns(&b_i, &y, &c, 1); bits_i = 1; //cod bits_i += mcbpc_inter[3*4+c].len; @@ -710,20 +907,63 @@ static int encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) bits_i += coefbits8x8(b_i.v, 1); } - { /* consider mvd(0,0)-block */ - fblock_t fbdiff; + { /* consider mvd(x,y)-block */ + block_t fbdiff; int y,c; - memcpy(&fbdiff, &fb, sizeof(fblock_t)); - getregion(&fbold_v00, s->oldpic, bx, by, s->linex); - yuvdiff(&fbdiff, &fbold_v00); - dodct(&fbdiff); - quantize(&fbdiff, &b_v00, 0, *quant); + + x_v00=0; + y_v00=0; + + if(s->do_motion) { + int hx,hy; + int bestx=0,besty=0,bestbits=65536; + int startx=-8,endx=8; + int starty=-8,endy=8; + + if(!bx) startx=0; + if(!by) starty=0; + if(bx==s->bbx-1) endx=0; + if(by==s->bby-1) endy=0; + + for(hx=startx;hx<=endx;hx+=4) + for(hy=starty;hy<=endy;hy+=4) + { + block_t b; + block_t fbold; + int bits = 0; + memcpy(&fbdiff, &fb, sizeof(block_t)); + getregion(&fbold, s->oldpic, bx*2*16+hx, by*2*16+hy, s->linex); + yuvdiff(&fbdiff, &fbold); + dodctandquant(&fbdiff, &b, 0, *quant); + //quantize(&fbdiff, &b, 0, *quant); + bits += coefbits8x8(b.y1, 0); + bits += coefbits8x8(b.y2, 0); + bits += coefbits8x8(b.y3, 0); + bits += coefbits8x8(b.y4, 0); + bits += coefbits8x8(b.u, 0); + bits += coefbits8x8(b.v, 0); + if(bitsoldpic, bx*2*16+x_v00, by*2*16+y_v00, s->linex); + yuvdiff(&fbdiff, &fbold_v00); + dodctandquant(&fbdiff, &b_v00, 0, *quant); + //quantize(&fbdiff, &b_v00, 0, *quant); getblockpatterns(&b_v00, &y, &c, 0); + bits_v00 = 1; //cod bits_v00 += mcbpc_inter[0*4+c].len; bits_v00 += cbpy[y^15].len; - bits_v00 += mvd[32].len; // (0,0) - bits_v00 += mvd[32].len; + bits_v00 += mvd[mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 0)].len; // (0,0) + bits_v00 += mvd[mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 1)].len; bits_v00 += coefbits8x8(b_v00.y1, 0); bits_v00 += coefbits8x8(b_v00.y2, 0); bits_v00 += coefbits8x8(b_v00.y3, 0); @@ -745,9 +985,11 @@ static int encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) codehuffman(tag, mcbpc_inter, mode*4+cbpcbits); codehuffman(tag, cbpy, cbpybits^15); - /* 0,0 */ - codehuffman(tag, mvd, 32); - codehuffman(tag, mvd, 32); + /* vector */ + codehuffman(tag, mvd, mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 0)); + codehuffman(tag, mvd, mvd2index(predictmvdx, predictmvdy, x_v00, y_v00, 1)); + s->mvdx[by*s->bbx+bx] = x_v00; + s->mvdy[by*s->bbx+bx] = y_v00; /* luminance */ encode8x8(tag, b.y1, has_dc, cbpybits&8); @@ -777,8 +1019,6 @@ static int encode_blockP(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) mode = 3; has_dc = 1; memcpy(&b, &b_i, sizeof(block_t)); - //dodct(&fb); - //quantize(&fb, &b, has_dc, *quant); getblockpatterns(&b, &cbpybits, &cbpcbits, has_dc); swf_SetBits(tag,0,1); // COD codehuffman(tag, mcbpc_inter, mode*4+cbpcbits); @@ -883,24 +1123,22 @@ static void writeHeader(TAG*tag, int width, int height, int frame, int quant, in swf_SetBits(tag, quant, 5); /* quantizer (1-31), may be updated later on*/ swf_SetBits(tag, 0, 1); /* No extra info */ } - void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant) { - int bx, by, bbx, bby; + int bx, by; if(quant<1) quant=1; if(quant>31) quant=31; writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_IFRAME); - bbx = (s->width+15)/16; //TODO: move bbx,bby into VIDEOSTREAM - bby = (s->height+15)/16; - rgb2yuv(s->current, pic, s->linex, s->olinex, s->width, s->height); - for(by=0;bybby;by++) { - for(bx=0;bxbbx;bx++) { encode_blockI(tag, s, bx, by, &quant); } @@ -911,28 +1149,27 @@ void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant) void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant) { - int bx, by, bbx, bby; + int bx, by; if(quant<1) quant=1; if(quant>31) quant=31; writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME); - bbx = (s->width+15)/16; - bby = (s->height+15)/16; - rgb2yuv(s->current, pic, s->linex, s->olinex, s->width, s->height); + memset(s->mvdx, 0, s->bbx*s->bby*sizeof(int)); + memset(s->mvdy, 0, s->bbx*s->bby*sizeof(int)); - for(by=0;bybby;by++) { - for(bx=0;bxbbx;bx++) { encode_blockP(tag, s, bx, by, &quant); } } s->frame++; memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV)); - +#ifdef MAIN { int t; FILE*fi = fopen("test.ppm", "wb"); @@ -946,6 +1183,7 @@ void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant) } fclose(fi); } +#endif } #ifdef MAIN @@ -960,10 +1198,10 @@ int main(int argn, char*argv[]) SWFPLACEOBJECT obj; int width = 0; int height = 0; - int frames = 10; + int frames = 5; int framerate = 29; unsigned char*data; - char* fname = "/home/kramm/pics/lena.png"; + char* fname = "/home/kramm/pics/peppers.png"; VIDEOSTREAM stream; double d = 1.0; @@ -993,6 +1231,7 @@ int main(int argn, char*argv[]) tag = swf_InsertTag(tag, ST_DEFINEVIDEOSTREAM); swf_SetU16(tag, 33); swf_SetVideoStreamDefine(tag, &stream, frames, width, height); + stream.do_motion = 1; for(t=0;t