1 /*****************************************************************************
2 * video_output.c : video output thread
4 * This module describes the programming interface for video output threads.
5 * It includes functions allowing to open a new thread, send pictures to a
6 * thread, and destroy a previously oppened video output thread.
7 *****************************************************************************
8 * Copyright (C) 2000-2004 the VideoLAN team
11 * Authors: Vincent Seguin <seguin@via.ecp.fr>
12 * Gildas Bazin <gbazin@videolan.org>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
34 #include <stdlib.h> /* free() */
38 #ifdef HAVE_SYS_TIMES_H
39 # include <sys/times.h>
43 #include <vlc_playlist.h>
45 #include <vlc_filter.h>
48 #if defined( __APPLE__ )
49 /* Include darwin_specific.h here if needed */
52 /** FIXME This is quite ugly but needed while we don't have counters
54 #include "input/input_internal.h"
56 /*****************************************************************************
58 *****************************************************************************/
59 static int InitThread ( vout_thread_t * );
60 static void RunThread ( vout_thread_t * );
61 static void ErrorThread ( vout_thread_t * );
62 static void EndThread ( vout_thread_t * );
63 static void DestroyThread ( vout_thread_t * );
65 static void AspectRatio ( int, int *, int * );
66 static int BinaryLog ( uint32_t );
67 static void MaskToShift ( int *, int *, uint32_t );
69 /* Object variables callbacks */
70 static int DeinterlaceCallback( vlc_object_t *, char const *,
71 vlc_value_t, vlc_value_t, void * );
72 static int FilterCallback( vlc_object_t *, char const *,
73 vlc_value_t, vlc_value_t, void * );
74 static int VideoFilter2Callback( vlc_object_t *, char const *,
75 vlc_value_t, vlc_value_t, void * );
77 /* From vout_intf.c */
78 int vout_Snapshot( vout_thread_t *, picture_t * );
80 /* Video filter2 parsing */
81 static int ParseVideoFilter2Chain( vout_thread_t *, char * );
82 static void RemoveVideoFilters2( vout_thread_t *p_vout );
84 /*****************************************************************************
85 * Video Filter2 functions
86 *****************************************************************************/
87 struct filter_owner_sys_t
89 vout_thread_t *p_vout;
92 static picture_t *video_new_buffer_filter( filter_t *p_filter )
95 vout_thread_t *p_vout = p_filter->p_owner->p_vout;
97 p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
102 static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
104 vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
107 /*****************************************************************************
108 * vout_Request: find a video output thread, create one, or destroy one.
109 *****************************************************************************
110 * This function looks for a video output thread matching the current
111 * properties. If not found, it spawns a new one.
112 *****************************************************************************/
113 vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout,
114 video_format_t *p_fmt )
118 /* Reattach video output to playlist before bailing out */
121 playlist_t *p_playlist = pl_Yield( p_this );
122 spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
123 vlc_object_detach( p_vout );
124 vlc_object_attach( p_vout, p_playlist );
125 pl_Release( p_this );
130 /* If a video output was provided, lock it, otherwise look for one. */
133 vlc_object_yield( p_vout );
137 p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );
141 playlist_t *p_playlist = pl_Yield( p_this );
142 vlc_mutex_lock( &p_playlist->gc_lock );
143 p_vout = vlc_object_find( p_playlist,
144 VLC_OBJECT_VOUT, FIND_CHILD );
145 /* only first children of p_input for unused vout */
146 if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist )
148 vlc_object_release( p_vout );
152 vlc_object_detach( p_vout ); /* Remove it from the GC */
153 vlc_mutex_unlock( &p_playlist->gc_lock );
154 pl_Release( p_this );
158 /* If we now have a video output, check it has the right properties */
161 char *psz_filter_chain;
164 /* We don't directly check for the "vout-filter" variable for obvious
165 * performance reasons. */
166 if( p_vout->b_filter_change )
168 var_Get( p_vout, "vout-filter", &val );
169 psz_filter_chain = val.psz_string;
171 if( psz_filter_chain && !*psz_filter_chain )
173 free( psz_filter_chain );
174 psz_filter_chain = NULL;
176 if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
178 free( p_vout->psz_filter_chain );
179 p_vout->psz_filter_chain = NULL;
182 if( !psz_filter_chain && !p_vout->psz_filter_chain )
184 p_vout->b_filter_change = VLC_FALSE;
187 if( psz_filter_chain ) free( psz_filter_chain );
190 if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
191 ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
192 ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
193 ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
194 p_vout->b_filter_change )
196 /* We are not interested in this format, close this vout */
197 vlc_object_release( p_vout );
198 vout_Destroy( p_vout );
203 /* This video output is cool! Hijack it. */
204 spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
205 vlc_object_attach( p_vout, p_this );
206 vlc_object_release( p_vout );
212 msg_Dbg( p_this, "no usable vout present, spawning one" );
214 p_vout = vout_Create( p_this, p_fmt );
220 /*****************************************************************************
221 * vout_Create: creates a new video output thread
222 *****************************************************************************
223 * This function creates a new video output thread, and returns a pointer
224 * to its description. On error, it returns NULL.
225 *****************************************************************************/
226 vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
228 vout_thread_t * p_vout; /* thread descriptor */
229 input_thread_t * p_input_thread;
230 int i_index; /* loop variable */
231 vlc_value_t val, text;
233 unsigned int i_width = p_fmt->i_width;
234 unsigned int i_height = p_fmt->i_height;
235 vlc_fourcc_t i_chroma = p_fmt->i_chroma;
236 unsigned int i_aspect = p_fmt->i_aspect;
238 config_chain_t *p_cfg;
242 /* Allocate descriptor */
243 p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
246 msg_Err( p_parent, "out of memory" );
250 /* Initialize pictures - translation tables and functions
251 * will be initialized later in InitThread */
252 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
254 p_vout->p_picture[i_index].pf_lock = NULL;
255 p_vout->p_picture[i_index].pf_unlock = NULL;
256 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
257 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
258 p_vout->p_picture[i_index].b_slow = 0;
261 /* No images in the heap */
262 p_vout->i_heap_size = 0;
264 /* Initialize the rendering heap */
265 I_RENDERPICTURES = 0;
267 vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
268 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
269 p_vout->fmt_render = *p_fmt; /* FIXME palette */
270 p_vout->fmt_in = *p_fmt; /* FIXME palette */
272 p_vout->render.i_width = i_width;
273 p_vout->render.i_height = i_height;
274 p_vout->render.i_chroma = i_chroma;
275 p_vout->render.i_aspect = i_aspect;
277 p_vout->render.i_rmask = 0;
278 p_vout->render.i_gmask = 0;
279 p_vout->render.i_bmask = 0;
281 p_vout->render.i_last_used_pic = -1;
282 p_vout->render.b_allow_modify_pics = 1;
284 /* Zero the output heap */
285 I_OUTPUTPICTURES = 0;
286 p_vout->output.i_width = 0;
287 p_vout->output.i_height = 0;
288 p_vout->output.i_chroma = 0;
289 p_vout->output.i_aspect = 0;
291 p_vout->output.i_rmask = 0;
292 p_vout->output.i_gmask = 0;
293 p_vout->output.i_bmask = 0;
295 /* Initialize misc stuff */
296 p_vout->i_changes = 0;
298 p_vout->b_grayscale = 0;
300 p_vout->b_interface = 0;
302 p_vout->b_fullscreen = 0;
303 p_vout->i_alignment = 0;
304 p_vout->render_time = 10;
305 p_vout->c_fps_samples = 0;
306 p_vout->b_filter_change = 0;
307 p_vout->pf_control = 0;
308 p_vout->p_parent_intf = 0;
309 p_vout->i_par_num = p_vout->i_par_den = 1;
311 /* Initialize locks */
312 vlc_mutex_init( p_vout, &p_vout->picture_lock );
313 vlc_mutex_init( p_vout, &p_vout->change_lock );
314 vlc_mutex_init( p_vout, &p_vout->vfilter_lock );
316 /* Mouse coordinates */
317 var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
318 var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
319 var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
320 var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
321 var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
323 /* Initialize subpicture unit */
324 p_vout->p_spu = spu_Create( p_vout );
325 spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
327 /* Attach the new object now so we can use var inheritance below */
328 vlc_object_attach( p_vout, p_parent );
330 spu_Init( p_vout->p_spu );
332 /* Take care of some "interface/control" related initialisations */
333 vout_IntfInit( p_vout );
335 /* If the parent is not a VOUT object, that means we are at the start of
336 * the video output pipe */
337 if( p_parent->i_object_type != VLC_OBJECT_VOUT )
339 /* Look for the default filter configuration */
340 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
341 var_Get( p_vout, "vout-filter", &val );
342 p_vout->psz_filter_chain = val.psz_string;
344 /* Apply video filter2 objects on the first vout */
345 var_Create( p_vout, "video-filter",
346 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
347 var_Get( p_vout, "video-filter", &val );
348 ParseVideoFilter2Chain( p_vout, val.psz_string );
349 free( val.psz_string );
353 /* continue the parent's filter chain */
356 /* FIXME: use config_ChainParse */
357 psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ':' );
358 if( psz_end && *(psz_end+1) )
359 p_vout->psz_filter_chain = strdup( psz_end+1 );
360 else p_vout->psz_filter_chain = NULL;
362 /* Create a video filter2 var ... but don't inherit values */
363 var_Create( p_vout, "video-filter", VLC_VAR_STRING );
364 ParseVideoFilter2Chain( p_vout, NULL );
367 var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
368 p_vout->b_vfilter_change = VLC_TRUE;
369 p_vout->i_vfilters = 0;
371 /* Choose the video output module */
372 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
374 var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
375 var_Get( p_vout, "vout", &val );
376 psz_parser = val.psz_string;
380 psz_parser = strdup( p_vout->psz_filter_chain );
383 /* Create the vout thread */
384 config_ChainCreate( &psz_name, &p_cfg, psz_parser );
386 p_vout->p_cfg = p_cfg;
387 p_vout->p_module = module_Need( p_vout,
388 ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
389 "video filter" : "video output", psz_name, 0 );
391 if( p_vout->p_module == NULL )
393 msg_Err( p_vout, "no suitable vout module" );
394 vlc_object_detach( p_vout );
395 vlc_object_destroy( p_vout );
399 /* Create a few object variables for interface interaction */
400 var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
401 text.psz_string = _("Deinterlace");
402 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
403 val.psz_string = (char *)""; text.psz_string = _("Disable");
404 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
405 val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
406 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
407 val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
408 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
409 val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
410 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
411 val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
412 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
413 val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
414 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
415 val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
416 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
418 if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
420 var_Set( p_vout, "deinterlace", val );
421 if( val.psz_string ) free( val.psz_string );
423 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
426 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
427 text.psz_string = _("Filters");
428 var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
429 var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
431 /* Calculate delay created by internal caching */
432 p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
433 VLC_OBJECT_INPUT, FIND_ANYWHERE );
436 p_vout->i_pts_delay = p_input_thread->i_pts_delay;
437 vlc_object_release( p_input_thread );
441 p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
444 if( vlc_thread_create( p_vout, "video output", RunThread,
445 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
447 msg_Err( p_vout, "out of memory" );
448 module_Unneed( p_vout, p_vout->p_module );
449 vlc_object_detach( p_vout );
450 vlc_object_destroy( p_vout );
454 if( p_vout->b_error )
456 msg_Err( p_vout, "video output creation failed" );
458 /* Make sure the thread is destroyed */
459 p_vout->b_die = VLC_TRUE;
461 vlc_thread_join( p_vout );
463 vlc_object_detach( p_vout );
464 vlc_object_destroy( p_vout );
471 /*****************************************************************************
472 * vout_Destroy: destroys a previously created video output
473 *****************************************************************************
474 * Destroy a terminated thread.
475 * The function will request a destruction of the specified thread. If pi_error
476 * is NULL, it will return once the thread is destroyed. Else, it will be
477 * update using one of the THREAD_* constants.
478 *****************************************************************************/
479 void vout_Destroy( vout_thread_t *p_vout )
481 vout_thread_t *p_another_vout;
482 playlist_t *p_playlist = pl_Yield( p_vout );
484 /* Request thread destruction */
485 p_vout->b_die = VLC_TRUE;
486 vlc_thread_join( p_vout );
488 var_Destroy( p_vout, "intf-change" );
490 if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
492 config_ChainDestroy( p_vout->p_cfg );
495 vlc_object_destroy( p_vout );
497 /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
498 back if you closed it while playing video. This is solved in Mac OS X,
499 where we have this novelty called menubar, that will always allow you access
500 to the applications main functionality. They should try that on linux sometime */
501 p_another_vout = vlc_object_find( p_playlist,
502 VLC_OBJECT_VOUT, FIND_ANYWHERE );
503 if( p_another_vout == NULL )
506 val.b_bool = VLC_TRUE;
507 var_Set( p_playlist, "intf-show", val );
511 vlc_object_release( p_another_vout );
514 vlc_object_release( p_playlist );
517 /*****************************************************************************
518 * InitThread: initialize video output thread
519 *****************************************************************************
520 * This function is called from RunThread and performs the second step of the
521 * initialization. It returns 0 on success. Note that the thread's flag are not
522 * modified inside this function.
523 *****************************************************************************/
524 static int InitThread( vout_thread_t *p_vout )
526 int i, i_aspect_x, i_aspect_y;
528 vlc_mutex_lock( &p_vout->change_lock );
534 /* Initialize output method, it allocates direct buffers for us */
535 if( p_vout->pf_init( p_vout ) )
537 vlc_mutex_unlock( &p_vout->change_lock );
541 if( !I_OUTPUTPICTURES )
543 msg_Err( p_vout, "plugin was unable to allocate at least "
544 "one direct buffer" );
545 p_vout->pf_end( p_vout );
546 vlc_mutex_unlock( &p_vout->change_lock );
550 if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
552 msg_Err( p_vout, "plugin allocated too many direct buffers, "
553 "our internal buffers must have overflown." );
554 p_vout->pf_end( p_vout );
555 vlc_mutex_unlock( &p_vout->change_lock );
559 msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
561 AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
563 msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
564 "chroma %4.4s, ar %i:%i, sar %i:%i",
565 p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
566 p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
567 p_vout->fmt_render.i_visible_width,
568 p_vout->fmt_render.i_visible_height,
569 (char*)&p_vout->fmt_render.i_chroma,
570 i_aspect_x, i_aspect_y,
571 p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
573 AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
575 msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
576 "chroma %4.4s, ar %i:%i, sar %i:%i",
577 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
578 p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
579 p_vout->fmt_in.i_visible_width,
580 p_vout->fmt_in.i_visible_height,
581 (char*)&p_vout->fmt_in.i_chroma,
582 i_aspect_x, i_aspect_y,
583 p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
585 if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
587 p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
588 p_vout->output.i_width;
589 p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
590 p_vout->output.i_height;
591 p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
593 p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
594 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
596 if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
598 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
599 p_vout->fmt_out.i_height;
600 p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
601 p_vout->fmt_out.i_width;
604 vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
605 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
607 AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
609 msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
610 "chroma %4.4s, ar %i:%i, sar %i:%i",
611 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
612 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
613 p_vout->fmt_out.i_visible_width,
614 p_vout->fmt_out.i_visible_height,
615 (char*)&p_vout->fmt_out.i_chroma,
616 i_aspect_x, i_aspect_y,
617 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
619 /* Calculate shifts from system-updated masks */
620 MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
621 p_vout->output.i_rmask );
622 MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
623 p_vout->output.i_gmask );
624 MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
625 p_vout->output.i_bmask );
627 /* Check whether we managed to create direct buffers similar to
628 * the render buffers, ie same size and chroma */
629 if( ( p_vout->output.i_width == p_vout->render.i_width )
630 && ( p_vout->output.i_height == p_vout->render.i_height )
631 && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
633 /* Cool ! We have direct buffers, we can ask the decoder to
634 * directly decode into them ! Map the first render buffers to
635 * the first direct buffers, but keep the first direct buffer
636 * for memcpy operations */
637 p_vout->b_direct = 1;
639 for( i = 1; i < VOUT_MAX_PICTURES; i++ )
641 if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
642 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
643 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
645 /* We have enough direct buffers so there's no need to
646 * try to use system memory buffers. */
649 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
653 msg_Dbg( p_vout, "direct render, mapping "
654 "render pictures 0-%i to system pictures 1-%i",
655 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
659 /* Rats... Something is wrong here, we could not find an output
660 * plugin able to directly render what we decode. See if we can
661 * find a chroma plugin to do the conversion */
662 p_vout->b_direct = 0;
664 /* Choose the best module */
665 p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
667 if( p_vout->chroma.p_module == NULL )
669 msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
670 (char*)&p_vout->render.i_chroma,
671 (char*)&p_vout->output.i_chroma );
672 p_vout->pf_end( p_vout );
673 vlc_mutex_unlock( &p_vout->change_lock );
677 msg_Dbg( p_vout, "indirect render, mapping "
678 "render pictures 0-%i to system pictures %i-%i",
679 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
680 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
682 /* Append render buffers after the direct buffers */
683 for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
685 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
688 /* Check if we have enough render pictures */
689 if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
694 /* Link pictures back to their heap */
695 for( i = 0 ; i < I_RENDERPICTURES ; i++ )
697 PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
700 for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
702 PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
705 /* XXX XXX mark thread ready */
709 /*****************************************************************************
710 * RunThread: video output thread
711 *****************************************************************************
712 * Video output thread. This function does only returns when the thread is
713 * terminated. It handles the pictures arriving in the video heap and the
714 * display device events.
715 *****************************************************************************/
716 static void RunThread( vout_thread_t *p_vout)
718 int i_index; /* index in heap */
719 int i_idle_loops = 0; /* loops without displaying a picture */
720 mtime_t current_date; /* current date */
721 mtime_t display_date; /* display date */
723 picture_t * p_picture; /* picture pointer */
724 picture_t * p_last_picture = NULL; /* last picture */
725 picture_t * p_directbuffer; /* direct buffer to display */
727 subpicture_t * p_subpic = NULL; /* subpicture pointer */
729 input_thread_t *p_input = NULL ; /* Parent input, if it exists */
732 vlc_bool_t b_drop_late;
734 int i_displayed = 0, i_lost = 0, i_loops = 0;
739 p_vout->b_error = InitThread( p_vout );
741 var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
742 var_Get( p_vout, "drop-late-frames", &val );
743 b_drop_late = val.b_bool;
745 /* signal the creation of the vout */
746 vlc_thread_ready( p_vout );
748 if( p_vout->b_error )
750 /* Destroy thread structures allocated by Create and InitThread */
751 DestroyThread( p_vout );
756 * Main loop - it is not executed if an error occurred during
759 while( (!p_vout->b_die) && (!p_vout->b_error) )
761 /* Initialize loop variables */
764 current_date = mdate();
766 if( p_input && p_input->b_die )
768 vlc_object_release( p_input );
773 if( i_loops % 20 == 0 )
777 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
782 vlc_mutex_lock( &p_input->p->counters.counters_lock );
783 stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures,
785 stats_UpdateInteger( p_vout,
786 p_input->p->counters.p_displayed_pictures,
788 i_displayed = i_lost = 0;
789 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
794 if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
796 msg_Dbg( p_vout, "picture heap: %d/%d",
797 I_RENDERPICTURES, p_vout->i_heap_size );
802 * Find the picture to display (the one with the earliest date).
803 * This operation does not need lock, since only READY_PICTUREs
805 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
807 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
808 && ( (p_picture == NULL) ||
809 (PP_RENDERPICTURE[i_index]->date < display_date) ) )
811 p_picture = PP_RENDERPICTURE[i_index];
812 display_date = p_picture->date;
818 /* If we met the last picture, parse again to see whether there is
819 * a more appropriate one. */
820 if( p_picture == p_last_picture )
822 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
824 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
825 && (PP_RENDERPICTURE[i_index] != p_last_picture)
826 && ((p_picture == p_last_picture) ||
827 (PP_RENDERPICTURE[i_index]->date < display_date)) )
829 p_picture = PP_RENDERPICTURE[i_index];
830 display_date = p_picture->date;
835 /* If we found better than the last picture, destroy it */
836 if( p_last_picture && p_picture != p_last_picture )
838 vlc_mutex_lock( &p_vout->picture_lock );
839 if( p_last_picture->i_refcount )
841 p_last_picture->i_status = DISPLAYED_PICTURE;
845 p_last_picture->i_status = DESTROYED_PICTURE;
846 p_vout->i_heap_size--;
848 vlc_mutex_unlock( &p_vout->picture_lock );
849 p_last_picture = NULL;
852 /* Compute FPS rate */
853 p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
856 if( !p_picture->b_force &&
857 p_picture != p_last_picture &&
858 display_date < current_date + p_vout->render_time &&
861 /* Picture is late: it will be destroyed and the thread
862 * will directly choose the next picture */
863 vlc_mutex_lock( &p_vout->picture_lock );
864 if( p_picture->i_refcount )
866 /* Pretend we displayed the picture, but don't destroy
867 * it since the decoder might still need it. */
868 p_picture->i_status = DISPLAYED_PICTURE;
872 /* Destroy the picture without displaying it */
873 p_picture->i_status = DESTROYED_PICTURE;
874 p_vout->i_heap_size--;
876 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
877 current_date - display_date );
879 vlc_mutex_unlock( &p_vout->picture_lock );
885 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
887 /* Picture is waaay too early: it will be destroyed */
888 vlc_mutex_lock( &p_vout->picture_lock );
889 if( p_picture->i_refcount )
891 /* Pretend we displayed the picture, but don't destroy
892 * it since the decoder might still need it. */
893 p_picture->i_status = DISPLAYED_PICTURE;
897 /* Destroy the picture without displaying it */
898 p_picture->i_status = DESTROYED_PICTURE;
899 p_vout->i_heap_size--;
902 msg_Warn( p_vout, "vout warning: early picture skipped "
903 "("I64Fd")", display_date - current_date
904 - p_vout->i_pts_delay );
905 vlc_mutex_unlock( &p_vout->picture_lock );
910 if( display_date > current_date + VOUT_DISPLAY_DELAY )
912 /* A picture is ready to be rendered, but its rendering date
913 * is far from the current one so the thread will perform an
914 * empty loop as if no picture were found. The picture state
919 else if( p_picture == p_last_picture )
921 /* We are asked to repeat the previous picture, but we first
922 * wait for a couple of idle loops */
923 if( i_idle_loops < 4 )
930 /* We set the display date to something high, otherwise
931 * we'll have lots of problems with late pictures */
932 display_date = current_date + p_vout->render_time;
937 if( p_picture == NULL )
942 /* Video Filter2 stuff */
943 if( p_vout->b_vfilter_change == VLC_TRUE )
946 vlc_mutex_lock( &p_vout->vfilter_lock );
947 RemoveVideoFilters2( p_vout );
948 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
950 filter_t *p_vfilter =
951 p_vout->pp_vfilters[p_vout->i_vfilters] =
952 vlc_object_create( p_vout, VLC_OBJECT_FILTER );
954 vlc_object_attach( p_vfilter, p_vout );
956 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
957 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
959 if( !p_vout->i_vfilters )
961 p_vfilter->fmt_in.video = p_vout->fmt_render;
965 p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
967 /* TODO: one day filters in the middle of the chain might
968 * have a different fmt_out.video than fmt_render ... */
969 p_vfilter->fmt_out.video = p_vout->fmt_render;
971 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
972 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
973 p_vout->psz_vfilters[i], 0 );
975 if( p_vfilter->p_module )
978 malloc( sizeof( filter_owner_sys_t ) );
979 p_vfilter->p_owner->p_vout = p_vout;
980 p_vout->i_vfilters++;
981 msg_Dbg( p_vout, "video filter found (%s)",
982 p_vout->psz_vfilters[i] );
986 msg_Err( p_vout, "no video filter found (%s)",
987 p_vout->psz_vfilters[i] );
988 vlc_object_detach( p_vfilter );
989 vlc_object_destroy( p_vfilter );
992 p_vout->b_vfilter_change = VLC_FALSE;
993 vlc_mutex_unlock( &p_vout->vfilter_lock );
999 for( i = 0; i < p_vout->i_vfilters; i++ )
1001 picture_t *p_old = p_picture;
1002 p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
1003 p_vout->pp_vfilters[i], p_picture );
1008 /* FIXME: this is kind of wrong
1009 * if you have 2 or more vfilters and the 2nd breaks,
1010 * on the next loop the 1st one will be applied again */
1012 /* if p_old and p_picture are the same (ie the filter
1013 * worked on the old picture), then following code is
1014 * still alright since i_status gets changed back to
1015 * the right value */
1016 if( p_old->i_refcount )
1018 p_old->i_status = DISPLAYED_PICTURE;
1022 p_old->i_status = DESTROYED_PICTURE;
1024 p_picture->i_status = READY_PICTURE;
1028 if( p_picture && p_vout->b_snapshot )
1030 p_vout->b_snapshot = VLC_FALSE;
1031 vout_Snapshot( p_vout, p_picture );
1035 * Check for subpictures to display
1037 if( display_date > 0 )
1041 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1044 p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1045 p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1052 p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1055 * Call the plugin-specific rendering method if there is one
1057 if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1059 /* Render the direct buffer returned by vout_RenderPicture */
1060 p_vout->pf_render( p_vout, p_directbuffer );
1066 if( display_date != 0 && p_directbuffer != NULL )
1068 mtime_t current_render_time = mdate() - current_date;
1069 /* if render time is very large we don't include it in the mean */
1070 if( current_render_time < p_vout->render_time +
1071 VOUT_DISPLAY_DELAY )
1073 /* Store render time using a sliding mean weighting to
1074 * current value in a 3 to 1 ratio*/
1075 p_vout->render_time *= 3;
1076 p_vout->render_time += current_render_time;
1077 p_vout->render_time >>= 2;
1081 /* Give back change lock */
1082 vlc_mutex_unlock( &p_vout->change_lock );
1084 /* Sleep a while or until a given date */
1085 if( display_date != 0 )
1087 /* If there are filters in the chain, better give them the picture
1089 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1091 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1096 msleep( VOUT_IDLE_SLEEP );
1099 /* On awakening, take back lock and send immediately picture
1101 vlc_mutex_lock( &p_vout->change_lock );
1104 * Display the previously rendered picture
1106 if( p_picture != NULL && p_directbuffer != NULL )
1108 /* Display the direct buffer returned by vout_RenderPicture */
1109 if( p_vout->pf_display )
1111 p_vout->pf_display( p_vout, p_directbuffer );
1114 /* Tell the vout this was the last picture and that it does not
1115 * need to be forced anymore. */
1116 p_last_picture = p_picture;
1117 p_last_picture->b_force = 0;
1120 if( p_picture != NULL )
1122 /* Reinitialize idle loop count */
1127 * Check events and manage thread
1129 if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1131 /* A fatal error occurred, and the thread must terminate
1132 * immediately, without displaying anything - setting b_error to 1
1133 * causes the immediate end of the main while() loop. */
1134 p_vout->b_error = 1;
1137 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1139 /* this must only happen when the vout plugin is incapable of
1140 * rescaling the picture itself. In this case we need to destroy
1141 * the current picture buffers and recreate new ones with the right
1145 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1147 p_vout->pf_end( p_vout );
1148 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1149 p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1151 I_OUTPUTPICTURES = 0;
1152 if( p_vout->pf_init( p_vout ) )
1154 msg_Err( p_vout, "cannot resize display" );
1155 /* FIXME: pf_end will be called again in EndThread() */
1156 p_vout->b_error = 1;
1159 /* Need to reinitialise the chroma plugin */
1160 if( p_vout->chroma.p_module )
1162 if( p_vout->chroma.p_module->pf_deactivate )
1163 p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1164 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1168 if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1170 /* This happens when the picture buffers need to be recreated.
1171 * This is useful on multimonitor displays for instance.
1173 * Warning: This only works when the vout creates only 1 picture
1175 p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1177 if( !p_vout->b_direct )
1179 module_Unneed( p_vout, p_vout->chroma.p_module );
1182 vlc_mutex_lock( &p_vout->picture_lock );
1184 p_vout->pf_end( p_vout );
1186 I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1188 p_vout->b_error = InitThread( p_vout );
1190 vlc_mutex_unlock( &p_vout->picture_lock );
1196 vlc_object_release( p_input );
1200 * Error loop - wait until the thread destruction is requested
1202 if( p_vout->b_error )
1204 ErrorThread( p_vout );
1208 EndThread( p_vout );
1210 /* Destroy thread structures allocated by CreateThread */
1211 DestroyThread( p_vout );
1214 /*****************************************************************************
1215 * ErrorThread: RunThread() error loop
1216 *****************************************************************************
1217 * This function is called when an error occurred during thread main's loop.
1218 * The thread can still receive feed, but must be ready to terminate as soon
1220 *****************************************************************************/
1221 static void ErrorThread( vout_thread_t *p_vout )
1223 /* Wait until a `die' order */
1224 while( !p_vout->b_die )
1227 msleep( VOUT_IDLE_SLEEP );
1231 /*****************************************************************************
1232 * EndThread: thread destruction
1233 *****************************************************************************
1234 * This function is called when the thread ends after a sucessful
1235 * initialization. It frees all resources allocated by InitThread.
1236 *****************************************************************************/
1237 static void EndThread( vout_thread_t *p_vout )
1239 int i_index; /* index in heap */
1243 struct tms cpu_usage;
1244 times( &cpu_usage );
1246 msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1247 cpu_usage.tms_utime, cpu_usage.tms_stime );
1251 if( !p_vout->b_direct )
1253 module_Unneed( p_vout, p_vout->chroma.p_module );
1256 /* Destroy all remaining pictures */
1257 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1259 if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1261 free( p_vout->p_picture[i_index].p_data_orig );
1265 /* Destroy subpicture unit */
1266 spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1267 spu_Destroy( p_vout->p_spu );
1269 /* Destroy the video filters2 */
1270 RemoveVideoFilters2( p_vout );
1272 /* Destroy translation tables */
1273 p_vout->pf_end( p_vout );
1275 /* Release the change lock */
1276 vlc_mutex_unlock( &p_vout->change_lock );
1279 /*****************************************************************************
1280 * DestroyThread: thread destruction
1281 *****************************************************************************
1282 * This function is called when the thread ends. It frees all ressources
1283 * allocated by CreateThread. Status is available at this stage.
1284 *****************************************************************************/
1285 static void DestroyThread( vout_thread_t *p_vout )
1287 /* Destroy the locks */
1288 vlc_mutex_destroy( &p_vout->picture_lock );
1289 vlc_mutex_destroy( &p_vout->change_lock );
1290 vlc_mutex_destroy( &p_vout->vfilter_lock );
1292 /* Release the module */
1293 if( p_vout && p_vout->p_module )
1295 module_Unneed( p_vout, p_vout->p_module );
1299 /* following functions are local */
1301 static int ReduceHeight( int i_ratio )
1303 int i_dummy = VOUT_ASPECT_FACTOR;
1311 /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1312 while( !(i_ratio & 1) && !(i_dummy & 1) )
1319 while( !(i_ratio % 3) && !(i_dummy % 3) )
1326 while( !(i_ratio % 5) && !(i_dummy % 5) )
1336 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1338 unsigned int i_pgcd = ReduceHeight( i_aspect );
1339 *i_aspect_x = i_aspect / i_pgcd;
1340 *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1343 /*****************************************************************************
1344 * BinaryLog: computes the base 2 log of a binary value
1345 *****************************************************************************
1346 * This functions is used by MaskToShift, to get a bit index from a binary
1348 *****************************************************************************/
1349 static int BinaryLog( uint32_t i )
1353 if( i == 0 ) return -31337;
1355 if( i & 0xffff0000 ) i_log += 16;
1356 if( i & 0xff00ff00 ) i_log += 8;
1357 if( i & 0xf0f0f0f0 ) i_log += 4;
1358 if( i & 0xcccccccc ) i_log += 2;
1359 if( i & 0xaaaaaaaa ) i_log += 1;
1364 /*****************************************************************************
1365 * MaskToShift: transform a color mask into right and left shifts
1366 *****************************************************************************
1367 * This function is used for obtaining color shifts from masks.
1368 *****************************************************************************/
1369 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1371 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
1375 *pi_left = *pi_right = 0;
1380 i_low = i_high = i_mask;
1382 i_low &= - (int32_t)i_low; /* lower bit of the mask */
1383 i_high += i_low; /* higher bit of the mask */
1385 /* Transform bits into an index. Also deal with i_high overflow, which
1386 * is faster than changing the BinaryLog code to handle 64 bit integers. */
1387 i_low = BinaryLog (i_low);
1388 i_high = i_high ? BinaryLog (i_high) : 32;
1390 /* Update pointers and return */
1392 *pi_right = (8 - i_high + i_low);
1395 /*****************************************************************************
1396 * vout_VarCallback: generic callback for intf variables
1397 *****************************************************************************/
1398 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1399 vlc_value_t old_value, vlc_value_t new_value,
1402 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1404 val.b_bool = VLC_TRUE;
1405 var_Set( p_vout, "intf-change", val );
1409 /*****************************************************************************
1410 * Helper thread for object variables callbacks.
1411 * Only used to avoid deadlocks when using the video embedded mode.
1412 *****************************************************************************/
1413 typedef struct suxor_thread_t
1416 input_thread_t *p_input;
1420 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1424 vlc_thread_ready( p_this );
1426 /* Now restart current video stream */
1427 var_Get( p_this->p_input, "video-es", &val );
1428 if( val.i_int >= 0 )
1431 val_es.i_int = -VIDEO_ES;
1432 var_Set( p_this->p_input, "video-es", val_es );
1433 var_Set( p_this->p_input, "video-es", val );
1436 vlc_object_release( p_this->p_input );
1439 CloseHandle( p_this->thread_id );
1442 vlc_object_destroy( p_this );
1445 /*****************************************************************************
1446 * object variables callbacks: a bunch of object variables are used by the
1447 * interfaces to interact with the vout.
1448 *****************************************************************************/
1449 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1450 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1452 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1453 input_thread_t *p_input;
1456 char *psz_mode = newval.psz_string;
1457 char *psz_filter, *psz_deinterlace = NULL;
1459 var_Get( p_vout, "vout-filter", &val );
1460 psz_filter = val.psz_string;
1461 if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1463 if( !psz_mode || !*psz_mode )
1465 if( psz_deinterlace )
1467 char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1468 if( psz_src[0] == ':' ) psz_src++;
1469 memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1472 else if( !psz_deinterlace )
1474 psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1475 sizeof(":deinterlace") );
1476 if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1477 strcat( psz_filter, "deinterlace" );
1480 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1482 if( !p_input ) return VLC_EGENERIC;
1484 if( psz_mode && *psz_mode )
1486 /* Modify input as well because the vout might have to be restarted */
1487 val.psz_string = psz_mode;
1488 var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1489 var_Set( p_input, "deinterlace-mode", val );
1491 vlc_object_release( p_input );
1493 val.b_bool = VLC_TRUE;
1494 var_Set( p_vout, "intf-change", val );
1496 val.psz_string = psz_filter;
1497 var_Set( p_vout, "vout-filter", val );
1498 if( psz_filter ) free( psz_filter );
1503 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1504 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1506 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1507 input_thread_t *p_input;
1510 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1514 msg_Err( p_vout, "Input not found" );
1515 return( VLC_EGENERIC );
1518 val.b_bool = VLC_TRUE;
1519 var_Set( p_vout, "intf-change", val );
1521 /* Modify input as well because the vout might have to be restarted */
1522 val.psz_string = newval.psz_string;
1523 var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1525 var_Set( p_input, "vout-filter", val );
1527 /* Now restart current video stream */
1528 var_Get( p_input, "video-es", &val );
1529 if( val.i_int >= 0 )
1531 suxor_thread_t *p_suxor =
1532 vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1533 p_suxor->p_input = p_input;
1534 p_vout->b_filter_change = VLC_TRUE;
1535 vlc_object_yield( p_input );
1536 vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1537 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1540 vlc_object_release( p_input );
1545 /*****************************************************************************
1546 * Video Filter2 stuff
1547 *****************************************************************************/
1548 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1551 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1553 struct config_chain_t *p_cfg =
1554 p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1555 config_ChainDestroy( p_cfg );
1556 if( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] )
1558 free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1559 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
1562 p_vout->i_vfilters_cfg = 0;
1563 if( psz_vfilters && *psz_vfilters )
1565 char *psz_parser = psz_vfilters;
1567 while( psz_parser && *psz_parser )
1569 psz_parser = config_ChainCreate(
1570 &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1571 &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1573 msg_Dbg( p_vout, "adding vfilter: %s",
1574 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1575 p_vout->i_vfilters_cfg++;
1576 if( psz_parser && *psz_parser )
1578 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1581 "maximum number of video filters reached. \"%s\" discarded",
1591 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1592 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1594 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1596 vlc_mutex_lock( &p_vout->vfilter_lock );
1597 ParseVideoFilter2Chain( p_vout, newval.psz_string );
1598 p_vout->b_vfilter_change = VLC_TRUE;
1599 vlc_mutex_unlock( &p_vout->vfilter_lock );
1604 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1607 for( i = 0; i < p_vout->i_vfilters; i++ )
1609 vlc_object_detach( p_vout->pp_vfilters[i] );
1610 if( p_vout->pp_vfilters[i]->p_module )
1612 module_Unneed( p_vout->pp_vfilters[i],
1613 p_vout->pp_vfilters[i]->p_module );
1616 free( p_vout->pp_vfilters[i]->p_owner );
1617 vlc_object_destroy( p_vout->pp_vfilters[i] );
1619 p_vout->i_vfilters = 0;