/** * Maps CPU capabilities computed by VLC to libav DSP mask. */ unsigned GetVlcDspMask( void ) { unsigned mask = 0; #if defined (__i386__) || defined (__x86_64__) if( !vlc_CPU_MMX() ) mask |= AV_CPU_FLAG_MMX; if( !vlc_CPU_MMXEXT() ) mask |= AV_CPU_FLAG_MMX2; if( !vlc_CPU_3dNOW() ) mask |= AV_CPU_FLAG_3DNOW; if( !vlc_CPU_SSE() ) mask |= AV_CPU_FLAG_SSE; if( !vlc_CPU_SSE2() ) mask |= AV_CPU_FLAG_SSE2; # ifdef AV_CPU_FLAG_SSE3 if( !vlc_CPU_SSE3() ) mask |= AV_CPU_FLAG_SSE3; # endif # ifdef AV_CPU_FLAG_SSSE3 if( !vlc_CPU_SSSE3() ) mask |= AV_CPU_FLAG_SSSE3; # endif # ifdef AV_CPU_FLAG_SSE4 if( !vlc_CPU_SSE4_1() ) mask |= AV_CPU_FLAG_SSE4; # endif # ifdef AV_CPU_FLAG_SSE42 if( !vlc_CPU_SSE4_2() ) mask |= AV_CPU_FLAG_SSE42; # endif # ifdef AV_CPU_FLAG_AVX if( !vlc_CPU_AVX() ) mask |= AV_CPU_FLAG_AVX; # endif # ifdef AV_CPU_FLAG_XOP if( !vlc_CPU_XOP() ) mask |= AV_CPU_FLAG_XOP; # endif # ifdef AV_CPU_FLAG_FMA4 if( !vlc_CPU_FMA4() ) mask |= AV_CPU_FLAG_FMA4; # endif #endif #if defined (__ppc__) || defined (__ppc64__) || defined (__powerpc__) if( !vlc_CPU_ALTIVEC() ) mask |= AV_CPU_FLAG_ALTIVEC; #endif #if defined ( __arm__) #if LIBAVUTIL_VERSION_INT >= ((51<<16)+(29<<8)+0) if( !vlc_CPU_ARM_NEON() ) mask |= AV_CPU_FLAG_NEON; #endif #endif return mask; }
static int Open(vlc_object_t *object) { filter_t *filter = (filter_t *)object; const vlc_fourcc_t fourcc = filter->fmt_in.video.i_chroma; const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription(fourcc); if (!chroma || chroma->plane_count < 3 || chroma->pixel_size != 1) { msg_Err(filter, "Unsupported chroma (%4.4s)", (char*)&fourcc); return VLC_EGENERIC; } filter_sys_t *sys = malloc(sizeof(*sys)); if (!sys) return VLC_ENOMEM; vlc_mutex_init(&sys->lock); sys->chroma = chroma; sys->strength = var_CreateGetFloatCommand(filter, CFG_PREFIX "strength"); sys->radius = var_CreateGetIntegerCommand(filter, CFG_PREFIX "radius"); var_AddCallback(filter, CFG_PREFIX "strength", Callback, NULL); var_AddCallback(filter, CFG_PREFIX "radius", Callback, NULL); sys->cfg.buf = NULL; struct vf_priv_s *cfg = &sys->cfg; cfg->thresh = 0.0; cfg->radius = 0; cfg->buf = NULL; #if HAVE_SSE2 && HAVE_6REGS if (vlc_CPU_SSE2()) cfg->blur_line = blur_line_sse2; else #endif cfg->blur_line = blur_line_c; #if HAVE_SSSE3 if (vlc_CPU_SSSE3()) cfg->filter_line = filter_line_ssse3; else #endif #if HAVE_MMX2 if (vlc_CPU_MMXEXT()) cfg->filter_line = filter_line_mmx2; else #endif cfg->filter_line = filter_line_c; filter->p_sys = sys; filter->pf_video_filter = Filter; return VLC_SUCCESS; }
/***************************************************************************** * Helpers *****************************************************************************/ static int GetSwsCpuMask(void) { int i_sws_cpu = 0; #if defined(__i386__) || defined(__x86_64__) if( vlc_CPU_MMX() ) i_sws_cpu |= SWS_CPU_CAPS_MMX; #if (LIBSWSCALE_VERSION_INT >= ((0<<16)+(5<<8)+0)) if( vlc_CPU_MMXEXT() ) i_sws_cpu |= SWS_CPU_CAPS_MMX2; #endif if( vlc_CPU_3dNOW() ) i_sws_cpu |= SWS_CPU_CAPS_3DNOW; #elif defined(__ppc__) || defined(__ppc64__) || defined(__powerpc__) if( vlc_CPU_ALTIVEC() ) i_sws_cpu |= SWS_CPU_CAPS_ALTIVEC; #endif return i_sws_cpu; }
VLC_MMX static int CalculateInterlaceScoreMMX( const picture_t* p_pic_top, const picture_t* p_pic_bot ) { assert( p_pic_top->i_planes == p_pic_bot->i_planes ); /* Amount of bits must be known for MMX, thus int32_t. Doesn't hurt the C implementation. */ int32_t i_score_mmx = 0; /* this must be divided by 255 when finished */ int32_t i_score_c = 0; /* this counts as-is (used for non-MMX parts) */ pxor_r2r( mm7, mm7 ); /* we will keep score in mm7 */ for( int i_plane = 0 ; i_plane < p_pic_top->i_planes ; ++i_plane ) { /* Sanity check */ if( p_pic_top->p[i_plane].i_visible_lines != p_pic_bot->p[i_plane].i_visible_lines ) return -1; const int i_lasty = p_pic_top->p[i_plane].i_visible_lines-1; const int w = FFMIN( p_pic_top->p[i_plane].i_visible_pitch, p_pic_bot->p[i_plane].i_visible_pitch ); const int wm8 = w % 8; /* remainder */ const int w8 = w - wm8; /* part of width that is divisible by 8 */ /* Current line / neighbouring lines picture pointers */ const picture_t *cur = p_pic_bot; const picture_t *ngh = p_pic_top; int wc = cur->p[i_plane].i_pitch; int wn = ngh->p[i_plane].i_pitch; /* Transcode 1.1.5 only checks every other line. Checking every line works better for anime, which may contain horizontal, one pixel thick cartoon outlines. */ for( int y = 1; y < i_lasty; ++y ) { uint8_t *p_c = &cur->p[i_plane].p_pixels[y*wc]; /* this line */ uint8_t *p_p = &ngh->p[i_plane].p_pixels[(y-1)*wn]; /* prev line */ uint8_t *p_n = &ngh->p[i_plane].p_pixels[(y+1)*wn]; /* next line */ int x = 0; /* Easy-to-read C version further below. Assumptions: 0 < T < 127 # of pixels < (2^32)/255 Note: calculates score * 255 */ static alignas (8) const mmx_t b0 = { .uq = 0x0000000000000000ULL }; static alignas (8) const mmx_t b128 = { .uq = 0x8080808080808080ULL }; static alignas (8) const mmx_t bT = { .ub = { T, T, T, T, T, T, T, T } }; for( ; x < w8; x += 8 ) { movq_m2r( *((int64_t*)p_c), mm0 ); movq_m2r( *((int64_t*)p_p), mm1 ); movq_m2r( *((int64_t*)p_n), mm2 ); psubb_m2r( b128, mm0 ); psubb_m2r( b128, mm1 ); psubb_m2r( b128, mm2 ); psubsb_r2r( mm0, mm1 ); psubsb_r2r( mm0, mm2 ); pxor_r2r( mm3, mm3 ); pxor_r2r( mm4, mm4 ); pxor_r2r( mm5, mm5 ); pxor_r2r( mm6, mm6 ); punpcklbw_r2r( mm1, mm3 ); punpcklbw_r2r( mm2, mm4 ); punpckhbw_r2r( mm1, mm5 ); punpckhbw_r2r( mm2, mm6 ); pmulhw_r2r( mm3, mm4 ); pmulhw_r2r( mm5, mm6 ); packsswb_r2r(mm4, mm6); pcmpgtb_m2r( bT, mm6 ); psadbw_m2r( b0, mm6 ); paddd_r2r( mm6, mm7 ); p_c += 8; p_p += 8; p_n += 8; } for( ; x < w; ++x ) { /* Worst case: need 17 bits for "comb". */ int_fast32_t C = *p_c; int_fast32_t P = *p_p; int_fast32_t N = *p_n; /* Comments in Transcode's filter_ivtc.c attribute this combing metric to Gunnar Thalin. The idea is that if the picture is interlaced, both expressions will have the same sign, and this comes up positive. The value T = 100 has been chosen such that a pixel difference of 10 (on average) will trigger the detector. */ int_fast32_t comb = (P - C) * (N - C); if( comb > T ) ++i_score_c; ++p_c; ++p_p; ++p_n; } /* Now the other field - swap current and neighbour pictures */ const picture_t *tmp = cur; cur = ngh; ngh = tmp; int tmp_pitch = wc; wc = wn; wn = tmp_pitch; } } movd_r2m( mm7, i_score_mmx ); emms(); return i_score_mmx/255 + i_score_c; } #endif /* See header for function doc. */ int CalculateInterlaceScore( const picture_t* p_pic_top, const picture_t* p_pic_bot ) { /* We use the comb metric from the IVTC filter of Transcode 1.1.5. This was found to work better for the particular purpose of IVTC than RenderX()'s comb metric. Note that we *must not* subsample at all in order to catch interlacing in telecined frames with localized motion (e.g. anime with characters talking, where only mouths move and everything else stays still.) */ assert( p_pic_top != NULL ); assert( p_pic_bot != NULL ); if( p_pic_top->i_planes != p_pic_bot->i_planes ) return -1; #ifdef CAN_COMPILE_MMXEXT if (vlc_CPU_MMXEXT()) return CalculateInterlaceScoreMMX( p_pic_top, p_pic_bot ); #endif int32_t i_score = 0; for( int i_plane = 0 ; i_plane < p_pic_top->i_planes ; ++i_plane ) { /* Sanity check */ if( p_pic_top->p[i_plane].i_visible_lines != p_pic_bot->p[i_plane].i_visible_lines ) return -1; const int i_lasty = p_pic_top->p[i_plane].i_visible_lines-1; const int w = FFMIN( p_pic_top->p[i_plane].i_visible_pitch, p_pic_bot->p[i_plane].i_visible_pitch ); /* Current line / neighbouring lines picture pointers */ const picture_t *cur = p_pic_bot; const picture_t *ngh = p_pic_top; int wc = cur->p[i_plane].i_pitch; int wn = ngh->p[i_plane].i_pitch; /* Transcode 1.1.5 only checks every other line. Checking every line works better for anime, which may contain horizontal, one pixel thick cartoon outlines. */ for( int y = 1; y < i_lasty; ++y ) { uint8_t *p_c = &cur->p[i_plane].p_pixels[y*wc]; /* this line */ uint8_t *p_p = &ngh->p[i_plane].p_pixels[(y-1)*wn]; /* prev line */ uint8_t *p_n = &ngh->p[i_plane].p_pixels[(y+1)*wn]; /* next line */ for( int x = 0; x < w; ++x ) { /* Worst case: need 17 bits for "comb". */ int_fast32_t C = *p_c; int_fast32_t P = *p_p; int_fast32_t N = *p_n; /* Comments in Transcode's filter_ivtc.c attribute this combing metric to Gunnar Thalin. The idea is that if the picture is interlaced, both expressions will have the same sign, and this comes up positive. The value T = 100 has been chosen such that a pixel difference of 10 (on average) will trigger the detector. */ int_fast32_t comb = (P - C) * (N - C); if( comb > T ) ++i_score; ++p_c; ++p_p; ++p_n; } /* Now the other field - swap current and neighbour pictures */ const picture_t *tmp = cur; cur = ngh; ngh = tmp; int tmp_pitch = wc; wc = wn; wn = tmp_pitch; } } return i_score; }
/* See header for function doc. */ int EstimateNumBlocksWithMotion( const picture_t* p_prev, const picture_t* p_curr, int *pi_top, int *pi_bot) { assert( p_prev != NULL ); assert( p_curr != NULL ); int i_score_top = 0; int i_score_bot = 0; if( p_prev->i_planes != p_curr->i_planes ) return -1; int (*motion_in_block)(uint8_t *, uint8_t *, int , int, int *, int *) = TestForMotionInBlock; /* We must tell our inline helper whether to use MMX acceleration. */ #ifdef CAN_COMPILE_MMXEXT if (vlc_CPU_MMXEXT()) motion_in_block = TestForMotionInBlockMMX; #endif int i_score = 0; for( int i_plane = 0 ; i_plane < p_prev->i_planes ; i_plane++ ) { /* Sanity check */ if( p_prev->p[i_plane].i_visible_lines != p_curr->p[i_plane].i_visible_lines ) return -1; const int i_pitch_prev = p_prev->p[i_plane].i_pitch; const int i_pitch_curr = p_curr->p[i_plane].i_pitch; /* Last pixels and lines (which do not make whole blocks) are ignored. Shouldn't really matter for our purposes. */ const int i_mby = p_prev->p[i_plane].i_visible_lines / 8; const int w = FFMIN( p_prev->p[i_plane].i_visible_pitch, p_curr->p[i_plane].i_visible_pitch ); const int i_mbx = w / 8; for( int by = 0; by < i_mby; ++by ) { uint8_t *p_pix_p = &p_prev->p[i_plane].p_pixels[i_pitch_prev*8*by]; uint8_t *p_pix_c = &p_curr->p[i_plane].p_pixels[i_pitch_curr*8*by]; for( int bx = 0; bx < i_mbx; ++bx ) { int i_top_temp, i_bot_temp; i_score += motion_in_block( p_pix_p, p_pix_c, i_pitch_prev, i_pitch_curr, &i_top_temp, &i_bot_temp ); i_score_top += i_top_temp; i_score_bot += i_bot_temp; p_pix_p += 8; p_pix_c += 8; } } } if( pi_top ) (*pi_top) = i_score_top; if( pi_bot ) (*pi_bot) = i_score_bot; return i_score; }
/***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/ static int OpenDecoder( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; uint32_t i_accel = 0; if( p_dec->fmt_in.i_codec != VLC_CODEC_MPGV ) return VLC_EGENERIC; /* Select onl recognized original format (standard mpeg video) */ switch( p_dec->fmt_in.i_original_fourcc ) { case VLC_FOURCC('m','p','g','1'): case VLC_FOURCC('m','p','g','2'): case VLC_FOURCC('m','p','g','v'): case VLC_FOURCC('P','I','M','1'): case VLC_FOURCC('h','d','v','2'): break; default: if( p_dec->fmt_in.i_original_fourcc ) return VLC_EGENERIC; break; } /* Allocate the memory needed to store the decoder's structure */ if( ( p_dec->p_sys = p_sys = calloc( 1, sizeof(*p_sys)) ) == NULL ) return VLC_ENOMEM; /* Initialize the thread properties */ p_sys->p_mpeg2dec = NULL; p_sys->p_synchro = NULL; p_sys->p_info = NULL; p_sys->i_current_pts = 0; p_sys->i_previous_pts = 0; p_sys->i_current_dts = 0; p_sys->i_previous_dts = 0; p_sys->i_sar_num = 0; p_sys->i_sar_den = 0; p_sys->b_garbage_pic = false; p_sys->b_slice_i = false; p_sys->b_second_field = false; p_sys->b_skip = false; p_sys->b_preroll = false; DpbInit( p_dec ); p_sys->i_cc_pts = 0; p_sys->i_cc_dts = 0; p_sys->i_cc_flags = 0; #if MPEG2_RELEASE >= MPEG2_VERSION (0, 5, 0) p_dec->pf_get_cc = GetCc; cc_Init( &p_sys->cc ); #endif p_sys->p_gop_user_data = NULL; p_sys->i_gop_user_data = 0; #if defined( __i386__ ) || defined( __x86_64__ ) if( vlc_CPU_MMX() ) i_accel |= MPEG2_ACCEL_X86_MMX; if( vlc_CPU_3dNOW() ) i_accel |= MPEG2_ACCEL_X86_3DNOW; if( vlc_CPU_MMXEXT() ) i_accel |= MPEG2_ACCEL_X86_MMXEXT; #elif defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc64__ ) if( vlc_CPU_ALTIVEC() ) i_accel |= MPEG2_ACCEL_PPC_ALTIVEC; #elif defined(__arm__) # ifdef MPEG2_ACCEL_ARM i_accel |= MPEG2_ACCEL_ARM; # endif # ifdef MPEG2_ACCEL_ARM_NEON if( vlc_CPU_ARM_NEON() ) i_accel |= MPEG2_ACCEL_ARM_NEON; # endif /* TODO: sparc */ #else /* If we do not know this CPU, trust libmpeg2's feature detection */ i_accel = MPEG2_ACCEL_DETECT; #endif /* Set CPU acceleration features */ mpeg2_accel( i_accel ); /* Initialize decoder */ p_sys->p_mpeg2dec = mpeg2_init(); if( p_sys->p_mpeg2dec == NULL) { msg_Err( p_dec, "mpeg2_init() failed" ); free( p_sys ); return VLC_EGENERIC; } p_sys->p_info = mpeg2_info( p_sys->p_mpeg2dec ); p_dec->pf_decode_video = DecodeBlock; p_dec->fmt_out.i_cat = VIDEO_ES; p_dec->fmt_out.i_codec = 0; return VLC_SUCCESS; }
/* See header for function doc. */ int CalculateInterlaceScore( const picture_t* p_pic_top, const picture_t* p_pic_bot ) { /* We use the comb metric from the IVTC filter of Transcode 1.1.5. This was found to work better for the particular purpose of IVTC than RenderX()'s comb metric. Note that we *must not* subsample at all in order to catch interlacing in telecined frames with localized motion (e.g. anime with characters talking, where only mouths move and everything else stays still.) */ assert( p_pic_top != NULL ); assert( p_pic_bot != NULL ); if( p_pic_top->i_planes != p_pic_bot->i_planes ) return -1; #ifdef CAN_COMPILE_MMXEXT if (vlc_CPU_MMXEXT()) return CalculateInterlaceScoreMMX( p_pic_top, p_pic_bot ); #endif int32_t i_score = 0; for( int i_plane = 0 ; i_plane < p_pic_top->i_planes ; ++i_plane ) { /* Sanity check */ if( p_pic_top->p[i_plane].i_visible_lines != p_pic_bot->p[i_plane].i_visible_lines ) return -1; const int i_lasty = p_pic_top->p[i_plane].i_visible_lines-1; const int w = FFMIN( p_pic_top->p[i_plane].i_visible_pitch, p_pic_bot->p[i_plane].i_visible_pitch ); /* Current line / neighbouring lines picture pointers */ const picture_t *cur = p_pic_bot; const picture_t *ngh = p_pic_top; int wc = cur->p[i_plane].i_pitch; int wn = ngh->p[i_plane].i_pitch; /* Transcode 1.1.5 only checks every other line. Checking every line works better for anime, which may contain horizontal, one pixel thick cartoon outlines. */ for( int y = 1; y < i_lasty; ++y ) { uint8_t *p_c = &cur->p[i_plane].p_pixels[y*wc]; /* this line */ uint8_t *p_p = &ngh->p[i_plane].p_pixels[(y-1)*wn]; /* prev line */ uint8_t *p_n = &ngh->p[i_plane].p_pixels[(y+1)*wn]; /* next line */ for( int x = 0; x < w; ++x ) { /* Worst case: need 17 bits for "comb". */ int_fast32_t C = *p_c; int_fast32_t P = *p_p; int_fast32_t N = *p_n; /* Comments in Transcode's filter_ivtc.c attribute this combing metric to Gunnar Thalin. The idea is that if the picture is interlaced, both expressions will have the same sign, and this comes up positive. The value T = 100 has been chosen such that a pixel difference of 10 (on average) will trigger the detector. */ int_fast32_t comb = (P - C) * (N - C); if( comb > T ) ++i_score; ++p_c; ++p_p; ++p_n; } /* Now the other field - swap current and neighbour pictures */ const picture_t *tmp = cur; cur = ngh; ngh = tmp; int tmp_pitch = wc; wc = wn; wn = tmp_pitch; } } return i_score; }
int Open( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t*)p_this; filter_sys_t *p_sys; const vlc_fourcc_t fourcc = p_filter->fmt_in.video.i_chroma; const vlc_chroma_description_t *chroma = vlc_fourcc_GetChromaDescription( fourcc ); if( !vlc_fourcc_IsYUV( fourcc ) || !chroma || chroma->plane_count != 3 || chroma->pixel_size > 2 ) { msg_Err( p_filter, "Unsupported chroma (%4.4s)", (char*)&fourcc ); return VLC_EGENERIC; } /* */ p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) ); if( !p_sys ) return VLC_ENOMEM; p_sys->chroma = chroma; p_sys->i_mode = DEINTERLACE_BLEND; p_sys->b_double_rate = false; p_sys->b_half_height = true; p_sys->b_use_frame_history = false; for( int i = 0; i < METADATA_SIZE; i++ ) { p_sys->meta.pi_date[i] = VLC_TS_INVALID; p_sys->meta.pi_nb_fields[i] = 2; p_sys->meta.pb_top_field_first[i] = true; } p_sys->i_frame_offset = 0; /* start with default value (first-ever frame cannot have offset) */ for( int i = 0; i < HISTORY_SIZE; i++ ) p_sys->pp_history[i] = NULL; IVTCClearState( p_filter ); #if defined(CAN_COMPILE_C_ALTIVEC) if( chroma->pixel_size == 1 && vlc_CPU_ALTIVEC() ) p_sys->pf_merge = MergeAltivec; else #endif #if defined(CAN_COMPILE_SSE2) if( vlc_CPU_SSE2() ) { p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitSSE2 : Merge16BitSSE2; p_sys->pf_end_merge = EndMMX; } else #endif #if defined(CAN_COMPILE_MMXEXT) if( chroma->pixel_size == 1 && vlc_CPU_MMXEXT() ) { p_sys->pf_merge = MergeMMXEXT; p_sys->pf_end_merge = EndMMX; } else #endif #if defined(CAN_COMPILE_3DNOW) if( chroma->pixel_size == 1 && vlc_CPU_3dNOW() ) { p_sys->pf_merge = Merge3DNow; p_sys->pf_end_merge = End3DNow; } else #endif #if defined(CAN_COMPILE_ARM) if( vlc_CPU_ARM_NEON() ) p_sys->pf_merge = (chroma->pixel_size == 1) ? merge8_arm_neon : merge16_arm_neon; else if( vlc_CPU_ARMv6() ) p_sys->pf_merge = (chroma->pixel_size == 1) ? merge8_armv6 : merge16_armv6; else #endif { p_sys->pf_merge = chroma->pixel_size == 1 ? Merge8BitGeneric : Merge16BitGeneric; #if defined(__i386__) || defined(__x86_64__) p_sys->pf_end_merge = NULL; #endif } /* */ config_ChainParse( p_filter, FILTER_CFG_PREFIX, ppsz_filter_options, p_filter->p_cfg ); char *psz_mode = var_GetNonEmptyString( p_filter, FILTER_CFG_PREFIX "mode" ); SetFilterMethod( p_filter, psz_mode ); free( psz_mode ); if( p_sys->i_mode == DEINTERLACE_PHOSPHOR ) { int i_c420 = var_GetInteger( p_filter, FILTER_CFG_PREFIX "phosphor-chroma" ); if( i_c420 != PC_LATEST && i_c420 != PC_ALTLINE && i_c420 != PC_BLEND && i_c420 != PC_UPCONVERT ) { msg_Dbg( p_filter, "Phosphor 4:2:0 input chroma mode not set"\ "or out of range (valid: 1, 2, 3 or 4), "\ "using default" ); i_c420 = PC_ALTLINE; } msg_Dbg( p_filter, "using Phosphor 4:2:0 input chroma mode %d", i_c420 ); /* This maps directly to the phosphor_chroma_t enum. */ p_sys->phosphor.i_chroma_for_420 = i_c420; int i_dimmer = var_GetInteger( p_filter, FILTER_CFG_PREFIX "phosphor-dimmer" ); if( i_dimmer < 1 || i_dimmer > 4 ) { msg_Dbg( p_filter, "Phosphor dimmer strength not set "\ "or out of range (valid: 1, 2, 3 or 4), "\ "using default" ); i_dimmer = 2; /* low */ } msg_Dbg( p_filter, "using Phosphor dimmer strength %d", i_dimmer ); /* The internal value ranges from 0 to 3. */ p_sys->phosphor.i_dimmer_strength = i_dimmer - 1; } else { p_sys->phosphor.i_chroma_for_420 = PC_ALTLINE; p_sys->phosphor.i_dimmer_strength = 1; } /* */ video_format_t fmt; GetOutputFormat( p_filter, &fmt, &p_filter->fmt_in.video ); if( !p_filter->b_allow_fmt_out_change && ( fmt.i_chroma != p_filter->fmt_in.video.i_chroma || fmt.i_height != p_filter->fmt_in.video.i_height ) ) { Close( VLC_OBJECT(p_filter) ); return VLC_EGENERIC; } p_filter->fmt_out.video = fmt; p_filter->fmt_out.i_codec = fmt.i_chroma; p_filter->pf_video_filter = Deinterlace; p_filter->pf_video_flush = Flush; p_filter->pf_video_mouse = Mouse; msg_Dbg( p_filter, "deinterlacing" ); return VLC_SUCCESS; }