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-2007 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 #include "modules/modules.h"
58 /*****************************************************************************
60 *****************************************************************************/
61 static int InitThread ( vout_thread_t * );
62 static void RunThread ( vout_thread_t * );
63 static void ErrorThread ( vout_thread_t * );
64 static void EndThread ( vout_thread_t * );
65 static void DestroyThread ( vout_thread_t * );
67 static void AspectRatio ( int, int *, int * );
68 static int BinaryLog ( uint32_t );
69 static void MaskToShift ( int *, int *, uint32_t );
71 /* Object variables callbacks */
72 static int DeinterlaceCallback( vlc_object_t *, char const *,
73 vlc_value_t, vlc_value_t, void * );
74 static int FilterCallback( vlc_object_t *, char const *,
75 vlc_value_t, vlc_value_t, void * );
76 static int VideoFilter2Callback( vlc_object_t *, char const *,
77 vlc_value_t, vlc_value_t, void * );
79 /* From vout_intf.c */
80 int vout_Snapshot( vout_thread_t *, picture_t * );
82 /* Video filter2 parsing */
83 static int ParseVideoFilter2Chain( vout_thread_t *, char * );
84 static void RemoveVideoFilters2( vout_thread_t *p_vout );
86 /*****************************************************************************
87 * Video Filter2 functions
88 *****************************************************************************/
89 struct filter_owner_sys_t
91 vout_thread_t *p_vout;
94 static picture_t *video_new_buffer_filter( filter_t *p_filter )
97 vout_thread_t *p_vout = p_filter->p_owner->p_vout;
99 p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
104 static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
106 vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
109 /*****************************************************************************
110 * vout_Request: find a video output thread, create one, or destroy one.
111 *****************************************************************************
112 * This function looks for a video output thread matching the current
113 * properties. If not found, it spawns a new one.
114 *****************************************************************************/
115 vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout,
116 video_format_t *p_fmt )
120 /* Reattach video output to playlist before bailing out */
123 playlist_t *p_playlist = pl_Yield( p_this );
124 spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
125 vlc_object_detach( p_vout );
126 vlc_object_attach( p_vout, p_playlist );
127 pl_Release( p_this );
132 /* If a video output was provided, lock it, otherwise look for one. */
135 vlc_object_yield( p_vout );
139 p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );
143 playlist_t *p_playlist = pl_Yield( p_this );
144 vlc_mutex_lock( &p_playlist->gc_lock );
145 p_vout = vlc_object_find( p_playlist,
146 VLC_OBJECT_VOUT, FIND_CHILD );
147 /* only first children of p_input for unused vout */
148 if( p_vout && p_vout->p_parent != (vlc_object_t *)p_playlist )
150 vlc_object_release( p_vout );
154 vlc_object_detach( p_vout ); /* Remove it from the GC */
155 vlc_mutex_unlock( &p_playlist->gc_lock );
156 pl_Release( p_this );
160 /* If we now have a video output, check it has the right properties */
163 char *psz_filter_chain;
166 /* We don't directly check for the "vout-filter" variable for obvious
167 * performance reasons. */
168 if( p_vout->b_filter_change )
170 var_Get( p_vout, "vout-filter", &val );
171 psz_filter_chain = val.psz_string;
173 if( psz_filter_chain && !*psz_filter_chain )
175 free( psz_filter_chain );
176 psz_filter_chain = NULL;
178 if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
180 free( p_vout->psz_filter_chain );
181 p_vout->psz_filter_chain = NULL;
184 if( !psz_filter_chain && !p_vout->psz_filter_chain )
186 p_vout->b_filter_change = VLC_FALSE;
189 if( psz_filter_chain ) free( psz_filter_chain );
192 if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
193 ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
194 ( p_vout->fmt_render.i_chroma != p_fmt->i_chroma ) ||
195 ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
196 p_vout->b_filter_change )
198 /* We are not interested in this format, close this vout */
199 vlc_object_release( p_vout );
200 vout_Destroy( p_vout );
205 /* This video output is cool! Hijack it. */
206 spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
207 vlc_object_attach( p_vout, p_this );
208 vlc_object_release( p_vout );
214 msg_Dbg( p_this, "no usable vout present, spawning one" );
216 p_vout = vout_Create( p_this, p_fmt );
222 /*****************************************************************************
223 * vout_Create: creates a new video output thread
224 *****************************************************************************
225 * This function creates a new video output thread, and returns a pointer
226 * to its description. On error, it returns NULL.
227 *****************************************************************************/
228 vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
230 vout_thread_t * p_vout; /* thread descriptor */
231 input_thread_t * p_input_thread;
232 int i_index; /* loop variable */
233 vlc_value_t val, text;
235 unsigned int i_width = p_fmt->i_width;
236 unsigned int i_height = p_fmt->i_height;
237 vlc_fourcc_t i_chroma = p_fmt->i_chroma;
238 unsigned int i_aspect = p_fmt->i_aspect;
240 config_chain_t *p_cfg;
244 /* Allocate descriptor */
245 p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
248 msg_Err( p_parent, "out of memory" );
252 /* Initialize pictures - translation tables and functions
253 * will be initialized later in InitThread */
254 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
256 p_vout->p_picture[i_index].pf_lock = NULL;
257 p_vout->p_picture[i_index].pf_unlock = NULL;
258 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
259 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
260 p_vout->p_picture[i_index].b_slow = 0;
263 /* No images in the heap */
264 p_vout->i_heap_size = 0;
266 /* Initialize the rendering heap */
267 I_RENDERPICTURES = 0;
269 vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
270 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
271 p_vout->fmt_render = *p_fmt; /* FIXME palette */
272 p_vout->fmt_in = *p_fmt; /* FIXME palette */
274 p_vout->render.i_width = i_width;
275 p_vout->render.i_height = i_height;
276 p_vout->render.i_chroma = i_chroma;
277 p_vout->render.i_aspect = i_aspect;
279 p_vout->render.i_rmask = 0;
280 p_vout->render.i_gmask = 0;
281 p_vout->render.i_bmask = 0;
283 p_vout->render.i_last_used_pic = -1;
284 p_vout->render.b_allow_modify_pics = 1;
286 /* Zero the output heap */
287 I_OUTPUTPICTURES = 0;
288 p_vout->output.i_width = 0;
289 p_vout->output.i_height = 0;
290 p_vout->output.i_chroma = 0;
291 p_vout->output.i_aspect = 0;
293 p_vout->output.i_rmask = 0;
294 p_vout->output.i_gmask = 0;
295 p_vout->output.i_bmask = 0;
297 /* Initialize misc stuff */
298 p_vout->i_changes = 0;
300 p_vout->b_grayscale = 0;
302 p_vout->b_interface = 0;
304 p_vout->b_fullscreen = 0;
305 p_vout->i_alignment = 0;
306 p_vout->render_time = 10;
307 p_vout->c_fps_samples = 0;
308 p_vout->b_filter_change = 0;
309 p_vout->pf_control = 0;
310 p_vout->p_parent_intf = 0;
311 p_vout->i_par_num = p_vout->i_par_den = 1;
313 /* Initialize locks */
314 vlc_mutex_init( p_vout, &p_vout->picture_lock );
315 vlc_mutex_init( p_vout, &p_vout->change_lock );
316 vlc_mutex_init( p_vout, &p_vout->vfilter_lock );
318 /* Mouse coordinates */
319 var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
320 var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
321 var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
322 var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
323 var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
325 /* Initialize subpicture unit */
326 p_vout->p_spu = spu_Create( p_vout );
327 spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
329 /* Attach the new object now so we can use var inheritance below */
330 vlc_object_attach( p_vout, p_parent );
332 spu_Init( p_vout->p_spu );
334 /* Take care of some "interface/control" related initialisations */
335 vout_IntfInit( p_vout );
337 /* If the parent is not a VOUT object, that means we are at the start of
338 * the video output pipe */
339 if( p_parent->i_object_type != VLC_OBJECT_VOUT )
341 /* Look for the default filter configuration */
342 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
343 var_Get( p_vout, "vout-filter", &val );
344 p_vout->psz_filter_chain = val.psz_string;
346 /* Apply video filter2 objects on the first vout */
347 var_Create( p_vout, "video-filter",
348 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
349 var_Get( p_vout, "video-filter", &val );
350 ParseVideoFilter2Chain( p_vout, val.psz_string );
351 free( val.psz_string );
355 /* continue the parent's filter chain */
358 /* Ugly hack to jump to our configuration chain */
359 p_vout->psz_filter_chain
360 = ((vout_thread_t *)p_parent)->psz_filter_chain;
361 p_vout->psz_filter_chain
362 = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain );
363 config_ChainDestroy( p_cfg );
366 /* Create a video filter2 var ... but don't inherit values */
367 var_Create( p_vout, "video-filter", VLC_VAR_STRING );
368 ParseVideoFilter2Chain( p_vout, NULL );
371 var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
372 p_vout->b_vfilter_change = VLC_TRUE;
373 p_vout->i_vfilters = 0;
375 /* Choose the video output module */
376 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
378 var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
379 var_Get( p_vout, "vout", &val );
380 psz_parser = val.psz_string;
384 psz_parser = strdup( p_vout->psz_filter_chain );
387 /* Create the vout thread */
388 config_ChainCreate( &psz_name, &p_cfg, psz_parser );
390 p_vout->p_cfg = p_cfg;
391 p_vout->p_module = module_Need( p_vout,
392 ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
393 "video filter" : "video output", psz_name, 0 );
396 if( p_vout->p_module == NULL )
398 msg_Err( p_vout, "no suitable vout module" );
399 vlc_object_detach( p_vout );
400 vlc_object_destroy( p_vout );
404 /* Create a few object variables for interface interaction */
405 var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
406 text.psz_string = _("Deinterlace");
407 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
408 val.psz_string = (char *)""; text.psz_string = _("Disable");
409 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
410 val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
411 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
412 val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
413 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
414 val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
415 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
416 val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
417 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
418 val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
419 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
420 val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
421 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
423 if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
425 var_Set( p_vout, "deinterlace", val );
426 if( val.psz_string ) free( val.psz_string );
428 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
431 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
432 text.psz_string = _("Filters");
433 var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
434 var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
436 /* Calculate delay created by internal caching */
437 p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
438 VLC_OBJECT_INPUT, FIND_ANYWHERE );
441 p_vout->i_pts_delay = p_input_thread->i_pts_delay;
442 vlc_object_release( p_input_thread );
446 p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
449 if( vlc_thread_create( p_vout, "video output", RunThread,
450 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
452 msg_Err( p_vout, "out of memory" );
453 module_Unneed( p_vout, p_vout->p_module );
454 vlc_object_detach( p_vout );
455 vlc_object_destroy( p_vout );
459 if( p_vout->b_error )
461 msg_Err( p_vout, "video output creation failed" );
463 /* Make sure the thread is destroyed */
464 p_vout->b_die = VLC_TRUE;
466 vlc_thread_join( p_vout );
468 vlc_object_detach( p_vout );
469 vlc_object_destroy( p_vout );
476 /*****************************************************************************
477 * vout_Destroy: destroys a previously created video output
478 *****************************************************************************
479 * Destroy a terminated thread.
480 * The function will request a destruction of the specified thread. If pi_error
481 * is NULL, it will return once the thread is destroyed. Else, it will be
482 * update using one of the THREAD_* constants.
483 *****************************************************************************/
484 void vout_Destroy( vout_thread_t *p_vout )
486 vout_thread_t *p_another_vout;
487 playlist_t *p_playlist = pl_Yield( p_vout );
489 /* Request thread destruction */
490 p_vout->b_die = VLC_TRUE;
491 vlc_thread_join( p_vout );
493 var_Destroy( p_vout, "intf-change" );
495 if( p_vout->psz_filter_chain ) free( p_vout->psz_filter_chain );
497 config_ChainDestroy( p_vout->p_cfg );
500 vlc_object_destroy( p_vout );
502 /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
503 back if you closed it while playing video. This is solved in Mac OS X,
504 where we have this novelty called menubar, that will always allow you access
505 to the applications main functionality. They should try that on linux sometime */
506 p_another_vout = vlc_object_find( p_playlist,
507 VLC_OBJECT_VOUT, FIND_ANYWHERE );
508 if( p_another_vout == NULL )
511 val.b_bool = VLC_TRUE;
512 var_Set( p_playlist, "intf-show", val );
516 vlc_object_release( p_another_vout );
519 vlc_object_release( p_playlist );
522 /*****************************************************************************
523 * InitThread: initialize video output thread
524 *****************************************************************************
525 * This function is called from RunThread and performs the second step of the
526 * initialization. It returns 0 on success. Note that the thread's flag are not
527 * modified inside this function.
528 *****************************************************************************/
529 static int InitThread( vout_thread_t *p_vout )
531 int i, i_aspect_x, i_aspect_y;
533 vlc_mutex_lock( &p_vout->change_lock );
539 /* Initialize output method, it allocates direct buffers for us */
540 if( p_vout->pf_init( p_vout ) )
542 vlc_mutex_unlock( &p_vout->change_lock );
546 if( !I_OUTPUTPICTURES )
548 msg_Err( p_vout, "plugin was unable to allocate at least "
549 "one direct buffer" );
550 p_vout->pf_end( p_vout );
551 vlc_mutex_unlock( &p_vout->change_lock );
555 if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
557 msg_Err( p_vout, "plugin allocated too many direct buffers, "
558 "our internal buffers must have overflown." );
559 p_vout->pf_end( p_vout );
560 vlc_mutex_unlock( &p_vout->change_lock );
564 msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
566 AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
568 msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
569 "chroma %4.4s, ar %i:%i, sar %i:%i",
570 p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
571 p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
572 p_vout->fmt_render.i_visible_width,
573 p_vout->fmt_render.i_visible_height,
574 (char*)&p_vout->fmt_render.i_chroma,
575 i_aspect_x, i_aspect_y,
576 p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
578 AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
580 msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
581 "chroma %4.4s, ar %i:%i, sar %i:%i",
582 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
583 p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
584 p_vout->fmt_in.i_visible_width,
585 p_vout->fmt_in.i_visible_height,
586 (char*)&p_vout->fmt_in.i_chroma,
587 i_aspect_x, i_aspect_y,
588 p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
590 if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
592 p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
593 p_vout->output.i_width;
594 p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
595 p_vout->output.i_height;
596 p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
598 p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
599 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
601 if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
603 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
604 p_vout->fmt_out.i_height;
605 p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
606 p_vout->fmt_out.i_width;
609 vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
610 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
612 AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
614 msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
615 "chroma %4.4s, ar %i:%i, sar %i:%i",
616 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
617 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
618 p_vout->fmt_out.i_visible_width,
619 p_vout->fmt_out.i_visible_height,
620 (char*)&p_vout->fmt_out.i_chroma,
621 i_aspect_x, i_aspect_y,
622 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
624 /* Calculate shifts from system-updated masks */
625 MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
626 p_vout->output.i_rmask );
627 MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
628 p_vout->output.i_gmask );
629 MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
630 p_vout->output.i_bmask );
632 /* Check whether we managed to create direct buffers similar to
633 * the render buffers, ie same size and chroma */
634 if( ( p_vout->output.i_width == p_vout->render.i_width )
635 && ( p_vout->output.i_height == p_vout->render.i_height )
636 && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
638 /* Cool ! We have direct buffers, we can ask the decoder to
639 * directly decode into them ! Map the first render buffers to
640 * the first direct buffers, but keep the first direct buffer
641 * for memcpy operations */
642 p_vout->b_direct = 1;
644 for( i = 1; i < VOUT_MAX_PICTURES; i++ )
646 if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
647 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
648 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
650 /* We have enough direct buffers so there's no need to
651 * try to use system memory buffers. */
654 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
658 msg_Dbg( p_vout, "direct render, mapping "
659 "render pictures 0-%i to system pictures 1-%i",
660 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
664 /* Rats... Something is wrong here, we could not find an output
665 * plugin able to directly render what we decode. See if we can
666 * find a chroma plugin to do the conversion */
667 p_vout->b_direct = 0;
669 /* Choose the best module */
670 p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
672 if( p_vout->chroma.p_module == NULL )
674 msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
675 (char*)&p_vout->render.i_chroma,
676 (char*)&p_vout->output.i_chroma );
677 p_vout->pf_end( p_vout );
678 vlc_mutex_unlock( &p_vout->change_lock );
682 msg_Dbg( p_vout, "indirect render, mapping "
683 "render pictures 0-%i to system pictures %i-%i",
684 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
685 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
687 /* Append render buffers after the direct buffers */
688 for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
690 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
693 /* Check if we have enough render pictures */
694 if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
699 /* Link pictures back to their heap */
700 for( i = 0 ; i < I_RENDERPICTURES ; i++ )
702 PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
705 for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
707 PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
710 /* XXX XXX mark thread ready */
714 /*****************************************************************************
715 * RunThread: video output thread
716 *****************************************************************************
717 * Video output thread. This function does only returns when the thread is
718 * terminated. It handles the pictures arriving in the video heap and the
719 * display device events.
720 *****************************************************************************/
721 static void RunThread( vout_thread_t *p_vout)
723 int i_index; /* index in heap */
724 int i_idle_loops = 0; /* loops without displaying a picture */
725 mtime_t current_date; /* current date */
726 mtime_t display_date; /* display date */
728 picture_t * p_picture; /* picture pointer */
729 picture_t * p_last_picture = NULL; /* last picture */
730 picture_t * p_directbuffer; /* direct buffer to display */
732 subpicture_t * p_subpic = NULL; /* subpicture pointer */
734 input_thread_t *p_input = NULL ; /* Parent input, if it exists */
737 vlc_bool_t b_drop_late;
739 int i_displayed = 0, i_lost = 0, i_loops = 0;
744 p_vout->b_error = InitThread( p_vout );
746 var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
747 var_Get( p_vout, "drop-late-frames", &val );
748 b_drop_late = val.b_bool;
750 /* signal the creation of the vout */
751 vlc_thread_ready( p_vout );
753 if( p_vout->b_error )
755 /* Destroy thread structures allocated by Create and InitThread */
756 DestroyThread( p_vout );
761 * Main loop - it is not executed if an error occurred during
764 while( (!p_vout->b_die) && (!p_vout->b_error) )
766 /* Initialize loop variables */
769 current_date = mdate();
771 if( p_input && p_input->b_die )
773 vlc_object_release( p_input );
778 if( i_loops % 20 == 0 )
782 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
787 vlc_mutex_lock( &p_input->p->counters.counters_lock );
788 stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures,
790 stats_UpdateInteger( p_vout,
791 p_input->p->counters.p_displayed_pictures,
793 i_displayed = i_lost = 0;
794 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
799 if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
801 msg_Dbg( p_vout, "picture heap: %d/%d",
802 I_RENDERPICTURES, p_vout->i_heap_size );
807 * Find the picture to display (the one with the earliest date).
808 * This operation does not need lock, since only READY_PICTUREs
810 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
812 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
813 && ( (p_picture == NULL) ||
814 (PP_RENDERPICTURE[i_index]->date < display_date) ) )
816 p_picture = PP_RENDERPICTURE[i_index];
817 display_date = p_picture->date;
823 /* If we met the last picture, parse again to see whether there is
824 * a more appropriate one. */
825 if( p_picture == p_last_picture )
827 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
829 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
830 && (PP_RENDERPICTURE[i_index] != p_last_picture)
831 && ((p_picture == p_last_picture) ||
832 (PP_RENDERPICTURE[i_index]->date < display_date)) )
834 p_picture = PP_RENDERPICTURE[i_index];
835 display_date = p_picture->date;
840 /* If we found better than the last picture, destroy it */
841 if( p_last_picture && p_picture != p_last_picture )
843 vlc_mutex_lock( &p_vout->picture_lock );
844 if( p_last_picture->i_refcount )
846 p_last_picture->i_status = DISPLAYED_PICTURE;
850 p_last_picture->i_status = DESTROYED_PICTURE;
851 p_vout->i_heap_size--;
853 vlc_mutex_unlock( &p_vout->picture_lock );
854 p_last_picture = NULL;
857 /* Compute FPS rate */
858 p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
861 if( !p_picture->b_force &&
862 p_picture != p_last_picture &&
863 display_date < current_date + p_vout->render_time &&
866 /* Picture is late: it will be destroyed and the thread
867 * will directly choose the next picture */
868 vlc_mutex_lock( &p_vout->picture_lock );
869 if( p_picture->i_refcount )
871 /* Pretend we displayed the picture, but don't destroy
872 * it since the decoder might still need it. */
873 p_picture->i_status = DISPLAYED_PICTURE;
877 /* Destroy the picture without displaying it */
878 p_picture->i_status = DESTROYED_PICTURE;
879 p_vout->i_heap_size--;
881 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
882 current_date - display_date );
884 vlc_mutex_unlock( &p_vout->picture_lock );
890 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
892 /* Picture is waaay too early: it will be destroyed */
893 vlc_mutex_lock( &p_vout->picture_lock );
894 if( p_picture->i_refcount )
896 /* Pretend we displayed the picture, but don't destroy
897 * it since the decoder might still need it. */
898 p_picture->i_status = DISPLAYED_PICTURE;
902 /* Destroy the picture without displaying it */
903 p_picture->i_status = DESTROYED_PICTURE;
904 p_vout->i_heap_size--;
907 msg_Warn( p_vout, "vout warning: early picture skipped "
908 "("I64Fd")", display_date - current_date
909 - p_vout->i_pts_delay );
910 vlc_mutex_unlock( &p_vout->picture_lock );
915 if( display_date > current_date + VOUT_DISPLAY_DELAY )
917 /* A picture is ready to be rendered, but its rendering date
918 * is far from the current one so the thread will perform an
919 * empty loop as if no picture were found. The picture state
924 else if( p_picture == p_last_picture )
926 /* We are asked to repeat the previous picture, but we first
927 * wait for a couple of idle loops */
928 if( i_idle_loops < 4 )
935 /* We set the display date to something high, otherwise
936 * we'll have lots of problems with late pictures */
937 display_date = current_date + p_vout->render_time;
942 if( p_picture == NULL )
947 /* Video Filter2 stuff */
948 if( p_vout->b_vfilter_change == VLC_TRUE )
951 vlc_mutex_lock( &p_vout->vfilter_lock );
952 RemoveVideoFilters2( p_vout );
953 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
955 filter_t *p_vfilter =
956 p_vout->pp_vfilters[p_vout->i_vfilters] =
957 vlc_object_create( p_vout, VLC_OBJECT_FILTER );
959 vlc_object_attach( p_vfilter, p_vout );
961 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
962 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
964 if( !p_vout->i_vfilters )
966 p_vfilter->fmt_in.video = p_vout->fmt_render;
970 p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
972 /* TODO: one day filters in the middle of the chain might
973 * have a different fmt_out.video than fmt_render ... */
974 p_vfilter->fmt_out.video = p_vout->fmt_render;
976 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
977 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
978 p_vout->psz_vfilters[i],
981 if( p_vfilter->p_module )
984 malloc( sizeof( filter_owner_sys_t ) );
985 p_vfilter->p_owner->p_vout = p_vout;
986 p_vout->i_vfilters++;
987 msg_Dbg( p_vout, "video filter found (%s)",
988 p_vout->psz_vfilters[i] );
992 msg_Err( p_vout, "no video filter found (%s)",
993 p_vout->psz_vfilters[i] );
994 vlc_object_detach( p_vfilter );
995 vlc_object_destroy( p_vfilter );
998 p_vout->b_vfilter_change = VLC_FALSE;
999 vlc_mutex_unlock( &p_vout->vfilter_lock );
1005 for( i = 0; i < p_vout->i_vfilters; i++ )
1007 picture_t *p_old = p_picture;
1008 p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
1009 p_vout->pp_vfilters[i], p_picture );
1014 /* FIXME: this is kind of wrong
1015 * if you have 2 or more vfilters and the 2nd breaks,
1016 * on the next loop the 1st one will be applied again */
1018 /* if p_old and p_picture are the same (ie the filter
1019 * worked on the old picture), then following code is
1020 * still alright since i_status gets changed back to
1021 * the right value */
1022 if( p_old->i_refcount )
1024 p_old->i_status = DISPLAYED_PICTURE;
1028 p_old->i_status = DESTROYED_PICTURE;
1030 p_picture->i_status = READY_PICTURE;
1034 if( p_picture && p_vout->b_snapshot )
1036 p_vout->b_snapshot = VLC_FALSE;
1037 vout_Snapshot( p_vout, p_picture );
1041 * Check for subpictures to display
1043 if( display_date > 0 )
1047 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1050 p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1051 p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1058 p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1061 * Call the plugin-specific rendering method if there is one
1063 if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1065 /* Render the direct buffer returned by vout_RenderPicture */
1066 p_vout->pf_render( p_vout, p_directbuffer );
1072 if( display_date != 0 && p_directbuffer != NULL )
1074 mtime_t current_render_time = mdate() - current_date;
1075 /* if render time is very large we don't include it in the mean */
1076 if( current_render_time < p_vout->render_time +
1077 VOUT_DISPLAY_DELAY )
1079 /* Store render time using a sliding mean weighting to
1080 * current value in a 3 to 1 ratio*/
1081 p_vout->render_time *= 3;
1082 p_vout->render_time += current_render_time;
1083 p_vout->render_time >>= 2;
1087 /* Give back change lock */
1088 vlc_mutex_unlock( &p_vout->change_lock );
1090 /* Sleep a while or until a given date */
1091 if( display_date != 0 )
1093 /* If there are filters in the chain, better give them the picture
1095 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1097 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1102 msleep( VOUT_IDLE_SLEEP );
1105 /* On awakening, take back lock and send immediately picture
1107 vlc_mutex_lock( &p_vout->change_lock );
1110 * Display the previously rendered picture
1112 if( p_picture != NULL && p_directbuffer != NULL )
1114 /* Display the direct buffer returned by vout_RenderPicture */
1115 if( p_vout->pf_display )
1117 p_vout->pf_display( p_vout, p_directbuffer );
1120 /* Tell the vout this was the last picture and that it does not
1121 * need to be forced anymore. */
1122 p_last_picture = p_picture;
1123 p_last_picture->b_force = 0;
1126 if( p_picture != NULL )
1128 /* Reinitialize idle loop count */
1133 * Check events and manage thread
1135 if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1137 /* A fatal error occurred, and the thread must terminate
1138 * immediately, without displaying anything - setting b_error to 1
1139 * causes the immediate end of the main while() loop. */
1140 p_vout->b_error = 1;
1143 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1145 /* this must only happen when the vout plugin is incapable of
1146 * rescaling the picture itself. In this case we need to destroy
1147 * the current picture buffers and recreate new ones with the right
1151 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1153 p_vout->pf_end( p_vout );
1154 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1155 p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1157 I_OUTPUTPICTURES = 0;
1158 if( p_vout->pf_init( p_vout ) )
1160 msg_Err( p_vout, "cannot resize display" );
1161 /* FIXME: pf_end will be called again in EndThread() */
1162 p_vout->b_error = 1;
1165 /* Need to reinitialise the chroma plugin */
1166 if( p_vout->chroma.p_module )
1168 if( p_vout->chroma.p_module->pf_deactivate )
1169 p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1170 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1174 if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1176 /* This happens when the picture buffers need to be recreated.
1177 * This is useful on multimonitor displays for instance.
1179 * Warning: This only works when the vout creates only 1 picture
1181 p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1183 if( !p_vout->b_direct )
1185 module_Unneed( p_vout, p_vout->chroma.p_module );
1188 vlc_mutex_lock( &p_vout->picture_lock );
1190 p_vout->pf_end( p_vout );
1192 I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1194 p_vout->b_error = InitThread( p_vout );
1196 vlc_mutex_unlock( &p_vout->picture_lock );
1202 vlc_object_release( p_input );
1206 * Error loop - wait until the thread destruction is requested
1208 if( p_vout->b_error )
1210 ErrorThread( p_vout );
1214 EndThread( p_vout );
1216 /* Destroy thread structures allocated by CreateThread */
1217 DestroyThread( p_vout );
1220 /*****************************************************************************
1221 * ErrorThread: RunThread() error loop
1222 *****************************************************************************
1223 * This function is called when an error occurred during thread main's loop.
1224 * The thread can still receive feed, but must be ready to terminate as soon
1226 *****************************************************************************/
1227 static void ErrorThread( vout_thread_t *p_vout )
1229 /* Wait until a `die' order */
1230 while( !p_vout->b_die )
1233 msleep( VOUT_IDLE_SLEEP );
1237 /*****************************************************************************
1238 * EndThread: thread destruction
1239 *****************************************************************************
1240 * This function is called when the thread ends after a sucessful
1241 * initialization. It frees all resources allocated by InitThread.
1242 *****************************************************************************/
1243 static void EndThread( vout_thread_t *p_vout )
1245 int i_index; /* index in heap */
1249 struct tms cpu_usage;
1250 times( &cpu_usage );
1252 msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1253 cpu_usage.tms_utime, cpu_usage.tms_stime );
1257 if( !p_vout->b_direct )
1259 module_Unneed( p_vout, p_vout->chroma.p_module );
1262 /* Destroy all remaining pictures */
1263 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1265 if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1267 free( p_vout->p_picture[i_index].p_data_orig );
1271 /* Destroy subpicture unit */
1272 spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1273 spu_Destroy( p_vout->p_spu );
1275 /* Destroy the video filters2 */
1276 RemoveVideoFilters2( p_vout );
1278 /* Destroy translation tables */
1279 p_vout->pf_end( p_vout );
1281 /* Release the change lock */
1282 vlc_mutex_unlock( &p_vout->change_lock );
1285 /*****************************************************************************
1286 * DestroyThread: thread destruction
1287 *****************************************************************************
1288 * This function is called when the thread ends. It frees all ressources
1289 * allocated by CreateThread. Status is available at this stage.
1290 *****************************************************************************/
1291 static void DestroyThread( vout_thread_t *p_vout )
1293 /* Destroy the locks */
1294 vlc_mutex_destroy( &p_vout->picture_lock );
1295 vlc_mutex_destroy( &p_vout->change_lock );
1296 vlc_mutex_destroy( &p_vout->vfilter_lock );
1298 /* Release the module */
1299 if( p_vout && p_vout->p_module )
1301 module_Unneed( p_vout, p_vout->p_module );
1305 /* following functions are local */
1307 static int ReduceHeight( int i_ratio )
1309 int i_dummy = VOUT_ASPECT_FACTOR;
1317 /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1318 while( !(i_ratio & 1) && !(i_dummy & 1) )
1325 while( !(i_ratio % 3) && !(i_dummy % 3) )
1332 while( !(i_ratio % 5) && !(i_dummy % 5) )
1342 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1344 unsigned int i_pgcd = ReduceHeight( i_aspect );
1345 *i_aspect_x = i_aspect / i_pgcd;
1346 *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1349 /*****************************************************************************
1350 * BinaryLog: computes the base 2 log of a binary value
1351 *****************************************************************************
1352 * This functions is used by MaskToShift, to get a bit index from a binary
1354 *****************************************************************************/
1355 static int BinaryLog( uint32_t i )
1359 if( i == 0 ) return -31337;
1361 if( i & 0xffff0000 ) i_log += 16;
1362 if( i & 0xff00ff00 ) i_log += 8;
1363 if( i & 0xf0f0f0f0 ) i_log += 4;
1364 if( i & 0xcccccccc ) i_log += 2;
1365 if( i & 0xaaaaaaaa ) i_log += 1;
1370 /*****************************************************************************
1371 * MaskToShift: transform a color mask into right and left shifts
1372 *****************************************************************************
1373 * This function is used for obtaining color shifts from masks.
1374 *****************************************************************************/
1375 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1377 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
1381 *pi_left = *pi_right = 0;
1386 i_low = i_high = i_mask;
1388 i_low &= - (int32_t)i_low; /* lower bit of the mask */
1389 i_high += i_low; /* higher bit of the mask */
1391 /* Transform bits into an index. Also deal with i_high overflow, which
1392 * is faster than changing the BinaryLog code to handle 64 bit integers. */
1393 i_low = BinaryLog (i_low);
1394 i_high = i_high ? BinaryLog (i_high) : 32;
1396 /* Update pointers and return */
1398 *pi_right = (8 - i_high + i_low);
1401 /*****************************************************************************
1402 * vout_VarCallback: generic callback for intf variables
1403 *****************************************************************************/
1404 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1405 vlc_value_t oldval, vlc_value_t newval,
1408 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1410 (void)psz_variable; (void)newval; (void)oldval; (void)p_data;
1411 val.b_bool = VLC_TRUE;
1412 var_Set( p_vout, "intf-change", val );
1416 /*****************************************************************************
1417 * Helper thread for object variables callbacks.
1418 * Only used to avoid deadlocks when using the video embedded mode.
1419 *****************************************************************************/
1420 typedef struct suxor_thread_t
1423 input_thread_t *p_input;
1427 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1431 vlc_thread_ready( p_this );
1433 /* Now restart current video stream */
1434 var_Get( p_this->p_input, "video-es", &val );
1435 if( val.i_int >= 0 )
1438 val_es.i_int = -VIDEO_ES;
1439 var_Set( p_this->p_input, "video-es", val_es );
1440 var_Set( p_this->p_input, "video-es", val );
1443 vlc_object_release( p_this->p_input );
1446 CloseHandle( p_this->thread_id );
1449 vlc_object_destroy( p_this );
1452 /*****************************************************************************
1453 * object variables callbacks: a bunch of object variables are used by the
1454 * interfaces to interact with the vout.
1455 *****************************************************************************/
1456 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1457 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1459 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1460 input_thread_t *p_input;
1463 char *psz_mode = newval.psz_string;
1464 char *psz_filter, *psz_deinterlace = NULL;
1465 (void)psz_cmd; (void)oldval; (void)p_data;
1467 var_Get( p_vout, "vout-filter", &val );
1468 psz_filter = val.psz_string;
1469 if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1471 if( !psz_mode || !*psz_mode )
1473 if( psz_deinterlace )
1475 char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1476 if( psz_src[0] == ':' ) psz_src++;
1477 memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1480 else if( !psz_deinterlace )
1482 psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1483 sizeof(":deinterlace") );
1484 if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1485 strcat( psz_filter, "deinterlace" );
1488 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1490 if( !p_input ) return VLC_EGENERIC;
1492 if( psz_mode && *psz_mode )
1494 /* Modify input as well because the vout might have to be restarted */
1495 val.psz_string = psz_mode;
1496 var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1497 var_Set( p_input, "deinterlace-mode", val );
1499 vlc_object_release( p_input );
1501 val.b_bool = VLC_TRUE;
1502 var_Set( p_vout, "intf-change", val );
1504 val.psz_string = psz_filter;
1505 var_Set( p_vout, "vout-filter", val );
1506 if( psz_filter ) free( psz_filter );
1511 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1512 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1514 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1515 input_thread_t *p_input;
1517 (void)psz_cmd; (void)oldval; (void)p_data;
1519 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1523 msg_Err( p_vout, "Input not found" );
1524 return( VLC_EGENERIC );
1527 val.b_bool = VLC_TRUE;
1528 var_Set( p_vout, "intf-change", val );
1530 /* Modify input as well because the vout might have to be restarted */
1531 val.psz_string = newval.psz_string;
1532 var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1534 var_Set( p_input, "vout-filter", val );
1536 /* Now restart current video stream */
1537 var_Get( p_input, "video-es", &val );
1538 if( val.i_int >= 0 )
1540 suxor_thread_t *p_suxor =
1541 vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1542 p_suxor->p_input = p_input;
1543 p_vout->b_filter_change = VLC_TRUE;
1544 vlc_object_yield( p_input );
1545 vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1546 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1549 vlc_object_release( p_input );
1554 /*****************************************************************************
1555 * Video Filter2 stuff
1556 *****************************************************************************/
1557 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1560 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1562 struct config_chain_t *p_cfg =
1563 p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1564 config_ChainDestroy( p_cfg );
1565 if( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] )
1567 free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1568 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
1571 p_vout->i_vfilters_cfg = 0;
1572 if( psz_vfilters && *psz_vfilters )
1574 char *psz_parser = psz_vfilters;
1576 while( psz_parser && *psz_parser )
1578 psz_parser = config_ChainCreate(
1579 &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1580 &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1582 msg_Dbg( p_vout, "adding vfilter: %s",
1583 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1584 p_vout->i_vfilters_cfg++;
1585 if( psz_parser && *psz_parser )
1587 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1590 "maximum number of video filters reached. \"%s\" discarded",
1600 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1601 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1603 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1604 (void)psz_cmd; (void)oldval; (void)p_data;
1606 vlc_mutex_lock( &p_vout->vfilter_lock );
1607 ParseVideoFilter2Chain( p_vout, newval.psz_string );
1608 p_vout->b_vfilter_change = VLC_TRUE;
1609 vlc_mutex_unlock( &p_vout->vfilter_lock );
1614 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1617 for( i = 0; i < p_vout->i_vfilters; i++ )
1619 vlc_object_detach( p_vout->pp_vfilters[i] );
1620 if( p_vout->pp_vfilters[i]->p_module )
1622 module_Unneed( p_vout->pp_vfilters[i],
1623 p_vout->pp_vfilters[i]->p_module );
1626 free( p_vout->pp_vfilters[i]->p_owner );
1627 vlc_object_destroy( p_vout->pp_vfilters[i] );
1629 p_vout->i_vfilters = 0;