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>
42 #include "vlc_video.h"
43 #include "video_output.h"
45 #include <vlc/input.h> /* for input_thread_t and i_pts_delay */
46 #include "vlc_playlist.h"
48 #include "vlc_filter.h"
50 #if defined( __APPLE__ )
51 #include "darwin_specific.h"
54 /*****************************************************************************
56 *****************************************************************************/
57 static int InitThread ( vout_thread_t * );
58 static void RunThread ( vout_thread_t * );
59 static void ErrorThread ( vout_thread_t * );
60 static void EndThread ( vout_thread_t * );
61 static void DestroyThread ( vout_thread_t * );
63 static void AspectRatio ( int, int *, int * );
64 static int BinaryLog ( uint32_t );
65 static void MaskToShift ( int *, int *, uint32_t );
67 /* Object variables callbacks */
68 static int DeinterlaceCallback( vlc_object_t *, char const *,
69 vlc_value_t, vlc_value_t, void * );
70 static int FilterCallback( vlc_object_t *, char const *,
71 vlc_value_t, vlc_value_t, void * );
72 static int VideoFilter2Callback( vlc_object_t *, char const *,
73 vlc_value_t, vlc_value_t, void * );
75 /* From vout_intf.c */
76 int vout_Snapshot( vout_thread_t *, picture_t * );
78 /* Video filter2 parsing */
79 static int ParseVideoFilter2Chain( vout_thread_t *, char * );
80 static void RemoveVideoFilters2( vout_thread_t *p_vout );
82 /*****************************************************************************
83 * Video Filter2 functions
84 *****************************************************************************/
85 struct filter_owner_sys_t
87 vout_thread_t *p_vout;
90 static picture_t *video_new_buffer_filter( filter_t *p_filter )
93 vout_thread_t *p_vout = p_filter->p_owner->p_vout;
95 p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
100 static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
102 vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
105 /*****************************************************************************
106 * vout_Request: find a video output thread, create one, or destroy one.
107 *****************************************************************************
108 * This function looks for a video output thread matching the current
109 * properties. If not found, it spawns a new one.
110 *****************************************************************************/
111 vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout,
112 video_format_t *p_fmt )
116 /* Reattach video output to playlist before bailing out */
119 playlist_t *p_playlist = pl_Yield( p_this );
120 spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
121 vlc_object_detach( p_vout );
122 vlc_object_attach( p_vout, p_playlist );
123 pl_Release( p_this );
128 /* If a video output was provided, lock it, otherwise look for one. */
131 vlc_object_yield( p_vout );
135 p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );
139 playlist_t *p_playlist = pl_Yield( p_this );
140 vlc_mutex_lock( &p_playlist->gc_lock );
141 p_vout = vlc_object_find( p_playlist,
142 VLC_OBJECT_VOUT, FIND_CHILD );
143 /* only first children of p_input for unused vout */
144 if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist )
146 vlc_object_release( p_vout );
149 vlc_mutex_unlock( &p_playlist->gc_lock );
150 pl_Release( p_this );
154 /* If we now have a video output, check it has the right properties */
157 char *psz_filter_chain;
160 /* We don't directly check for the "vout-filter" variable for obvious
161 * performance reasons. */
162 if( p_vout->b_filter_change )
164 var_Get( p_vout, "vout-filter", &val );
165 psz_filter_chain = val.psz_string;
167 if( psz_filter_chain && !*psz_filter_chain )
169 free( psz_filter_chain );
170 psz_filter_chain = NULL;
172 if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
174 free( p_vout->psz_filter_chain );
175 p_vout->psz_filter_chain = NULL;
178 if( !psz_filter_chain && !p_vout->psz_filter_chain )
180 p_vout->b_filter_change = VLC_FALSE;
183 if( psz_filter_chain ) free( psz_filter_chain );
186 if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
187 ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
188 ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
189 ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
190 p_vout->b_filter_change )
192 /* We are not interested in this format, close this vout */
193 vlc_object_detach( p_vout );
194 vlc_object_release( p_vout );
195 vout_Destroy( p_vout );
200 /* This video output is cool! Hijack it. */
201 vlc_object_detach( p_vout );
202 spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
203 vlc_object_attach( p_vout, p_this );
204 vlc_object_release( p_vout );
210 msg_Dbg( p_this, "no usable vout present, spawning one" );
212 p_vout = vout_Create( p_this, p_fmt );
218 /*****************************************************************************
219 * vout_Create: creates a new video output thread
220 *****************************************************************************
221 * This function creates a new video output thread, and returns a pointer
222 * to its description. On error, it returns NULL.
223 *****************************************************************************/
224 vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
226 vout_thread_t * p_vout; /* thread descriptor */
227 input_thread_t * p_input_thread;
228 int i_index; /* loop variable */
230 vlc_value_t val, text;
232 unsigned int i_width = p_fmt->i_width;
233 unsigned int i_height = p_fmt->i_height;
234 vlc_fourcc_t i_chroma = p_fmt->i_chroma;
235 unsigned int i_aspect = p_fmt->i_aspect;
237 /* Allocate descriptor */
238 p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
241 msg_Err( p_parent, "out of memory" );
245 /* Initialize pictures - translation tables and functions
246 * will be initialized later in InitThread */
247 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
249 p_vout->p_picture[i_index].pf_lock = NULL;
250 p_vout->p_picture[i_index].pf_unlock = NULL;
251 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
252 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
253 p_vout->p_picture[i_index].b_slow = 0;
256 /* No images in the heap */
257 p_vout->i_heap_size = 0;
259 /* Initialize the rendering heap */
260 I_RENDERPICTURES = 0;
262 vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
263 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
264 p_vout->fmt_render = *p_fmt; /* FIXME palette */
265 p_vout->fmt_in = *p_fmt; /* FIXME palette */
267 p_vout->render.i_width = i_width;
268 p_vout->render.i_height = i_height;
269 p_vout->render.i_chroma = i_chroma;
270 p_vout->render.i_aspect = i_aspect;
272 p_vout->render.i_rmask = 0;
273 p_vout->render.i_gmask = 0;
274 p_vout->render.i_bmask = 0;
276 p_vout->render.i_last_used_pic = -1;
277 p_vout->render.b_allow_modify_pics = 1;
279 /* Zero the output heap */
280 I_OUTPUTPICTURES = 0;
281 p_vout->output.i_width = 0;
282 p_vout->output.i_height = 0;
283 p_vout->output.i_chroma = 0;
284 p_vout->output.i_aspect = 0;
286 p_vout->output.i_rmask = 0;
287 p_vout->output.i_gmask = 0;
288 p_vout->output.i_bmask = 0;
290 /* Initialize misc stuff */
291 p_vout->i_changes = 0;
293 p_vout->b_grayscale = 0;
295 p_vout->b_interface = 0;
297 p_vout->b_fullscreen = 0;
298 p_vout->i_alignment = 0;
299 p_vout->render_time = 10;
300 p_vout->c_fps_samples = 0;
301 p_vout->b_filter_change = 0;
302 p_vout->pf_control = 0;
303 p_vout->p_parent_intf = 0;
304 p_vout->i_par_num = p_vout->i_par_den = 1;
306 /* Initialize locks */
307 vlc_mutex_init( p_vout, &p_vout->picture_lock );
308 vlc_mutex_init( p_vout, &p_vout->change_lock );
310 /* Mouse coordinates */
311 var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
312 var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
313 var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
314 var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
315 var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
317 /* Initialize subpicture unit */
318 p_vout->p_spu = spu_Create( p_vout );
319 spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
321 /* Attach the new object now so we can use var inheritance below */
322 vlc_object_attach( p_vout, p_parent );
324 spu_Init( p_vout->p_spu );
326 /* Take care of some "interface/control" related initialisations */
327 vout_IntfInit( p_vout );
329 /* If the parent is not a VOUT object, that means we are at the start of
330 * the video output pipe */
331 if( p_parent->i_object_type != VLC_OBJECT_VOUT )
333 /* Look for the default filter configuration */
334 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
335 var_Get( p_vout, "vout-filter", &val );
336 p_vout->psz_filter_chain = val.psz_string;
338 /* Apply video filter2 objects on the first vout */
339 var_Create( p_vout, "video-filter",
340 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
341 var_Get( p_vout, "video-filter", &val );
342 ParseVideoFilter2Chain( p_vout, val.psz_string );
343 free( val.psz_string );
347 /* continue the parent's filter chain */
350 psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ':' );
351 if( psz_end && *(psz_end+1) )
352 p_vout->psz_filter_chain = strdup( psz_end+1 );
353 else p_vout->psz_filter_chain = NULL;
355 /* Create a video filter2 var ... but don't inherit values */
356 var_Create( p_vout, "video-filter", VLC_VAR_STRING );
357 ParseVideoFilter2Chain( p_vout, NULL );
360 var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
361 p_vout->b_vfilter_change = VLC_TRUE;
362 p_vout->i_vfilters = 0;
364 /* Choose the video output module */
365 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
367 var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
368 var_Get( p_vout, "vout", &val );
369 psz_plugin = val.psz_string;
373 /* the filter chain is a string list of filters separated by double
377 psz_end = strchr( p_vout->psz_filter_chain, ':' );
379 psz_plugin = strndup( p_vout->psz_filter_chain,
380 psz_end - p_vout->psz_filter_chain );
381 else psz_plugin = strdup( p_vout->psz_filter_chain );
384 /* Create the vout thread */
385 p_vout->p_module = module_Need( p_vout,
386 ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
387 "video filter" : "video output", psz_plugin, 0 );
389 if( psz_plugin ) free( psz_plugin );
390 if( p_vout->p_module == NULL )
392 msg_Err( p_vout, "no suitable vout module" );
393 vlc_object_detach( p_vout );
394 vlc_object_destroy( p_vout );
398 /* Create a few object variables for interface interaction */
399 var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
400 text.psz_string = _("Deinterlace");
401 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
402 val.psz_string = ""; text.psz_string = _("Disable");
403 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
404 val.psz_string = "discard"; text.psz_string = _("Discard");
405 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
406 val.psz_string = "blend"; text.psz_string = _("Blend");
407 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
408 val.psz_string = "mean"; text.psz_string = _("Mean");
409 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
410 val.psz_string = "bob"; text.psz_string = _("Bob");
411 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
412 val.psz_string = "linear"; text.psz_string = _("Linear");
413 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
414 val.psz_string = "x"; text.psz_string = "X";
415 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
417 if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
419 var_Set( p_vout, "deinterlace", val );
420 if( val.psz_string ) free( val.psz_string );
422 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
425 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
426 text.psz_string = _("Filters");
427 var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
428 var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
430 /* Calculate delay created by internal caching */
431 p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
432 VLC_OBJECT_INPUT, FIND_ANYWHERE );
435 p_vout->i_pts_delay = p_input_thread->i_pts_delay;
436 vlc_object_release( p_input_thread );
440 p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
443 if( vlc_thread_create( p_vout, "video output", RunThread,
444 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
446 msg_Err( p_vout, "out of memory" );
447 module_Unneed( p_vout, p_vout->p_module );
448 vlc_object_detach( p_vout );
449 vlc_object_destroy( p_vout );
453 if( p_vout->b_error )
455 msg_Err( p_vout, "video output creation failed" );
457 /* Make sure the thread is destroyed */
458 p_vout->b_die = VLC_TRUE;
460 vlc_thread_join( p_vout );
462 vlc_object_detach( p_vout );
463 vlc_object_destroy( p_vout );
470 /*****************************************************************************
471 * vout_Destroy: destroys a previously created video output
472 *****************************************************************************
473 * Destroy a terminated thread.
474 * The function will request a destruction of the specified thread. If pi_error
475 * is NULL, it will return once the thread is destroyed. Else, it will be
476 * update using one of the THREAD_* constants.
477 *****************************************************************************/
478 void vout_Destroy( vout_thread_t *p_vout )
480 vout_thread_t *p_another_vout;
481 playlist_t *p_playlist = pl_Yield( p_vout );
483 /* Request thread destruction */
484 p_vout->b_die = VLC_TRUE;
485 vlc_thread_join( p_vout );
487 var_Destroy( p_vout, "intf-change" );
489 if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
492 vlc_object_destroy( p_vout );
494 /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
495 back if you closed it while playing video. This is solved in Mac OS X,
496 where we have this novelty called menubar, that will always allow you access
497 to the applications main functionality. They should try that on linux sometime */
498 p_another_vout = vlc_object_find( p_playlist,
499 VLC_OBJECT_VOUT, FIND_ANYWHERE );
500 if( p_another_vout == NULL )
503 val.b_bool = VLC_TRUE;
504 var_Set( p_playlist, "intf-show", val );
508 vlc_object_release( p_another_vout );
511 vlc_object_release( p_playlist );
514 /*****************************************************************************
515 * InitThread: initialize video output thread
516 *****************************************************************************
517 * This function is called from RunThread and performs the second step of the
518 * initialization. It returns 0 on success. Note that the thread's flag are not
519 * modified inside this function.
520 *****************************************************************************/
521 static int InitThread( vout_thread_t *p_vout )
523 int i, i_aspect_x, i_aspect_y;
525 vlc_mutex_lock( &p_vout->change_lock );
531 /* Initialize output method, it allocates direct buffers for us */
532 if( p_vout->pf_init( p_vout ) )
534 vlc_mutex_unlock( &p_vout->change_lock );
538 if( !I_OUTPUTPICTURES )
540 msg_Err( p_vout, "plugin was unable to allocate at least "
541 "one direct buffer" );
542 p_vout->pf_end( p_vout );
543 vlc_mutex_unlock( &p_vout->change_lock );
547 if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
549 msg_Err( p_vout, "plugin allocated too many direct buffers, "
550 "our internal buffers must have overflown." );
551 p_vout->pf_end( p_vout );
552 vlc_mutex_unlock( &p_vout->change_lock );
556 msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
558 AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
560 msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
561 "chroma %4.4s, ar %i:%i, sar %i:%i",
562 p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
563 p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
564 p_vout->fmt_render.i_visible_width,
565 p_vout->fmt_render.i_visible_height,
566 (char*)&p_vout->fmt_render.i_chroma,
567 i_aspect_x, i_aspect_y,
568 p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
570 AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
572 msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
573 "chroma %4.4s, ar %i:%i, sar %i:%i",
574 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
575 p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
576 p_vout->fmt_in.i_visible_width,
577 p_vout->fmt_in.i_visible_height,
578 (char*)&p_vout->fmt_in.i_chroma,
579 i_aspect_x, i_aspect_y,
580 p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
582 if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
584 p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
585 p_vout->output.i_width;
586 p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
587 p_vout->output.i_height;
588 p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
590 p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
591 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
593 if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
595 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
596 p_vout->fmt_out.i_height;
597 p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
598 p_vout->fmt_out.i_width;
601 vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
602 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
604 AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
606 msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
607 "chroma %4.4s, ar %i:%i, sar %i:%i",
608 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
609 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
610 p_vout->fmt_out.i_visible_width,
611 p_vout->fmt_out.i_visible_height,
612 (char*)&p_vout->fmt_out.i_chroma,
613 i_aspect_x, i_aspect_y,
614 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
616 /* Calculate shifts from system-updated masks */
617 MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
618 p_vout->output.i_rmask );
619 MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
620 p_vout->output.i_gmask );
621 MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
622 p_vout->output.i_bmask );
624 /* Check whether we managed to create direct buffers similar to
625 * the render buffers, ie same size and chroma */
626 if( ( p_vout->output.i_width == p_vout->render.i_width )
627 && ( p_vout->output.i_height == p_vout->render.i_height )
628 && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
630 /* Cool ! We have direct buffers, we can ask the decoder to
631 * directly decode into them ! Map the first render buffers to
632 * the first direct buffers, but keep the first direct buffer
633 * for memcpy operations */
634 p_vout->b_direct = 1;
636 for( i = 1; i < VOUT_MAX_PICTURES; i++ )
638 if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
639 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
640 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
642 /* We have enough direct buffers so there's no need to
643 * try to use system memory buffers. */
646 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
650 msg_Dbg( p_vout, "direct render, mapping "
651 "render pictures 0-%i to system pictures 1-%i",
652 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
656 /* Rats... Something is wrong here, we could not find an output
657 * plugin able to directly render what we decode. See if we can
658 * find a chroma plugin to do the conversion */
659 p_vout->b_direct = 0;
661 /* Choose the best module */
662 p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
664 if( p_vout->chroma.p_module == NULL )
666 msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
667 (char*)&p_vout->render.i_chroma,
668 (char*)&p_vout->output.i_chroma );
669 p_vout->pf_end( p_vout );
670 vlc_mutex_unlock( &p_vout->change_lock );
674 msg_Dbg( p_vout, "indirect render, mapping "
675 "render pictures 0-%i to system pictures %i-%i",
676 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
677 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
679 /* Append render buffers after the direct buffers */
680 for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
682 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
685 /* Check if we have enough render pictures */
686 if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
691 /* Link pictures back to their heap */
692 for( i = 0 ; i < I_RENDERPICTURES ; i++ )
694 PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
697 for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
699 PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
702 /* XXX XXX mark thread ready */
706 /*****************************************************************************
707 * RunThread: video output thread
708 *****************************************************************************
709 * Video output thread. This function does only returns when the thread is
710 * terminated. It handles the pictures arriving in the video heap and the
711 * display device events.
712 *****************************************************************************/
713 static void RunThread( vout_thread_t *p_vout)
715 int i_index; /* index in heap */
716 int i_idle_loops = 0; /* loops without displaying a picture */
717 mtime_t current_date; /* current date */
718 mtime_t display_date; /* display date */
720 picture_t * p_picture; /* picture pointer */
721 picture_t * p_last_picture = NULL; /* last picture */
722 picture_t * p_directbuffer; /* direct buffer to display */
724 subpicture_t * p_subpic = NULL; /* subpicture pointer */
726 input_thread_t *p_input = NULL ; /* Parent input, if it exists */
729 vlc_bool_t b_drop_late;
731 int i_displayed = 0, i_lost = 0, i_loops = 0;
736 p_vout->b_error = InitThread( p_vout );
738 var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
739 var_Get( p_vout, "drop-late-frames", &val );
740 b_drop_late = val.b_bool;
742 /* signal the creation of the vout */
743 vlc_thread_ready( p_vout );
745 if( p_vout->b_error )
747 /* Destroy thread structures allocated by Create and InitThread */
748 DestroyThread( p_vout );
753 * Main loop - it is not executed if an error occurred during
756 while( (!p_vout->b_die) && (!p_vout->b_error) )
758 /* Initialize loop variables */
761 current_date = mdate();
763 if( p_input && p_input->b_die )
765 vlc_object_release( p_input );
770 if( i_loops % 20 == 0 )
774 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
779 vlc_mutex_lock( &p_input->counters.counters_lock );
780 stats_UpdateInteger( p_vout, p_input->counters.p_lost_pictures,
782 stats_UpdateInteger( p_vout,
783 p_input->counters.p_displayed_pictures,
785 i_displayed = i_lost = 0;
786 vlc_mutex_unlock( &p_input->counters.counters_lock );
791 if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
793 msg_Dbg( p_vout, "picture heap: %d/%d",
794 I_RENDERPICTURES, p_vout->i_heap_size );
799 * Find the picture to display (the one with the earliest date).
800 * This operation does not need lock, since only READY_PICTUREs
802 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
804 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
805 && ( (p_picture == NULL) ||
806 (PP_RENDERPICTURE[i_index]->date < display_date) ) )
808 p_picture = PP_RENDERPICTURE[i_index];
809 display_date = p_picture->date;
815 /* If we met the last picture, parse again to see whether there is
816 * a more appropriate one. */
817 if( p_picture == p_last_picture )
819 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
821 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
822 && (PP_RENDERPICTURE[i_index] != p_last_picture)
823 && ((p_picture == p_last_picture) ||
824 (PP_RENDERPICTURE[i_index]->date < display_date)) )
826 p_picture = PP_RENDERPICTURE[i_index];
827 display_date = p_picture->date;
832 /* If we found better than the last picture, destroy it */
833 if( p_last_picture && p_picture != p_last_picture )
835 vlc_mutex_lock( &p_vout->picture_lock );
836 if( p_last_picture->i_refcount )
838 p_last_picture->i_status = DISPLAYED_PICTURE;
842 p_last_picture->i_status = DESTROYED_PICTURE;
843 p_vout->i_heap_size--;
845 vlc_mutex_unlock( &p_vout->picture_lock );
846 p_last_picture = NULL;
849 /* Compute FPS rate */
850 p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
853 if( !p_picture->b_force &&
854 p_picture != p_last_picture &&
855 display_date < current_date + p_vout->render_time &&
858 /* Picture is late: it will be destroyed and the thread
859 * will directly choose the next picture */
860 vlc_mutex_lock( &p_vout->picture_lock );
861 if( p_picture->i_refcount )
863 /* Pretend we displayed the picture, but don't destroy
864 * it since the decoder might still need it. */
865 p_picture->i_status = DISPLAYED_PICTURE;
869 /* Destroy the picture without displaying it */
870 p_picture->i_status = DESTROYED_PICTURE;
871 p_vout->i_heap_size--;
873 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
874 current_date - display_date );
876 vlc_mutex_unlock( &p_vout->picture_lock );
882 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
884 /* Picture is waaay too early: it will be destroyed */
885 vlc_mutex_lock( &p_vout->picture_lock );
886 if( p_picture->i_refcount )
888 /* Pretend we displayed the picture, but don't destroy
889 * it since the decoder might still need it. */
890 p_picture->i_status = DISPLAYED_PICTURE;
894 /* Destroy the picture without displaying it */
895 p_picture->i_status = DESTROYED_PICTURE;
896 p_vout->i_heap_size--;
899 msg_Warn( p_vout, "vout warning: early picture skipped "
900 "("I64Fd")", display_date - current_date
901 - p_vout->i_pts_delay );
902 vlc_mutex_unlock( &p_vout->picture_lock );
907 if( display_date > current_date + VOUT_DISPLAY_DELAY )
909 /* A picture is ready to be rendered, but its rendering date
910 * is far from the current one so the thread will perform an
911 * empty loop as if no picture were found. The picture state
916 else if( p_picture == p_last_picture )
918 /* We are asked to repeat the previous picture, but we first
919 * wait for a couple of idle loops */
920 if( i_idle_loops < 4 )
927 /* We set the display date to something high, otherwise
928 * we'll have lots of problems with late pictures */
929 display_date = current_date + p_vout->render_time;
934 if( p_picture == NULL )
939 /* Video Filter2 stuff */
940 if( p_vout->b_vfilter_change == VLC_TRUE )
943 RemoveVideoFilters2( p_vout );
944 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
946 filter_t *p_vfilter =
947 p_vout->pp_vfilters[p_vout->i_vfilters] =
948 vlc_object_create( p_vout, VLC_OBJECT_FILTER );
950 vlc_object_attach( p_vfilter, p_vout );
952 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
953 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
955 if( !p_vout->i_vfilters )
957 p_vfilter->fmt_in.video = p_vout->fmt_render;
961 p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
963 /* TODO: one day filters in the middle of the chain might
964 * have a different fmt_out.video than fmt_render ... */
965 p_vfilter->fmt_out.video = p_vout->fmt_render;
967 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
968 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
969 p_vout->psz_vfilters[i], 0 );
971 if( p_vfilter->p_module )
974 malloc( sizeof( filter_owner_sys_t ) );
975 p_vfilter->p_owner->p_vout = p_vout;
976 p_vout->i_vfilters++;
977 msg_Dbg( p_vout, "video filter found (%s)",
978 p_vout->psz_vfilters[i] );
982 msg_Err( p_vout, "no video filter found (%s)",
983 p_vout->psz_vfilters[i] );
984 vlc_object_detach( p_vfilter );
985 vlc_object_destroy( p_vfilter );
988 p_vout->b_vfilter_change = VLC_FALSE;
994 for( i = 0; i < p_vout->i_vfilters; i++ )
996 picture_t *p_old = p_picture;
997 p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
998 p_vout->pp_vfilters[i], p_picture );
1003 /* FIXME: this is kind of wrong
1004 * if you have 2 or more vfilters and the 2nd breaks,
1005 * on the next loop the 1st one will be applied again */
1007 /* if p_old and p_picture are the same (ie the filter
1008 * worked on the old picture), then following code is
1009 * still alright since i_status gets changed back to
1010 * the right value */
1011 if( p_old->i_refcount )
1013 p_old->i_status = DISPLAYED_PICTURE;
1017 p_old->i_status = DESTROYED_PICTURE;
1019 p_picture->i_status = READY_PICTURE;
1023 if( p_picture && p_vout->b_snapshot )
1025 p_vout->b_snapshot = VLC_FALSE;
1026 vout_Snapshot( p_vout, p_picture );
1030 * Check for subpictures to display
1032 if( display_date > 0 )
1036 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1039 p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1040 p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1047 p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1050 * Call the plugin-specific rendering method if there is one
1052 if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1054 /* Render the direct buffer returned by vout_RenderPicture */
1055 p_vout->pf_render( p_vout, p_directbuffer );
1061 if( display_date != 0 && p_directbuffer != NULL )
1063 mtime_t current_render_time = mdate() - current_date;
1064 /* if render time is very large we don't include it in the mean */
1065 if( current_render_time < p_vout->render_time +
1066 VOUT_DISPLAY_DELAY )
1068 /* Store render time using a sliding mean weighting to
1069 * current value in a 3 to 1 ratio*/
1070 p_vout->render_time *= 3;
1071 p_vout->render_time += current_render_time;
1072 p_vout->render_time >>= 2;
1076 /* Give back change lock */
1077 vlc_mutex_unlock( &p_vout->change_lock );
1079 /* Sleep a while or until a given date */
1080 if( display_date != 0 )
1082 /* If there are filters in the chain, better give them the picture
1084 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1086 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1091 msleep( VOUT_IDLE_SLEEP );
1094 /* On awakening, take back lock and send immediately picture
1096 vlc_mutex_lock( &p_vout->change_lock );
1099 * Display the previously rendered picture
1101 if( p_picture != NULL && p_directbuffer != NULL )
1103 /* Display the direct buffer returned by vout_RenderPicture */
1104 if( p_vout->pf_display )
1106 p_vout->pf_display( p_vout, p_directbuffer );
1109 /* Tell the vout this was the last picture and that it does not
1110 * need to be forced anymore. */
1111 p_last_picture = p_picture;
1112 p_last_picture->b_force = 0;
1115 if( p_picture != NULL )
1117 /* Reinitialize idle loop count */
1122 * Check events and manage thread
1124 if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1126 /* A fatal error occurred, and the thread must terminate
1127 * immediately, without displaying anything - setting b_error to 1
1128 * causes the immediate end of the main while() loop. */
1129 p_vout->b_error = 1;
1132 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1134 /* this must only happen when the vout plugin is incapable of
1135 * rescaling the picture itself. In this case we need to destroy
1136 * the current picture buffers and recreate new ones with the right
1140 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1142 p_vout->pf_end( p_vout );
1143 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1144 p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1146 I_OUTPUTPICTURES = 0;
1147 if( p_vout->pf_init( p_vout ) )
1149 msg_Err( p_vout, "cannot resize display" );
1150 /* FIXME: pf_end will be called again in EndThread() */
1151 p_vout->b_error = 1;
1154 /* Need to reinitialise the chroma plugin */
1155 if( p_vout->chroma.p_module )
1157 if( p_vout->chroma.p_module->pf_deactivate )
1158 p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1159 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1163 if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1165 /* This happens when the picture buffers need to be recreated.
1166 * This is useful on multimonitor displays for instance.
1168 * Warning: This only works when the vout creates only 1 picture
1170 p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1172 if( !p_vout->b_direct )
1174 module_Unneed( p_vout, p_vout->chroma.p_module );
1177 vlc_mutex_lock( &p_vout->picture_lock );
1179 p_vout->pf_end( p_vout );
1181 I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1183 p_vout->b_error = InitThread( p_vout );
1185 vlc_mutex_unlock( &p_vout->picture_lock );
1191 vlc_object_release( p_input );
1195 * Error loop - wait until the thread destruction is requested
1197 if( p_vout->b_error )
1199 ErrorThread( p_vout );
1203 EndThread( p_vout );
1205 /* Destroy thread structures allocated by CreateThread */
1206 DestroyThread( p_vout );
1209 /*****************************************************************************
1210 * ErrorThread: RunThread() error loop
1211 *****************************************************************************
1212 * This function is called when an error occurred during thread main's loop.
1213 * The thread can still receive feed, but must be ready to terminate as soon
1215 *****************************************************************************/
1216 static void ErrorThread( vout_thread_t *p_vout )
1218 /* Wait until a `die' order */
1219 while( !p_vout->b_die )
1222 msleep( VOUT_IDLE_SLEEP );
1226 /*****************************************************************************
1227 * EndThread: thread destruction
1228 *****************************************************************************
1229 * This function is called when the thread ends after a sucessful
1230 * initialization. It frees all resources allocated by InitThread.
1231 *****************************************************************************/
1232 static void EndThread( vout_thread_t *p_vout )
1234 int i_index; /* index in heap */
1238 struct tms cpu_usage;
1239 times( &cpu_usage );
1241 msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1242 cpu_usage.tms_utime, cpu_usage.tms_stime );
1246 if( !p_vout->b_direct )
1248 module_Unneed( p_vout, p_vout->chroma.p_module );
1251 /* Destroy all remaining pictures */
1252 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1254 if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1256 free( p_vout->p_picture[i_index].p_data_orig );
1260 /* Destroy subpicture unit */
1261 spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1262 spu_Destroy( p_vout->p_spu );
1264 /* Destroy the video filters2 */
1265 RemoveVideoFilters2( p_vout );
1267 /* Destroy translation tables */
1268 p_vout->pf_end( p_vout );
1270 /* Release the change lock */
1271 vlc_mutex_unlock( &p_vout->change_lock );
1274 /*****************************************************************************
1275 * DestroyThread: thread destruction
1276 *****************************************************************************
1277 * This function is called when the thread ends. It frees all ressources
1278 * allocated by CreateThread. Status is available at this stage.
1279 *****************************************************************************/
1280 static void DestroyThread( vout_thread_t *p_vout )
1282 /* Destroy the locks */
1283 vlc_mutex_destroy( &p_vout->picture_lock );
1284 vlc_mutex_destroy( &p_vout->change_lock );
1286 /* Release the module */
1287 if( p_vout && p_vout->p_module )
1289 module_Unneed( p_vout, p_vout->p_module );
1293 /* following functions are local */
1295 static int ReduceHeight( int i_ratio )
1297 int i_dummy = VOUT_ASPECT_FACTOR;
1305 /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1306 while( !(i_ratio & 1) && !(i_dummy & 1) )
1313 while( !(i_ratio % 3) && !(i_dummy % 3) )
1320 while( !(i_ratio % 5) && !(i_dummy % 5) )
1330 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1332 unsigned int i_pgcd = ReduceHeight( i_aspect );
1333 *i_aspect_x = i_aspect / i_pgcd;
1334 *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1337 /*****************************************************************************
1338 * BinaryLog: computes the base 2 log of a binary value
1339 *****************************************************************************
1340 * This functions is used by MaskToShift, to get a bit index from a binary
1342 *****************************************************************************/
1343 static int BinaryLog( uint32_t i )
1347 if( i == 0 ) return -31337;
1349 if( i & 0xffff0000 ) i_log += 16;
1350 if( i & 0xff00ff00 ) i_log += 8;
1351 if( i & 0xf0f0f0f0 ) i_log += 4;
1352 if( i & 0xcccccccc ) i_log += 2;
1353 if( i & 0xaaaaaaaa ) i_log += 1;
1358 /*****************************************************************************
1359 * MaskToShift: transform a color mask into right and left shifts
1360 *****************************************************************************
1361 * This function is used for obtaining color shifts from masks.
1362 *****************************************************************************/
1363 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1365 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
1369 *pi_left = *pi_right = 0;
1374 i_low = i_high = i_mask;
1376 i_low &= - (int32_t)i_low; /* lower bit of the mask */
1377 i_high += i_low; /* higher bit of the mask */
1379 /* Transform bits into an index. Also deal with i_high overflow, which
1380 * is faster than changing the BinaryLog code to handle 64 bit integers. */
1381 i_low = BinaryLog (i_low);
1382 i_high = i_high ? BinaryLog (i_high) : 32;
1384 /* Update pointers and return */
1386 *pi_right = (8 - i_high + i_low);
1389 /*****************************************************************************
1390 * vout_VarCallback: generic callback for intf variables
1391 *****************************************************************************/
1392 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1393 vlc_value_t old_value, vlc_value_t new_value,
1396 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1398 val.b_bool = VLC_TRUE;
1399 var_Set( p_vout, "intf-change", val );
1403 /*****************************************************************************
1404 * Helper thread for object variables callbacks.
1405 * Only used to avoid deadlocks when using the video embedded mode.
1406 *****************************************************************************/
1407 typedef struct suxor_thread_t
1410 input_thread_t *p_input;
1414 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1418 vlc_thread_ready( p_this );
1420 /* Now restart current video stream */
1421 var_Get( p_this->p_input, "video-es", &val );
1422 if( val.i_int >= 0 )
1425 val_es.i_int = -VIDEO_ES;
1426 var_Set( p_this->p_input, "video-es", val_es );
1427 var_Set( p_this->p_input, "video-es", val );
1430 vlc_object_release( p_this->p_input );
1433 CloseHandle( p_this->thread_id );
1436 vlc_object_destroy( p_this );
1439 /*****************************************************************************
1440 * object variables callbacks: a bunch of object variables are used by the
1441 * interfaces to interact with the vout.
1442 *****************************************************************************/
1443 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1444 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1446 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1447 input_thread_t *p_input;
1450 char *psz_mode = newval.psz_string;
1451 char *psz_filter, *psz_deinterlace = NULL;
1453 var_Get( p_vout, "vout-filter", &val );
1454 psz_filter = val.psz_string;
1455 if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1457 if( !psz_mode || !*psz_mode )
1459 if( psz_deinterlace )
1461 char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1462 if( psz_src[0] == ':' ) psz_src++;
1463 memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1466 else if( !psz_deinterlace )
1468 psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1469 sizeof(":deinterlace") );
1470 if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1471 strcat( psz_filter, "deinterlace" );
1474 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1476 if( !p_input ) return VLC_EGENERIC;
1478 if( psz_mode && *psz_mode )
1480 /* Modify input as well because the vout might have to be restarted */
1481 val.psz_string = psz_mode;
1482 var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1483 var_Set( p_input, "deinterlace-mode", val );
1485 vlc_object_release( p_input );
1487 val.b_bool = VLC_TRUE;
1488 var_Set( p_vout, "intf-change", val );
1490 val.psz_string = psz_filter;
1491 var_Set( p_vout, "vout-filter", val );
1492 if( psz_filter ) free( psz_filter );
1497 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1498 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1500 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1501 input_thread_t *p_input;
1504 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1508 msg_Err( p_vout, "Input not found" );
1509 return( VLC_EGENERIC );
1512 val.b_bool = VLC_TRUE;
1513 var_Set( p_vout, "intf-change", val );
1515 /* Modify input as well because the vout might have to be restarted */
1516 val.psz_string = newval.psz_string;
1517 var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1519 var_Set( p_input, "vout-filter", val );
1521 /* Now restart current video stream */
1522 var_Get( p_input, "video-es", &val );
1523 if( val.i_int >= 0 )
1525 suxor_thread_t *p_suxor =
1526 vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1527 p_suxor->p_input = p_input;
1528 p_vout->b_filter_change = VLC_TRUE;
1529 vlc_object_yield( p_input );
1530 vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1531 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1534 vlc_object_release( p_input );
1539 /*****************************************************************************
1540 * Video Filter2 stuff
1541 *****************************************************************************/
1542 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1545 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1547 struct config_chain_t *p_cfg =
1548 p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1549 config_ChainDestroy( p_cfg );
1550 free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1552 p_vout->i_vfilters_cfg = 0;
1553 if( psz_vfilters && *psz_vfilters )
1555 char *psz_parser = psz_vfilters;
1557 while( psz_parser && *psz_parser )
1559 psz_parser = config_ChainCreate(
1560 &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1561 &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1563 msg_Dbg( p_vout, "adding vfilter: %s",
1564 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1565 p_vout->i_vfilters_cfg++;
1566 if( psz_parser && psz_parser )
1568 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1571 "maximum number of video filters reached. \"%s\" discarded",
1581 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1582 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1584 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1586 ParseVideoFilter2Chain( p_vout, newval.psz_string );
1587 p_vout->b_vfilter_change = VLC_TRUE;
1592 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1595 for( i = 0; i < p_vout->i_vfilters; i++ )
1597 vlc_object_detach( p_vout->pp_vfilters[i] );
1598 if( p_vout->pp_vfilters[i]->p_module )
1600 module_Unneed( p_vout->pp_vfilters[i],
1601 p_vout->pp_vfilters[i]->p_module );
1604 free( p_vout->pp_vfilters[i]->p_owner );
1605 vlc_object_destroy( p_vout->pp_vfilters[i] );
1607 p_vout->i_vfilters = 0;