From: Laurent Aimar Date: Sat, 3 Oct 2009 22:17:57 +0000 (+0200) Subject: Added yadif deinterlacer to our module. X-Git-Tag: 1.1.0-ff~3046 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=158925b1a4099ed6e2db32f8f9ca3c558a462d76;p=vlc Added yadif deinterlacer to our module. There is 2 new deinterlacing modes: "Yadif" and "Yadif (2x)". "Yadif (2x)" doubles the frame rate, whereas "Yadif" throws away one field. yadif.h comes from vf_yadif.c (GPLv2+) from MPayer project. I have stripped it a bit but let the functions unmodified for easier maintainance. --- diff --git a/modules/video_filter/deinterlace.c b/modules/video_filter/deinterlace.c index 671d57f65b..8fba3715f7 100644 --- a/modules/video_filter/deinterlace.c +++ b/modules/video_filter/deinterlace.c @@ -30,6 +30,7 @@ #endif #include +#include #ifdef HAVE_ALTIVEC_H # include @@ -54,6 +55,8 @@ #define DEINTERLACE_BOB 4 #define DEINTERLACE_LINEAR 5 #define DEINTERLACE_X 6 +#define DEINTERLACE_YADIF 7 +#define DEINTERLACE_YADIF2X 8 /***************************************************************************** * Local protypes @@ -74,6 +77,7 @@ static void RenderMean ( vout_thread_t *, picture_t *, picture_t * ); static void RenderBlend ( vout_thread_t *, picture_t *, picture_t * ); static void RenderLinear ( vout_thread_t *, picture_t *, picture_t *, int ); static void RenderX ( picture_t *, picture_t * ); +static void RenderYadif ( vout_thread_t *, picture_t *, picture_t *, int, int ); static void MergeGeneric ( void *, const void *, const void *, size_t ); #if defined(CAN_COMPILE_C_ALTIVEC) @@ -122,9 +126,9 @@ static int FilterCallback( vlc_object_t *, char const *, #define FILTER_CFG_PREFIX "sout-deinterlace-" static const char *const mode_list[] = { - "discard", "blend", "mean", "bob", "linear", "x" }; + "discard", "blend", "mean", "bob", "linear", "x", "yadif", "yadif2x" }; static const char *const mode_list_text[] = { - N_("Discard"), N_("Blend"), N_("Mean"), N_("Bob"), N_("Linear"), "X" }; + N_("Discard"), N_("Blend"), N_("Mean"), N_("Bob"), N_("Linear"), "X", "Yadif", "Yadif (2x)" }; vlc_module_begin () set_description( N_("Deinterlacing video filter") ) @@ -162,6 +166,7 @@ static const char *const ppsz_filter_options[] = { * This structure is part of the video output thread descriptor. * It describes the Deinterlace specific properties of an output thread. *****************************************************************************/ +#define HISTORY_SIZE (3) struct vout_sys_t { int i_mode; /* Deinterlace mode */ @@ -177,6 +182,9 @@ struct vout_sys_t void (*pf_merge) ( void *, const void *, const void *, size_t ); void (*pf_end_merge) ( void ); + + /* Yadif */ + picture_t *pp_history[HISTORY_SIZE]; }; /***************************************************************************** @@ -319,6 +327,18 @@ static void SetFilterMethod( vout_thread_t *p_vout, const char *psz_method ) p_sys->b_double_rate = false; p_sys->b_half_height = false; } + else if( !strcmp( psz_method, "yadif" ) ) + { + p_sys->i_mode = DEINTERLACE_YADIF; + p_sys->b_double_rate = false; + p_sys->b_half_height = false; + } + else if( !strcmp( psz_method, "yadif2x" ) ) + { + p_sys->i_mode = DEINTERLACE_YADIF2X; + p_sys->b_double_rate = true; + p_sys->b_half_height = false; + } else { const bool b_i422 = p_vout->render.i_chroma == VLC_CODEC_I422 || @@ -356,6 +376,8 @@ static void GetOutputFormat( vout_thread_t *p_vout, case DEINTERLACE_MEAN: case DEINTERLACE_LINEAR: case DEINTERLACE_X: + case DEINTERLACE_YADIF: + case DEINTERLACE_YADIF2X: p_dst->i_chroma = p_src->i_chroma; break; default: @@ -404,6 +426,9 @@ static int Init( vout_thread_t *p_vout ) return VLC_EGENERIC; } + for( int i = 0; i < HISTORY_SIZE; i++ ) + p_vout->p_sys->pp_history[i] = NULL; + vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES ); vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent ); @@ -435,6 +460,12 @@ static void End( vout_thread_t *p_vout ) var_DelCallback( p_vout, "deinterlace-mode", FilterCallback, NULL ); + for( int i = 0; i < HISTORY_SIZE; i++ ) + { + if( p_sys->pp_history[i] ) + picture_Release( p_sys->pp_history[i] ); + } + if( p_sys->p_vout ) { vout_filter_DelChild( p_vout, p_sys->p_vout, MouseEvent ); @@ -598,6 +629,18 @@ static void Render ( vout_thread_t *p_vout, picture_t *p_pic ) RenderX( pp_outpic[0], p_pic ); vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); break; + + case DEINTERLACE_YADIF: + RenderYadif( p_vout, pp_outpic[0], p_pic, 0, 0 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + break; + + case DEINTERLACE_YADIF2X: + RenderYadif( p_vout, pp_outpic[0], p_pic, 0, p_pic->b_top_field_first ? 0 : 1 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] ); + RenderYadif( p_vout, pp_outpic[1], p_pic, 1, p_pic->b_top_field_first ? 1 : 0 ); + vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] ); + break; } vlc_mutex_unlock( &p_vout->p_sys->filter_lock ); } @@ -1752,6 +1795,126 @@ static void RenderX( picture_t *p_outpic, picture_t *p_pic ) #endif } +/***************************************************************************** + * Yadif (Yet Another DeInterlacing Filter). + *****************************************************************************/ +/* */ +struct vf_priv_s { + /* + * 0: Output 1 frame for each frame. + * 1: Output 1 frame for each field. + * 2: Like 0 but skips spatial interlacing check. + * 3: Like 1 but skips spatial interlacing check. + * + * In vlc, only & 0x02 has meaning, as we do the & 0x01 ourself. + */ + int mode; +}; + +/* I am unsure it is the right one */ +typedef intptr_t x86_reg; + +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFMAX(a,b) __MAX(a,b) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN(a,b) __MIN(a,b) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +/* yadif.h comes from vf_yadif.c of mplayer project */ +#include "yadif.h" + +static void RenderYadif( vout_thread_t *p_vout, picture_t *p_dst, picture_t *p_src, int i_order, int i_field ) +{ + vout_sys_t *p_sys = p_vout->p_sys; + + /* */ + assert( i_order == 0 || i_order == 1 ); + assert( i_field == 0 || i_field == 1 ); + + if( i_order == 0 ) + { + /* Duplicate the picture + * TODO when the vout rework is finished, picture_Hold() might be enough + * but becarefull, the pitches must match */ + picture_t *p_dup = picture_NewFromFormat( &p_src->format ); + if( p_dup ) + picture_Copy( p_dup, p_src ); + + /* Slide the history */ + if( p_sys->pp_history[0] ) + picture_Release( p_sys->pp_history[0] ); + for( int i = 1; i < HISTORY_SIZE; i++ ) + p_sys->pp_history[i-1] = p_sys->pp_history[i]; + p_sys->pp_history[HISTORY_SIZE-1] = p_dup; + } + + /* As the pitches must match, use ONLY pictures coming from picture_New()! */ + picture_t *p_prev = p_sys->pp_history[0]; + picture_t *p_cur = p_sys->pp_history[1]; + picture_t *p_next = p_sys->pp_history[2]; + + /* Filter if we have all the pictures we need */ + if( p_prev && p_cur && p_next ) + { + /* */ + void (*filter)(struct vf_priv_s *p, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int refs, int parity); +#if defined(HAVE_YADIF_SSE2) + if( vlc_CPU() & CPU_CAPABILITY_SSE2 ) + filter = yadif_filter_line_mmx2; + else +#endif + filter = yadif_filter_line_c; + + for( int n = 0; n < p_dst->i_planes; n++ ) + { + const plane_t *prevp = &p_prev->p[n]; + const plane_t *curp = &p_cur->p[n]; + const plane_t *nextp = &p_next->p[n]; + plane_t *dstp = &p_dst->p[n]; + + for( int y = 1; y < dstp->i_visible_lines - 1; y++ ) + { + if( (y % 2) == i_field ) + { + vlc_memcpy( &dstp->p_pixels[y * dstp->i_pitch], + &curp->p_pixels[y * curp->i_pitch], dstp->i_visible_pitch ); + } + else + { + struct vf_priv_s cfg; + /* Spatial checks only when enough data */ + cfg.mode = (y >= 2 && y < dstp->i_visible_lines - 2) ? 0 : 2; + + assert( prevp->i_pitch == curp->i_pitch && curp->i_pitch == nextp->i_pitch ); + filter( &cfg, + &dstp->p_pixels[y * dstp->i_pitch], + &prevp->p_pixels[y * prevp->i_pitch], + &curp->p_pixels[y * curp->i_pitch], + &nextp->p_pixels[y * nextp->i_pitch], + dstp->i_visible_pitch, + curp->i_pitch, + (i_field ^ (i_order == i_field)) & 1 ); + } + + /* We duplicate the first and last lines */ + if( y == 1 ) + vlc_memcpy(&dstp->p_pixels[(y-1) * dstp->i_pitch], &dstp->p_pixels[y * dstp->i_pitch], dstp->i_pitch); + else if( y == dstp->i_visible_lines - 2 ) + vlc_memcpy(&dstp->p_pixels[(y+1) * dstp->i_pitch], &dstp->p_pixels[y * dstp->i_pitch], dstp->i_pitch); + } + } + + /* */ + p_dst->date = (p_next->date - p_cur->date) * i_order / 2 + p_cur->date; + } + else + { + /* Fallback to something simple + * XXX it is wrong when we have 2 pictures, we should not output a picture */ + RenderX( p_dst, p_src ); + } +} + /***************************************************************************** * FilterCallback: called when changing the deinterlace method on the fly. *****************************************************************************/ @@ -1851,6 +2014,18 @@ static picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic ) case DEINTERLACE_X: RenderX( p_pic_dst, p_pic ); break; + + case DEINTERLACE_YADIF: + msg_Err( p_vout, "delaying frames is not supported yet" ); + picture_Release( p_pic_dst ); + picture_Release( p_pic ); + return NULL; + + case DEINTERLACE_YADIF2X: + msg_Err( p_vout, "doubling the frame rate is not supported yet" ); + picture_Release( p_pic_dst ); + picture_Release( p_pic ); + return NULL; } picture_CopyProperties( p_pic_dst, p_pic ); diff --git a/modules/video_filter/yadif.h b/modules/video_filter/yadif.h new file mode 100644 index 0000000000..2d2a56f071 --- /dev/null +++ b/modules/video_filter/yadif.h @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2006 Michael Niedermayer + * + * This file is part of MPlayer. + * + * MPlayer is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * MPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with MPlayer; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* */ +#if defined(CAN_COMPILE_SSE2) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) + +#define HAVE_YADIF_SSE2 + +#define LOAD4(mem,dst) \ + "movd "mem", "#dst" \n\t"\ + "punpcklbw %%mm7, "#dst" \n\t" + +#define PABS(tmp,dst) \ + "pxor "#tmp", "#tmp" \n\t"\ + "psubw "#dst", "#tmp" \n\t"\ + "pmaxsw "#tmp", "#dst" \n\t" + +#define CHECK(pj,mj) \ + "movq "#pj"(%[cur],%[mrefs]), %%mm2 \n\t" /* cur[x-refs-1+j] */\ + "movq "#mj"(%[cur],%[prefs]), %%mm3 \n\t" /* cur[x+refs-1-j] */\ + "movq %%mm2, %%mm4 \n\t"\ + "movq %%mm2, %%mm5 \n\t"\ + "pxor %%mm3, %%mm4 \n\t"\ + "pavgb %%mm3, %%mm5 \n\t"\ + "pand %[pb1], %%mm4 \n\t"\ + "psubusb %%mm4, %%mm5 \n\t"\ + "psrlq $8, %%mm5 \n\t"\ + "punpcklbw %%mm7, %%mm5 \n\t" /* (cur[x-refs+j] + cur[x+refs-j])>>1 */\ + "movq %%mm2, %%mm4 \n\t"\ + "psubusb %%mm3, %%mm2 \n\t"\ + "psubusb %%mm4, %%mm3 \n\t"\ + "pmaxub %%mm3, %%mm2 \n\t"\ + "movq %%mm2, %%mm3 \n\t"\ + "movq %%mm2, %%mm4 \n\t" /* ABS(cur[x-refs-1+j] - cur[x+refs-1-j]) */\ + "psrlq $8, %%mm3 \n\t" /* ABS(cur[x-refs +j] - cur[x+refs -j]) */\ + "psrlq $16, %%mm4 \n\t" /* ABS(cur[x-refs+1+j] - cur[x+refs+1-j]) */\ + "punpcklbw %%mm7, %%mm2 \n\t"\ + "punpcklbw %%mm7, %%mm3 \n\t"\ + "punpcklbw %%mm7, %%mm4 \n\t"\ + "paddw %%mm3, %%mm2 \n\t"\ + "paddw %%mm4, %%mm2 \n\t" /* score */ + +#define CHECK1 \ + "movq %%mm0, %%mm3 \n\t"\ + "pcmpgtw %%mm2, %%mm3 \n\t" /* if(score < spatial_score) */\ + "pminsw %%mm2, %%mm0 \n\t" /* spatial_score= score; */\ + "movq %%mm3, %%mm6 \n\t"\ + "pand %%mm3, %%mm5 \n\t"\ + "pandn %%mm1, %%mm3 \n\t"\ + "por %%mm5, %%mm3 \n\t"\ + "movq %%mm3, %%mm1 \n\t" /* spatial_pred= (cur[x-refs+j] + cur[x+refs-j])>>1; */ + +#define CHECK2 /* pretend not to have checked dir=2 if dir=1 was bad.\ + hurts both quality and speed, but matches the C version. */\ + "paddw %[pw1], %%mm6 \n\t"\ + "psllw $14, %%mm6 \n\t"\ + "paddsw %%mm6, %%mm2 \n\t"\ + "movq %%mm0, %%mm3 \n\t"\ + "pcmpgtw %%mm2, %%mm3 \n\t"\ + "pminsw %%mm2, %%mm0 \n\t"\ + "pand %%mm3, %%mm5 \n\t"\ + "pandn %%mm1, %%mm3 \n\t"\ + "por %%mm5, %%mm3 \n\t"\ + "movq %%mm3, %%mm1 \n\t" + +static void yadif_filter_line_mmx2(struct vf_priv_s *p, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int refs, int parity){ + static const uint64_t pw_1 = 0x0001000100010001ULL; + static const uint64_t pb_1 = 0x0101010101010101ULL; + const int mode = p->mode; + uint64_t tmp0, tmp1, tmp2, tmp3; + int x; + +#define FILTER\ + for(x=0; x>1 */\ + "movq %%mm0, %[tmp0] \n\t" /* c */\ + "movq %%mm3, %[tmp1] \n\t" /* d */\ + "movq %%mm1, %[tmp2] \n\t" /* e */\ + "psubw %%mm4, %%mm2 \n\t"\ + PABS( %%mm4, %%mm2) /* temporal_diff0 */\ + LOAD4("(%[prev],%[mrefs])", %%mm3) /* prev[x-refs] */\ + LOAD4("(%[prev],%[prefs])", %%mm4) /* prev[x+refs] */\ + "psubw %%mm0, %%mm3 \n\t"\ + "psubw %%mm1, %%mm4 \n\t"\ + PABS( %%mm5, %%mm3)\ + PABS( %%mm5, %%mm4)\ + "paddw %%mm4, %%mm3 \n\t" /* temporal_diff1 */\ + "psrlw $1, %%mm2 \n\t"\ + "psrlw $1, %%mm3 \n\t"\ + "pmaxsw %%mm3, %%mm2 \n\t"\ + LOAD4("(%[next],%[mrefs])", %%mm3) /* next[x-refs] */\ + LOAD4("(%[next],%[prefs])", %%mm4) /* next[x+refs] */\ + "psubw %%mm0, %%mm3 \n\t"\ + "psubw %%mm1, %%mm4 \n\t"\ + PABS( %%mm5, %%mm3)\ + PABS( %%mm5, %%mm4)\ + "paddw %%mm4, %%mm3 \n\t" /* temporal_diff2 */\ + "psrlw $1, %%mm3 \n\t"\ + "pmaxsw %%mm3, %%mm2 \n\t"\ + "movq %%mm2, %[tmp3] \n\t" /* diff */\ +\ + "paddw %%mm0, %%mm1 \n\t"\ + "paddw %%mm0, %%mm0 \n\t"\ + "psubw %%mm1, %%mm0 \n\t"\ + "psrlw $1, %%mm1 \n\t" /* spatial_pred */\ + PABS( %%mm2, %%mm0) /* ABS(c-e) */\ +\ + "movq -1(%[cur],%[mrefs]), %%mm2 \n\t" /* cur[x-refs-1] */\ + "movq -1(%[cur],%[prefs]), %%mm3 \n\t" /* cur[x+refs-1] */\ + "movq %%mm2, %%mm4 \n\t"\ + "psubusb %%mm3, %%mm2 \n\t"\ + "psubusb %%mm4, %%mm3 \n\t"\ + "pmaxub %%mm3, %%mm2 \n\t"\ + "pshufw $9,%%mm2, %%mm3 \n\t"\ + "punpcklbw %%mm7, %%mm2 \n\t" /* ABS(cur[x-refs-1] - cur[x+refs-1]) */\ + "punpcklbw %%mm7, %%mm3 \n\t" /* ABS(cur[x-refs+1] - cur[x+refs+1]) */\ + "paddw %%mm2, %%mm0 \n\t"\ + "paddw %%mm3, %%mm0 \n\t"\ + "psubw %[pw1], %%mm0 \n\t" /* spatial_score */\ +\ + CHECK(-2,0)\ + CHECK1\ + CHECK(-3,1)\ + CHECK2\ + CHECK(0,-2)\ + CHECK1\ + CHECK(1,-3)\ + CHECK2\ +\ + /* if(p->mode<2) ... */\ + "movq %[tmp3], %%mm6 \n\t" /* diff */\ + "cmp $2, %[mode] \n\t"\ + "jge 1f \n\t"\ + LOAD4("(%["prev2"],%[mrefs],2)", %%mm2) /* prev2[x-2*refs] */\ + LOAD4("(%["next2"],%[mrefs],2)", %%mm4) /* next2[x-2*refs] */\ + LOAD4("(%["prev2"],%[prefs],2)", %%mm3) /* prev2[x+2*refs] */\ + LOAD4("(%["next2"],%[prefs],2)", %%mm5) /* next2[x+2*refs] */\ + "paddw %%mm4, %%mm2 \n\t"\ + "paddw %%mm5, %%mm3 \n\t"\ + "psrlw $1, %%mm2 \n\t" /* b */\ + "psrlw $1, %%mm3 \n\t" /* f */\ + "movq %[tmp0], %%mm4 \n\t" /* c */\ + "movq %[tmp1], %%mm5 \n\t" /* d */\ + "movq %[tmp2], %%mm7 \n\t" /* e */\ + "psubw %%mm4, %%mm2 \n\t" /* b-c */\ + "psubw %%mm7, %%mm3 \n\t" /* f-e */\ + "movq %%mm5, %%mm0 \n\t"\ + "psubw %%mm4, %%mm5 \n\t" /* d-c */\ + "psubw %%mm7, %%mm0 \n\t" /* d-e */\ + "movq %%mm2, %%mm4 \n\t"\ + "pminsw %%mm3, %%mm2 \n\t"\ + "pmaxsw %%mm4, %%mm3 \n\t"\ + "pmaxsw %%mm5, %%mm2 \n\t"\ + "pminsw %%mm5, %%mm3 \n\t"\ + "pmaxsw %%mm0, %%mm2 \n\t" /* max */\ + "pminsw %%mm0, %%mm3 \n\t" /* min */\ + "pxor %%mm4, %%mm4 \n\t"\ + "pmaxsw %%mm3, %%mm6 \n\t"\ + "psubw %%mm2, %%mm4 \n\t" /* -max */\ + "pmaxsw %%mm4, %%mm6 \n\t" /* diff= MAX3(diff, min, -max); */\ + "1: \n\t"\ +\ + "movq %[tmp1], %%mm2 \n\t" /* d */\ + "movq %%mm2, %%mm3 \n\t"\ + "psubw %%mm6, %%mm2 \n\t" /* d-diff */\ + "paddw %%mm6, %%mm3 \n\t" /* d+diff */\ + "pmaxsw %%mm2, %%mm1 \n\t"\ + "pminsw %%mm3, %%mm1 \n\t" /* d = clip(spatial_pred, d-diff, d+diff); */\ + "packuswb %%mm1, %%mm1 \n\t"\ +\ + :[tmp0]"=m"(tmp0),\ + [tmp1]"=m"(tmp1),\ + [tmp2]"=m"(tmp2),\ + [tmp3]"=m"(tmp3)\ + :[prev] "r"(prev),\ + [cur] "r"(cur),\ + [next] "r"(next),\ + [prefs]"r"((x86_reg)refs),\ + [mrefs]"r"((x86_reg)-refs),\ + [pw1] "m"(pw_1),\ + [pb1] "m"(pb_1),\ + [mode] "g"(mode)\ + );\ + __asm__ volatile("movd %%mm1, %0" :"=m"(*dst));\ + dst += 4;\ + prev+= 4;\ + cur += 4;\ + next+= 4;\ + } + + if(parity){ +#define prev2 "prev" +#define next2 "cur" + FILTER +#undef prev2 +#undef next2 + }else{ +#define prev2 "cur" +#define next2 "next" + FILTER +#undef prev2 +#undef next2 + } +} +#undef LOAD4 +#undef PABS +#undef CHECK +#undef CHECK1 +#undef CHECK2 +#undef FILTER + +#endif + +static void yadif_filter_line_c(struct vf_priv_s *p, uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int refs, int parity){ + int x; + uint8_t *prev2= parity ? prev : cur ; + uint8_t *next2= parity ? cur : next; + for(x=0; x>1; + int e= cur[+refs]; + int temporal_diff0= FFABS(prev2[0] - next2[0]); + int temporal_diff1=( FFABS(prev[-refs] - c) + FFABS(prev[+refs] - e) )>>1; + int temporal_diff2=( FFABS(next[-refs] - c) + FFABS(next[+refs] - e) )>>1; + int diff= FFMAX3(temporal_diff0>>1, temporal_diff1, temporal_diff2); + int spatial_pred= (c+e)>>1; + int spatial_score= FFABS(cur[-refs-1] - cur[+refs-1]) + FFABS(c-e) + + FFABS(cur[-refs+1] - cur[+refs+1]) - 1; + +#define CHECK(j)\ + { int score= FFABS(cur[-refs-1+j] - cur[+refs-1-j])\ + + FFABS(cur[-refs +j] - cur[+refs -j])\ + + FFABS(cur[-refs+1+j] - cur[+refs+1-j]);\ + if(score < spatial_score){\ + spatial_score= score;\ + spatial_pred= (cur[-refs +j] + cur[+refs -j])>>1;\ + + CHECK(-1) CHECK(-2) }} }} + CHECK( 1) CHECK( 2) }} }} + + if(p->mode<2){ + int b= (prev2[-2*refs] + next2[-2*refs])>>1; + int f= (prev2[+2*refs] + next2[+2*refs])>>1; +#if 0 + int a= cur[-3*refs]; + int g= cur[+3*refs]; + int max= FFMAX3(d-e, d-c, FFMIN3(FFMAX(b-c,f-e),FFMAX(b-c,b-a),FFMAX(f-g,f-e)) ); + int min= FFMIN3(d-e, d-c, FFMAX3(FFMIN(b-c,f-e),FFMIN(b-c,b-a),FFMIN(f-g,f-e)) ); +#else + int max= FFMAX3(d-e, d-c, FFMIN(b-c, f-e)); + int min= FFMIN3(d-e, d-c, FFMAX(b-c, f-e)); +#endif + + diff= FFMAX3(diff, min, -max); + } + + if(spatial_pred > d + diff) + spatial_pred = d + diff; + else if(spatial_pred < d - diff) + spatial_pred = d - diff; + + dst[0] = spatial_pred; + + dst++; + cur++; + prev++; + next++; + prev2++; + next2++; + } +} +