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 );
151 vlc_mutex_unlock( &p_playlist->gc_lock );
152 pl_Release( p_this );
156 /* If we now have a video output, check it has the right properties */
159 char *psz_filter_chain;
162 /* We don't directly check for the "vout-filter" variable for obvious
163 * performance reasons. */
164 if( p_vout->b_filter_change )
166 var_Get( p_vout, "vout-filter", &val );
167 psz_filter_chain = val.psz_string;
169 if( psz_filter_chain && !*psz_filter_chain )
171 free( psz_filter_chain );
172 psz_filter_chain = NULL;
174 if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
176 free( p_vout->psz_filter_chain );
177 p_vout->psz_filter_chain = NULL;
180 if( !psz_filter_chain && !p_vout->psz_filter_chain )
182 p_vout->b_filter_change = VLC_FALSE;
185 if( psz_filter_chain ) free( psz_filter_chain );
188 if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
189 ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
190 ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
191 ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
192 p_vout->b_filter_change )
194 /* We are not interested in this format, close this vout */
195 vlc_object_detach( p_vout );
196 vlc_object_release( p_vout );
197 vout_Destroy( p_vout );
202 /* This video output is cool! Hijack it. */
203 vlc_object_detach( p_vout );
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 */
232 vlc_value_t val, text;
234 unsigned int i_width = p_fmt->i_width;
235 unsigned int i_height = p_fmt->i_height;
236 vlc_fourcc_t i_chroma = p_fmt->i_chroma;
237 unsigned int i_aspect = p_fmt->i_aspect;
239 /* Allocate descriptor */
240 p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
243 msg_Err( p_parent, "out of memory" );
247 /* Initialize pictures - translation tables and functions
248 * will be initialized later in InitThread */
249 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
251 p_vout->p_picture[i_index].pf_lock = NULL;
252 p_vout->p_picture[i_index].pf_unlock = NULL;
253 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
254 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
255 p_vout->p_picture[i_index].b_slow = 0;
258 /* No images in the heap */
259 p_vout->i_heap_size = 0;
261 /* Initialize the rendering heap */
262 I_RENDERPICTURES = 0;
264 vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
265 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
266 p_vout->fmt_render = *p_fmt; /* FIXME palette */
267 p_vout->fmt_in = *p_fmt; /* FIXME palette */
269 p_vout->render.i_width = i_width;
270 p_vout->render.i_height = i_height;
271 p_vout->render.i_chroma = i_chroma;
272 p_vout->render.i_aspect = i_aspect;
274 p_vout->render.i_rmask = 0;
275 p_vout->render.i_gmask = 0;
276 p_vout->render.i_bmask = 0;
278 p_vout->render.i_last_used_pic = -1;
279 p_vout->render.b_allow_modify_pics = 1;
281 /* Zero the output heap */
282 I_OUTPUTPICTURES = 0;
283 p_vout->output.i_width = 0;
284 p_vout->output.i_height = 0;
285 p_vout->output.i_chroma = 0;
286 p_vout->output.i_aspect = 0;
288 p_vout->output.i_rmask = 0;
289 p_vout->output.i_gmask = 0;
290 p_vout->output.i_bmask = 0;
292 /* Initialize misc stuff */
293 p_vout->i_changes = 0;
295 p_vout->b_grayscale = 0;
297 p_vout->b_interface = 0;
299 p_vout->b_fullscreen = 0;
300 p_vout->i_alignment = 0;
301 p_vout->render_time = 10;
302 p_vout->c_fps_samples = 0;
303 p_vout->b_filter_change = 0;
304 p_vout->pf_control = 0;
305 p_vout->p_parent_intf = 0;
306 p_vout->i_par_num = p_vout->i_par_den = 1;
308 /* Initialize locks */
309 vlc_mutex_init( p_vout, &p_vout->picture_lock );
310 vlc_mutex_init( p_vout, &p_vout->change_lock );
312 /* Mouse coordinates */
313 var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
314 var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
315 var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
316 var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
317 var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
319 /* Initialize subpicture unit */
320 p_vout->p_spu = spu_Create( p_vout );
321 spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
323 /* Attach the new object now so we can use var inheritance below */
324 vlc_object_attach( p_vout, p_parent );
326 spu_Init( p_vout->p_spu );
328 /* Take care of some "interface/control" related initialisations */
329 vout_IntfInit( p_vout );
331 /* If the parent is not a VOUT object, that means we are at the start of
332 * the video output pipe */
333 if( p_parent->i_object_type != VLC_OBJECT_VOUT )
335 /* Look for the default filter configuration */
336 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
337 var_Get( p_vout, "vout-filter", &val );
338 p_vout->psz_filter_chain = val.psz_string;
340 /* Apply video filter2 objects on the first vout */
341 var_Create( p_vout, "video-filter",
342 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
343 var_Get( p_vout, "video-filter", &val );
344 ParseVideoFilter2Chain( p_vout, val.psz_string );
345 free( val.psz_string );
349 /* continue the parent's filter chain */
352 psz_end = strchr( ((vout_thread_t *)p_parent)->psz_filter_chain, ':' );
353 if( psz_end && *(psz_end+1) )
354 p_vout->psz_filter_chain = strdup( psz_end+1 );
355 else p_vout->psz_filter_chain = NULL;
357 /* Create a video filter2 var ... but don't inherit values */
358 var_Create( p_vout, "video-filter", VLC_VAR_STRING );
359 ParseVideoFilter2Chain( p_vout, NULL );
362 var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
363 p_vout->b_vfilter_change = VLC_TRUE;
364 p_vout->i_vfilters = 0;
366 /* Choose the video output module */
367 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
369 var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
370 var_Get( p_vout, "vout", &val );
371 psz_plugin = val.psz_string;
375 /* the filter chain is a string list of filters separated by double
379 psz_end = strchr( p_vout->psz_filter_chain, ':' );
381 psz_plugin = strndup( p_vout->psz_filter_chain,
382 psz_end - p_vout->psz_filter_chain );
383 else psz_plugin = strdup( p_vout->psz_filter_chain );
386 /* Create the vout thread */
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_plugin, 0 );
391 if( psz_plugin ) free( psz_plugin );
392 if( p_vout->p_module == NULL )
394 msg_Err( p_vout, "no suitable vout module" );
395 vlc_object_detach( p_vout );
396 vlc_object_destroy( p_vout );
400 /* Create a few object variables for interface interaction */
401 var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
402 text.psz_string = _("Deinterlace");
403 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
404 val.psz_string = (char *)""; text.psz_string = _("Disable");
405 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
406 val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
407 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
408 val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
409 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
410 val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
411 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
412 val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
413 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
414 val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
415 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
416 val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
417 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
419 if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
421 var_Set( p_vout, "deinterlace", val );
422 if( val.psz_string ) free( val.psz_string );
424 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
427 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
428 text.psz_string = _("Filters");
429 var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
430 var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
432 /* Calculate delay created by internal caching */
433 p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
434 VLC_OBJECT_INPUT, FIND_ANYWHERE );
437 p_vout->i_pts_delay = p_input_thread->i_pts_delay;
438 vlc_object_release( p_input_thread );
442 p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
445 if( vlc_thread_create( p_vout, "video output", RunThread,
446 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
448 msg_Err( p_vout, "out of memory" );
449 module_Unneed( p_vout, p_vout->p_module );
450 vlc_object_detach( p_vout );
451 vlc_object_destroy( p_vout );
455 if( p_vout->b_error )
457 msg_Err( p_vout, "video output creation failed" );
459 /* Make sure the thread is destroyed */
460 p_vout->b_die = VLC_TRUE;
462 vlc_thread_join( p_vout );
464 vlc_object_detach( p_vout );
465 vlc_object_destroy( p_vout );
472 /*****************************************************************************
473 * vout_Destroy: destroys a previously created video output
474 *****************************************************************************
475 * Destroy a terminated thread.
476 * The function will request a destruction of the specified thread. If pi_error
477 * is NULL, it will return once the thread is destroyed. Else, it will be
478 * update using one of the THREAD_* constants.
479 *****************************************************************************/
480 void vout_Destroy( vout_thread_t *p_vout )
482 vout_thread_t *p_another_vout;
483 playlist_t *p_playlist = pl_Yield( p_vout );
485 /* Request thread destruction */
486 p_vout->b_die = VLC_TRUE;
487 vlc_thread_join( p_vout );
489 var_Destroy( p_vout, "intf-change" );
491 if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
494 vlc_object_destroy( p_vout );
496 /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
497 back if you closed it while playing video. This is solved in Mac OS X,
498 where we have this novelty called menubar, that will always allow you access
499 to the applications main functionality. They should try that on linux sometime */
500 p_another_vout = vlc_object_find( p_playlist,
501 VLC_OBJECT_VOUT, FIND_ANYWHERE );
502 if( p_another_vout == NULL )
505 val.b_bool = VLC_TRUE;
506 var_Set( p_playlist, "intf-show", val );
510 vlc_object_release( p_another_vout );
513 vlc_object_release( p_playlist );
516 /*****************************************************************************
517 * InitThread: initialize video output thread
518 *****************************************************************************
519 * This function is called from RunThread and performs the second step of the
520 * initialization. It returns 0 on success. Note that the thread's flag are not
521 * modified inside this function.
522 *****************************************************************************/
523 static int InitThread( vout_thread_t *p_vout )
525 int i, i_aspect_x, i_aspect_y;
527 vlc_mutex_lock( &p_vout->change_lock );
533 /* Initialize output method, it allocates direct buffers for us */
534 if( p_vout->pf_init( p_vout ) )
536 vlc_mutex_unlock( &p_vout->change_lock );
540 if( !I_OUTPUTPICTURES )
542 msg_Err( p_vout, "plugin was unable to allocate at least "
543 "one direct buffer" );
544 p_vout->pf_end( p_vout );
545 vlc_mutex_unlock( &p_vout->change_lock );
549 if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
551 msg_Err( p_vout, "plugin allocated too many direct buffers, "
552 "our internal buffers must have overflown." );
553 p_vout->pf_end( p_vout );
554 vlc_mutex_unlock( &p_vout->change_lock );
558 msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
560 AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
562 msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
563 "chroma %4.4s, ar %i:%i, sar %i:%i",
564 p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
565 p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
566 p_vout->fmt_render.i_visible_width,
567 p_vout->fmt_render.i_visible_height,
568 (char*)&p_vout->fmt_render.i_chroma,
569 i_aspect_x, i_aspect_y,
570 p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
572 AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
574 msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
575 "chroma %4.4s, ar %i:%i, sar %i:%i",
576 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
577 p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
578 p_vout->fmt_in.i_visible_width,
579 p_vout->fmt_in.i_visible_height,
580 (char*)&p_vout->fmt_in.i_chroma,
581 i_aspect_x, i_aspect_y,
582 p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
584 if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
586 p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
587 p_vout->output.i_width;
588 p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
589 p_vout->output.i_height;
590 p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
592 p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
593 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
595 if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
597 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
598 p_vout->fmt_out.i_height;
599 p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
600 p_vout->fmt_out.i_width;
603 vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
604 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
606 AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
608 msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
609 "chroma %4.4s, ar %i:%i, sar %i:%i",
610 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
611 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
612 p_vout->fmt_out.i_visible_width,
613 p_vout->fmt_out.i_visible_height,
614 (char*)&p_vout->fmt_out.i_chroma,
615 i_aspect_x, i_aspect_y,
616 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
618 /* Calculate shifts from system-updated masks */
619 MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
620 p_vout->output.i_rmask );
621 MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
622 p_vout->output.i_gmask );
623 MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
624 p_vout->output.i_bmask );
626 /* Check whether we managed to create direct buffers similar to
627 * the render buffers, ie same size and chroma */
628 if( ( p_vout->output.i_width == p_vout->render.i_width )
629 && ( p_vout->output.i_height == p_vout->render.i_height )
630 && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
632 /* Cool ! We have direct buffers, we can ask the decoder to
633 * directly decode into them ! Map the first render buffers to
634 * the first direct buffers, but keep the first direct buffer
635 * for memcpy operations */
636 p_vout->b_direct = 1;
638 for( i = 1; i < VOUT_MAX_PICTURES; i++ )
640 if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
641 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
642 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
644 /* We have enough direct buffers so there's no need to
645 * try to use system memory buffers. */
648 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
652 msg_Dbg( p_vout, "direct render, mapping "
653 "render pictures 0-%i to system pictures 1-%i",
654 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
658 /* Rats... Something is wrong here, we could not find an output
659 * plugin able to directly render what we decode. See if we can
660 * find a chroma plugin to do the conversion */
661 p_vout->b_direct = 0;
663 /* Choose the best module */
664 p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
666 if( p_vout->chroma.p_module == NULL )
668 msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
669 (char*)&p_vout->render.i_chroma,
670 (char*)&p_vout->output.i_chroma );
671 p_vout->pf_end( p_vout );
672 vlc_mutex_unlock( &p_vout->change_lock );
676 msg_Dbg( p_vout, "indirect render, mapping "
677 "render pictures 0-%i to system pictures %i-%i",
678 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
679 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
681 /* Append render buffers after the direct buffers */
682 for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
684 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
687 /* Check if we have enough render pictures */
688 if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
693 /* Link pictures back to their heap */
694 for( i = 0 ; i < I_RENDERPICTURES ; i++ )
696 PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
699 for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
701 PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
704 /* XXX XXX mark thread ready */
708 /*****************************************************************************
709 * RunThread: video output thread
710 *****************************************************************************
711 * Video output thread. This function does only returns when the thread is
712 * terminated. It handles the pictures arriving in the video heap and the
713 * display device events.
714 *****************************************************************************/
715 static void RunThread( vout_thread_t *p_vout)
717 int i_index; /* index in heap */
718 int i_idle_loops = 0; /* loops without displaying a picture */
719 mtime_t current_date; /* current date */
720 mtime_t display_date; /* display date */
722 picture_t * p_picture; /* picture pointer */
723 picture_t * p_last_picture = NULL; /* last picture */
724 picture_t * p_directbuffer; /* direct buffer to display */
726 subpicture_t * p_subpic = NULL; /* subpicture pointer */
728 input_thread_t *p_input = NULL ; /* Parent input, if it exists */
731 vlc_bool_t b_drop_late;
733 int i_displayed = 0, i_lost = 0, i_loops = 0;
738 p_vout->b_error = InitThread( p_vout );
740 var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
741 var_Get( p_vout, "drop-late-frames", &val );
742 b_drop_late = val.b_bool;
744 /* signal the creation of the vout */
745 vlc_thread_ready( p_vout );
747 if( p_vout->b_error )
749 /* Destroy thread structures allocated by Create and InitThread */
750 DestroyThread( p_vout );
755 * Main loop - it is not executed if an error occurred during
758 while( (!p_vout->b_die) && (!p_vout->b_error) )
760 /* Initialize loop variables */
763 current_date = mdate();
765 if( p_input && p_input->b_die )
767 vlc_object_release( p_input );
772 if( i_loops % 20 == 0 )
776 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
781 vlc_mutex_lock( &p_input->p->counters.counters_lock );
782 stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures,
784 stats_UpdateInteger( p_vout,
785 p_input->p->counters.p_displayed_pictures,
787 i_displayed = i_lost = 0;
788 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
793 if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
795 msg_Dbg( p_vout, "picture heap: %d/%d",
796 I_RENDERPICTURES, p_vout->i_heap_size );
801 * Find the picture to display (the one with the earliest date).
802 * This operation does not need lock, since only READY_PICTUREs
804 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
806 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
807 && ( (p_picture == NULL) ||
808 (PP_RENDERPICTURE[i_index]->date < display_date) ) )
810 p_picture = PP_RENDERPICTURE[i_index];
811 display_date = p_picture->date;
817 /* If we met the last picture, parse again to see whether there is
818 * a more appropriate one. */
819 if( p_picture == p_last_picture )
821 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
823 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
824 && (PP_RENDERPICTURE[i_index] != p_last_picture)
825 && ((p_picture == p_last_picture) ||
826 (PP_RENDERPICTURE[i_index]->date < display_date)) )
828 p_picture = PP_RENDERPICTURE[i_index];
829 display_date = p_picture->date;
834 /* If we found better than the last picture, destroy it */
835 if( p_last_picture && p_picture != p_last_picture )
837 vlc_mutex_lock( &p_vout->picture_lock );
838 if( p_last_picture->i_refcount )
840 p_last_picture->i_status = DISPLAYED_PICTURE;
844 p_last_picture->i_status = DESTROYED_PICTURE;
845 p_vout->i_heap_size--;
847 vlc_mutex_unlock( &p_vout->picture_lock );
848 p_last_picture = NULL;
851 /* Compute FPS rate */
852 p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
855 if( !p_picture->b_force &&
856 p_picture != p_last_picture &&
857 display_date < current_date + p_vout->render_time &&
860 /* Picture is late: it will be destroyed and the thread
861 * will directly choose the next picture */
862 vlc_mutex_lock( &p_vout->picture_lock );
863 if( p_picture->i_refcount )
865 /* Pretend we displayed the picture, but don't destroy
866 * it since the decoder might still need it. */
867 p_picture->i_status = DISPLAYED_PICTURE;
871 /* Destroy the picture without displaying it */
872 p_picture->i_status = DESTROYED_PICTURE;
873 p_vout->i_heap_size--;
875 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
876 current_date - display_date );
878 vlc_mutex_unlock( &p_vout->picture_lock );
884 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
886 /* Picture is waaay too early: it will be destroyed */
887 vlc_mutex_lock( &p_vout->picture_lock );
888 if( p_picture->i_refcount )
890 /* Pretend we displayed the picture, but don't destroy
891 * it since the decoder might still need it. */
892 p_picture->i_status = DISPLAYED_PICTURE;
896 /* Destroy the picture without displaying it */
897 p_picture->i_status = DESTROYED_PICTURE;
898 p_vout->i_heap_size--;
901 msg_Warn( p_vout, "vout warning: early picture skipped "
902 "("I64Fd")", display_date - current_date
903 - p_vout->i_pts_delay );
904 vlc_mutex_unlock( &p_vout->picture_lock );
909 if( display_date > current_date + VOUT_DISPLAY_DELAY )
911 /* A picture is ready to be rendered, but its rendering date
912 * is far from the current one so the thread will perform an
913 * empty loop as if no picture were found. The picture state
918 else if( p_picture == p_last_picture )
920 /* We are asked to repeat the previous picture, but we first
921 * wait for a couple of idle loops */
922 if( i_idle_loops < 4 )
929 /* We set the display date to something high, otherwise
930 * we'll have lots of problems with late pictures */
931 display_date = current_date + p_vout->render_time;
936 if( p_picture == NULL )
941 /* Video Filter2 stuff */
942 if( p_vout->b_vfilter_change == VLC_TRUE )
945 RemoveVideoFilters2( p_vout );
946 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
948 filter_t *p_vfilter =
949 p_vout->pp_vfilters[p_vout->i_vfilters] =
950 vlc_object_create( p_vout, VLC_OBJECT_FILTER );
952 vlc_object_attach( p_vfilter, p_vout );
954 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
955 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
957 if( !p_vout->i_vfilters )
959 p_vfilter->fmt_in.video = p_vout->fmt_render;
963 p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
965 /* TODO: one day filters in the middle of the chain might
966 * have a different fmt_out.video than fmt_render ... */
967 p_vfilter->fmt_out.video = p_vout->fmt_render;
969 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
970 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
971 p_vout->psz_vfilters[i], 0 );
973 if( p_vfilter->p_module )
976 malloc( sizeof( filter_owner_sys_t ) );
977 p_vfilter->p_owner->p_vout = p_vout;
978 p_vout->i_vfilters++;
979 msg_Dbg( p_vout, "video filter found (%s)",
980 p_vout->psz_vfilters[i] );
984 msg_Err( p_vout, "no video filter found (%s)",
985 p_vout->psz_vfilters[i] );
986 vlc_object_detach( p_vfilter );
987 vlc_object_destroy( p_vfilter );
990 p_vout->b_vfilter_change = VLC_FALSE;
996 for( i = 0; i < p_vout->i_vfilters; i++ )
998 picture_t *p_old = p_picture;
999 p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
1000 p_vout->pp_vfilters[i], p_picture );
1005 /* FIXME: this is kind of wrong
1006 * if you have 2 or more vfilters and the 2nd breaks,
1007 * on the next loop the 1st one will be applied again */
1009 /* if p_old and p_picture are the same (ie the filter
1010 * worked on the old picture), then following code is
1011 * still alright since i_status gets changed back to
1012 * the right value */
1013 if( p_old->i_refcount )
1015 p_old->i_status = DISPLAYED_PICTURE;
1019 p_old->i_status = DESTROYED_PICTURE;
1021 p_picture->i_status = READY_PICTURE;
1025 if( p_picture && p_vout->b_snapshot )
1027 p_vout->b_snapshot = VLC_FALSE;
1028 vout_Snapshot( p_vout, p_picture );
1032 * Check for subpictures to display
1034 if( display_date > 0 )
1038 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1041 p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1042 p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1049 p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1052 * Call the plugin-specific rendering method if there is one
1054 if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1056 /* Render the direct buffer returned by vout_RenderPicture */
1057 p_vout->pf_render( p_vout, p_directbuffer );
1063 if( display_date != 0 && p_directbuffer != NULL )
1065 mtime_t current_render_time = mdate() - current_date;
1066 /* if render time is very large we don't include it in the mean */
1067 if( current_render_time < p_vout->render_time +
1068 VOUT_DISPLAY_DELAY )
1070 /* Store render time using a sliding mean weighting to
1071 * current value in a 3 to 1 ratio*/
1072 p_vout->render_time *= 3;
1073 p_vout->render_time += current_render_time;
1074 p_vout->render_time >>= 2;
1078 /* Give back change lock */
1079 vlc_mutex_unlock( &p_vout->change_lock );
1081 /* Sleep a while or until a given date */
1082 if( display_date != 0 )
1084 /* If there are filters in the chain, better give them the picture
1086 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1088 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1093 msleep( VOUT_IDLE_SLEEP );
1096 /* On awakening, take back lock and send immediately picture
1098 vlc_mutex_lock( &p_vout->change_lock );
1101 * Display the previously rendered picture
1103 if( p_picture != NULL && p_directbuffer != NULL )
1105 /* Display the direct buffer returned by vout_RenderPicture */
1106 if( p_vout->pf_display )
1108 p_vout->pf_display( p_vout, p_directbuffer );
1111 /* Tell the vout this was the last picture and that it does not
1112 * need to be forced anymore. */
1113 p_last_picture = p_picture;
1114 p_last_picture->b_force = 0;
1117 if( p_picture != NULL )
1119 /* Reinitialize idle loop count */
1124 * Check events and manage thread
1126 if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1128 /* A fatal error occurred, and the thread must terminate
1129 * immediately, without displaying anything - setting b_error to 1
1130 * causes the immediate end of the main while() loop. */
1131 p_vout->b_error = 1;
1134 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1136 /* this must only happen when the vout plugin is incapable of
1137 * rescaling the picture itself. In this case we need to destroy
1138 * the current picture buffers and recreate new ones with the right
1142 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1144 p_vout->pf_end( p_vout );
1145 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1146 p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1148 I_OUTPUTPICTURES = 0;
1149 if( p_vout->pf_init( p_vout ) )
1151 msg_Err( p_vout, "cannot resize display" );
1152 /* FIXME: pf_end will be called again in EndThread() */
1153 p_vout->b_error = 1;
1156 /* Need to reinitialise the chroma plugin */
1157 if( p_vout->chroma.p_module )
1159 if( p_vout->chroma.p_module->pf_deactivate )
1160 p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1161 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1165 if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1167 /* This happens when the picture buffers need to be recreated.
1168 * This is useful on multimonitor displays for instance.
1170 * Warning: This only works when the vout creates only 1 picture
1172 p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1174 if( !p_vout->b_direct )
1176 module_Unneed( p_vout, p_vout->chroma.p_module );
1179 vlc_mutex_lock( &p_vout->picture_lock );
1181 p_vout->pf_end( p_vout );
1183 I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1185 p_vout->b_error = InitThread( p_vout );
1187 vlc_mutex_unlock( &p_vout->picture_lock );
1193 vlc_object_release( p_input );
1197 * Error loop - wait until the thread destruction is requested
1199 if( p_vout->b_error )
1201 ErrorThread( p_vout );
1205 EndThread( p_vout );
1207 /* Destroy thread structures allocated by CreateThread */
1208 DestroyThread( p_vout );
1211 /*****************************************************************************
1212 * ErrorThread: RunThread() error loop
1213 *****************************************************************************
1214 * This function is called when an error occurred during thread main's loop.
1215 * The thread can still receive feed, but must be ready to terminate as soon
1217 *****************************************************************************/
1218 static void ErrorThread( vout_thread_t *p_vout )
1220 /* Wait until a `die' order */
1221 while( !p_vout->b_die )
1224 msleep( VOUT_IDLE_SLEEP );
1228 /*****************************************************************************
1229 * EndThread: thread destruction
1230 *****************************************************************************
1231 * This function is called when the thread ends after a sucessful
1232 * initialization. It frees all resources allocated by InitThread.
1233 *****************************************************************************/
1234 static void EndThread( vout_thread_t *p_vout )
1236 int i_index; /* index in heap */
1240 struct tms cpu_usage;
1241 times( &cpu_usage );
1243 msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1244 cpu_usage.tms_utime, cpu_usage.tms_stime );
1248 if( !p_vout->b_direct )
1250 module_Unneed( p_vout, p_vout->chroma.p_module );
1253 /* Destroy all remaining pictures */
1254 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1256 if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1258 free( p_vout->p_picture[i_index].p_data_orig );
1262 /* Destroy subpicture unit */
1263 spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1264 spu_Destroy( p_vout->p_spu );
1266 /* Destroy the video filters2 */
1267 RemoveVideoFilters2( p_vout );
1269 /* Destroy translation tables */
1270 p_vout->pf_end( p_vout );
1272 /* Release the change lock */
1273 vlc_mutex_unlock( &p_vout->change_lock );
1276 /*****************************************************************************
1277 * DestroyThread: thread destruction
1278 *****************************************************************************
1279 * This function is called when the thread ends. It frees all ressources
1280 * allocated by CreateThread. Status is available at this stage.
1281 *****************************************************************************/
1282 static void DestroyThread( vout_thread_t *p_vout )
1284 /* Destroy the locks */
1285 vlc_mutex_destroy( &p_vout->picture_lock );
1286 vlc_mutex_destroy( &p_vout->change_lock );
1288 /* Release the module */
1289 if( p_vout && p_vout->p_module )
1291 module_Unneed( p_vout, p_vout->p_module );
1295 /* following functions are local */
1297 static int ReduceHeight( int i_ratio )
1299 int i_dummy = VOUT_ASPECT_FACTOR;
1307 /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1308 while( !(i_ratio & 1) && !(i_dummy & 1) )
1315 while( !(i_ratio % 3) && !(i_dummy % 3) )
1322 while( !(i_ratio % 5) && !(i_dummy % 5) )
1332 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1334 unsigned int i_pgcd = ReduceHeight( i_aspect );
1335 *i_aspect_x = i_aspect / i_pgcd;
1336 *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1339 /*****************************************************************************
1340 * BinaryLog: computes the base 2 log of a binary value
1341 *****************************************************************************
1342 * This functions is used by MaskToShift, to get a bit index from a binary
1344 *****************************************************************************/
1345 static int BinaryLog( uint32_t i )
1349 if( i == 0 ) return -31337;
1351 if( i & 0xffff0000 ) i_log += 16;
1352 if( i & 0xff00ff00 ) i_log += 8;
1353 if( i & 0xf0f0f0f0 ) i_log += 4;
1354 if( i & 0xcccccccc ) i_log += 2;
1355 if( i & 0xaaaaaaaa ) i_log += 1;
1360 /*****************************************************************************
1361 * MaskToShift: transform a color mask into right and left shifts
1362 *****************************************************************************
1363 * This function is used for obtaining color shifts from masks.
1364 *****************************************************************************/
1365 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1367 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
1371 *pi_left = *pi_right = 0;
1376 i_low = i_high = i_mask;
1378 i_low &= - (int32_t)i_low; /* lower bit of the mask */
1379 i_high += i_low; /* higher bit of the mask */
1381 /* Transform bits into an index. Also deal with i_high overflow, which
1382 * is faster than changing the BinaryLog code to handle 64 bit integers. */
1383 i_low = BinaryLog (i_low);
1384 i_high = i_high ? BinaryLog (i_high) : 32;
1386 /* Update pointers and return */
1388 *pi_right = (8 - i_high + i_low);
1391 /*****************************************************************************
1392 * vout_VarCallback: generic callback for intf variables
1393 *****************************************************************************/
1394 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1395 vlc_value_t old_value, vlc_value_t new_value,
1398 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1400 val.b_bool = VLC_TRUE;
1401 var_Set( p_vout, "intf-change", val );
1405 /*****************************************************************************
1406 * Helper thread for object variables callbacks.
1407 * Only used to avoid deadlocks when using the video embedded mode.
1408 *****************************************************************************/
1409 typedef struct suxor_thread_t
1412 input_thread_t *p_input;
1416 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1420 vlc_thread_ready( p_this );
1422 /* Now restart current video stream */
1423 var_Get( p_this->p_input, "video-es", &val );
1424 if( val.i_int >= 0 )
1427 val_es.i_int = -VIDEO_ES;
1428 var_Set( p_this->p_input, "video-es", val_es );
1429 var_Set( p_this->p_input, "video-es", val );
1432 vlc_object_release( p_this->p_input );
1435 CloseHandle( p_this->thread_id );
1438 vlc_object_destroy( p_this );
1441 /*****************************************************************************
1442 * object variables callbacks: a bunch of object variables are used by the
1443 * interfaces to interact with the vout.
1444 *****************************************************************************/
1445 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1446 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1448 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1449 input_thread_t *p_input;
1452 char *psz_mode = newval.psz_string;
1453 char *psz_filter, *psz_deinterlace = NULL;
1455 var_Get( p_vout, "vout-filter", &val );
1456 psz_filter = val.psz_string;
1457 if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1459 if( !psz_mode || !*psz_mode )
1461 if( psz_deinterlace )
1463 char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1464 if( psz_src[0] == ':' ) psz_src++;
1465 memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1468 else if( !psz_deinterlace )
1470 psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1471 sizeof(":deinterlace") );
1472 if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1473 strcat( psz_filter, "deinterlace" );
1476 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1478 if( !p_input ) return VLC_EGENERIC;
1480 if( psz_mode && *psz_mode )
1482 /* Modify input as well because the vout might have to be restarted */
1483 val.psz_string = psz_mode;
1484 var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1485 var_Set( p_input, "deinterlace-mode", val );
1487 vlc_object_release( p_input );
1489 val.b_bool = VLC_TRUE;
1490 var_Set( p_vout, "intf-change", val );
1492 val.psz_string = psz_filter;
1493 var_Set( p_vout, "vout-filter", val );
1494 if( psz_filter ) free( psz_filter );
1499 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1500 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1502 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1503 input_thread_t *p_input;
1506 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1510 msg_Err( p_vout, "Input not found" );
1511 return( VLC_EGENERIC );
1514 val.b_bool = VLC_TRUE;
1515 var_Set( p_vout, "intf-change", val );
1517 /* Modify input as well because the vout might have to be restarted */
1518 val.psz_string = newval.psz_string;
1519 var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1521 var_Set( p_input, "vout-filter", val );
1523 /* Now restart current video stream */
1524 var_Get( p_input, "video-es", &val );
1525 if( val.i_int >= 0 )
1527 suxor_thread_t *p_suxor =
1528 vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1529 p_suxor->p_input = p_input;
1530 p_vout->b_filter_change = VLC_TRUE;
1531 vlc_object_yield( p_input );
1532 vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1533 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1536 vlc_object_release( p_input );
1541 /*****************************************************************************
1542 * Video Filter2 stuff
1543 *****************************************************************************/
1544 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1547 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1549 struct config_chain_t *p_cfg =
1550 p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1551 config_ChainDestroy( p_cfg );
1552 if( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] )
1554 free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1555 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
1558 p_vout->i_vfilters_cfg = 0;
1559 if( psz_vfilters && *psz_vfilters )
1561 char *psz_parser = psz_vfilters;
1563 while( psz_parser && *psz_parser )
1565 psz_parser = config_ChainCreate(
1566 &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1567 &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1569 msg_Dbg( p_vout, "adding vfilter: %s",
1570 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1571 p_vout->i_vfilters_cfg++;
1572 if( psz_parser && psz_parser )
1574 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1577 "maximum number of video filters reached. \"%s\" discarded",
1587 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1588 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1590 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1592 ParseVideoFilter2Chain( p_vout, newval.psz_string );
1593 p_vout->b_vfilter_change = VLC_TRUE;
1598 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1601 for( i = 0; i < p_vout->i_vfilters; i++ )
1603 vlc_object_detach( p_vout->pp_vfilters[i] );
1604 if( p_vout->pp_vfilters[i]->p_module )
1606 module_Unneed( p_vout->pp_vfilters[i],
1607 p_vout->pp_vfilters[i]->p_module );
1610 free( p_vout->pp_vfilters[i]->p_owner );
1611 vlc_object_destroy( p_vout->pp_vfilters[i] );
1613 p_vout->i_vfilters = 0;