/** * 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; }
void ArchitectureSpecificCopyHooksDestroy( int i_color_format, ArchitectureSpecificCopyData *p_architecture_specific ) { if (!p_architecture_specific->data) return; #ifdef CAN_COMPILE_SSE2 if( i_color_format == OMX_COLOR_FormatYUV420SemiPlanar && vlc_CPU_SSE2() ) { copy_cache_t *p_surface_cache = (copy_cache_t*)p_architecture_specific->data; CopyCleanCache(p_surface_cache); } #endif free(p_architecture_specific->data); p_architecture_specific->data = NULL; }
void CopyOmxPicture( int i_color_format, picture_t *p_pic, int i_slice_height, int i_src_stride, uint8_t *p_src, int i_chroma_div, ArchitectureSpecificCopyData *p_architecture_specific ) { uint8_t *p_dst; int i_dst_stride; int i_plane, i_width, i_line; if( i_color_format == QOMX_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka ) { qcom_convert(p_src, p_pic); return; } #ifdef CAN_COMPILE_SSE2 if( i_color_format == OMX_COLOR_FormatYUV420SemiPlanar && vlc_CPU_SSE2() && p_architecture_specific->data ) { copy_cache_t *p_surface_cache = (copy_cache_t*)p_architecture_specific->data; uint8_t *ppi_src_pointers[2] = { p_src, p_src + i_src_stride * i_slice_height }; size_t pi_src_strides[2] = { i_src_stride, i_src_stride }; CopyFromNv12( p_pic, ppi_src_pointers, pi_src_strides, i_src_stride, i_slice_height, p_surface_cache ); return; } #endif for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { if(i_plane == 1) i_src_stride /= i_chroma_div; p_dst = p_pic->p[i_plane].p_pixels; i_dst_stride = p_pic->p[i_plane].i_pitch; i_width = p_pic->p[i_plane].i_visible_pitch; for( i_line = 0; i_line < p_pic->p[i_plane].i_visible_lines; i_line++ ) { memcpy( p_dst, p_src, i_width ); p_src += i_src_stride; p_dst += i_dst_stride; } /* Handle plane height, which may be indicated via nSliceHeight in OMX. * The handling for chroma planes currently assumes vertically * subsampled chroma, e.g. 422 planar wouldn't work right. */ if( i_plane == 0 && i_slice_height > p_pic->p[i_plane].i_visible_lines ) p_src += i_src_stride * (i_slice_height - p_pic->p[i_plane].i_visible_lines); else if ( i_plane > 0 && i_slice_height/2 > p_pic->p[i_plane].i_visible_lines ) p_src += i_src_stride * (i_slice_height/2 - p_pic->p[i_plane].i_visible_lines); } }
/***************************************************************************** * Picture utility functions *****************************************************************************/ void ArchitectureSpecificCopyHooks( decoder_t *p_dec, int i_color_format, int i_slice_height, int i_src_stride, ArchitectureSpecificCopyData *p_architecture_specific ) { (void)i_slice_height; #ifdef CAN_COMPILE_SSE2 if( i_color_format == OMX_COLOR_FormatYUV420SemiPlanar && vlc_CPU_SSE2() ) { copy_cache_t *p_surface_cache = malloc( sizeof(copy_cache_t) ); if( !p_surface_cache || CopyInitCache( p_surface_cache, i_src_stride ) ) { free( p_surface_cache ); return; } p_architecture_specific->data = p_surface_cache; p_dec->fmt_out.i_codec = VLC_CODEC_YV12; } #endif }
int RenderYadif( filter_t *p_filter, picture_t *p_dst, picture_t *p_src, int i_order, int i_field ) { VLC_UNUSED(p_src); filter_sys_t *p_sys = p_filter->p_sys; /* */ assert( i_order >= 0 && i_order <= 2 ); /* 2 = soft field repeat */ assert( i_field == 0 || i_field == 1 ); /* 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]; /* Account for soft field repeat. The "parity" parameter affects the algorithm like this (from yadif.h): uint8_t *prev2= parity ? prev : cur ; uint8_t *next2= parity ? cur : next; The original parity expression that was used here is: (i_field ^ (i_order == i_field)) & 1 Truth table: i_field = 0, i_order = 0 => 1 i_field = 1, i_order = 1 => 0 i_field = 1, i_order = 0 => 1 i_field = 0, i_order = 1 => 0 => equivalent with e.g. (1 - i_order) or (i_order + 1) % 2 Thus, in a normal two-field frame, parity 1 = first field (i_order == 0) parity 0 = second field (i_order == 1) Now, with three fields, where the third is a copy of the first, i_order = 0 => parity 1 (as usual) i_order = 1 => due to the repeat, prev = cur, but also next = cur. Because in such a case there is no motion (otherwise field repeat makes no sense), we don't actually need to invoke Yadif's filter(). Thus, set "parity" to 2, and use this to bypass the filter. i_order = 2 => parity 0 (as usual) */ int yadif_parity; if( p_cur && p_cur->i_nb_fields > 2 ) yadif_parity = (i_order + 1) % 3; /* 1, *2*, 0; where 2 is a special value meaning "bypass filter". */ else yadif_parity = (i_order + 1) % 2; /* 1, 0 */ /* Filter if we have all the pictures we need */ if( p_prev && p_cur && p_next ) { /* */ void (*filter)(uint8_t *dst, uint8_t *prev, uint8_t *cur, uint8_t *next, int w, int prefs, int mrefs, int parity, int mode); #if defined(HAVE_YADIF_SSSE3) if( vlc_CPU_SSSE3() ) filter = yadif_filter_line_ssse3; else #endif #if defined(HAVE_YADIF_SSE2) if( vlc_CPU_SSE2() ) filter = yadif_filter_line_sse2; else #endif #if defined(HAVE_YADIF_MMX) if( vlc_CPU_MMX() ) filter = yadif_filter_line_mmx; else #endif filter = yadif_filter_line_c; if( p_sys->chroma->pixel_size == 2 ) filter = (void (__cdecl *)(uint8_t *,uint8_t *,uint8_t *,uint8_t *,int,int,int,int,int))yadif_filter_line_c_16bit; // sunqueen modify 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 || yadif_parity == 2 ) { memcpy( &dstp->p_pixels[y * dstp->i_pitch], &curp->p_pixels[y * curp->i_pitch], dstp->i_visible_pitch ); } else { int mode; /* Spatial checks only when enough data */ 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( &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, y < dstp->i_visible_lines - 2 ? curp->i_pitch : -curp->i_pitch, y - 1 ? -curp->i_pitch : curp->i_pitch, yadif_parity, mode ); } /* We duplicate the first and last lines */ if( y == 1 ) 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 ) memcpy(&dstp->p_pixels[(y+1) * dstp->i_pitch], &dstp->p_pixels[ y * dstp->i_pitch], dstp->i_pitch); } } p_sys->i_frame_offset = 1; /* p_cur will be rendered at next frame, too */ return VLC_SUCCESS; } else if( !p_prev && !p_cur && p_next ) { /* NOTE: For the first frame, we use the default frame offset as set by Open() or SetFilterMethod(). It is always 0. */ /* FIXME not good as it does not use i_order/i_field */ RenderX( p_dst, p_next ); return VLC_SUCCESS; } else { p_sys->i_frame_offset = 1; /* p_cur will be rendered at next frame */ return VLC_EGENERIC; } }
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; }