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 *****************************************************************************/
38 #include <stdlib.h> /* free() */
42 #ifdef HAVE_SYS_TIMES_H
43 # include <sys/times.h>
47 #include <vlc_playlist.h>
49 #include <vlc_filter.h>
52 #if defined( __APPLE__ )
53 /* Include darwin_specific.h here if needed */
56 /** FIXME This is quite ugly but needed while we don't have counters
58 #include "input/input_internal.h"
60 #include "modules/modules.h"
62 /*****************************************************************************
64 *****************************************************************************/
65 static int InitThread ( vout_thread_t * );
66 static void RunThread ( vout_thread_t * );
67 static void ErrorThread ( vout_thread_t * );
68 static void EndThread ( vout_thread_t * );
69 static void DestroyThread ( vout_thread_t * );
71 static void AspectRatio ( int, int *, int * );
72 static int BinaryLog ( uint32_t );
73 static void MaskToShift ( int *, int *, uint32_t );
75 static void vout_Destructor ( vlc_object_t * p_this );
77 /* Object variables callbacks */
78 static int DeinterlaceCallback( vlc_object_t *, char const *,
79 vlc_value_t, vlc_value_t, void * );
80 static int FilterCallback( vlc_object_t *, char const *,
81 vlc_value_t, vlc_value_t, void * );
82 static int VideoFilter2Callback( vlc_object_t *, char const *,
83 vlc_value_t, vlc_value_t, void * );
85 /* From vout_intf.c */
86 int vout_Snapshot( vout_thread_t *, picture_t * );
88 /* Video filter2 parsing */
89 static int ParseVideoFilter2Chain( vout_thread_t *, char * );
90 static void RemoveVideoFilters2( vout_thread_t *p_vout );
92 /* Display media title in OSD */
93 static void DisplayTitleOnOSD( vout_thread_t *p_vout );
95 /*****************************************************************************
96 * Video Filter2 functions
97 *****************************************************************************/
98 struct filter_owner_sys_t
100 vout_thread_t *p_vout;
103 static picture_t *video_new_buffer_filter( filter_t *p_filter )
105 picture_t *p_picture;
106 vout_thread_t *p_vout = p_filter->p_owner->p_vout;
108 p_picture = vout_CreatePicture( p_vout, 0, 0, 0 );
113 static void video_del_buffer_filter( filter_t *p_filter, picture_t *p_pic )
115 vout_DestroyPicture( p_filter->p_owner->p_vout, p_pic );
118 /*****************************************************************************
119 * vout_Request: find a video output thread, create one, or destroy one.
120 *****************************************************************************
121 * This function looks for a video output thread matching the current
122 * properties. If not found, it spawns a new one.
123 *****************************************************************************/
124 vout_thread_t *__vout_Request( vlc_object_t *p_this, vout_thread_t *p_vout,
125 video_format_t *p_fmt )
129 /* Reattach video output to playlist before bailing out */
132 spu_Attach( p_vout->p_spu, p_this, VLC_FALSE );
133 vlc_object_detach( p_vout );
134 vlc_object_attach( p_vout, p_this->p_libvlc );
139 /* If a video output was provided, lock it, otherwise look for one. */
142 vlc_object_yield( p_vout );
146 p_vout = vlc_object_find( p_this, VLC_OBJECT_VOUT, FIND_CHILD );
150 p_vout = vlc_object_find( p_this->p_libvlc,
151 VLC_OBJECT_VOUT, FIND_CHILD );
152 /* only first children of p_input for unused vout */
153 if( p_vout && p_vout->p_parent != VLC_OBJECT(p_this->p_libvlc) )
155 vlc_object_release( p_vout );
159 vlc_object_detach( p_vout ); /* Remove it from the GC */
163 /* If we now have a video output, check it has the right properties */
166 char *psz_filter_chain;
169 /* We don't directly check for the "vout-filter" variable for obvious
170 * performance reasons. */
171 if( p_vout->b_filter_change )
173 var_Get( p_vout, "vout-filter", &val );
174 psz_filter_chain = val.psz_string;
176 if( psz_filter_chain && !*psz_filter_chain )
178 free( psz_filter_chain );
179 psz_filter_chain = NULL;
181 if( p_vout->psz_filter_chain && !*p_vout->psz_filter_chain )
183 free( p_vout->psz_filter_chain );
184 p_vout->psz_filter_chain = NULL;
187 if( !psz_filter_chain && !p_vout->psz_filter_chain )
189 p_vout->b_filter_change = VLC_FALSE;
192 free( psz_filter_chain );
195 if( ( p_vout->fmt_render.i_width != p_fmt->i_width ) ||
196 ( p_vout->fmt_render.i_height != p_fmt->i_height ) ||
197 ( p_vout->fmt_render.i_aspect != p_fmt->i_aspect ) ||
198 p_vout->b_filter_change )
200 /* We are not interested in this format, close this vout */
201 vlc_object_release( p_vout );
202 vout_Destroy( p_vout );
207 /* This video output is cool! Hijack it. */
208 spu_Attach( p_vout->p_spu, p_this, VLC_TRUE );
209 vlc_object_attach( p_vout, p_this );
210 if( p_vout->b_title_show )
211 DisplayTitleOnOSD( p_vout );
212 vlc_object_release( p_vout );
218 msg_Dbg( p_this, "no usable vout present, spawning one" );
220 p_vout = vout_Create( p_this, p_fmt );
226 /*****************************************************************************
227 * vout_Create: creates a new video output thread
228 *****************************************************************************
229 * This function creates a new video output thread, and returns a pointer
230 * to its description. On error, it returns NULL.
231 *****************************************************************************/
232 vout_thread_t * __vout_Create( vlc_object_t *p_parent, video_format_t *p_fmt )
234 vout_thread_t * p_vout; /* thread descriptor */
235 input_thread_t * p_input_thread;
236 int i_index; /* loop variable */
237 vlc_value_t val, text;
239 unsigned int i_width = p_fmt->i_width;
240 unsigned int i_height = p_fmt->i_height;
241 vlc_fourcc_t i_chroma = p_fmt->i_chroma;
242 unsigned int i_aspect = p_fmt->i_aspect;
244 config_chain_t *p_cfg;
248 /* Allocate descriptor */
249 p_vout = vlc_object_create( p_parent, VLC_OBJECT_VOUT );
252 msg_Err( p_parent, "out of memory" );
256 /* Initialize pictures - translation tables and functions
257 * will be initialized later in InitThread */
258 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++)
260 p_vout->p_picture[i_index].pf_lock = NULL;
261 p_vout->p_picture[i_index].pf_unlock = NULL;
262 p_vout->p_picture[i_index].i_status = FREE_PICTURE;
263 p_vout->p_picture[i_index].i_type = EMPTY_PICTURE;
264 p_vout->p_picture[i_index].b_slow = 0;
267 /* No images in the heap */
268 p_vout->i_heap_size = 0;
270 /* Initialize the rendering heap */
271 I_RENDERPICTURES = 0;
273 vlc_ureduce( &p_fmt->i_sar_num, &p_fmt->i_sar_den,
274 p_fmt->i_sar_num, p_fmt->i_sar_den, 50000 );
275 p_vout->fmt_render = *p_fmt; /* FIXME palette */
276 p_vout->fmt_in = *p_fmt; /* FIXME palette */
278 p_vout->render.i_width = i_width;
279 p_vout->render.i_height = i_height;
280 p_vout->render.i_chroma = i_chroma;
281 p_vout->render.i_aspect = i_aspect;
283 p_vout->render.i_rmask = 0;
284 p_vout->render.i_gmask = 0;
285 p_vout->render.i_bmask = 0;
287 p_vout->render.i_last_used_pic = -1;
288 p_vout->render.b_allow_modify_pics = 1;
290 /* Zero the output heap */
291 I_OUTPUTPICTURES = 0;
292 p_vout->output.i_width = 0;
293 p_vout->output.i_height = 0;
294 p_vout->output.i_chroma = 0;
295 p_vout->output.i_aspect = 0;
297 p_vout->output.i_rmask = 0;
298 p_vout->output.i_gmask = 0;
299 p_vout->output.i_bmask = 0;
301 /* Initialize misc stuff */
302 p_vout->i_changes = 0;
304 p_vout->b_grayscale = 0;
306 p_vout->b_interface = 0;
308 p_vout->b_fullscreen = 0;
309 p_vout->i_alignment = 0;
310 p_vout->render_time = 10;
311 p_vout->c_fps_samples = 0;
312 p_vout->b_filter_change = 0;
313 p_vout->pf_control = 0;
314 p_vout->p_parent_intf = 0;
315 p_vout->i_par_num = p_vout->i_par_den = 1;
317 /* Initialize locks */
318 vlc_mutex_init( p_vout, &p_vout->picture_lock );
319 vlc_mutex_init( p_vout, &p_vout->change_lock );
320 vlc_mutex_init( p_vout, &p_vout->vfilter_lock );
322 /* Mouse coordinates */
323 var_Create( p_vout, "mouse-x", VLC_VAR_INTEGER );
324 var_Create( p_vout, "mouse-y", VLC_VAR_INTEGER );
325 var_Create( p_vout, "mouse-button-down", VLC_VAR_INTEGER );
326 var_Create( p_vout, "mouse-moved", VLC_VAR_BOOL );
327 var_Create( p_vout, "mouse-clicked", VLC_VAR_INTEGER );
329 /* Initialize subpicture unit */
330 p_vout->p_spu = spu_Create( p_vout );
331 spu_Attach( p_vout->p_spu, p_parent, VLC_TRUE );
333 /* Attach the new object now so we can use var inheritance below */
334 vlc_object_attach( p_vout, p_parent );
336 spu_Init( p_vout->p_spu );
338 /* Take care of some "interface/control" related initialisations */
339 vout_IntfInit( p_vout );
341 /* If the parent is not a VOUT object, that means we are at the start of
342 * the video output pipe */
343 if( p_parent->i_object_type != VLC_OBJECT_VOUT )
345 /* Look for the default filter configuration */
346 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
347 var_Get( p_vout, "vout-filter", &val );
348 p_vout->psz_filter_chain = val.psz_string;
350 /* Apply video filter2 objects on the first vout */
351 var_Create( p_vout, "video-filter",
352 VLC_VAR_STRING | VLC_VAR_DOINHERIT );
353 var_Get( p_vout, "video-filter", &val );
354 ParseVideoFilter2Chain( p_vout, val.psz_string );
355 free( val.psz_string );
359 /* continue the parent's filter chain */
362 /* Ugly hack to jump to our configuration chain */
363 p_vout->psz_filter_chain
364 = ((vout_thread_t *)p_parent)->psz_filter_chain;
365 p_vout->psz_filter_chain
366 = config_ChainCreate( &psz_tmp, &p_cfg, p_vout->psz_filter_chain );
367 config_ChainDestroy( p_cfg );
370 /* Create a video filter2 var ... but don't inherit values */
371 var_Create( p_vout, "video-filter", VLC_VAR_STRING );
372 ParseVideoFilter2Chain( p_vout, NULL );
375 var_AddCallback( p_vout, "video-filter", VideoFilter2Callback, NULL );
376 p_vout->b_vfilter_change = VLC_TRUE;
377 p_vout->i_vfilters = 0;
379 /* Choose the video output module */
380 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
382 var_Create( p_vout, "vout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
383 var_Get( p_vout, "vout", &val );
384 psz_parser = val.psz_string;
388 psz_parser = strdup( p_vout->psz_filter_chain );
391 /* Create the vout thread */
392 config_ChainCreate( &psz_name, &p_cfg, psz_parser );
394 p_vout->p_cfg = p_cfg;
395 p_vout->p_module = module_Need( p_vout,
396 ( p_vout->psz_filter_chain && *p_vout->psz_filter_chain ) ?
397 "video filter" : "video output", psz_name, p_vout->psz_filter_chain && *p_vout->psz_filter_chain );
400 if( p_vout->p_module == NULL )
402 msg_Err( p_vout, "no suitable vout module" );
403 vlc_object_detach( p_vout );
404 vlc_object_release( p_vout );
408 /* Create a few object variables for interface interaction */
409 var_Create( p_vout, "deinterlace", VLC_VAR_STRING | VLC_VAR_HASCHOICE );
410 text.psz_string = _("Deinterlace");
411 var_Change( p_vout, "deinterlace", VLC_VAR_SETTEXT, &text, NULL );
412 val.psz_string = (char *)""; text.psz_string = _("Disable");
413 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
414 val.psz_string = (char *)"discard"; text.psz_string = _("Discard");
415 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
416 val.psz_string = (char *)"blend"; text.psz_string = _("Blend");
417 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
418 val.psz_string = (char *)"mean"; text.psz_string = _("Mean");
419 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
420 val.psz_string = (char *)"bob"; text.psz_string = _("Bob");
421 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
422 val.psz_string = (char *)"linear"; text.psz_string = _("Linear");
423 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
424 val.psz_string = (char *)"x"; text.psz_string = (char *)"X";
425 var_Change( p_vout, "deinterlace", VLC_VAR_ADDCHOICE, &val, &text );
427 if( var_Get( p_vout, "deinterlace-mode", &val ) == VLC_SUCCESS )
429 var_Set( p_vout, "deinterlace", val );
430 free( val.psz_string );
432 var_AddCallback( p_vout, "deinterlace", DeinterlaceCallback, NULL );
434 var_Create( p_vout, "vout-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
435 text.psz_string = _("Filters");
436 var_Change( p_vout, "vout-filter", VLC_VAR_SETTEXT, &text, NULL );
437 var_AddCallback( p_vout, "vout-filter", FilterCallback, NULL );
439 /* Calculate delay created by internal caching */
440 p_input_thread = (input_thread_t *)vlc_object_find( p_vout,
441 VLC_OBJECT_INPUT, FIND_ANYWHERE );
444 p_vout->i_pts_delay = p_input_thread->i_pts_delay;
445 vlc_object_release( p_input_thread );
449 p_vout->i_pts_delay = DEFAULT_PTS_DELAY;
452 if( vlc_thread_create( p_vout, "video output", RunThread,
453 VLC_THREAD_PRIORITY_OUTPUT, VLC_TRUE ) )
455 msg_Err( p_vout, "out of memory" );
456 module_Unneed( p_vout, p_vout->p_module );
457 vlc_object_release( p_vout );
461 if( p_vout->b_error )
463 msg_Err( p_vout, "video output creation failed" );
465 /* Make sure the thread is destroyed */
466 vlc_object_release( p_vout );
470 vlc_object_set_destructor( p_vout, vout_Destructor );
475 /*****************************************************************************
476 * vout_Destroy: destroys a previously created video output
477 *****************************************************************************
478 * Destroy a terminated thread.
479 * The function will request a destruction of the specified thread. If pi_error
480 * is NULL, it will return once the thread is destroyed. Else, it will be
481 * update using one of the THREAD_* constants.
482 *****************************************************************************/
483 void vout_Destroy( vout_thread_t *p_vout )
485 /* XXX: should go in the destructor */
486 var_Destroy( p_vout, "intf-change" );
488 vlc_object_release( p_vout );
491 static void vout_Destructor( vlc_object_t * p_this )
493 vout_thread_t *p_vout = (vout_thread_t *)p_this;
495 free( p_vout->psz_filter_chain );
497 config_ChainDestroy( p_vout->p_cfg );
500 vout_thread_t *p_another_vout;
501 playlist_t *p_playlist = pl_Yield( p_vout );
503 /* This is a dirty hack for mostly Linux, where there is no way to get the GUI
504 back if you closed it while playing video. This is solved in Mac OS X,
505 where we have this novelty called menubar, that will always allow you access
506 to the applications main functionality. They should try that on linux sometime */
507 p_another_vout = vlc_object_find( p_this->p_libvlc,
508 VLC_OBJECT_VOUT, FIND_ANYWHERE );
509 if( p_another_vout == NULL )
512 val.b_bool = VLC_TRUE;
513 var_Set( p_playlist, "intf-show", val );
517 vlc_object_release( p_another_vout );
519 vlc_object_release( p_playlist );
523 /*****************************************************************************
524 * InitThread: initialize video output thread
525 *****************************************************************************
526 * This function is called from RunThread and performs the second step of the
527 * initialization. It returns 0 on success. Note that the thread's flag are not
528 * modified inside this function.
529 *****************************************************************************/
530 static int InitThread( vout_thread_t *p_vout )
532 int i, i_aspect_x, i_aspect_y;
534 vlc_mutex_lock( &p_vout->change_lock );
540 /* Initialize output method, it allocates direct buffers for us */
541 if( p_vout->pf_init( p_vout ) )
543 vlc_mutex_unlock( &p_vout->change_lock );
547 if( !I_OUTPUTPICTURES )
549 msg_Err( p_vout, "plugin was unable to allocate at least "
550 "one direct buffer" );
551 p_vout->pf_end( p_vout );
552 vlc_mutex_unlock( &p_vout->change_lock );
556 if( I_OUTPUTPICTURES > VOUT_MAX_PICTURES )
558 msg_Err( p_vout, "plugin allocated too many direct buffers, "
559 "our internal buffers must have overflown." );
560 p_vout->pf_end( p_vout );
561 vlc_mutex_unlock( &p_vout->change_lock );
565 msg_Dbg( p_vout, "got %i direct buffer(s)", I_OUTPUTPICTURES );
567 AspectRatio( p_vout->fmt_render.i_aspect, &i_aspect_x, &i_aspect_y );
569 msg_Dbg( p_vout, "picture in %ix%i (%i,%i,%ix%i), "
570 "chroma %4.4s, ar %i:%i, sar %i:%i",
571 p_vout->fmt_render.i_width, p_vout->fmt_render.i_height,
572 p_vout->fmt_render.i_x_offset, p_vout->fmt_render.i_y_offset,
573 p_vout->fmt_render.i_visible_width,
574 p_vout->fmt_render.i_visible_height,
575 (char*)&p_vout->fmt_render.i_chroma,
576 i_aspect_x, i_aspect_y,
577 p_vout->fmt_render.i_sar_num, p_vout->fmt_render.i_sar_den );
579 AspectRatio( p_vout->fmt_in.i_aspect, &i_aspect_x, &i_aspect_y );
581 msg_Dbg( p_vout, "picture user %ix%i (%i,%i,%ix%i), "
582 "chroma %4.4s, ar %i:%i, sar %i:%i",
583 p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
584 p_vout->fmt_in.i_x_offset, p_vout->fmt_in.i_y_offset,
585 p_vout->fmt_in.i_visible_width,
586 p_vout->fmt_in.i_visible_height,
587 (char*)&p_vout->fmt_in.i_chroma,
588 i_aspect_x, i_aspect_y,
589 p_vout->fmt_in.i_sar_num, p_vout->fmt_in.i_sar_den );
591 if( !p_vout->fmt_out.i_width || !p_vout->fmt_out.i_height )
593 p_vout->fmt_out.i_width = p_vout->fmt_out.i_visible_width =
594 p_vout->output.i_width;
595 p_vout->fmt_out.i_height = p_vout->fmt_out.i_visible_height =
596 p_vout->output.i_height;
597 p_vout->fmt_out.i_x_offset = p_vout->fmt_out.i_y_offset = 0;
599 p_vout->fmt_out.i_aspect = p_vout->output.i_aspect;
600 p_vout->fmt_out.i_chroma = p_vout->output.i_chroma;
602 if( !p_vout->fmt_out.i_sar_num || !p_vout->fmt_out.i_sar_num )
604 p_vout->fmt_out.i_sar_num = p_vout->fmt_out.i_aspect *
605 p_vout->fmt_out.i_height;
606 p_vout->fmt_out.i_sar_den = VOUT_ASPECT_FACTOR *
607 p_vout->fmt_out.i_width;
610 vlc_ureduce( &p_vout->fmt_out.i_sar_num, &p_vout->fmt_out.i_sar_den,
611 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den, 0 );
613 AspectRatio( p_vout->fmt_out.i_aspect, &i_aspect_x, &i_aspect_y );
615 msg_Dbg( p_vout, "picture out %ix%i (%i,%i,%ix%i), "
616 "chroma %4.4s, ar %i:%i, sar %i:%i",
617 p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
618 p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset,
619 p_vout->fmt_out.i_visible_width,
620 p_vout->fmt_out.i_visible_height,
621 (char*)&p_vout->fmt_out.i_chroma,
622 i_aspect_x, i_aspect_y,
623 p_vout->fmt_out.i_sar_num, p_vout->fmt_out.i_sar_den );
625 /* Calculate shifts from system-updated masks */
626 MaskToShift( &p_vout->output.i_lrshift, &p_vout->output.i_rrshift,
627 p_vout->output.i_rmask );
628 MaskToShift( &p_vout->output.i_lgshift, &p_vout->output.i_rgshift,
629 p_vout->output.i_gmask );
630 MaskToShift( &p_vout->output.i_lbshift, &p_vout->output.i_rbshift,
631 p_vout->output.i_bmask );
633 /* Check whether we managed to create direct buffers similar to
634 * the render buffers, ie same size and chroma */
635 if( ( p_vout->output.i_width == p_vout->render.i_width )
636 && ( p_vout->output.i_height == p_vout->render.i_height )
637 && ( vout_ChromaCmp( p_vout->output.i_chroma, p_vout->render.i_chroma ) ) )
639 /* Cool ! We have direct buffers, we can ask the decoder to
640 * directly decode into them ! Map the first render buffers to
641 * the first direct buffers, but keep the first direct buffer
642 * for memcpy operations */
643 p_vout->b_direct = 1;
645 for( i = 1; i < VOUT_MAX_PICTURES; i++ )
647 if( p_vout->p_picture[ i ].i_type != DIRECT_PICTURE &&
648 I_RENDERPICTURES >= VOUT_MIN_DIRECT_PICTURES - 1 &&
649 p_vout->p_picture[ i - 1 ].i_type == DIRECT_PICTURE )
651 /* We have enough direct buffers so there's no need to
652 * try to use system memory buffers. */
655 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
659 msg_Dbg( p_vout, "direct render, mapping "
660 "render pictures 0-%i to system pictures 1-%i",
661 VOUT_MAX_PICTURES - 2, VOUT_MAX_PICTURES - 1 );
665 /* Rats... Something is wrong here, we could not find an output
666 * plugin able to directly render what we decode. See if we can
667 * find a chroma plugin to do the conversion */
668 p_vout->b_direct = 0;
670 /* Choose the best module */
671 p_vout->chroma.p_module = module_Need( p_vout, "chroma", NULL, 0 );
673 if( p_vout->chroma.p_module == NULL )
675 msg_Err( p_vout, "no chroma module for %4.4s to %4.4s",
676 (char*)&p_vout->render.i_chroma,
677 (char*)&p_vout->output.i_chroma );
678 p_vout->pf_end( p_vout );
679 vlc_mutex_unlock( &p_vout->change_lock );
683 msg_Dbg( p_vout, "indirect render, mapping "
684 "render pictures 0-%i to system pictures %i-%i",
685 VOUT_MAX_PICTURES - 1, I_OUTPUTPICTURES,
686 I_OUTPUTPICTURES + VOUT_MAX_PICTURES - 1 );
688 /* Append render buffers after the direct buffers */
689 for( i = I_OUTPUTPICTURES; i < 2 * VOUT_MAX_PICTURES; i++ )
691 PP_RENDERPICTURE[ I_RENDERPICTURES ] = &p_vout->p_picture[ i ];
694 /* Check if we have enough render pictures */
695 if( I_RENDERPICTURES == VOUT_MAX_PICTURES )
700 /* Link pictures back to their heap */
701 for( i = 0 ; i < I_RENDERPICTURES ; i++ )
703 PP_RENDERPICTURE[ i ]->p_heap = &p_vout->render;
706 for( i = 0 ; i < I_OUTPUTPICTURES ; i++ )
708 PP_OUTPUTPICTURE[ i ]->p_heap = &p_vout->output;
711 /* XXX XXX mark thread ready */
715 /*****************************************************************************
716 * RunThread: video output thread
717 *****************************************************************************
718 * Video output thread. This function does only returns when the thread is
719 * terminated. It handles the pictures arriving in the video heap and the
720 * display device events.
721 *****************************************************************************/
722 static void RunThread( vout_thread_t *p_vout)
724 int i_index; /* index in heap */
725 int i_idle_loops = 0; /* loops without displaying a picture */
726 mtime_t current_date; /* current date */
727 mtime_t display_date; /* display date */
729 picture_t * p_picture; /* picture pointer */
730 picture_t * p_last_picture = NULL; /* last picture */
731 picture_t * p_directbuffer; /* direct buffer to display */
733 subpicture_t * p_subpic = NULL; /* subpicture pointer */
735 input_thread_t *p_input = NULL ; /* Parent input, if it exists */
738 vlc_bool_t b_drop_late;
740 int i_displayed = 0, i_lost = 0, i_loops = 0;
745 p_vout->b_error = InitThread( p_vout );
747 var_Create( p_vout, "drop-late-frames", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
748 var_Get( p_vout, "drop-late-frames", &val );
749 b_drop_late = val.b_bool;
751 /* signal the creation of the vout */
752 vlc_thread_ready( p_vout );
754 if( p_vout->b_error )
756 /* Destroy thread structures allocated by Create and InitThread */
757 DestroyThread( p_vout );
761 if( p_vout->b_title_show )
762 DisplayTitleOnOSD( p_vout );
765 * Main loop - it is not executed if an error occurred during
768 while( (!p_vout->b_die) && (!p_vout->b_error) )
770 /* Initialize loop variables */
773 current_date = mdate();
775 if( p_input && p_input->b_die )
777 vlc_object_release( p_input );
784 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
789 vlc_mutex_lock( &p_input->p->counters.counters_lock );
790 stats_UpdateInteger( p_vout, p_input->p->counters.p_lost_pictures,
792 stats_UpdateInteger( p_vout,
793 p_input->p->counters.p_displayed_pictures,
795 i_displayed = i_lost = 0;
796 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
800 if( !(p_vout->c_loops % VOUT_STATS_NB_LOOPS) )
802 msg_Dbg( p_vout, "picture heap: %d/%d",
803 I_RENDERPICTURES, p_vout->i_heap_size );
808 * Find the picture to display (the one with the earliest date).
809 * This operation does not need lock, since only READY_PICTUREs
811 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
813 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
814 && ( (p_picture == NULL) ||
815 (PP_RENDERPICTURE[i_index]->date < display_date) ) )
817 p_picture = PP_RENDERPICTURE[i_index];
818 display_date = p_picture->date;
824 /* If we met the last picture, parse again to see whether there is
825 * a more appropriate one. */
826 if( p_picture == p_last_picture )
828 for( i_index = 0; i_index < I_RENDERPICTURES; i_index++ )
830 if( (PP_RENDERPICTURE[i_index]->i_status == READY_PICTURE)
831 && (PP_RENDERPICTURE[i_index] != p_last_picture)
832 && ((p_picture == p_last_picture) ||
833 (PP_RENDERPICTURE[i_index]->date < display_date)) )
835 p_picture = PP_RENDERPICTURE[i_index];
836 display_date = p_picture->date;
841 /* If we found better than the last picture, destroy it */
842 if( p_last_picture && p_picture != p_last_picture )
844 vlc_mutex_lock( &p_vout->picture_lock );
845 if( p_last_picture->i_refcount )
847 p_last_picture->i_status = DISPLAYED_PICTURE;
851 p_last_picture->i_status = DESTROYED_PICTURE;
852 p_vout->i_heap_size--;
854 vlc_mutex_unlock( &p_vout->picture_lock );
855 p_last_picture = NULL;
858 /* Compute FPS rate */
859 p_vout->p_fps_sample[ p_vout->c_fps_samples++ % VOUT_FPS_SAMPLES ]
862 if( !p_picture->b_force &&
863 p_picture != p_last_picture &&
864 display_date < current_date + p_vout->render_time &&
867 /* Picture is late: it will be destroyed and the thread
868 * will directly choose the next picture */
869 vlc_mutex_lock( &p_vout->picture_lock );
870 if( p_picture->i_refcount )
872 /* Pretend we displayed the picture, but don't destroy
873 * it since the decoder might still need it. */
874 p_picture->i_status = DISPLAYED_PICTURE;
878 /* Destroy the picture without displaying it */
879 p_picture->i_status = DESTROYED_PICTURE;
880 p_vout->i_heap_size--;
882 msg_Warn( p_vout, "late picture skipped ("I64Fd")",
883 current_date - display_date );
885 vlc_mutex_unlock( &p_vout->picture_lock );
891 current_date + p_vout->i_pts_delay + VOUT_BOGUS_DELAY )
893 /* Picture is waaay too early: it will be destroyed */
894 vlc_mutex_lock( &p_vout->picture_lock );
895 if( p_picture->i_refcount )
897 /* Pretend we displayed the picture, but don't destroy
898 * it since the decoder might still need it. */
899 p_picture->i_status = DISPLAYED_PICTURE;
903 /* Destroy the picture without displaying it */
904 p_picture->i_status = DESTROYED_PICTURE;
905 p_vout->i_heap_size--;
908 msg_Warn( p_vout, "vout warning: early picture skipped "
909 "("I64Fd")", display_date - current_date
910 - p_vout->i_pts_delay );
911 vlc_mutex_unlock( &p_vout->picture_lock );
916 if( display_date > current_date + VOUT_DISPLAY_DELAY )
918 /* A picture is ready to be rendered, but its rendering date
919 * is far from the current one so the thread will perform an
920 * empty loop as if no picture were found. The picture state
925 else if( p_picture == p_last_picture )
927 /* We are asked to repeat the previous picture, but we first
928 * wait for a couple of idle loops */
929 if( i_idle_loops < 4 )
936 /* We set the display date to something high, otherwise
937 * we'll have lots of problems with late pictures */
938 display_date = current_date + p_vout->render_time;
943 if( p_picture == NULL )
948 /* Video Filter2 stuff */
949 if( p_vout->b_vfilter_change == VLC_TRUE )
952 vlc_mutex_lock( &p_vout->vfilter_lock );
953 RemoveVideoFilters2( p_vout );
954 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
956 filter_t *p_vfilter =
957 p_vout->pp_vfilters[p_vout->i_vfilters] =
958 vlc_object_create( p_vout, VLC_OBJECT_FILTER );
960 vlc_object_attach( p_vfilter, p_vout );
962 p_vfilter->pf_vout_buffer_new = video_new_buffer_filter;
963 p_vfilter->pf_vout_buffer_del = video_del_buffer_filter;
965 if( !p_vout->i_vfilters )
967 p_vfilter->fmt_in.video = p_vout->fmt_render;
971 p_vfilter->fmt_in.video = (p_vfilter-1)->fmt_out.video;
973 /* TODO: one day filters in the middle of the chain might
974 * have a different fmt_out.video than fmt_render ... */
975 p_vfilter->fmt_out.video = p_vout->fmt_render;
977 p_vfilter->p_cfg = p_vout->p_vfilters_cfg[i];
978 p_vfilter->p_module = module_Need( p_vfilter, "video filter2",
979 p_vout->psz_vfilters[i],
982 if( p_vfilter->p_module )
985 malloc( sizeof( filter_owner_sys_t ) );
986 p_vfilter->p_owner->p_vout = p_vout;
987 p_vout->i_vfilters++;
988 msg_Dbg( p_vout, "video filter found (%s)",
989 p_vout->psz_vfilters[i] );
993 msg_Err( p_vout, "no video filter found (%s)",
994 p_vout->psz_vfilters[i] );
995 vlc_object_detach( p_vfilter );
996 vlc_object_release( p_vfilter );
999 p_vout->b_vfilter_change = VLC_FALSE;
1000 vlc_mutex_unlock( &p_vout->vfilter_lock );
1006 for( i = 0; i < p_vout->i_vfilters; i++ )
1008 picture_t *p_old = p_picture;
1009 p_picture = p_vout->pp_vfilters[i]->pf_video_filter(
1010 p_vout->pp_vfilters[i], p_picture );
1015 /* FIXME: this is kind of wrong
1016 * if you have 2 or more vfilters and the 2nd breaks,
1017 * on the next loop the 1st one will be applied again */
1019 /* if p_old and p_picture are the same (ie the filter
1020 * worked on the old picture), then following code is
1021 * still alright since i_status gets changed back to
1022 * the right value */
1023 if( p_old->i_refcount )
1025 p_old->i_status = DISPLAYED_PICTURE;
1029 p_old->i_status = DESTROYED_PICTURE;
1031 p_picture->i_status = READY_PICTURE;
1035 if( p_picture && p_vout->b_snapshot )
1037 p_vout->b_snapshot = VLC_FALSE;
1038 vout_Snapshot( p_vout, p_picture );
1042 * Check for subpictures to display
1044 if( display_date > 0 )
1048 p_input = vlc_object_find( p_vout, VLC_OBJECT_INPUT,
1051 p_subpic = spu_SortSubpictures( p_vout->p_spu, display_date,
1052 p_input ? var_GetBool( p_input, "state" ) == PAUSE_S : VLC_FALSE );
1059 p_directbuffer = vout_RenderPicture( p_vout, p_picture, p_subpic );
1062 * Call the plugin-specific rendering method if there is one
1064 if( p_picture != NULL && p_directbuffer != NULL && p_vout->pf_render )
1066 /* Render the direct buffer returned by vout_RenderPicture */
1067 p_vout->pf_render( p_vout, p_directbuffer );
1073 if( display_date != 0 && p_directbuffer != NULL )
1075 mtime_t current_render_time = mdate() - current_date;
1076 /* if render time is very large we don't include it in the mean */
1077 if( current_render_time < p_vout->render_time +
1078 VOUT_DISPLAY_DELAY )
1080 /* Store render time using a sliding mean weighting to
1081 * current value in a 3 to 1 ratio*/
1082 p_vout->render_time *= 3;
1083 p_vout->render_time += current_render_time;
1084 p_vout->render_time >>= 2;
1088 /* Give back change lock */
1089 vlc_mutex_unlock( &p_vout->change_lock );
1091 /* Sleep a while or until a given date */
1092 if( display_date != 0 )
1094 /* If there are filters in the chain, better give them the picture
1096 if( !p_vout->psz_filter_chain || !*p_vout->psz_filter_chain )
1098 mwait( display_date - VOUT_MWAIT_TOLERANCE );
1103 msleep( VOUT_IDLE_SLEEP );
1106 /* On awakening, take back lock and send immediately picture
1108 vlc_mutex_lock( &p_vout->change_lock );
1111 * Display the previously rendered picture
1113 if( p_picture != NULL && p_directbuffer != NULL )
1115 /* Display the direct buffer returned by vout_RenderPicture */
1116 if( p_vout->pf_display )
1118 p_vout->pf_display( p_vout, p_directbuffer );
1121 /* Tell the vout this was the last picture and that it does not
1122 * need to be forced anymore. */
1123 p_last_picture = p_picture;
1124 p_last_picture->b_force = 0;
1127 if( p_picture != NULL )
1129 /* Reinitialize idle loop count */
1134 * Check events and manage thread
1136 if( p_vout->pf_manage && p_vout->pf_manage( p_vout ) )
1138 /* A fatal error occurred, and the thread must terminate
1139 * immediately, without displaying anything - setting b_error to 1
1140 * causes the immediate end of the main while() loop. */
1141 p_vout->b_error = 1;
1144 if( p_vout->i_changes & VOUT_SIZE_CHANGE )
1146 /* this must only happen when the vout plugin is incapable of
1147 * rescaling the picture itself. In this case we need to destroy
1148 * the current picture buffers and recreate new ones with the right
1152 p_vout->i_changes &= ~VOUT_SIZE_CHANGE;
1154 p_vout->pf_end( p_vout );
1155 for( i = 0; i < I_OUTPUTPICTURES; i++ )
1156 p_vout->p_picture[ i ].i_status = FREE_PICTURE;
1158 I_OUTPUTPICTURES = 0;
1159 if( p_vout->pf_init( p_vout ) )
1161 msg_Err( p_vout, "cannot resize display" );
1162 /* FIXME: pf_end will be called again in EndThread() */
1163 p_vout->b_error = 1;
1166 /* Need to reinitialise the chroma plugin */
1167 if( p_vout->chroma.p_module )
1169 if( p_vout->chroma.p_module->pf_deactivate )
1170 p_vout->chroma.p_module->pf_deactivate( VLC_OBJECT(p_vout) );
1171 p_vout->chroma.p_module->pf_activate( VLC_OBJECT(p_vout) );
1175 if( p_vout->i_changes & VOUT_PICTURE_BUFFERS_CHANGE )
1177 /* This happens when the picture buffers need to be recreated.
1178 * This is useful on multimonitor displays for instance.
1180 * Warning: This only works when the vout creates only 1 picture
1182 p_vout->i_changes &= ~VOUT_PICTURE_BUFFERS_CHANGE;
1184 if( !p_vout->b_direct )
1186 module_Unneed( p_vout, p_vout->chroma.p_module );
1189 vlc_mutex_lock( &p_vout->picture_lock );
1191 p_vout->pf_end( p_vout );
1193 I_OUTPUTPICTURES = I_RENDERPICTURES = 0;
1195 p_vout->b_error = InitThread( p_vout );
1197 vlc_mutex_unlock( &p_vout->picture_lock );
1203 vlc_object_release( p_input );
1207 * Error loop - wait until the thread destruction is requested
1209 if( p_vout->b_error )
1211 ErrorThread( p_vout );
1215 EndThread( p_vout );
1217 /* Destroy thread structures allocated by CreateThread */
1218 DestroyThread( p_vout );
1221 /*****************************************************************************
1222 * ErrorThread: RunThread() error loop
1223 *****************************************************************************
1224 * This function is called when an error occurred during thread main's loop.
1225 * The thread can still receive feed, but must be ready to terminate as soon
1227 *****************************************************************************/
1228 static void ErrorThread( vout_thread_t *p_vout )
1230 /* Wait until a `die' order */
1231 while( !p_vout->b_die )
1234 msleep( VOUT_IDLE_SLEEP );
1238 /*****************************************************************************
1239 * EndThread: thread destruction
1240 *****************************************************************************
1241 * This function is called when the thread ends after a sucessful
1242 * initialization. It frees all resources allocated by InitThread.
1243 *****************************************************************************/
1244 static void EndThread( vout_thread_t *p_vout )
1246 int i_index; /* index in heap */
1250 struct tms cpu_usage;
1251 times( &cpu_usage );
1253 msg_Dbg( p_vout, "cpu usage (user: %d, system: %d)",
1254 cpu_usage.tms_utime, cpu_usage.tms_stime );
1258 if( !p_vout->b_direct )
1260 module_Unneed( p_vout, p_vout->chroma.p_module );
1263 /* Destroy all remaining pictures */
1264 for( i_index = 0; i_index < 2 * VOUT_MAX_PICTURES + 1; i_index++ )
1266 if ( p_vout->p_picture[i_index].i_type == MEMORY_PICTURE )
1268 free( p_vout->p_picture[i_index].p_data_orig );
1272 /* Destroy subpicture unit */
1273 spu_Attach( p_vout->p_spu, VLC_OBJECT(p_vout), VLC_FALSE );
1274 spu_Destroy( p_vout->p_spu );
1276 /* Destroy the video filters2 */
1277 RemoveVideoFilters2( p_vout );
1279 /* Destroy translation tables */
1280 p_vout->pf_end( p_vout );
1282 /* Release the change lock */
1283 vlc_mutex_unlock( &p_vout->change_lock );
1286 /*****************************************************************************
1287 * DestroyThread: thread destruction
1288 *****************************************************************************
1289 * This function is called when the thread ends. It frees all ressources
1290 * allocated by CreateThread. Status is available at this stage.
1291 *****************************************************************************/
1292 static void DestroyThread( vout_thread_t *p_vout )
1294 /* Destroy the locks */
1295 vlc_mutex_destroy( &p_vout->picture_lock );
1296 vlc_mutex_destroy( &p_vout->change_lock );
1297 vlc_mutex_destroy( &p_vout->vfilter_lock );
1299 /* Release the module */
1300 if( p_vout && p_vout->p_module )
1302 module_Unneed( p_vout, p_vout->p_module );
1306 /* following functions are local */
1308 static int ReduceHeight( int i_ratio )
1310 int i_dummy = VOUT_ASPECT_FACTOR;
1318 /* VOUT_ASPECT_FACTOR is (2^7 * 3^3 * 5^3), we just check for 2, 3 and 5 */
1319 while( !(i_ratio & 1) && !(i_dummy & 1) )
1326 while( !(i_ratio % 3) && !(i_dummy % 3) )
1333 while( !(i_ratio % 5) && !(i_dummy % 5) )
1343 static void AspectRatio( int i_aspect, int *i_aspect_x, int *i_aspect_y )
1345 unsigned int i_pgcd = ReduceHeight( i_aspect );
1346 *i_aspect_x = i_aspect / i_pgcd;
1347 *i_aspect_y = VOUT_ASPECT_FACTOR / i_pgcd;
1350 /*****************************************************************************
1351 * BinaryLog: computes the base 2 log of a binary value
1352 *****************************************************************************
1353 * This functions is used by MaskToShift, to get a bit index from a binary
1355 *****************************************************************************/
1356 static int BinaryLog( uint32_t i )
1360 if( i == 0 ) return -31337;
1362 if( i & 0xffff0000 ) i_log += 16;
1363 if( i & 0xff00ff00 ) i_log += 8;
1364 if( i & 0xf0f0f0f0 ) i_log += 4;
1365 if( i & 0xcccccccc ) i_log += 2;
1366 if( i & 0xaaaaaaaa ) i_log += 1;
1371 /*****************************************************************************
1372 * MaskToShift: transform a color mask into right and left shifts
1373 *****************************************************************************
1374 * This function is used for obtaining color shifts from masks.
1375 *****************************************************************************/
1376 static void MaskToShift( int *pi_left, int *pi_right, uint32_t i_mask )
1378 uint32_t i_low, i_high; /* lower hand higher bits of the mask */
1382 *pi_left = *pi_right = 0;
1387 i_low = i_high = i_mask;
1389 i_low &= - (int32_t)i_low; /* lower bit of the mask */
1390 i_high += i_low; /* higher bit of the mask */
1392 /* Transform bits into an index. Also deal with i_high overflow, which
1393 * is faster than changing the BinaryLog code to handle 64 bit integers. */
1394 i_low = BinaryLog (i_low);
1395 i_high = i_high ? BinaryLog (i_high) : 32;
1397 /* Update pointers and return */
1399 *pi_right = (8 - i_high + i_low);
1402 /*****************************************************************************
1403 * vout_VarCallback: generic callback for intf variables
1404 *****************************************************************************/
1405 int vout_VarCallback( vlc_object_t * p_this, const char * psz_variable,
1406 vlc_value_t oldval, vlc_value_t newval,
1409 vout_thread_t * p_vout = (vout_thread_t *)p_this;
1411 (void)psz_variable; (void)newval; (void)oldval; (void)p_data;
1412 val.b_bool = VLC_TRUE;
1413 var_Set( p_vout, "intf-change", val );
1417 /*****************************************************************************
1418 * Helper thread for object variables callbacks.
1419 * Only used to avoid deadlocks when using the video embedded mode.
1420 *****************************************************************************/
1421 typedef struct suxor_thread_t
1424 input_thread_t *p_input;
1428 static void SuxorRestartVideoES( suxor_thread_t *p_this )
1432 vlc_thread_ready( p_this );
1434 /* Now restart current video stream */
1435 var_Get( p_this->p_input, "video-es", &val );
1436 if( val.i_int >= 0 )
1439 val_es.i_int = -VIDEO_ES;
1440 var_Set( p_this->p_input, "video-es", val_es );
1441 var_Set( p_this->p_input, "video-es", val );
1444 vlc_object_release( p_this->p_input );
1446 vlc_object_release( p_this );
1449 /*****************************************************************************
1450 * object variables callbacks: a bunch of object variables are used by the
1451 * interfaces to interact with the vout.
1452 *****************************************************************************/
1453 static int DeinterlaceCallback( vlc_object_t *p_this, char const *psz_cmd,
1454 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1456 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1457 input_thread_t *p_input;
1460 char *psz_mode = newval.psz_string;
1461 char *psz_filter, *psz_deinterlace = NULL;
1462 (void)psz_cmd; (void)oldval; (void)p_data;
1464 var_Get( p_vout, "vout-filter", &val );
1465 psz_filter = val.psz_string;
1466 if( psz_filter ) psz_deinterlace = strstr( psz_filter, "deinterlace" );
1468 if( !psz_mode || !*psz_mode )
1470 if( psz_deinterlace )
1472 char *psz_src = psz_deinterlace + sizeof("deinterlace") - 1;
1473 if( psz_src[0] == ':' ) psz_src++;
1474 memmove( psz_deinterlace, psz_src, strlen(psz_src) + 1 );
1477 else if( !psz_deinterlace )
1479 psz_filter = realloc( psz_filter, strlen( psz_filter ) +
1480 sizeof(":deinterlace") );
1481 if( psz_filter && *psz_filter ) strcat( psz_filter, ":" );
1482 strcat( psz_filter, "deinterlace" );
1485 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1487 if( !p_input ) return VLC_EGENERIC;
1489 if( psz_mode && *psz_mode )
1491 /* Modify input as well because the vout might have to be restarted */
1492 val.psz_string = psz_mode;
1493 var_Create( p_input, "deinterlace-mode", VLC_VAR_STRING );
1494 var_Set( p_input, "deinterlace-mode", val );
1496 vlc_object_release( p_input );
1498 val.b_bool = VLC_TRUE;
1499 var_Set( p_vout, "intf-change", val );
1501 val.psz_string = psz_filter;
1502 var_Set( p_vout, "vout-filter", val );
1508 static int FilterCallback( vlc_object_t *p_this, char const *psz_cmd,
1509 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1511 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1512 input_thread_t *p_input;
1514 (void)psz_cmd; (void)oldval; (void)p_data;
1516 p_input = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT,
1520 msg_Err( p_vout, "Input not found" );
1521 return( VLC_EGENERIC );
1524 val.b_bool = VLC_TRUE;
1525 var_Set( p_vout, "intf-change", val );
1527 /* Modify input as well because the vout might have to be restarted */
1528 val.psz_string = newval.psz_string;
1529 var_Create( p_input, "vout-filter", VLC_VAR_STRING );
1531 var_Set( p_input, "vout-filter", val );
1533 /* Now restart current video stream */
1534 var_Get( p_input, "video-es", &val );
1535 if( val.i_int >= 0 )
1537 suxor_thread_t *p_suxor =
1538 vlc_object_create( p_vout, sizeof(suxor_thread_t) );
1539 p_suxor->p_input = p_input;
1540 p_vout->b_filter_change = VLC_TRUE;
1541 vlc_object_yield( p_input );
1542 vlc_thread_create( p_suxor, "suxor", SuxorRestartVideoES,
1543 VLC_THREAD_PRIORITY_LOW, VLC_FALSE );
1546 vlc_object_release( p_input );
1551 /*****************************************************************************
1552 * Video Filter2 stuff
1553 *****************************************************************************/
1554 static int ParseVideoFilter2Chain( vout_thread_t *p_vout, char *psz_vfilters )
1557 for( i = 0; i < p_vout->i_vfilters_cfg; i++ )
1559 struct config_chain_t *p_cfg =
1560 p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg];
1561 config_ChainDestroy( p_cfg );
1562 free( p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1563 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] = NULL;
1565 p_vout->i_vfilters_cfg = 0;
1566 if( psz_vfilters && *psz_vfilters )
1568 char *psz_parser = psz_vfilters;
1570 while( psz_parser && *psz_parser )
1572 psz_parser = config_ChainCreate(
1573 &p_vout->psz_vfilters[p_vout->i_vfilters_cfg],
1574 &p_vout->p_vfilters_cfg[p_vout->i_vfilters_cfg],
1576 msg_Dbg( p_vout, "adding vfilter: %s",
1577 p_vout->psz_vfilters[p_vout->i_vfilters_cfg] );
1578 p_vout->i_vfilters_cfg++;
1579 if( psz_parser && *psz_parser )
1581 if( p_vout->i_vfilters_cfg == MAX_VFILTERS )
1584 "maximum number of video filters reached. \"%s\" discarded",
1594 static int VideoFilter2Callback( vlc_object_t *p_this, char const *psz_cmd,
1595 vlc_value_t oldval, vlc_value_t newval, void *p_data )
1597 vout_thread_t *p_vout = (vout_thread_t *)p_this;
1598 (void)psz_cmd; (void)oldval; (void)p_data;
1600 vlc_mutex_lock( &p_vout->vfilter_lock );
1601 ParseVideoFilter2Chain( p_vout, newval.psz_string );
1602 p_vout->b_vfilter_change = VLC_TRUE;
1603 vlc_mutex_unlock( &p_vout->vfilter_lock );
1608 static void RemoveVideoFilters2( vout_thread_t *p_vout )
1611 for( i = 0; i < p_vout->i_vfilters; i++ )
1613 vlc_object_detach( p_vout->pp_vfilters[i] );
1614 if( p_vout->pp_vfilters[i]->p_module )
1616 module_Unneed( p_vout->pp_vfilters[i],
1617 p_vout->pp_vfilters[i]->p_module );
1620 free( p_vout->pp_vfilters[i]->p_owner );
1621 vlc_object_release( p_vout->pp_vfilters[i] );
1623 p_vout->i_vfilters = 0;
1626 static void DisplayTitleOnOSD( vout_thread_t *p_vout )
1628 input_thread_t *p_input;
1629 mtime_t i_now, i_stop;
1631 p_input = (input_thread_t *)vlc_object_find( p_vout,
1632 VLC_OBJECT_INPUT, FIND_ANYWHERE );
1636 i_stop = i_now + (mtime_t)(p_vout->i_title_timeout * 1000);
1637 char *psz_nowplaying =
1638 input_item_GetNowPlaying( input_GetItem( p_input ) );
1639 char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) );
1640 char *psz_name = input_item_GetTitle( input_GetItem( p_input ) );
1641 if( EMPTY_STR( psz_name ) )
1644 psz_name = input_item_GetName( input_GetItem( p_input ) );
1646 if( !EMPTY_STR( psz_nowplaying ) )
1648 vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
1649 psz_nowplaying, NULL,
1650 p_vout->i_title_position,
1651 30 + p_vout->fmt_in.i_width
1652 - p_vout->fmt_in.i_visible_width
1653 - p_vout->fmt_in.i_x_offset,
1654 20 + p_vout->fmt_in.i_y_offset,
1657 else if( !EMPTY_STR( psz_artist ) )
1659 char *psz_string = NULL;
1660 if( asprintf( &psz_string, "%s - %s", psz_name, psz_artist ) != -1 )
1662 vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
1664 p_vout->i_title_position,
1665 30 + p_vout->fmt_in.i_width
1666 - p_vout->fmt_in.i_visible_width
1667 - p_vout->fmt_in.i_x_offset,
1668 20 + p_vout->fmt_in.i_y_offset,
1675 vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN,
1677 p_vout->i_title_position,
1678 30 + p_vout->fmt_in.i_width
1679 - p_vout->fmt_in.i_visible_width
1680 - p_vout->fmt_in.i_x_offset,
1681 20 + p_vout->fmt_in.i_y_offset,
1684 vlc_object_release( p_input );
1687 free( psz_nowplaying );