-static void iterative_me(SnowContext *s){
- int pass, mb_x, mb_y;
- const int b_width = s->b_width << s->block_max_depth;
- const int b_height= s->b_height << s->block_max_depth;
- const int b_stride= b_width;
- int color[3];
-
- {
- RangeCoder r = s->c;
- uint8_t state[sizeof(s->block_state)];
- memcpy(state, s->block_state, sizeof(s->block_state));
- for(mb_y= 0; mb_y<s->b_height; mb_y++)
- for(mb_x= 0; mb_x<s->b_width; mb_x++)
- encode_q_branch(s, 0, mb_x, mb_y);
- s->c = r;
- memcpy(s->block_state, state, sizeof(s->block_state));
- }
-
- for(pass=0; pass<25; pass++){
- int change= 0;
-
- for(mb_y= 0; mb_y<b_height; mb_y++){
- for(mb_x= 0; mb_x<b_width; mb_x++){
- int dia_change, i, j, ref;
- int best_rd= INT_MAX, ref_rd;
- BlockNode backup, ref_b;
- const int index= mb_x + mb_y * b_stride;
- BlockNode *block= &s->block[index];
- BlockNode *tb = mb_y ? &s->block[index-b_stride ] : NULL;
- BlockNode *lb = mb_x ? &s->block[index -1] : NULL;
- BlockNode *rb = mb_x+1<b_width ? &s->block[index +1] : NULL;
- BlockNode *bb = mb_y+1<b_height ? &s->block[index+b_stride ] : NULL;
- BlockNode *tlb= mb_x && mb_y ? &s->block[index-b_stride-1] : NULL;
- BlockNode *trb= mb_x+1<b_width && mb_y ? &s->block[index-b_stride+1] : NULL;
- BlockNode *blb= mb_x && mb_y+1<b_height ? &s->block[index+b_stride-1] : NULL;
- BlockNode *brb= mb_x+1<b_width && mb_y+1<b_height ? &s->block[index+b_stride+1] : NULL;
- const int b_w= (MB_SIZE >> s->block_max_depth);
- uint8_t obmc_edged[b_w*2][b_w*2];
-
- if(pass && (block->type & BLOCK_OPT))
- continue;
- block->type |= BLOCK_OPT;
-
- backup= *block;
-
- if(!s->me_cache_generation)
- memset(s->me_cache, 0, sizeof(s->me_cache));
- s->me_cache_generation += 1<<22;
-
- //FIXME precalculate
- {
- int x, y;
- memcpy(obmc_edged, obmc_tab[s->block_max_depth], b_w*b_w*4);
- if(mb_x==0)
- for(y=0; y<b_w*2; y++)
- memset(obmc_edged[y], obmc_edged[y][0] + obmc_edged[y][b_w-1], b_w);
- if(mb_x==b_stride-1)
- for(y=0; y<b_w*2; y++)
- memset(obmc_edged[y]+b_w, obmc_edged[y][b_w] + obmc_edged[y][b_w*2-1], b_w);
- if(mb_y==0){
- for(x=0; x<b_w*2; x++)
- obmc_edged[0][x] += obmc_edged[b_w-1][x];
- for(y=1; y<b_w; y++)
- memcpy(obmc_edged[y], obmc_edged[0], b_w*2);
- }
- if(mb_y==b_height-1){
- for(x=0; x<b_w*2; x++)
- obmc_edged[b_w*2-1][x] += obmc_edged[b_w][x];
- for(y=b_w; y<b_w*2-1; y++)
- memcpy(obmc_edged[y], obmc_edged[b_w*2-1], b_w*2);
- }
- }
-
- //skip stuff outside the picture
- if(mb_x==0 || mb_y==0 || mb_x==b_width-1 || mb_y==b_height-1){
- uint8_t *src= s-> input_picture.data[0];
- uint8_t *dst= s->current_picture.data[0];
- const int stride= s->current_picture.linesize[0];
- const int block_w= MB_SIZE >> s->block_max_depth;
- const int sx= block_w*mb_x - block_w/2;
- const int sy= block_w*mb_y - block_w/2;
- const int w= s->plane[0].width;
- const int h= s->plane[0].height;
- int y;
-
- for(y=sy; y<0; y++)
- memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
- for(y=h; y<sy+block_w*2; y++)
- memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);
- if(sx<0){
- for(y=sy; y<sy+block_w*2; y++)
- memcpy(dst + sx + y*stride, src + sx + y*stride, -sx);
- }
- if(sx+block_w*2 > w){
- for(y=sy; y<sy+block_w*2; y++)
- memcpy(dst + w + y*stride, src + w + y*stride, sx+block_w*2 - w);
- }
- }
-
- // intra(black) = neighbors' contribution to the current block
- for(i=0; i<3; i++)
- color[i]= get_dc(s, mb_x, mb_y, i);
-
- // get previous score (cannot be cached due to OBMC)
- if(pass > 0 && (block->type&BLOCK_INTRA)){
- int color0[3]= {block->color[0], block->color[1], block->color[2]};
- check_block(s, mb_x, mb_y, color0, 1, *obmc_edged, &best_rd);
- }else
- check_block_inter(s, mb_x, mb_y, block->mx, block->my, *obmc_edged, &best_rd);
-
- ref_b= *block;
- ref_rd= best_rd;
- for(ref=0; ref < s->ref_frames; ref++){
- int16_t (*mvr)[2]= &s->ref_mvs[ref][index];
- if(s->ref_scores[ref][index] > s->ref_scores[ref_b.ref][index]*3/2) //FIXME tune threshold
- continue;
- block->ref= ref;
- best_rd= INT_MAX;
-
- check_block_inter(s, mb_x, mb_y, mvr[0][0], mvr[0][1], *obmc_edged, &best_rd);
- check_block_inter(s, mb_x, mb_y, 0, 0, *obmc_edged, &best_rd);
- if(tb)
- check_block_inter(s, mb_x, mb_y, mvr[-b_stride][0], mvr[-b_stride][1], *obmc_edged, &best_rd);
- if(lb)
- check_block_inter(s, mb_x, mb_y, mvr[-1][0], mvr[-1][1], *obmc_edged, &best_rd);
- if(rb)
- check_block_inter(s, mb_x, mb_y, mvr[1][0], mvr[1][1], *obmc_edged, &best_rd);
- if(bb)
- check_block_inter(s, mb_x, mb_y, mvr[b_stride][0], mvr[b_stride][1], *obmc_edged, &best_rd);
-
- /* fullpel ME */
- //FIXME avoid subpel interpolation / round to nearest integer
- do{
- dia_change=0;
- for(i=0; i<FFMAX(s->avctx->dia_size, 1); i++){
- for(j=0; j<i; j++){
- dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+4*(i-j), block->my+(4*j), *obmc_edged, &best_rd);
- dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my-(4*j), *obmc_edged, &best_rd);
- dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+4*(i-j), block->my-(4*j), *obmc_edged, &best_rd);
- dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my+(4*j), *obmc_edged, &best_rd);
- }
- }
- }while(dia_change);
- /* subpel ME */
- do{
- static const int square[8][2]= {{+1, 0},{-1, 0},{ 0,+1},{ 0,-1},{+1,+1},{-1,-1},{+1,-1},{-1,+1},};
- dia_change=0;
- for(i=0; i<8; i++)
- dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+square[i][0], block->my+square[i][1], *obmc_edged, &best_rd);
- }while(dia_change);
- //FIXME or try the standard 2 pass qpel or similar
-
- mvr[0][0]= block->mx;
- mvr[0][1]= block->my;
- if(ref_rd > best_rd){
- ref_rd= best_rd;
- ref_b= *block;
- }
- }
- best_rd= ref_rd;
- *block= ref_b;
-#if 1
- check_block(s, mb_x, mb_y, color, 1, *obmc_edged, &best_rd);
- //FIXME RD style color selection
-#endif
- if(!same_block(block, &backup)){
- if(tb ) tb ->type &= ~BLOCK_OPT;
- if(lb ) lb ->type &= ~BLOCK_OPT;
- if(rb ) rb ->type &= ~BLOCK_OPT;
- if(bb ) bb ->type &= ~BLOCK_OPT;
- if(tlb) tlb->type &= ~BLOCK_OPT;
- if(trb) trb->type &= ~BLOCK_OPT;
- if(blb) blb->type &= ~BLOCK_OPT;
- if(brb) brb->type &= ~BLOCK_OPT;
- change ++;
- }
- }
- }
- av_log(NULL, AV_LOG_ERROR, "pass:%d changed:%d\n", pass, change);
- if(!change)
- break;
- }
-
- if(s->block_max_depth == 1){
- int change= 0;
- for(mb_y= 0; mb_y<b_height; mb_y+=2){
- for(mb_x= 0; mb_x<b_width; mb_x+=2){
- int i;
- int best_rd, init_rd;
- const int index= mb_x + mb_y * b_stride;
- BlockNode *b[4];