#include <vlc/vlc.h>
#include <vlc/vout.h>
-#include "../filter_common.h"
+#ifdef HAVE_ALTIVEC_H
+# include <altivec.h>
+#endif
+
+#include "filter_common.h"
#define DEINTERLACE_DISCARD 1
#define DEINTERLACE_MEAN 2
#if defined(CAN_COMPILE_C_ALTIVEC)
static void MergeAltivec ( void *, const void *, const void *, size_t );
#endif
-#if defined(CAN_COMPILE_MMX)
+#if defined(CAN_COMPILE_MMXEXT)
static void MergeMMX ( void *, const void *, const void *, size_t );
#endif
#if defined(CAN_COMPILE_SSE)
static void MergeSSE2 ( void *, const void *, const void *, size_t );
#endif
-#if defined(CAN_COMPILE_MMX) || defined(CAN_COMPILE_SSE)
+#if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
static void EndMMX ( void );
#endif
void (*pf_end_merge) ( void );
};
+/*****************************************************************************
+ * Control: control facility for the vout (forwards to child vout)
+ *****************************************************************************/
+static int Control( vout_thread_t *p_vout, int i_query, va_list args )
+{
+ return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
+}
+
/*****************************************************************************
* Create: allocates Deinterlace video thread output method
*****************************************************************************
p_vout->pf_manage = NULL;
p_vout->pf_render = Render;
p_vout->pf_display = NULL;
+ p_vout->pf_control = Control;
p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
p_vout->p_sys->b_double_rate = 0;
p_vout->p_sys->last_date = 0;
+ p_vout->p_sys->p_vout = 0;
vlc_mutex_init( p_vout, &p_vout->p_sys->filter_lock );
#if defined(CAN_COMPILE_C_ALTIVEC)
}
else
#endif
-#if defined(CAN_COMPILE_MMX)
+#if defined(CAN_COMPILE_MMXEXT)
if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_MMX )
{
p_vout->p_sys->pf_merge = MergeMMX;
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
- DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
-
- vlc_object_detach( p_vout->p_sys->p_vout );
- vout_Destroy( p_vout->p_sys->p_vout );
+ if( p_vout->p_sys->p_vout )
+ {
+ DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
+ vlc_object_detach( p_vout->p_sys->p_vout );
+ vout_Destroy( p_vout->p_sys->p_vout );
+ }
DEL_PARENT_CALLBACKS( SendEventsToChild );
p_out = p_outpic->p[i_plane].p_pixels;
p_out_end = p_out + p_outpic->p[i_plane].i_pitch
- * p_outpic->p[i_plane].i_lines;
+ * p_outpic->p[i_plane].i_visible_lines;
switch( p_vout->render.i_chroma )
{
p_in = p_pic->p[i_plane].p_pixels;
p_out = p_outpic->p[i_plane].p_pixels;
p_out_end = p_out + p_outpic->p[i_plane].i_pitch
- * p_outpic->p[i_plane].i_lines;
+ * p_outpic->p[i_plane].i_visible_lines;
switch( p_vout->render.i_chroma )
{
p_in = p_pic->p[i_plane].p_pixels;
p_out = p_outpic->p[i_plane].p_pixels;
p_out_end = p_out + p_outpic->p[i_plane].i_pitch
- * p_outpic->p[i_plane].i_lines;
+ * p_outpic->p[i_plane].i_visible_lines;
/* For BOTTOM field we need to add the first line */
if( i_field == 1 )
p_out = p_outpic->p[i_plane].p_pixels;
p_out_end = p_out + p_outpic->p[i_plane].i_pitch
- * p_outpic->p[i_plane].i_lines;
+ * p_outpic->p[i_plane].i_visible_lines;
/* All lines: mean value */
for( ; p_out < p_out_end ; )
p_out = p_outpic->p[i_plane].p_pixels;
p_out_end = p_out + p_outpic->p[i_plane].i_pitch
- * p_outpic->p[i_plane].i_lines;
+ * p_outpic->p[i_plane].i_visible_lines;
switch( p_vout->render.i_chroma )
{
}
}
-#if defined(CAN_COMPILE_MMX)
+#if defined(CAN_COMPILE_MMXEXT)
static void MergeMMX( void *_p_dest, const void *_p_s1, const void *_p_s2,
size_t i_bytes )
{
uint8_t* p_dest = (uint8_t*)_p_dest;
const uint8_t *p_s1 = (const uint8_t *)_p_s1;
const uint8_t *p_s2 = (const uint8_t *)_p_s2;
+ uint8_t* p_end;
while( (int)p_s1 % 16 )
{
*p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
}
- uint8_t* p_end = p_dest + i_bytes - 16;
+ p_end = p_dest + i_bytes - 16;
while( p_dest < p_end )
{
__asm__ __volatile__( "movdqu %2,%%xmm1;"
}
#endif
-#if defined(CAN_COMPILE_MMX) || defined(CAN_COMPILE_SSE)
+#if defined(CAN_COMPILE_MMXEXT) || defined(CAN_COMPILE_SSE)
static void EndMMX( void )
{
__asm__ __volatile__( "emms" :: );
static void MergeAltivec( void *_p_dest, const void *_p_s1,
const void *_p_s2, size_t i_bytes )
{
- uint8_t *p_dest = (uint8_t*)_p_dest;
- const uint8_t *p_s1 = (const uint8_t *)_p_s1;
- const uint8_t *p_s2 = (const uint8_t *)_p_s2;
- uint8_t *p_end = p_dest + i_bytes - 16;
+ uint8_t *p_dest = (uint8_t *)_p_dest;
+ uint8_t *p_s1 = (uint8_t *)_p_s1;
+ uint8_t *p_s2 = (uint8_t *)_p_s2;
+ uint8_t *p_end = p_dest + i_bytes - 15;
- if( ( (int)p_s1 & 0xF ) | ( (int)p_s2 & 0xF ) |
- ( (int)p_dest & 0xF ) )
+ /* Use C until the first 16-bytes aligned destination pixel */
+ while( (int)p_dest & 0xF )
{
- /* TODO Handle non 16-bytes aligned planes */
- MergeGeneric( _p_dest, _p_s1, _p_s2, i_bytes );
- return;
+ *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
}
- while( p_dest < p_end )
+ if( ( (int)p_s1 & 0xF ) | ( (int)p_s2 & 0xF ) )
{
- vec_st( vec_avg( vec_ld( 0, p_s1 ), vec_ld( 0, p_s2 ) ),
- 0, p_dest );
- p_s1 += 16;
- p_s2 += 16;
- p_dest += 16;
+ /* Unaligned source */
+ vector unsigned char s1v, s2v, destv;
+ vector unsigned char s1oldv, s2oldv, s1newv, s2newv;
+ vector unsigned char perm1v, perm2v;
+
+ perm1v = vec_lvsl( 0, p_s1 );
+ perm2v = vec_lvsl( 0, p_s2 );
+ s1oldv = vec_ld( 0, p_s1 );
+ s2oldv = vec_ld( 0, p_s2 );
+
+ while( p_dest < p_end )
+ {
+ s1newv = vec_ld( 16, p_s1 );
+ s2newv = vec_ld( 16, p_s2 );
+ s1v = vec_perm( s1oldv, s1newv, perm1v );
+ s2v = vec_perm( s2oldv, s2newv, perm2v );
+ s1oldv = s1newv;
+ s2oldv = s2newv;
+ destv = vec_avg( s1v, s2v );
+ vec_st( destv, 0, p_dest );
+
+ p_s1 += 16;
+ p_s2 += 16;
+ p_dest += 16;
+ }
}
+ else
+ {
+ /* Aligned source */
+ vector unsigned char s1v, s2v, destv;
- p_end += 16;
+ while( p_dest < p_end )
+ {
+ s1v = vec_ld( 0, p_s1 );
+ s2v = vec_ld( 0, p_s2 );
+ destv = vec_avg( s1v, s2v );
+ vec_st( destv, 0, p_dest );
+
+ p_s1 += 16;
+ p_s2 += 16;
+ p_dest += 16;
+ }
+ }
+
+ p_end += 15;
while( p_dest < p_end )
{