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;
                {
                    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);
                    }
                }
                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);
                    }
                }
                for(i=0; i<3; i++)
                    color[i]= get_dc(s, mb_x, mb_y, i);
                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)
                        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);
                    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);
                    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);
                    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);
#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];
                b[0]= &s->block[index];
                b[1]= b[0]+1;
                b[2]= b[0]+b_stride;
                b[3]= b[2]+1;
                if(same_block(b[0], b[1]) &&
                   same_block(b[0], b[2]) &&
                   same_block(b[0], b[3]))
                    continue;
                if(!s->me_cache_generation)
                    memset(s->me_cache, 0, sizeof(s->me_cache));
                s->me_cache_generation += 1<<22;
                init_rd= best_rd= get_4block_rd(s, mb_x, mb_y, 0);
                check_4block_inter(s, mb_x, mb_y,
                                   (b[0]->mx + b[1]->mx + b[2]->mx + b[3]->mx + 2) >> 2,
                                   (b[0]->my + b[1]->my + b[2]->my + b[3]->my + 2) >> 2, 0, &best_rd);
                for(i=0; i<4; i++)
                    if(!(b[i]->type&BLOCK_INTRA))
                        check_4block_inter(s, mb_x, mb_y, b[i]->mx, b[i]->my, b[i]->ref, &best_rd);
                if(init_rd != best_rd)
                    change++;
            }
        }
        av_log(NULL, AV_LOG_ERROR, "pass:4mv changed:%d\n", change*4);
    }
}
['static void iterative_me(SnowContext *s){\n    int pass, mb_x, mb_y;\n    const int b_width = s->b_width  << s->block_max_depth;\n    const int b_height= s->b_height << s->block_max_depth;\n    const int b_stride= b_width;\n    int color[3];\n    {\n        RangeCoder r = s->c;\n        uint8_t state[sizeof(s->block_state)];\n        memcpy(state, s->block_state, sizeof(s->block_state));\n        for(mb_y= 0; mb_y<s->b_height; mb_y++)\n            for(mb_x= 0; mb_x<s->b_width; mb_x++)\n                encode_q_branch(s, 0, mb_x, mb_y);\n        s->c = r;\n        memcpy(s->block_state, state, sizeof(s->block_state));\n    }\n    for(pass=0; pass<25; pass++){\n        int change= 0;\n        for(mb_y= 0; mb_y<b_height; mb_y++){\n            for(mb_x= 0; mb_x<b_width; mb_x++){\n                int dia_change, i, j, ref;\n                int best_rd= INT_MAX, ref_rd;\n                BlockNode backup, ref_b;\n                const int index= mb_x + mb_y * b_stride;\n                BlockNode *block= &s->block[index];\n                BlockNode *tb =                   mb_y            ? &s->block[index-b_stride  ] : NULL;\n                BlockNode *lb = mb_x                              ? &s->block[index         -1] : NULL;\n                BlockNode *rb = mb_x+1<b_width                    ? &s->block[index         +1] : NULL;\n                BlockNode *bb =                   mb_y+1<b_height ? &s->block[index+b_stride  ] : NULL;\n                BlockNode *tlb= mb_x           && mb_y            ? &s->block[index-b_stride-1] : NULL;\n                BlockNode *trb= mb_x+1<b_width && mb_y            ? &s->block[index-b_stride+1] : NULL;\n                BlockNode *blb= mb_x           && mb_y+1<b_height ? &s->block[index+b_stride-1] : NULL;\n                BlockNode *brb= mb_x+1<b_width && mb_y+1<b_height ? &s->block[index+b_stride+1] : NULL;\n                const int b_w= (MB_SIZE >> s->block_max_depth);\n                uint8_t obmc_edged[b_w*2][b_w*2];\n                if(pass && (block->type & BLOCK_OPT))\n                    continue;\n                block->type |= BLOCK_OPT;\n                backup= *block;\n                if(!s->me_cache_generation)\n                    memset(s->me_cache, 0, sizeof(s->me_cache));\n                s->me_cache_generation += 1<<22;\n                {\n                    int x, y;\n                    memcpy(obmc_edged, obmc_tab[s->block_max_depth], b_w*b_w*4);\n                    if(mb_x==0)\n                        for(y=0; y<b_w*2; y++)\n                            memset(obmc_edged[y], obmc_edged[y][0] + obmc_edged[y][b_w-1], b_w);\n                    if(mb_x==b_stride-1)\n                        for(y=0; y<b_w*2; y++)\n                            memset(obmc_edged[y]+b_w, obmc_edged[y][b_w] + obmc_edged[y][b_w*2-1], b_w);\n                    if(mb_y==0){\n                        for(x=0; x<b_w*2; x++)\n                            obmc_edged[0][x] += obmc_edged[b_w-1][x];\n                        for(y=1; y<b_w; y++)\n                            memcpy(obmc_edged[y], obmc_edged[0], b_w*2);\n                    }\n                    if(mb_y==b_height-1){\n                        for(x=0; x<b_w*2; x++)\n                            obmc_edged[b_w*2-1][x] += obmc_edged[b_w][x];\n                        for(y=b_w; y<b_w*2-1; y++)\n                            memcpy(obmc_edged[y], obmc_edged[b_w*2-1], b_w*2);\n                    }\n                }\n                if(mb_x==0 || mb_y==0 || mb_x==b_width-1 || mb_y==b_height-1){\n                    uint8_t *src= s->  input_picture.data[0];\n                    uint8_t *dst= s->current_picture.data[0];\n                    const int stride= s->current_picture.linesize[0];\n                    const int block_w= MB_SIZE >> s->block_max_depth;\n                    const int sx= block_w*mb_x - block_w/2;\n                    const int sy= block_w*mb_y - block_w/2;\n                    const int w= s->plane[0].width;\n                    const int h= s->plane[0].height;\n                    int y;\n                    for(y=sy; y<0; y++)\n                        memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);\n                    for(y=h; y<sy+block_w*2; y++)\n                        memcpy(dst + sx + y*stride, src + sx + y*stride, block_w*2);\n                    if(sx<0){\n                        for(y=sy; y<sy+block_w*2; y++)\n                            memcpy(dst + sx + y*stride, src + sx + y*stride, -sx);\n                    }\n                    if(sx+block_w*2 > w){\n                        for(y=sy; y<sy+block_w*2; y++)\n                            memcpy(dst + w + y*stride, src + w + y*stride, sx+block_w*2 - w);\n                    }\n                }\n                for(i=0; i<3; i++)\n                    color[i]= get_dc(s, mb_x, mb_y, i);\n                if(pass > 0 && (block->type&BLOCK_INTRA)){\n                    int color0[3]= {block->color[0], block->color[1], block->color[2]};\n                    check_block(s, mb_x, mb_y, color0, 1, *obmc_edged, &best_rd);\n                }else\n                    check_block_inter(s, mb_x, mb_y, block->mx, block->my, *obmc_edged, &best_rd);\n                ref_b= *block;\n                ref_rd= best_rd;\n                for(ref=0; ref < s->ref_frames; ref++){\n                    int16_t (*mvr)[2]= &s->ref_mvs[ref][index];\n                    if(s->ref_scores[ref][index] > s->ref_scores[ref_b.ref][index]*3/2)\n                        continue;\n                    block->ref= ref;\n                    best_rd= INT_MAX;\n                    check_block_inter(s, mb_x, mb_y, mvr[0][0], mvr[0][1], *obmc_edged, &best_rd);\n                    check_block_inter(s, mb_x, mb_y, 0, 0, *obmc_edged, &best_rd);\n                    if(tb)\n                        check_block_inter(s, mb_x, mb_y, mvr[-b_stride][0], mvr[-b_stride][1], *obmc_edged, &best_rd);\n                    if(lb)\n                        check_block_inter(s, mb_x, mb_y, mvr[-1][0], mvr[-1][1], *obmc_edged, &best_rd);\n                    if(rb)\n                        check_block_inter(s, mb_x, mb_y, mvr[1][0], mvr[1][1], *obmc_edged, &best_rd);\n                    if(bb)\n                        check_block_inter(s, mb_x, mb_y, mvr[b_stride][0], mvr[b_stride][1], *obmc_edged, &best_rd);\n                    do{\n                        dia_change=0;\n                        for(i=0; i<FFMAX(s->avctx->dia_size, 1); i++){\n                            for(j=0; j<i; j++){\n                                dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+4*(i-j), block->my+(4*j), *obmc_edged, &best_rd);\n                                dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my-(4*j), *obmc_edged, &best_rd);\n                                dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+4*(i-j), block->my-(4*j), *obmc_edged, &best_rd);\n                                dia_change |= check_block_inter(s, mb_x, mb_y, block->mx-4*(i-j), block->my+(4*j), *obmc_edged, &best_rd);\n                            }\n                        }\n                    }while(dia_change);\n                    do{\n                        static const int square[8][2]= {{+1, 0},{-1, 0},{ 0,+1},{ 0,-1},{+1,+1},{-1,-1},{+1,-1},{-1,+1},};\n                        dia_change=0;\n                        for(i=0; i<8; i++)\n                            dia_change |= check_block_inter(s, mb_x, mb_y, block->mx+square[i][0], block->my+square[i][1], *obmc_edged, &best_rd);\n                    }while(dia_change);\n                    mvr[0][0]= block->mx;\n                    mvr[0][1]= block->my;\n                    if(ref_rd > best_rd){\n                        ref_rd= best_rd;\n                        ref_b= *block;\n                    }\n                }\n                best_rd= ref_rd;\n                *block= ref_b;\n#if 1\n                check_block(s, mb_x, mb_y, color, 1, *obmc_edged, &best_rd);\n#endif\n                if(!same_block(block, &backup)){\n                    if(tb ) tb ->type &= ~BLOCK_OPT;\n                    if(lb ) lb ->type &= ~BLOCK_OPT;\n                    if(rb ) rb ->type &= ~BLOCK_OPT;\n                    if(bb ) bb ->type &= ~BLOCK_OPT;\n                    if(tlb) tlb->type &= ~BLOCK_OPT;\n                    if(trb) trb->type &= ~BLOCK_OPT;\n                    if(blb) blb->type &= ~BLOCK_OPT;\n                    if(brb) brb->type &= ~BLOCK_OPT;\n                    change ++;\n                }\n            }\n        }\n        av_log(NULL, AV_LOG_ERROR, "pass:%d changed:%d\\n", pass, change);\n        if(!change)\n            break;\n    }\n    if(s->block_max_depth == 1){\n        int change= 0;\n        for(mb_y= 0; mb_y<b_height; mb_y+=2){\n            for(mb_x= 0; mb_x<b_width; mb_x+=2){\n                int i;\n                int best_rd, init_rd;\n                const int index= mb_x + mb_y * b_stride;\n                BlockNode *b[4];\n                b[0]= &s->block[index];\n                b[1]= b[0]+1;\n                b[2]= b[0]+b_stride;\n                b[3]= b[2]+1;\n                if(same_block(b[0], b[1]) &&\n                   same_block(b[0], b[2]) &&\n                   same_block(b[0], b[3]))\n                    continue;\n                if(!s->me_cache_generation)\n                    memset(s->me_cache, 0, sizeof(s->me_cache));\n                s->me_cache_generation += 1<<22;\n                init_rd= best_rd= get_4block_rd(s, mb_x, mb_y, 0);\n                check_4block_inter(s, mb_x, mb_y,\n                                   (b[0]->mx + b[1]->mx + b[2]->mx + b[3]->mx + 2) >> 2,\n                                   (b[0]->my + b[1]->my + b[2]->my + b[3]->my + 2) >> 2, 0, &best_rd);\n                for(i=0; i<4; i++)\n                    if(!(b[i]->type&BLOCK_INTRA))\n                        check_4block_inter(s, mb_x, mb_y, b[i]->mx, b[i]->my, b[i]->ref, &best_rd);\n                if(init_rd != best_rd)\n                    change++;\n            }\n        }\n        av_log(NULL, AV_LOG_ERROR, "pass:4mv changed:%d\\n", change*4);\n    }\n}']