static void rv40_loop_filter(RV34DecContext *r, int row) { MpegEncContext *s = &r->s; int mb_pos, mb_x; int i, j, k; uint8_t *Y, *C; int alpha, beta, betaY, betaC; int q; int mbtype[4]; ///< current macroblock and its neighbours types /** * flags indicating that macroblock can be filtered with strong filter * it is set only for intra coded MB and MB with DCs coded separately */ int mb_strong[4]; int clip[4]; ///< MB filter clipping value calculated from filtering strength /** * coded block patterns for luma part of current macroblock and its neighbours * Format: * LSB corresponds to the top left block, * each nibble represents one row of subblocks. */ int cbp[4]; /** * coded block patterns for chroma part of current macroblock and its neighbours * Format is the same as for luma with two subblocks in a row. */ int uvcbp[4][2]; /** * This mask represents the pattern of luma subblocks that should be filtered * in addition to the coded ones because because they lie at the edge of * 8x8 block with different enough motion vectors */ int mvmasks[4]; mb_pos = row * s->mb_stride; for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ int mbtype = s->current_picture_ptr->f.mb_type[mb_pos]; if(IS_INTRA(mbtype) || IS_SEPARATE_DC(mbtype)) r->cbp_luma [mb_pos] = r->deblock_coefs[mb_pos] = 0xFFFF; if(IS_INTRA(mbtype)) r->cbp_chroma[mb_pos] = 0xFF; } mb_pos = row * s->mb_stride; for(mb_x = 0; mb_x < s->mb_width; mb_x++, mb_pos++){ int y_h_deblock, y_v_deblock; int c_v_deblock[2], c_h_deblock[2]; int clip_left; int avail[4]; int y_to_deblock, c_to_deblock[2]; q = s->current_picture_ptr->f.qscale_table[mb_pos]; alpha = rv40_alpha_tab[q]; beta = rv40_beta_tab [q]; betaY = betaC = beta * 3; if(s->width * s->height <= 176*144) betaY += beta; avail[0] = 1; avail[1] = row; avail[2] = mb_x; avail[3] = row < s->mb_height - 1; for(i = 0; i < 4; i++){ if(avail[i]){ int pos = mb_pos + neighbour_offs_x[i] + neighbour_offs_y[i]*s->mb_stride; mvmasks[i] = r->deblock_coefs[pos]; mbtype [i] = s->current_picture_ptr->f.mb_type[pos]; cbp [i] = r->cbp_luma[pos]; uvcbp[i][0] = r->cbp_chroma[pos] & 0xF; uvcbp[i][1] = r->cbp_chroma[pos] >> 4; }else{ mvmasks[i] = 0; mbtype [i] = mbtype[0]; cbp [i] = 0; uvcbp[i][0] = uvcbp[i][1] = 0; } mb_strong[i] = IS_INTRA(mbtype[i]) || IS_SEPARATE_DC(mbtype[i]); clip[i] = rv40_filter_clip_tbl[mb_strong[i] + 1][q]; } y_to_deblock = mvmasks[POS_CUR] | (mvmasks[POS_BOTTOM] << 16); /* This pattern contains bits signalling that horizontal edges of * the current block can be filtered. * That happens when either of adjacent subblocks is coded or lies on * the edge of 8x8 blocks with motion vectors differing by more than * 3/4 pel in any component (any edge orientation for some reason). */ y_h_deblock = y_to_deblock | ((cbp[POS_CUR] << 4) & ~MASK_Y_TOP_ROW) | ((cbp[POS_TOP] & MASK_Y_LAST_ROW) >> 12); /* This pattern contains bits signalling that vertical edges of * the current block can be filtered. * That happens when either of adjacent subblocks is coded or lies on * the edge of 8x8 blocks with motion vectors differing by more than * 3/4 pel in any component (any edge orientation for some reason). */ y_v_deblock = y_to_deblock | ((cbp[POS_CUR] << 1) & ~MASK_Y_LEFT_COL) | ((cbp[POS_LEFT] & MASK_Y_RIGHT_COL) >> 3); if(!mb_x) y_v_deblock &= ~MASK_Y_LEFT_COL; if(!row) y_h_deblock &= ~MASK_Y_TOP_ROW; if(row == s->mb_height - 1 || (mb_strong[POS_CUR] || mb_strong[POS_BOTTOM])) y_h_deblock &= ~(MASK_Y_TOP_ROW << 16); /* Calculating chroma patterns is similar and easier since there is * no motion vector pattern for them. */ for(i = 0; i < 2; i++){ c_to_deblock[i] = (uvcbp[POS_BOTTOM][i] << 4) | uvcbp[POS_CUR][i]; c_v_deblock[i] = c_to_deblock[i] | ((uvcbp[POS_CUR] [i] << 1) & ~MASK_C_LEFT_COL) | ((uvcbp[POS_LEFT][i] & MASK_C_RIGHT_COL) >> 1); c_h_deblock[i] = c_to_deblock[i] | ((uvcbp[POS_TOP][i] & MASK_C_LAST_ROW) >> 2) | (uvcbp[POS_CUR][i] << 2); if(!mb_x) c_v_deblock[i] &= ~MASK_C_LEFT_COL; if(!row) c_h_deblock[i] &= ~MASK_C_TOP_ROW; if(row == s->mb_height - 1 || mb_strong[POS_CUR] || mb_strong[POS_BOTTOM]) c_h_deblock[i] &= ~(MASK_C_TOP_ROW << 4); } for(j = 0; j < 16; j += 4){ Y = s->current_picture_ptr->f.data[0] + mb_x*16 + (row*16 + j) * s->linesize; for(i = 0; i < 4; i++, Y += 4){ int ij = i + j; int clip_cur = y_to_deblock & (MASK_CUR << ij) ? clip[POS_CUR] : 0; int dither = j ? ij : i*4; // if bottom block is coded then we can filter its top edge // (or bottom edge of this block, which is the same) if(y_h_deblock & (MASK_BOTTOM << ij)){ r->rdsp.rv40_h_loop_filter(Y+4*s->linesize, s->linesize, dither, y_to_deblock & (MASK_BOTTOM << ij) ? clip[POS_CUR] : 0, clip_cur, alpha, beta, betaY, 0, 0); } // filter left block edge in ordinary mode (with low filtering strength) if(y_v_deblock & (MASK_CUR << ij) && (i || !(mb_strong[POS_CUR] || mb_strong[POS_LEFT]))){ if(!i) clip_left = mvmasks[POS_LEFT] & (MASK_RIGHT << j) ? clip[POS_LEFT] : 0; else clip_left = y_to_deblock & (MASK_CUR << (ij-1)) ? clip[POS_CUR] : 0; r->rdsp.rv40_v_loop_filter(Y, s->linesize, dither, clip_cur, clip_left, alpha, beta, betaY, 0, 0); } // filter top edge of the current macroblock when filtering strength is high if(!j && y_h_deblock & (MASK_CUR << i) && (mb_strong[POS_CUR] || mb_strong[POS_TOP])){ r->rdsp.rv40_h_loop_filter(Y, s->linesize, dither, clip_cur, mvmasks[POS_TOP] & (MASK_TOP << i) ? clip[POS_TOP] : 0, alpha, beta, betaY, 0, 1); } // filter left block edge in edge mode (with high filtering strength) if(y_v_deblock & (MASK_CUR << ij) && !i && (mb_strong[POS_CUR] || mb_strong[POS_LEFT])){ clip_left = mvmasks[POS_LEFT] & (MASK_RIGHT << j) ? clip[POS_LEFT] : 0; r->rdsp.rv40_v_loop_filter(Y, s->linesize, dither, clip_cur, clip_left, alpha, beta, betaY, 0, 1); } } } for(k = 0; k < 2; k++){ for(j = 0; j < 2; j++){ C = s->current_picture_ptr->f.data[k + 1] + mb_x*8 + (row*8 + j*4) * s->uvlinesize; for(i = 0; i < 2; i++, C += 4){ int ij = i + j*2; int clip_cur = c_to_deblock[k] & (MASK_CUR << ij) ? clip[POS_CUR] : 0; if(c_h_deblock[k] & (MASK_CUR << (ij+2))){ int clip_bot = c_to_deblock[k] & (MASK_CUR << (ij+2)) ? clip[POS_CUR] : 0; r->rdsp.rv40_h_loop_filter(C+4*s->uvlinesize, s->uvlinesize, i*8, clip_bot, clip_cur, alpha, beta, betaC, 1, 0); } if((c_v_deblock[k] & (MASK_CUR << ij)) && (i || !(mb_strong[POS_CUR] || mb_strong[POS_LEFT]))){ if(!i) clip_left = uvcbp[POS_LEFT][k] & (MASK_CUR << (2*j+1)) ? clip[POS_LEFT] : 0; else clip_left = c_to_deblock[k] & (MASK_CUR << (ij-1)) ? clip[POS_CUR] : 0; r->rdsp.rv40_v_loop_filter(C, s->uvlinesize, j*8, clip_cur, clip_left, alpha, beta, betaC, 1, 0); } if(!j && c_h_deblock[k] & (MASK_CUR << ij) && (mb_strong[POS_CUR] || mb_strong[POS_TOP])){ int clip_top = uvcbp[POS_TOP][k] & (MASK_CUR << (ij+2)) ? clip[POS_TOP] : 0; r->rdsp.rv40_h_loop_filter(C, s->uvlinesize, i*8, clip_cur, clip_top, alpha, beta, betaC, 1, 1); } if(c_v_deblock[k] & (MASK_CUR << ij) && !i && (mb_strong[POS_CUR] || mb_strong[POS_LEFT])){ clip_left = uvcbp[POS_LEFT][k] & (MASK_CUR << (2*j+1)) ? clip[POS_LEFT] : 0; r->rdsp.rv40_v_loop_filter(C, s->uvlinesize, j*8, clip_cur, clip_left, alpha, beta, betaC, 1, 1); } } } } } }