1 /*****************************************************************************
2 * deinterlace.c : deinterlacer plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000, 2001, 2002, 2003 VideoLAN
5 * $Id: deinterlace.c,v 1.20 2004/01/25 20:05:28 hartman Exp $
7 * Author: Sam Hocevar <sam@zoy.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
34 #include "../filter_common.h"
36 #define DEINTERLACE_DISCARD 1
37 #define DEINTERLACE_MEAN 2
38 #define DEINTERLACE_BLEND 3
39 #define DEINTERLACE_BOB 4
40 #define DEINTERLACE_LINEAR 5
42 /*****************************************************************************
44 *****************************************************************************/
45 static int Create ( vlc_object_t * );
46 static void Destroy ( vlc_object_t * );
48 static int Init ( vout_thread_t * );
49 static void End ( vout_thread_t * );
50 static void Render ( vout_thread_t *, picture_t * );
52 static void RenderDiscard( vout_thread_t *, picture_t *, picture_t *, int );
53 static void RenderBob ( vout_thread_t *, picture_t *, picture_t *, int );
54 static void RenderMean ( vout_thread_t *, picture_t *, picture_t * );
55 static void RenderBlend ( vout_thread_t *, picture_t *, picture_t * );
56 static void RenderLinear ( vout_thread_t *, picture_t *, picture_t *, int );
58 static void MergeGeneric ( void *, const void *, const void *, size_t );
59 static void MergeAltivec ( void *, const void *, const void *, size_t );
61 static int SendEvents ( vlc_object_t *, char const *,
62 vlc_value_t, vlc_value_t, void * );
64 static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method );
65 static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout );
67 /*****************************************************************************
69 *****************************************************************************/
70 static int FilterCallback ( vlc_object_t *, char const *,
71 vlc_value_t, vlc_value_t, void * );
73 /*****************************************************************************
75 *****************************************************************************/
76 #define MODE_TEXT N_("Deinterlace mode")
77 #define MODE_LONGTEXT N_("You can choose the default deinterlace mode")
79 static char *mode_list[] = { "discard", "blend", "mean", "bob", "linear" };
80 static char *mode_list_text[] = { N_("Discard"), N_("Blend"), N_("Mean"),
81 N_("Bob"), N_("Linear") };
84 set_description( _("Deinterlacing video filter") );
85 set_capability( "video filter", 0 );
87 add_string( "deinterlace-mode", "discard", NULL, MODE_TEXT,
88 MODE_LONGTEXT, VLC_FALSE );
89 change_string_list( mode_list, mode_list_text, 0 );
91 add_shortcut( "deinterlace" );
92 set_callbacks( Create, Destroy );
95 /*****************************************************************************
96 * vout_sys_t: Deinterlace video output method descriptor
97 *****************************************************************************
98 * This structure is part of the video output thread descriptor.
99 * It describes the Deinterlace specific properties of an output thread.
100 *****************************************************************************/
103 int i_mode; /* Deinterlace mode */
104 vlc_bool_t b_double_rate; /* Shall we double the framerate? */
109 vout_thread_t *p_vout;
111 vlc_mutex_t filter_lock;
113 void (*pf_merge) ( void *, const void *, const void *, size_t );
116 /*****************************************************************************
117 * Create: allocates Deinterlace video thread output method
118 *****************************************************************************
119 * This function allocates and initializes a Deinterlace vout method.
120 *****************************************************************************/
121 static int Create( vlc_object_t *p_this )
123 vout_thread_t *p_vout = (vout_thread_t *)p_this;
126 /* Allocate structure */
127 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
128 if( p_vout->p_sys == NULL )
130 msg_Err( p_vout, "out of memory" );
134 p_vout->pf_init = Init;
135 p_vout->pf_end = End;
136 p_vout->pf_manage = NULL;
137 p_vout->pf_render = Render;
138 p_vout->pf_display = NULL;
140 p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
141 p_vout->p_sys->b_double_rate = 0;
142 p_vout->p_sys->last_date = 0;
143 vlc_mutex_init( p_vout, &p_vout->p_sys->filter_lock );
145 if( p_vout->p_libvlc->i_cpu & CPU_CAPABILITY_ALTIVEC )
147 p_vout->p_sys->pf_merge = MergeAltivec;
151 p_vout->p_sys->pf_merge = MergeGeneric;
154 /* Look what method was requested */
155 var_Create( p_vout, "deinterlace-mode", VLC_VAR_STRING );
156 var_Change( p_vout, "deinterlace-mode", VLC_VAR_INHERITVALUE, &val, NULL );
158 if( val.psz_string == NULL )
160 msg_Err( p_vout, "configuration variable deinterlace-mode empty" );
161 msg_Err( p_vout, "no deinterlace mode provided, using \"discard\"" );
163 val.psz_string = strdup( "discard" );
166 msg_Dbg( p_vout, "using %s deinterlace mode", val.psz_string );
168 SetFilterMethod( p_vout, val.psz_string );
170 free( val.psz_string );
172 var_AddCallback( p_vout, "deinterlace-mode", FilterCallback, NULL );
177 /*****************************************************************************
178 * SetFilterMethod: setup the deinterlace method to use.
179 *****************************************************************************/
180 static void SetFilterMethod( vout_thread_t *p_vout, char *psz_method )
182 if( !strcmp( psz_method, "discard" ) )
184 p_vout->p_sys->i_mode = DEINTERLACE_DISCARD;
185 p_vout->p_sys->b_double_rate = 0;
187 else if( !strcmp( psz_method, "mean" ) )
189 p_vout->p_sys->i_mode = DEINTERLACE_MEAN;
190 p_vout->p_sys->b_double_rate = 0;
192 else if( !strcmp( psz_method, "blend" )
193 || !strcmp( psz_method, "average" )
194 || !strcmp( psz_method, "combine-fields" ) )
196 p_vout->p_sys->i_mode = DEINTERLACE_BLEND;
197 p_vout->p_sys->b_double_rate = 0;
199 else if( !strcmp( psz_method, "bob" )
200 || !strcmp( psz_method, "progressive-scan" ) )
202 p_vout->p_sys->i_mode = DEINTERLACE_BOB;
203 p_vout->p_sys->b_double_rate = 1;
205 else if( !strcmp( psz_method, "linear" ) )
207 p_vout->p_sys->i_mode = DEINTERLACE_LINEAR;
208 p_vout->p_sys->b_double_rate = 1;
212 msg_Err( p_vout, "no valid deinterlace mode provided, "
213 "using \"discard\"" );
216 msg_Dbg( p_vout, "using %s deinterlace method", psz_method );
219 /*****************************************************************************
220 * Init: initialize Deinterlace video thread output method
221 *****************************************************************************/
222 static int Init( vout_thread_t *p_vout )
227 I_OUTPUTPICTURES = 0;
229 /* Initialize the output structure, full of directbuffers since we want
230 * the decoder to output directly to our structures. */
231 switch( p_vout->render.i_chroma )
233 case VLC_FOURCC('I','4','2','0'):
234 case VLC_FOURCC('I','Y','U','V'):
235 case VLC_FOURCC('Y','V','1','2'):
236 case VLC_FOURCC('I','4','2','2'):
237 p_vout->output.i_chroma = p_vout->render.i_chroma;
238 p_vout->output.i_width = p_vout->render.i_width;
239 p_vout->output.i_height = p_vout->render.i_height;
240 p_vout->output.i_aspect = p_vout->render.i_aspect;
244 return VLC_EGENERIC; /* unknown chroma */
248 /* Try to open the real video output */
249 p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
251 if( p_vout->p_sys->p_vout == NULL )
253 /* Everything failed */
254 msg_Err( p_vout, "cannot open vout, aborting" );
259 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
261 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
263 ADD_PARENT_CALLBACKS( SendEventsToChild );
268 /*****************************************************************************
269 * SpawnRealVout: spawn the real video output.
270 *****************************************************************************/
271 static vout_thread_t *SpawnRealVout( vout_thread_t *p_vout )
273 vout_thread_t *p_real_vout = NULL;
275 msg_Dbg( p_vout, "spawning the real video output" );
277 switch( p_vout->render.i_chroma )
279 case VLC_FOURCC('I','4','2','0'):
280 case VLC_FOURCC('I','Y','U','V'):
281 case VLC_FOURCC('Y','V','1','2'):
282 switch( p_vout->p_sys->i_mode )
284 case DEINTERLACE_MEAN:
285 case DEINTERLACE_DISCARD:
288 p_vout->output.i_width, p_vout->output.i_height / 2,
289 p_vout->output.i_chroma, p_vout->output.i_aspect );
292 case DEINTERLACE_BOB:
293 case DEINTERLACE_BLEND:
294 case DEINTERLACE_LINEAR:
297 p_vout->output.i_width, p_vout->output.i_height,
298 p_vout->output.i_chroma, p_vout->output.i_aspect );
303 case VLC_FOURCC('I','4','2','2'):
306 p_vout->output.i_width, p_vout->output.i_height,
307 VLC_FOURCC('I','4','2','0'), p_vout->output.i_aspect );
317 /*****************************************************************************
318 * End: terminate Deinterlace video thread output method
319 *****************************************************************************/
320 static void End( vout_thread_t *p_vout )
324 /* Free the fake output buffers we allocated */
325 for( i_index = I_OUTPUTPICTURES ; i_index ; )
328 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
332 /*****************************************************************************
333 * Destroy: destroy Deinterlace video thread output method
334 *****************************************************************************
335 * Terminate an output method created by DeinterlaceCreateOutputMethod
336 *****************************************************************************/
337 static void Destroy( vlc_object_t *p_this )
339 vout_thread_t *p_vout = (vout_thread_t *)p_this;
341 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
343 vlc_object_detach( p_vout->p_sys->p_vout );
344 vout_Destroy( p_vout->p_sys->p_vout );
346 DEL_PARENT_CALLBACKS( SendEventsToChild );
348 free( p_vout->p_sys );
351 /*****************************************************************************
352 * Render: displays previously rendered output
353 *****************************************************************************
354 * This function send the currently rendered image to Deinterlace image,
355 * waits until it is displayed and switch the two rendering buffers, preparing
357 *****************************************************************************/
358 static void Render ( vout_thread_t *p_vout, picture_t *p_pic )
360 picture_t *pp_outpic[2];
362 vlc_mutex_lock( &p_vout->p_sys->filter_lock );
364 /* Get a new picture */
365 while( ( pp_outpic[0] = vout_CreatePicture( p_vout->p_sys->p_vout,
369 if( p_vout->b_die || p_vout->b_error )
371 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
374 msleep( VOUT_OUTMEM_SLEEP );
377 vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[0], p_pic->date );
379 /* If we are using double rate, get an additional new picture */
380 if( p_vout->p_sys->b_double_rate )
382 while( ( pp_outpic[1] = vout_CreatePicture( p_vout->p_sys->p_vout,
386 if( p_vout->b_die || p_vout->b_error )
388 vout_DestroyPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
389 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
392 msleep( VOUT_OUTMEM_SLEEP );
395 /* 20ms is a bit arbitrary, but it's only for the first image we get */
396 if( !p_vout->p_sys->last_date )
398 vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1],
399 p_pic->date + 20000 );
403 vout_DatePicture( p_vout->p_sys->p_vout, pp_outpic[1],
404 (3 * p_pic->date - p_vout->p_sys->last_date) / 2 );
406 p_vout->p_sys->last_date = p_pic->date;
409 switch( p_vout->p_sys->i_mode )
411 case DEINTERLACE_DISCARD:
412 RenderDiscard( p_vout, pp_outpic[0], p_pic, 0 );
413 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
416 case DEINTERLACE_BOB:
417 RenderBob( p_vout, pp_outpic[0], p_pic, 0 );
418 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
419 RenderBob( p_vout, pp_outpic[1], p_pic, 1 );
420 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
423 case DEINTERLACE_LINEAR:
424 RenderLinear( p_vout, pp_outpic[0], p_pic, 0 );
425 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
426 RenderLinear( p_vout, pp_outpic[1], p_pic, 1 );
427 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[1] );
430 case DEINTERLACE_MEAN:
431 RenderMean( p_vout, pp_outpic[0], p_pic );
432 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
435 case DEINTERLACE_BLEND:
436 RenderBlend( p_vout, pp_outpic[0], p_pic );
437 vout_DisplayPicture( p_vout->p_sys->p_vout, pp_outpic[0] );
441 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
444 /*****************************************************************************
445 * RenderDiscard: only keep TOP or BOTTOM field, discard the other.
446 *****************************************************************************/
447 static void RenderDiscard( vout_thread_t *p_vout,
448 picture_t *p_outpic, picture_t *p_pic, int i_field )
452 /* Copy image and skip lines */
453 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
455 uint8_t *p_in, *p_out_end, *p_out;
458 p_in = p_pic->p[i_plane].p_pixels
459 + i_field * p_pic->p[i_plane].i_pitch;
461 p_out = p_outpic->p[i_plane].p_pixels;
462 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
463 * p_outpic->p[i_plane].i_lines;
465 switch( p_vout->render.i_chroma )
467 case VLC_FOURCC('I','4','2','0'):
468 case VLC_FOURCC('I','Y','U','V'):
469 case VLC_FOURCC('Y','V','1','2'):
471 for( ; p_out < p_out_end ; )
473 p_vout->p_vlc->pf_memcpy( p_out, p_in,
474 p_pic->p[i_plane].i_pitch );
476 p_out += p_pic->p[i_plane].i_pitch;
477 p_in += 2 * p_pic->p[i_plane].i_pitch;
481 case VLC_FOURCC('I','4','2','2'):
483 i_increment = 2 * p_pic->p[i_plane].i_pitch;
485 if( i_plane == Y_PLANE )
487 for( ; p_out < p_out_end ; )
489 p_vout->p_vlc->pf_memcpy( p_out, p_in,
490 p_pic->p[i_plane].i_pitch );
491 p_out += p_pic->p[i_plane].i_pitch;
492 p_vout->p_vlc->pf_memcpy( p_out, p_in,
493 p_pic->p[i_plane].i_pitch );
494 p_out += p_pic->p[i_plane].i_pitch;
500 for( ; p_out < p_out_end ; )
502 p_vout->p_vlc->pf_memcpy( p_out, p_in,
503 p_pic->p[i_plane].i_pitch );
504 p_out += p_pic->p[i_plane].i_pitch;
516 /*****************************************************************************
517 * RenderBob: renders a BOB picture - simple copy
518 *****************************************************************************/
519 static void RenderBob( vout_thread_t *p_vout,
520 picture_t *p_outpic, picture_t *p_pic, int i_field )
524 /* Copy image and skip lines */
525 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
527 uint8_t *p_in, *p_out_end, *p_out;
529 p_in = p_pic->p[i_plane].p_pixels;
530 p_out = p_outpic->p[i_plane].p_pixels;
531 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
532 * p_outpic->p[i_plane].i_lines;
534 switch( p_vout->render.i_chroma )
536 case VLC_FOURCC('I','4','2','0'):
537 case VLC_FOURCC('I','Y','U','V'):
538 case VLC_FOURCC('Y','V','1','2'):
539 /* For BOTTOM field we need to add the first line */
542 p_vout->p_vlc->pf_memcpy( p_out, p_in,
543 p_pic->p[i_plane].i_pitch );
544 p_in += p_pic->p[i_plane].i_pitch;
545 p_out += p_pic->p[i_plane].i_pitch;
548 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
550 for( ; p_out < p_out_end ; )
552 p_vout->p_vlc->pf_memcpy( p_out, p_in,
553 p_pic->p[i_plane].i_pitch );
555 p_out += p_pic->p[i_plane].i_pitch;
557 p_vout->p_vlc->pf_memcpy( p_out, p_in,
558 p_pic->p[i_plane].i_pitch );
560 p_in += 2 * p_pic->p[i_plane].i_pitch;
561 p_out += p_pic->p[i_plane].i_pitch;
564 p_vout->p_vlc->pf_memcpy( p_out, p_in,
565 p_pic->p[i_plane].i_pitch );
567 /* For TOP field we need to add the last line */
570 p_in += p_pic->p[i_plane].i_pitch;
571 p_out += p_pic->p[i_plane].i_pitch;
572 p_vout->p_vlc->pf_memcpy( p_out, p_in,
573 p_pic->p[i_plane].i_pitch );
577 case VLC_FOURCC('I','4','2','2'):
578 /* For BOTTOM field we need to add the first line */
581 p_vout->p_vlc->pf_memcpy( p_out, p_in,
582 p_pic->p[i_plane].i_pitch );
583 p_in += p_pic->p[i_plane].i_pitch;
584 p_out += p_pic->p[i_plane].i_pitch;
587 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
589 if( i_plane == Y_PLANE )
591 for( ; p_out < p_out_end ; )
593 p_vout->p_vlc->pf_memcpy( p_out, p_in,
594 p_pic->p[i_plane].i_pitch );
596 p_out += p_pic->p[i_plane].i_pitch;
598 p_vout->p_vlc->pf_memcpy( p_out, p_in,
599 p_pic->p[i_plane].i_pitch );
601 p_in += 2 * p_pic->p[i_plane].i_pitch;
602 p_out += p_pic->p[i_plane].i_pitch;
607 for( ; p_out < p_out_end ; )
609 p_vout->p_vlc->pf_memcpy( p_out, p_in,
610 p_pic->p[i_plane].i_pitch );
612 p_out += p_pic->p[i_plane].i_pitch;
613 p_in += 2 * p_pic->p[i_plane].i_pitch;
617 p_vout->p_vlc->pf_memcpy( p_out, p_in,
618 p_pic->p[i_plane].i_pitch );
620 /* For TOP field we need to add the last line */
623 p_in += p_pic->p[i_plane].i_pitch;
624 p_out += p_pic->p[i_plane].i_pitch;
625 p_vout->p_vlc->pf_memcpy( p_out, p_in,
626 p_pic->p[i_plane].i_pitch );
633 #define Merge p_vout->p_sys->pf_merge
635 /*****************************************************************************
636 * RenderLinear: BOB with linear interpolation
637 *****************************************************************************/
638 static void RenderLinear( vout_thread_t *p_vout,
639 picture_t *p_outpic, picture_t *p_pic, int i_field )
643 /* Copy image and skip lines */
644 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
646 uint8_t *p_in, *p_out_end, *p_out;
648 p_in = p_pic->p[i_plane].p_pixels;
649 p_out = p_outpic->p[i_plane].p_pixels;
650 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
651 * p_outpic->p[i_plane].i_lines;
653 /* For BOTTOM field we need to add the first line */
656 p_vout->p_vlc->pf_memcpy( p_out, p_in,
657 p_pic->p[i_plane].i_pitch );
658 p_in += p_pic->p[i_plane].i_pitch;
659 p_out += p_pic->p[i_plane].i_pitch;
662 p_out_end -= 2 * p_outpic->p[i_plane].i_pitch;
664 for( ; p_out < p_out_end ; )
666 p_vout->p_vlc->pf_memcpy( p_out, p_in,
667 p_pic->p[i_plane].i_pitch );
669 p_out += p_pic->p[i_plane].i_pitch;
671 Merge( p_out, p_in, p_in + 2 * p_pic->p[i_plane].i_pitch,
672 p_pic->p[i_plane].i_pitch );
674 p_in += 2 * p_pic->p[i_plane].i_pitch;
675 p_out += p_pic->p[i_plane].i_pitch;
678 p_vout->p_vlc->pf_memcpy( p_out, p_in,
679 p_pic->p[i_plane].i_pitch );
681 /* For TOP field we need to add the last line */
684 p_in += p_pic->p[i_plane].i_pitch;
685 p_out += p_pic->p[i_plane].i_pitch;
686 p_vout->p_vlc->pf_memcpy( p_out, p_in,
687 p_pic->p[i_plane].i_pitch );
692 static void RenderMean( vout_thread_t *p_vout,
693 picture_t *p_outpic, picture_t *p_pic )
697 /* Copy image and skip lines */
698 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
700 uint8_t *p_in, *p_out_end, *p_out;
702 p_in = p_pic->p[i_plane].p_pixels;
704 p_out = p_outpic->p[i_plane].p_pixels;
705 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
706 * p_outpic->p[i_plane].i_lines;
708 /* All lines: mean value */
709 for( ; p_out < p_out_end ; )
711 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
712 p_pic->p[i_plane].i_pitch );
714 p_out += p_pic->p[i_plane].i_pitch;
715 p_in += 2 * p_pic->p[i_plane].i_pitch;
720 static void RenderBlend( vout_thread_t *p_vout,
721 picture_t *p_outpic, picture_t *p_pic )
725 /* Copy image and skip lines */
726 for( i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ )
728 uint8_t *p_in, *p_out_end, *p_out;
730 p_in = p_pic->p[i_plane].p_pixels;
732 p_out = p_outpic->p[i_plane].p_pixels;
733 p_out_end = p_out + p_outpic->p[i_plane].i_pitch
734 * p_outpic->p[i_plane].i_lines;
736 switch( p_vout->render.i_chroma )
738 case VLC_FOURCC('I','4','2','0'):
739 case VLC_FOURCC('I','Y','U','V'):
740 case VLC_FOURCC('Y','V','1','2'):
741 /* First line: simple copy */
742 p_vout->p_vlc->pf_memcpy( p_out, p_in,
743 p_pic->p[i_plane].i_pitch );
744 p_out += p_pic->p[i_plane].i_pitch;
746 /* Remaining lines: mean value */
747 for( ; p_out < p_out_end ; )
749 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
750 p_pic->p[i_plane].i_pitch );
752 p_out += p_pic->p[i_plane].i_pitch;
753 p_in += p_pic->p[i_plane].i_pitch;
757 case VLC_FOURCC('I','4','2','2'):
758 /* First line: simple copy */
759 p_vout->p_vlc->pf_memcpy( p_out, p_in,
760 p_pic->p[i_plane].i_pitch );
761 p_out += p_pic->p[i_plane].i_pitch;
763 /* Remaining lines: mean value */
764 if( i_plane == Y_PLANE )
766 for( ; p_out < p_out_end ; )
768 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
769 p_pic->p[i_plane].i_pitch );
771 p_out += p_pic->p[i_plane].i_pitch;
772 p_in += p_pic->p[i_plane].i_pitch;
778 for( ; p_out < p_out_end ; )
780 Merge( p_out, p_in, p_in + p_pic->p[i_plane].i_pitch,
781 p_pic->p[i_plane].i_pitch );
783 p_out += p_pic->p[i_plane].i_pitch;
784 p_in += 2*p_pic->p[i_plane].i_pitch;
794 static void MergeGeneric( void *_p_dest, const void *_p_s1,
795 const void *_p_s2, size_t i_bytes )
797 uint8_t* p_dest = (uint8_t*)_p_dest;
798 const uint8_t *p_s1 = (const uint8_t *)_p_s1;
799 const uint8_t *p_s2 = (const uint8_t *)_p_s2;
800 uint8_t* p_end = p_dest + i_bytes - 8;
802 while( p_dest < p_end )
804 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
805 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
806 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
807 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
808 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
809 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
810 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
811 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
816 while( p_dest < p_end )
818 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
822 static void MergeAltivec( void *_p_dest, const void *_p_s1,
823 const void *_p_s2, size_t i_bytes )
825 #ifdef CAN_COMPILE_C_ALTIVEC
826 uint8_t *p_dest = (uint8_t*)_p_dest;
827 const uint8_t *p_s1 = (const uint8_t *)_p_s1;
828 const uint8_t *p_s2 = (const uint8_t *)_p_s2;
829 uint8_t *p_end = p_dest + i_bytes - 16;
831 if( ( (int)p_s1 & 0xF ) | ( (int)p_s2 & 0xF ) |
832 ( (int)p_dest & 0xF ) )
834 /* TODO Handle non 16-bytes aligned planes */
835 MergeGeneric( _p_dest, _p_s1, _p_s2, i_bytes );
839 while( p_dest < p_end )
841 vec_st( vec_avg( vec_ld( 0, p_s1 ), vec_ld( 0, p_s2 ) ),
850 while( p_dest < p_end )
852 *p_dest++ = ( (uint16_t)(*p_s1++) + (uint16_t)(*p_s2++) ) >> 1;
857 /*****************************************************************************
858 * SendEvents: forward mouse and keyboard events to the parent p_vout
859 *****************************************************************************/
860 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
861 vlc_value_t oldval, vlc_value_t newval, void *_p_vout )
863 vout_thread_t *p_vout = (vout_thread_t *)_p_vout;
864 vlc_value_t sentval = newval;
866 if( !strcmp( psz_var, "mouse-y" ) )
868 switch( p_vout->p_sys->i_mode )
870 case DEINTERLACE_MEAN:
871 case DEINTERLACE_DISCARD:
877 var_Set( p_vout, psz_var, sentval );
882 /*****************************************************************************
883 * FilterCallback: called when changing the deinterlace method on the fly.
884 *****************************************************************************/
885 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
886 vlc_value_t oldval, vlc_value_t newval,
889 vout_thread_t * p_vout = (vout_thread_t *)p_this;
890 int i_old_mode = p_vout->p_sys->i_mode;
892 msg_Dbg( p_vout, "using %s deinterlace mode", newval.psz_string );
894 vlc_mutex_lock( &p_vout->p_sys->filter_lock );
896 SetFilterMethod( p_vout, newval.psz_string );
898 switch( p_vout->render.i_chroma )
900 case VLC_FOURCC('I','4','2','2'):
901 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
905 case VLC_FOURCC('I','4','2','0'):
906 case VLC_FOURCC('I','Y','U','V'):
907 case VLC_FOURCC('Y','V','1','2'):
908 switch( p_vout->p_sys->i_mode )
910 case DEINTERLACE_MEAN:
911 case DEINTERLACE_DISCARD:
912 if( ( i_old_mode == DEINTERLACE_MEAN )
913 || ( i_old_mode == DEINTERLACE_DISCARD ) )
915 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
920 case DEINTERLACE_BOB:
921 case DEINTERLACE_BLEND:
922 case DEINTERLACE_LINEAR:
923 if( ( i_old_mode == DEINTERLACE_BOB )
924 || ( i_old_mode == DEINTERLACE_BLEND )
925 || ( i_old_mode == DEINTERLACE_LINEAR ) )
927 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
938 /* We need to kill the old vout */
940 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
942 vlc_object_detach( p_vout->p_sys->p_vout );
943 vout_Destroy( p_vout->p_sys->p_vout );
945 /* Try to open a new video output */
946 p_vout->p_sys->p_vout = SpawnRealVout( p_vout );
948 if( p_vout->p_sys->p_vout == NULL )
950 /* Everything failed */
951 msg_Err( p_vout, "cannot open vout, aborting" );
953 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
957 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
959 vlc_mutex_unlock( &p_vout->p_sys->filter_lock );
963 /*****************************************************************************
964 * SendEventsToChild: forward events to the child/children vout
965 *****************************************************************************/
966 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
967 vlc_value_t oldval, vlc_value_t newval, void *p_data )
969 vout_thread_t *p_vout = (vout_thread_t *)p_this;
970 var_Set( p_vout->p_sys->p_vout, psz_var, newval );