X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fh.263%2Fmkvideo.c;h=8fc554dcb8ddb491be5027c1ad76726ef4025d4b;hb=958c6ff463beca74ae616d04a21e709f4a016855;hp=250f4c738a5385e1c2ff9144b3386bf0dcbf1021;hpb=95ab8f4e51eac64a2cb420a9c309e0f3cbdf0048;p=swftools.git diff --git a/lib/h.263/mkvideo.c b/lib/h.263/mkvideo.c index 250f4c7..8fc554d 100644 --- a/lib/h.263/mkvideo.c +++ b/lib/h.263/mkvideo.c @@ -9,24 +9,9 @@ #include #include #include -#include "../lib/rfxswf.h" -#include "png.h" +#include "../rfxswf.h" #include "h263tables.c" - -typedef struct _YUV -{ - unsigned char y,u,v; -} YUV; - -typedef struct _VIDEOSTREAM -{ - int width; - int height; - int frame; - int linex; - YUV*oldpic; - YUV*current; -} VIDEOSTREAM; +#include "swfvideo.h" void swf_SetVideoStreamDefine(TAG*tag, VIDEOSTREAM*stream, U16 frames, U16 width, U16 height) { @@ -38,15 +23,29 @@ void swf_SetVideoStreamDefine(TAG*tag, VIDEOSTREAM*stream, U16 frames, U16 width swf_SetU8(tag, 2); /* codec = h.263 sorenson spark */ memset(stream, 0, sizeof(VIDEOSTREAM)); + stream->olinex = width; + width+=15;width&=~15; + height+=15;height&=~15; stream->linex = width; - width&=~15; - height&=~15; 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)); +} +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 @@ -166,9 +165,9 @@ 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(fblock_t* bb, YUV*pic, int posx, int posy, int linex) { - YUV*p1 = &pic[by*linex*16+bx*16]; + YUV*p1 = &pic[posy*linex+posx]; YUV*p2 = p1; int y1=0, y2=0, y3=0, y4=0; int u=0,v=0; @@ -186,18 +185,21 @@ static void getregion(fblock_t* bb, YUV*pic, int bx, int by, int linex) p2+=linex*2; } } -static void rgb2yuv(YUV*dest, RGBA*src, int linex, int width, int height) +static void rgb2yuv(YUV*dest, RGBA*src, int dlinex, int slinex, int width, int height) { int x,y; for(y=0;y>8; + dest[y*dlinex+x].u = (r*((int)(-0.169*256)) + g*((int)(-0.332*256)) + b*((int)( 0.500 *256))+ 128*256)>>8; + dest[y*dlinex+x].v = (r*((int)( 0.500*256)) + g*((int)(-0.419*256)) + b*((int)(-0.0813*256))+ 128*256)>>8; } } } @@ -275,7 +277,7 @@ static int compareregions(VIDEOSTREAM*s, int bx, int by) return diff/256; } -static int valtodc(int val) +static inline int valtodc(int val) { assert(val>=0); @@ -322,16 +324,21 @@ static int codehuffman(TAG*tag, struct huffcode*table, int index) static void quantize8x8(double*src, int*dest, int has_dc, int quant) { int t,pos=0; + double q = 1.0/(quant*2); if(has_dc) { dest[0] = valtodc((int)src[0]); /*DC*/ pos++; } for(t=pos;t<64;t++) { - dest[t] = (int)src[t]; + //dest[t] = (int)src[t]; /* exact: if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;} */ //if(quant&1){dest[t] = (dest[t]/quant - 1)/2;}else{dest[t] = ((dest[t]+1)/quant - 1)/2;} - dest[t] = dest[t]/(quant*2); + //dest[t] = dest[t]/(quant*2); + dest[t] = (int)(src[t]*q); + /* TODO: warn if this happens- the video will be buggy */ + if(dest[t]>127) dest[t]=127; + if(dest[t]<-127) dest[t]=-127; } } @@ -611,7 +618,7 @@ static void encode_blockI(TAG*tag, VIDEOSTREAM*s, int bx, int by, int*quant) int dquant=0; int cbpcbits = 0, cbpybits=0; - getregion(&fb, s->current, bx, by, s->width); + getregion(&fb, s->current, bx*16, by*16, s->width); dodct(&fb); change_quant(*quant, &dquant); @@ -664,6 +671,76 @@ 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; @@ -675,22 +752,28 @@ 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 b_v00; - int bits_v00; + int bits_v00 = 65535; + int x_v00=0; + int y_v00=0; diff = compareregions(s, bx, by); - if(diff < 24 /*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; + return 1; } - getregion(&fb, s->current, bx, by, s->width); + predictmvd(s,bx,by,&predictmvdx,&predictmvdy); + getregion(&fb, s->current, bx*16, by*16, s->width); { /* consider I-block */ fblock_t fb_i; @@ -710,20 +793,57 @@ 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 */ + if(bx&&by&&(bxbbx-1)&&(bybby-1)) + { /* consider mvd(x,y)-block */ fblock_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; + + for(hx=-8;hx<8;hx+=4) + for(hy=-8;hy<8;hy+=4) + { + block_t b; + fblock_t fbold; + int bits = 0; + memcpy(&fbdiff, &fb, sizeof(fblock_t)); + getregion(&fbold, s->oldpic, bx*16+hx/2, by*16+hy/2, s->linex); + yuvdiff(&fbdiff, &fbold); + dodct(&fbdiff); + 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*16+x_v00/2, by*16+y_v00/2, s->linex); + yuvdiff(&fbdiff, &fbold_v00); + dodct(&fbdiff); + 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 +865,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 +899,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); @@ -884,21 +1004,216 @@ static void writeHeader(TAG*tag, int width, int height, int frame, int quant, in swf_SetBits(tag, 0, 1); /* No extra info */ } -void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic) +int stat_qdiff(double*b1, double*b2) +{ + int x; + double diff=0; + for(x=0;x<64;x++) { + double y1 = b1[x] - b2[x]; + diff += y1*y1; + } + return (int)(diff/64); +} + +int stat_absdiff(double*b1, double*b2) +{ + int x; + double diff=0; + for(x=0;x<64;x++) { + double y1 = b1[x] - b2[x]; + diff += fabs(y1); + } + return (int)(diff/64); +} + +int stat_absfreq(double*b1, double*b2) +{ + int x; + double diff=0; + double d1[64],d2[64]; + memcpy(&d1, b1, 64*sizeof(double)); + dct(d1); + memcpy(&d2, b2, 64*sizeof(double)); + dct(d2); + for(x=0;x<64;x++) { + double y1 = d1[x] - d2[x]; + diff += fabs(y1); + } + return (int)(diff/64); +} + +int stat_qfreq(double*b1, double*b2) +{ + int x; + double diff=0; + double d1[64],d2[64]; + memcpy(&d1, b1, 64*sizeof(double)); + dct(d1); + memcpy(&d2, b2, 64*sizeof(double)); + dct(d2); + for(x=0;x<64;x++) { + double y1 = d1[x] - d2[x]; + diff += y1*y1; + } + return (int)(diff/64); +} + +int stat_nonnull(double*b1, double*b2) +{ + int x; + int diff=0; + double d1[64],d2[64]; + memcpy(&d1, b1, 64*sizeof(double)); + dct(d1); + memcpy(&d2, b2, 64*sizeof(double)); + dct(d2); + for(x=0;x<64;x++) { + int y1 = (int)((d1[x] - d2[x])/9); + if(y1) + diff++; + } + return diff; +} + +void stat_filter(FILE*fi, double*d1, double*d2) +{ + int x,y,xx,yy,b; + for(b=3;b>=0;b--) { + int d = 1<=0;b--) { + int d = 1<=0;b--) { + int d = 1<bby;by++) + for(bx=0;bxbbx;bx++) + { + for(by2=0;by2bby;by2++) + for(bx2=0;bx2current, bx*16, by*16, s->linex); + memcpy(&fbdiff, &fbnew, sizeof(fblock_t)); + getregion(&fbold, s->current, bx2*16, by2*16, s->linex); + yuvdiff(&fbdiff, &fbold); + dodct(&fbdiff); + quantize(&fbdiff, &b, 0, quant); + + stat(fi, b.y1, fbnew.y1, fbold.y1); + stat(fi, b.y2, fbnew.y2, fbold.y2); + stat(fi, b.y3, fbnew.y3, fbold.y3); + stat(fi, b.y4, fbnew.y4, fbold.y4); + stat(fi, b.u, fbnew.u, fbold.u); + stat(fi, b.v, fbnew.v, fbold.v); + + num++; + if(num==1000) { + fclose(fi); + exit(7); + } + } + printf("%d\n", num);fflush(stdout); + } + fclose(fi); + exit(7); +} + +void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant) +{ + 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); - rgb2yuv(s->current, pic, s->linex, s->width, s->height); + //dostat(s); - for(by=0;bybby;by++) { - for(bx=0;bxbbx;bx++) { encode_blockI(tag, s, bx, by, &quant); } @@ -907,28 +1222,29 @@ void swf_SetVideoStreamIFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic) memcpy(s->oldpic, s->current, s->width*s->height*sizeof(YUV)); } -void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic) +void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic, int quant) { - int bx, by, bbx, bby; - int quant = 31; + int bx, by; - writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME); + if(quant<1) quant=1; + if(quant>31) quant=31; - bbx = (s->width+15)/16; - bby = (s->height+15)/16; + writeHeader(tag, s->width, s->height, s->frame, quant, TYPE_PFRAME); - rgb2yuv(s->current, pic, s->linex, s->width, s->height); + 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"); @@ -942,8 +1258,11 @@ void swf_SetVideoStreamPFrame(TAG*tag, VIDEOSTREAM*s, RGBA*pic) } fclose(fi); } +#endif } +#ifdef MAIN +#include "png.h" int main(int argn, char*argv[]) { int fi; @@ -954,8 +1273,8 @@ int main(int argn, char*argv[]) SWFPLACEOBJECT obj; int width = 0; int height = 0; - int frames = 2; - int framerate = 1; + int frames = 50; + int framerate = 29; unsigned char*data; char* fname = "/home/kramm/pics/peppers.png"; VIDEOSTREAM stream; @@ -987,6 +1306,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