x264 环路滤波原理系列:fdec_filter_row 函数

时间:2024-12-13 07:16:27
static void fdec_filter_row( x264_t *h, int mb_y, int pass ) { /* mb_y is the mb to be encoded next, not the mb to be filtered here */ int b_hpel = h->fdec->b_kept_as_ref; int b_deblock = h->sh.i_disable_deblocking_filter_idc != 1; int b_end = mb_y == h->i_threadslice_end; int b_measure_quality = 1; int min_y = mb_y - (1 << SLICE_MBAFF); int b_start = min_y == h->i_threadslice_start; /* Even in interlaced mode, deblocking never modifies more than 4 pixels * above each MB, as bS=4 doesn't happen for the top of interlaced mbpairs. */ int minpix_y = min_y*16 - 4 * !b_start; int maxpix_y = mb_y*16 - 4 * !b_end; b_deblock &= b_hpel || h->param.b_full_recon || h->param.psz_dump_yuv; if( h->param.b_sliced_threads ) { switch( pass ) { /* During encode: only do deblock if asked for */ default: case 0: b_deblock &= h->param.b_full_recon; b_hpel = 0; break; /* During post-encode pass: do deblock if not done yet, do hpel for all * rows except those between slices. */ case 1: b_deblock &= !h->param.b_full_recon; b_hpel &= !(b_start && min_y > 0); b_measure_quality = 0; break; /* Final pass: do the rows between slices in sequence. */ case 2: b_deblock = 0; b_measure_quality = 0; break; } } if( mb_y & SLICE_MBAFF ) return; if( min_y < h->i_threadslice_start ) return; if( b_deblock ) for( int y = min_y; y < mb_y; y += (1 << SLICE_MBAFF) ) x264_frame_deblock_row( h, y ); /* FIXME: Prediction requires different borders for interlaced/progressive mc, * but the actual image data is equivalent. For now, maintain this * consistency by copying deblocked pixels between planes. */ if( PARAM_INTERLACED && (!h->param.b_sliced_threads || pass == 1) ) for( int p = 0; p < h->fdec->i_plane; p++ ) for( int i = minpix_y>>(CHROMA_V_SHIFT && p); i < maxpix_y>>(CHROMA_V_SHIFT && p); i++ ) memcpy( h->fdec->plane_fld[p] + i*h->fdec->i_stride[p], h->fdec->plane[p] + i*h->fdec->i_stride[p], h->mb.i_mb_width*16*SIZEOF_PIXEL ); if( h->fdec->b_kept_as_ref && (!h->param.b_sliced_threads || pass == 1) ) x264_frame_expand_border( h, h->fdec, min_y ); if( b_hpel ) { int end = mb_y == h->mb.i_mb_height; /* Can't do hpel until the previous slice is done encoding. */ if( h->param.analyse.i_subpel_refine ) { x264_frame_filter( h, h->fdec, min_y, end ); x264_frame_expand_border_filtered( h, h->fdec, min_y, end ); } } if( SLICE_MBAFF && pass == 0 ) for( int i = 0; i < 3; i++ ) { XCHG( pixel *, h->intra_border_backup[0][i], h->intra_border_backup[3][i] ); XCHG( pixel *, h->intra_border_backup[1][i], h->intra_border_backup[4][i] ); } if( h->i_thread_frames > 1 && h->fdec->b_kept_as_ref ) x264_frame_cond_broadcast( h->fdec, mb_y*16 + (b_end ? 10000 : -(X264_THREAD_HEIGHT << SLICE_MBAFF)) ); if( b_measure_quality ) { maxpix_y = X264_MIN( maxpix_y, h->param.i_height ); if( h->param.analyse.b_psnr ) { for( int p = 0; p < (CHROMA444 ? 3 : 1); p++ ) h->stat.frame.i_ssd[p] += x264_pixel_ssd_wxh( &h->pixf, h->fdec->plane[p] + minpix_y * h->fdec->i_stride[p], h->fdec->i_stride[p], h->fenc->plane[p] + minpix_y * h->fenc->i_stride[p], h->fenc->i_stride[p], h->param.i_width, maxpix_y-minpix_y ); if( !CHROMA444 ) { uint64_t ssd_u, ssd_v; int v_shift = CHROMA_V_SHIFT; x264_pixel_ssd_nv12( &h->pixf, h->fdec->plane[1] + (minpix_y>>v_shift) * h->fdec->i_stride[1], h->fdec->i_stride[1], h->fenc->plane[1] + (minpix_y>>v_shift) * h->fenc->i_stride[1], h->fenc->i_stride[1], h->param.i_width>>1, (maxpix_y-minpix_y)>>v_shift, &ssd_u, &ssd_v ); h->stat.frame.i_ssd[1] += ssd_u; h->stat.frame.i_ssd[2] += ssd_v; } } if( h->param.analyse.b_ssim ) { int ssim_cnt; x264_emms(); /* offset by 2 pixels to avoid alignment of ssim blocks with dct blocks, * and overlap by 4 */ minpix_y += b_start ? 2 : -6; h->stat.frame.f_ssim += x264_pixel_ssim_wxh( &h->pixf, h->fdec->plane[0] + 2+minpix_y*h->fdec->i_stride[0], h->fdec->i_stride[0], h->fenc->plane[0] + 2+minpix_y*h->fenc->i_stride[0], h->fenc->i_stride[0], h->param.i_width-2, maxpix_y-minpix_y, h->scratch_buffer, &ssim_cnt ); h->stat.frame.i_ssim_cnt += ssim_cnt; } } }