experimental (& faster) motion estimation squished a dirty uninitialized var bug mpeg1 fcode>1 support Originally committed as revision 349 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -81,6 +81,7 @@ typedef struct AVCodecContext { | |||||
| /* video only */ | /* video only */ | ||||
| int frame_rate; /* frames per sec multiplied by FRAME_RATE_BASE */ | int frame_rate; /* frames per sec multiplied by FRAME_RATE_BASE */ | ||||
| int width, height; | int width, height; | ||||
| int aspect_ratio_info; | |||||
| int gop_size; /* 0 = intra only */ | int gop_size; /* 0 = intra only */ | ||||
| int pix_fmt; /* pixel format, see PIX_FMT_xxx */ | int pix_fmt; /* pixel format, see PIX_FMT_xxx */ | ||||
| @@ -781,7 +781,10 @@ static void mpeg4_encode_vol_header(MpegEncContext * s) | |||||
| put_bits(&s->pb, 1, 1); /* is obj layer id= yes */ | put_bits(&s->pb, 1, 1); /* is obj layer id= yes */ | ||||
| put_bits(&s->pb, 4, vo_ver_id); /* is obj layer ver id */ | put_bits(&s->pb, 4, vo_ver_id); /* is obj layer ver id */ | ||||
| put_bits(&s->pb, 3, 1); /* is obj layer priority */ | put_bits(&s->pb, 3, 1); /* is obj layer priority */ | ||||
| put_bits(&s->pb, 4, 1); /* aspect ratio info= sqare pixel */ //FIXME real aspect | |||||
| if(s->aspect_ratio_info) | |||||
| put_bits(&s->pb, 4, s->aspect_ratio_info);/* aspect ratio info */ | |||||
| else | |||||
| put_bits(&s->pb, 4, 1); /* aspect ratio info= sqare pixel */ | |||||
| put_bits(&s->pb, 1, 0); /* vol control parameters= no */ | put_bits(&s->pb, 1, 0); /* vol control parameters= no */ | ||||
| put_bits(&s->pb, 2, RECT_SHAPE); /* vol shape= rectangle */ | put_bits(&s->pb, 2, RECT_SHAPE); /* vol shape= rectangle */ | ||||
| put_bits(&s->pb, 1, 1); /* marker bit */ | put_bits(&s->pb, 1, 1); /* marker bit */ | ||||
| @@ -2149,6 +2152,7 @@ int mpeg4_decode_picture_header(MpegEncContext * s) | |||||
| skip_bits(&s->gb, 8); //par_width | skip_bits(&s->gb, 8); //par_width | ||||
| skip_bits(&s->gb, 8); // par_height | skip_bits(&s->gb, 8); // par_height | ||||
| } | } | ||||
| if(get_bits1(&s->gb)){ /* vol control parameter */ | if(get_bits1(&s->gb)){ /* vol control parameter */ | ||||
| printf("vol control parameter not supported\n"); | printf("vol control parameter not supported\n"); | ||||
| return -1; | return -1; | ||||
| @@ -2388,7 +2392,6 @@ int mpeg4_decode_picture_header(MpegEncContext * s) | |||||
| //printf("b-code %d\n", s->b_code); | //printf("b-code %d\n", s->b_code); | ||||
| } | } | ||||
| //printf("quant:%d fcode:%d\n", s->qscale, s->f_code); | //printf("quant:%d fcode:%d\n", s->qscale, s->f_code); | ||||
| if(!s->scalability){ | if(!s->scalability){ | ||||
| if (s->shape!=RECT_SHAPE && s->pict_type!=I_TYPE) { | if (s->shape!=RECT_SHAPE && s->pict_type!=I_TYPE) { | ||||
| skip_bits1(&s->gb); // vop shape coding type | skip_bits1(&s->gb); // vop shape coding type | ||||
| @@ -123,6 +123,7 @@ static int h263_decode_frame(AVCodecContext *avctx, | |||||
| if (!s->context_initialized) { | if (!s->context_initialized) { | ||||
| avctx->width = s->width; | avctx->width = s->width; | ||||
| avctx->height = s->height; | avctx->height = s->height; | ||||
| avctx->aspect_ratio_info= s->aspect_ratio_info; | |||||
| if (MPV_common_init(s) < 0) | if (MPV_common_init(s) < 0) | ||||
| return -1; | return -1; | ||||
| } else if (s->width != avctx->width || s->height != avctx->height) { | } else if (s->width != avctx->width || s->height != avctx->height) { | ||||
| @@ -335,13 +335,15 @@ static int phods_motion_search(MpegEncContext * s, | |||||
| #define Z_THRESHOLD 256 | #define Z_THRESHOLD 256 | ||||
| #define CHECK_MV(x,y)\ | #define CHECK_MV(x,y)\ | ||||
| {\ | |||||
| d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16);\ | d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16);\ | ||||
| d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ | d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant;\ | ||||
| if(d<dmin){\ | if(d<dmin){\ | ||||
| best[0]=x;\ | best[0]=x;\ | ||||
| best[1]=y;\ | best[1]=y;\ | ||||
| dmin=d;\ | dmin=d;\ | ||||
| } | |||||
| }\ | |||||
| } | |||||
| #define CHECK_MV_DIR(x,y,new_dir)\ | #define CHECK_MV_DIR(x,y,new_dir)\ | ||||
| {\ | {\ | ||||
| @@ -355,6 +357,13 @@ static int phods_motion_search(MpegEncContext * s, | |||||
| }\ | }\ | ||||
| } | } | ||||
| #define check(x,y,S,v)\ | |||||
| if( (x)<(xmin<<(S)) ) printf("%d %d %d %d xmin" #v, (x), (y), s->mb_x, s->mb_y);\ | |||||
| if( (x)>(xmax<<(S)) ) printf("%d %d %d %d xmax" #v, (x), (y), s->mb_x, s->mb_y);\ | |||||
| if( (y)<(ymin<<(S)) ) printf("%d %d %d %d ymin" #v, (x), (y), s->mb_x, s->mb_y);\ | |||||
| if( (y)>(ymax<<(S)) ) printf("%d %d %d %d ymax" #v, (x), (y), s->mb_x, s->mb_y);\ | |||||
| static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin, | static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin, | ||||
| UINT8 *new_pic, UINT8 *old_pic, int pic_stride, | UINT8 *new_pic, UINT8 *old_pic, int pic_stride, | ||||
| int pred_x, int pred_y, UINT16 *mv_penalty, int quant, | int pred_x, int pred_y, UINT16 *mv_penalty, int quant, | ||||
| @@ -379,6 +388,91 @@ static inline int small_diamond_search(MpegEncContext * s, int *best, int dmin, | |||||
| return dmin; | return dmin; | ||||
| } | } | ||||
| } | } | ||||
| /* for(;;){ | |||||
| int d; | |||||
| const int x= best[0]; | |||||
| const int y= best[1]; | |||||
| const int last_min=dmin; | |||||
| if(x>xmin) CHECK_MV(x-1, y ) | |||||
| if(y>xmin) CHECK_MV(x , y-1) | |||||
| if(x<xmax) CHECK_MV(x+1, y ) | |||||
| if(y<xmax) CHECK_MV(x , y+1) | |||||
| if(x>xmin && y>ymin) CHECK_MV(x-1, y-1) | |||||
| if(x>xmin && y<ymax) CHECK_MV(x-1, y+1) | |||||
| if(x<xmax && y>ymin) CHECK_MV(x+1, y-1) | |||||
| if(x<xmax && y<ymax) CHECK_MV(x+1, y+1) | |||||
| if(x-1>xmin) CHECK_MV(x-2, y ) | |||||
| if(y-1>xmin) CHECK_MV(x , y-2) | |||||
| if(x+1<xmax) CHECK_MV(x+2, y ) | |||||
| if(y+1<xmax) CHECK_MV(x , y+2) | |||||
| if(x-1>xmin && y-1>ymin) CHECK_MV(x-2, y-2) | |||||
| if(x-1>xmin && y+1<ymax) CHECK_MV(x-2, y+2) | |||||
| if(x+1<xmax && y-1>ymin) CHECK_MV(x+2, y-2) | |||||
| if(x+1<xmax && y+1<ymax) CHECK_MV(x+2, y+2) | |||||
| if(dmin==last_min) return dmin; | |||||
| } | |||||
| */ | |||||
| } | |||||
| static inline int snake_search(MpegEncContext * s, int *best, int dmin, | |||||
| UINT8 *new_pic, UINT8 *old_pic, int pic_stride, | |||||
| int pred_x, int pred_y, UINT16 *mv_penalty, int quant, | |||||
| int xmin, int ymin, int xmax, int ymax, int shift) | |||||
| { | |||||
| int dir=0; | |||||
| int c=1; | |||||
| static int x_dir[8]= {1,1,0,-1,-1,-1, 0, 1}; | |||||
| static int y_dir[8]= {0,1,1, 1, 0,-1,-1,-1}; | |||||
| int fails=0; | |||||
| int last_d[2]={dmin, dmin}; | |||||
| /*static int good=0; | |||||
| static int bad=0; | |||||
| static int point=0; | |||||
| point++; | |||||
| if(256*256*256*64%point==0) | |||||
| { | |||||
| printf("%d %d %d\n", good, bad, point); | |||||
| }*/ | |||||
| for(;;){ | |||||
| int x= best[0]; | |||||
| int y= best[1]; | |||||
| int d; | |||||
| x+=x_dir[dir]; | |||||
| y+=y_dir[dir]; | |||||
| if(x>=xmin && x<=xmax && y>=ymin && y<=ymax){ | |||||
| d = pix_abs16x16(new_pic, old_pic + (x) + (y)*pic_stride, pic_stride, 16); | |||||
| d += (mv_penalty[((x)<<shift)-pred_x] + mv_penalty[((y)<<shift)-pred_y])*quant; | |||||
| }else{ | |||||
| d = dmin + 10000; //FIXME smarter boundary handling | |||||
| } | |||||
| if(d<dmin){ | |||||
| best[0]=x; | |||||
| best[1]=y; | |||||
| dmin=d; | |||||
| if(last_d[1] - last_d[0] > last_d[0] - d) c= -c; | |||||
| dir+=c; | |||||
| fails=0; | |||||
| //good++; | |||||
| last_d[1]=last_d[0]; | |||||
| last_d[0]=d; | |||||
| }else{ | |||||
| //bad++; | |||||
| if(fails){ | |||||
| if(fails>=3) return dmin; | |||||
| }else{ | |||||
| c= -c; | |||||
| } | |||||
| dir+=c*2; | |||||
| fails++; | |||||
| } | |||||
| dir&=7; | |||||
| } | |||||
| } | } | ||||
| static int epzs_motion_search(MpegEncContext * s, | static int epzs_motion_search(MpegEncContext * s, | ||||
| @@ -397,8 +491,7 @@ static int epzs_motion_search(MpegEncContext * s, | |||||
| new_pic = s->new_picture[0] + pic_xy; | new_pic = s->new_picture[0] + pic_xy; | ||||
| old_pic = s->last_picture[0] + pic_xy; | old_pic = s->last_picture[0] + pic_xy; | ||||
| //printf("%d %d %d %d\n", xmin, ymin, xmax, ymax); | |||||
| dmin = pix_abs16x16(new_pic, old_pic, pic_stride, 16); | dmin = pix_abs16x16(new_pic, old_pic, pic_stride, 16); | ||||
| if(dmin<Z_THRESHOLD){ | if(dmin<Z_THRESHOLD){ | ||||
| *mx_ptr= 0; | *mx_ptr= 0; | ||||
| @@ -424,13 +517,18 @@ static int epzs_motion_search(MpegEncContext * s, | |||||
| } | } | ||||
| CHECK_MV(P[0][0]>>shift, P[0][1]>>shift) | CHECK_MV(P[0][0]>>shift, P[0][1]>>shift) | ||||
| dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride, | |||||
| pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift); | |||||
| //check(best[0],best[1],0, b0) | |||||
| if(s->full_search==ME_EPZS) | |||||
| dmin= small_diamond_search(s, best, dmin, new_pic, old_pic, pic_stride, | |||||
| pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift); | |||||
| else | |||||
| dmin= snake_search(s, best, dmin, new_pic, old_pic, pic_stride, | |||||
| pred_x, pred_y, mv_penalty, quant, xmin, ymin, xmax, ymax, shift); | |||||
| //check(best[0],best[1],0, b1) | |||||
| *mx_ptr= best[0]; | *mx_ptr= best[0]; | ||||
| *my_ptr= best[1]; | *my_ptr= best[1]; | ||||
| // printf("%d %d %d \n", best[0], best[1], dmin); | // printf("%d %d %d \n", best[0], best[1], dmin); | ||||
| return dmin; | return dmin; | ||||
| } | } | ||||
| @@ -563,8 +661,8 @@ int estimate_motion(MpegEncContext * s, | |||||
| rel_ymax= ymax - s->mb_y*16; | rel_ymax= ymax - s->mb_y*16; | ||||
| if(s->out_format == FMT_H263){ | if(s->out_format == FMT_H263){ | ||||
| static const int off[4]= {2, 1, 1, -1}; | static const int off[4]= {2, 1, 1, -1}; | ||||
| const int mot_stride = s->block_wrap[0]; | |||||
| const int mot_xy = s->block_index[0]; | |||||
| const int mot_stride = s->mb_width*2 + 2; | |||||
| const int mot_xy = (s->mb_y*2 + 1)*mot_stride + s->mb_x*2 + 1; | |||||
| P[0][0] = s->motion_val[mot_xy ][0]; | P[0][0] = s->motion_val[mot_xy ][0]; | ||||
| P[0][1] = s->motion_val[mot_xy ][1]; | P[0][1] = s->motion_val[mot_xy ][1]; | ||||
| @@ -618,7 +716,8 @@ int estimate_motion(MpegEncContext * s, | |||||
| P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]); | P[4][1]= mid_pred(P[1][1], P[2][1], P[3][1]); | ||||
| } | } | ||||
| } | } | ||||
| dmin = epzs_motion_search(s, &mx, &my, P, pred_x, pred_y, rel_xmin, rel_ymin, rel_xmax, rel_ymax); | |||||
| dmin = epzs_motion_search(s, &mx, &my, P, pred_x, pred_y, rel_xmin, rel_ymin, rel_xmax, rel_ymax); | |||||
| mx+= s->mb_x*16; | mx+= s->mb_x*16; | ||||
| my+= s->mb_y*16; | my+= s->mb_y*16; | ||||
| break; | break; | ||||
| @@ -654,6 +753,8 @@ int estimate_motion(MpegEncContext * s, | |||||
| mx -= 16 * s->mb_x; | mx -= 16 * s->mb_x; | ||||
| my -= 16 * s->mb_y; | my -= 16 * s->mb_y; | ||||
| } | } | ||||
| // check(mx + 32*s->mb_x, my + 32*s->mb_y, 1, end) | |||||
| *mx_ptr = mx; | *mx_ptr = mx; | ||||
| *my_ptr = my; | *my_ptr = my; | ||||
| return 0; | return 0; | ||||
| @@ -51,6 +51,9 @@ static int mpeg2_decode_block_intra(MpegEncContext *s, | |||||
| int n); | int n); | ||||
| static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred); | static int mpeg_decode_motion(MpegEncContext *s, int fcode, int pred); | ||||
| static UINT16 mv_penalty[MAX_FCODE][MAX_MV*2+1]; | |||||
| static UINT8 fcode_tab[MAX_MV*2+1]; | |||||
| static void put_header(MpegEncContext *s, int header) | static void put_header(MpegEncContext *s, int header) | ||||
| { | { | ||||
| align_put_bits(&s->pb); | align_put_bits(&s->pb); | ||||
| @@ -353,6 +356,53 @@ static void mpeg1_encode_motion(MpegEncContext *s, int val) | |||||
| } | } | ||||
| } | } | ||||
| void mpeg1_encode_init(MpegEncContext *s) | |||||
| { | |||||
| static int done=0; | |||||
| if(!done){ | |||||
| int f_code; | |||||
| int mv; | |||||
| done=1; | |||||
| for(f_code=1; f_code<=MAX_FCODE; f_code++){ | |||||
| for(mv=-MAX_MV; mv<=MAX_MV; mv++){ | |||||
| int len; | |||||
| if(mv==0) len= mbMotionVectorTable[0][1]; | |||||
| else{ | |||||
| int val, bit_size, range, code; | |||||
| bit_size = s->f_code - 1; | |||||
| range = 1 << bit_size; | |||||
| val=mv; | |||||
| if (val < 0) | |||||
| val = -val; | |||||
| val--; | |||||
| code = (val >> bit_size) + 1; | |||||
| if(code<17){ | |||||
| len= mbMotionVectorTable[code][1] + 1 + bit_size; | |||||
| }else{ | |||||
| len= mbMotionVectorTable[16][1] + 2 + bit_size; | |||||
| } | |||||
| } | |||||
| mv_penalty[f_code][mv+MAX_MV]= len; | |||||
| } | |||||
| } | |||||
| for(f_code=MAX_FCODE; f_code>0; f_code--){ | |||||
| for(mv=-(8<<f_code); mv<(8<<f_code); mv++){ | |||||
| fcode_tab[mv+MAX_MV]= f_code; | |||||
| } | |||||
| } | |||||
| } | |||||
| s->mv_penalty= mv_penalty; | |||||
| s->fcode_tab= fcode_tab; | |||||
| } | |||||
| static inline void encode_dc(MpegEncContext *s, int diff, int component) | static inline void encode_dc(MpegEncContext *s, int diff, int component) | ||||
| { | { | ||||
| if (component == 0) { | if (component == 0) { | ||||
| @@ -294,6 +294,7 @@ int MPV_encode_init(AVCodecContext *avctx) | |||||
| s->qcompress= avctx->qcompress; | s->qcompress= avctx->qcompress; | ||||
| s->qblur= avctx->qblur; | s->qblur= avctx->qblur; | ||||
| s->avctx = avctx; | s->avctx = avctx; | ||||
| s->aspect_ratio_info= avctx->aspect_ratio_info; | |||||
| if (s->gop_size <= 1) { | if (s->gop_size <= 1) { | ||||
| s->intra_only = 1; | s->intra_only = 1; | ||||
| @@ -377,6 +378,8 @@ int MPV_encode_init(AVCodecContext *avctx) | |||||
| if (s->out_format == FMT_H263) | if (s->out_format == FMT_H263) | ||||
| h263_encode_init(s); | h263_encode_init(s); | ||||
| else if (s->out_format == FMT_MPEG1) | |||||
| mpeg1_encode_init(s); | |||||
| s->encoding = 1; | s->encoding = 1; | ||||
| @@ -1075,7 +1078,6 @@ static void encode_picture(MpegEncContext *s, int picture_number) | |||||
| /* Reset the average MB variance */ | /* Reset the average MB variance */ | ||||
| s->avg_mb_var = 0; | s->avg_mb_var = 0; | ||||
| s->mc_mb_var = 0; | s->mc_mb_var = 0; | ||||
| /* Estimate motion for every MB */ | /* Estimate motion for every MB */ | ||||
| for(mb_y=0; mb_y < s->mb_height; mb_y++) { | for(mb_y=0; mb_y < s->mb_height; mb_y++) { | ||||
| for(mb_x=0; mb_x < s->mb_width; mb_x++) { | for(mb_x=0; mb_x < s->mb_width; mb_x++) { | ||||
| @@ -1132,12 +1134,13 @@ static void encode_picture(MpegEncContext *s, int picture_number) | |||||
| for(i=MAX_FCODE; i>1; i--){ | for(i=MAX_FCODE; i>1; i--){ | ||||
| loose+= mv_num[i]; | loose+= mv_num[i]; | ||||
| if(loose > 4) break; | |||||
| if(loose > 4) break; //FIXME this is pretty ineffective | |||||
| } | } | ||||
| s->f_code= i; | s->f_code= i; | ||||
| }else{ | }else{ | ||||
| s->f_code= 1; | s->f_code= 1; | ||||
| } | } | ||||
| //printf("f_code %d ///\n", s->f_code); | //printf("f_code %d ///\n", s->f_code); | ||||
| /* convert MBs with too long MVs to I-Blocks */ | /* convert MBs with too long MVs to I-Blocks */ | ||||
| if(s->pict_type==P_TYPE){ | if(s->pict_type==P_TYPE){ | ||||
| @@ -309,6 +309,7 @@ void mpeg1_encode_picture_header(MpegEncContext *s, int picture_number); | |||||
| void mpeg1_encode_mb(MpegEncContext *s, | void mpeg1_encode_mb(MpegEncContext *s, | ||||
| DCTELEM block[6][64], | DCTELEM block[6][64], | ||||
| int motion_x, int motion_y); | int motion_x, int motion_y); | ||||
| void mpeg1_encode_init(MpegEncContext *s); | |||||
| /* h263enc.c */ | /* h263enc.c */ | ||||