]> git.sesse.net Git - vlc/blob - src/video_output/vout_subpictures.c
One more "Remove useless test before free"
[vlc] / src / video_output / vout_subpictures.c
1 /*****************************************************************************
2  * vout_subpictures.c : subpicture management functions
3  *****************************************************************************
4  * Copyright (C) 2000-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Vincent Seguin <seguin@via.ecp.fr>
8  *          Samuel Hocevar <sam@zoy.org>
9  *          Gildas Bazin <gbazin@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include <vlc/vlc.h>
34 #include <vlc_vout.h>
35 #include <vlc_block.h>
36 #include <vlc_filter.h>
37 #include <vlc_osd.h>
38
39 /*****************************************************************************
40  * Local prototypes
41  *****************************************************************************/
42 static void UpdateSPU   ( spu_t *, vlc_object_t * );
43 static int  CropCallback( vlc_object_t *, char const *,
44                           vlc_value_t, vlc_value_t, void * );
45
46 static int spu_vaControlDefault( spu_t *, int, va_list );
47
48 static subpicture_t *sub_new_buffer( filter_t * );
49 static void sub_del_buffer( filter_t *, subpicture_t * );
50 static subpicture_t *spu_new_buffer( filter_t * );
51 static void spu_del_buffer( filter_t *, subpicture_t * );
52 static picture_t *spu_new_video_buffer( filter_t * );
53 static void spu_del_video_buffer( filter_t *, picture_t * );
54
55 static int spu_ParseChain( spu_t * );
56 static void spu_DeleteChain( spu_t * );
57 static int SubFilterCallback( vlc_object_t *, char const *,
58                               vlc_value_t, vlc_value_t, void * );
59
60 struct filter_owner_sys_t
61 {
62     spu_t *p_spu;
63     int i_channel;
64 };
65
66 enum {
67     SCALE_DEFAULT,
68     SCALE_TEXT,
69     SCALE_SIZE
70 };
71 /**
72  * Creates the subpicture unit
73  *
74  * \param p_this the parent object which creates the subpicture unit
75  */
76 spu_t *__spu_Create( vlc_object_t *p_this )
77 {
78     int i_index;
79     spu_t *p_spu = vlc_object_create( p_this, VLC_OBJECT_SPU );
80
81     for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++)
82     {
83         p_spu->p_subpicture[i_index].i_status = FREE_SUBPICTURE;
84     }
85
86     p_spu->p_blend = NULL;
87     p_spu->p_text = NULL;
88     p_spu->p_scale = NULL;
89     p_spu->i_filter = 0;
90     p_spu->pf_control = spu_vaControlDefault;
91
92     /* Register the default subpicture channel */
93     p_spu->i_channel = 2;
94
95     vlc_mutex_init( p_this, &p_spu->subpicture_lock );
96
97     vlc_object_attach( p_spu, p_this );
98
99     return p_spu;
100 }
101
102 /**
103  * Initialise the subpicture unit
104  *
105  * \param p_spu the subpicture unit object
106  */
107 int spu_Init( spu_t *p_spu )
108 {
109     vlc_value_t val;
110
111     /* If the user requested a sub margin, we force the position. */
112     var_Create( p_spu, "sub-margin", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
113     var_Get( p_spu, "sub-margin", &val );
114     p_spu->i_margin = val.i_int;
115
116     var_Create( p_spu, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
117     var_AddCallback( p_spu, "sub-filter", SubFilterCallback, p_spu );
118
119     spu_ParseChain( p_spu );
120
121     return VLC_SUCCESS;
122 }
123
124 int spu_ParseChain( spu_t *p_spu )
125 {
126     char *psz_parser;
127     vlc_value_t val;
128     var_Get( p_spu, "sub-filter", &val );
129     psz_parser = val.psz_string;
130
131     while( psz_parser && *psz_parser )
132     {
133         config_chain_t *p_cfg;
134         char *psz_name;
135
136         psz_parser = config_ChainCreate( &psz_name, &p_cfg, psz_parser );
137
138         msg_Dbg( p_spu, "adding sub-filter: %s", psz_name );
139
140         p_spu->pp_filter[p_spu->i_filter] =
141             vlc_object_create( p_spu, VLC_OBJECT_FILTER );
142         vlc_object_attach( p_spu->pp_filter[p_spu->i_filter], p_spu );
143         p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_new = sub_new_buffer;
144         p_spu->pp_filter[p_spu->i_filter]->pf_sub_buffer_del = sub_del_buffer;
145         p_spu->pp_filter[p_spu->i_filter]->p_cfg = p_cfg;
146         p_spu->pp_filter[p_spu->i_filter]->p_module =
147             module_Need( p_spu->pp_filter[p_spu->i_filter],
148                          "sub filter", psz_name, VLC_TRUE );
149         if( p_spu->pp_filter[p_spu->i_filter]->p_module )
150         {
151             filter_owner_sys_t *p_sys = malloc( sizeof(filter_owner_sys_t) );
152             if( p_sys )
153             {
154                 p_spu->pp_filter[p_spu->i_filter]->p_owner = p_sys;
155                 spu_Control( p_spu, SPU_CHANNEL_REGISTER, &p_sys->i_channel );
156                 p_sys->p_spu = p_spu;
157                 p_spu->i_filter++;
158             }
159         }
160         else
161         {
162             msg_Dbg( p_spu, "no sub filter found" );
163             config_ChainDestroy( p_spu->pp_filter[p_spu->i_filter]->p_cfg );
164             vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] );
165             vlc_object_release( p_spu->pp_filter[p_spu->i_filter] );
166         }
167
168         if( p_spu->i_filter >= 10 )
169         {
170             msg_Dbg( p_spu, "can't add anymore filters" );
171         }
172
173         free( psz_name );
174     }
175     free( val.psz_string );
176
177     return VLC_SUCCESS;
178 }
179
180 /**
181  * Destroy the subpicture unit
182  *
183  * \param p_this the parent object which destroys the subpicture unit
184  */
185 void spu_Destroy( spu_t *p_spu )
186 {
187     int i_index;
188
189     vlc_object_detach( p_spu );
190
191     /* Destroy all remaining subpictures */
192     for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
193     {
194         if( p_spu->p_subpicture[i_index].i_status != FREE_SUBPICTURE )
195         {
196             spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] );
197         }
198     }
199
200     if( p_spu->p_blend )
201     {
202         if( p_spu->p_blend->p_module )
203             module_Unneed( p_spu->p_blend, p_spu->p_blend->p_module );
204
205         vlc_object_detach( p_spu->p_blend );
206         vlc_object_release( p_spu->p_blend );
207     }
208
209     if( p_spu->p_text )
210     {
211         if( p_spu->p_text->p_module )
212             module_Unneed( p_spu->p_text, p_spu->p_text->p_module );
213
214         vlc_object_detach( p_spu->p_text );
215         vlc_object_release( p_spu->p_text );
216     }
217
218     if( p_spu->p_scale )
219     {
220         if( p_spu->p_scale->p_module )
221             module_Unneed( p_spu->p_scale, p_spu->p_scale->p_module );
222
223         vlc_object_detach( p_spu->p_scale );
224         vlc_object_release( p_spu->p_scale );
225     }
226
227     spu_DeleteChain( p_spu );
228
229     vlc_mutex_destroy( &p_spu->subpicture_lock );
230     vlc_object_release( p_spu );
231 }
232
233 static void spu_DeleteChain( spu_t *p_spu )
234 {
235     if( p_spu->i_filter )
236     while( p_spu->i_filter )
237     {
238         p_spu->i_filter--;
239         module_Unneed( p_spu->pp_filter[p_spu->i_filter],
240                        p_spu->pp_filter[p_spu->i_filter]->p_module );
241         free( p_spu->pp_filter[p_spu->i_filter]->p_owner );
242         config_ChainDestroy( p_spu->pp_filter[p_spu->i_filter]->p_cfg );
243         vlc_object_detach( p_spu->pp_filter[p_spu->i_filter] );
244         vlc_object_release( p_spu->pp_filter[p_spu->i_filter] );
245     }
246 }
247
248 /**
249  * Attach/Detach the SPU from any input
250  *
251  * \param p_this the object in which to destroy the subpicture unit
252  * \param b_attach to select attach or detach
253  */
254 void spu_Attach( spu_t *p_spu, vlc_object_t *p_this, vlc_bool_t b_attach )
255 {
256     vlc_object_t *p_input;
257
258     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
259     if( !p_input ) return;
260
261     if( b_attach )
262     {
263         UpdateSPU( p_spu, VLC_OBJECT(p_input) );
264         var_AddCallback( p_input, "highlight", CropCallback, p_spu );
265         vlc_object_release( p_input );
266     }
267     else
268     {
269         /* Delete callback */
270         var_DelCallback( p_input, "highlight", CropCallback, p_spu );
271         vlc_object_release( p_input );
272     }
273 }
274
275 /**
276  * Create a subpicture region
277  *
278  * \param p_this vlc_object_t
279  * \param p_fmt the format that this subpicture region should have
280  */
281 static void RegionPictureRelease( picture_t *p_pic )
282 {
283     free( p_pic->p_data_orig );
284 }
285 subpicture_region_t *__spu_CreateRegion( vlc_object_t *p_this,
286                                          video_format_t *p_fmt )
287 {
288     subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
289     if( !p_region ) return NULL;
290
291     memset( p_region, 0, sizeof(subpicture_region_t) );
292     p_region->p_next = NULL;
293     p_region->p_cache = NULL;
294     p_region->fmt = *p_fmt;
295     p_region->psz_text = NULL;
296     p_region->p_style = NULL;
297
298     if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') )
299         p_fmt->p_palette = p_region->fmt.p_palette =
300             malloc( sizeof(video_palette_t) );
301     else p_fmt->p_palette = p_region->fmt.p_palette = NULL;
302
303     p_region->picture.p_data_orig = NULL;
304
305     if( p_fmt->i_chroma == VLC_FOURCC('T','E','X','T') ) return p_region;
306
307     vout_AllocatePicture( p_this, &p_region->picture, p_fmt->i_chroma,
308                           p_fmt->i_width, p_fmt->i_height, p_fmt->i_aspect );
309
310     if( !p_region->picture.i_planes )
311     {
312         free( p_region );
313         free( p_fmt->p_palette );
314         return NULL;
315     }
316
317     p_region->picture.pf_release = RegionPictureRelease;
318
319     return p_region;
320 }
321
322 /**
323  * Make a subpicture region from an existing picture_t
324  *
325  * \param p_this vlc_object_t
326  * \param p_fmt the format that this subpicture region should have
327  * \param p_pic a pointer to the picture creating the region (not freed)
328  */
329 subpicture_region_t *__spu_MakeRegion( vlc_object_t *p_this,
330                                        video_format_t *p_fmt,
331                                        picture_t *p_pic )
332 {
333     subpicture_region_t *p_region = malloc( sizeof(subpicture_region_t) );
334     (void)p_this;
335     if( !p_region ) return NULL;
336     memset( p_region, 0, sizeof(subpicture_region_t) );
337     p_region->p_next = 0;
338     p_region->p_cache = 0;
339     p_region->fmt = *p_fmt;
340     p_region->psz_text = 0;
341     p_region->p_style = NULL;
342
343     if( p_fmt->i_chroma == VLC_FOURCC('Y','U','V','P') )
344         p_fmt->p_palette = p_region->fmt.p_palette =
345             malloc( sizeof(video_palette_t) );
346     else p_fmt->p_palette = p_region->fmt.p_palette = NULL;
347
348     memcpy( &p_region->picture, p_pic, sizeof(picture_t) );
349     p_region->picture.pf_release = RegionPictureRelease;
350
351     return p_region;
352 }
353
354 /**
355  * Destroy a subpicture region
356  *
357  * \param p_this vlc_object_t
358  * \param p_region the subpicture region to destroy
359  */
360 void __spu_DestroyRegion( vlc_object_t *p_this, subpicture_region_t *p_region )
361 {
362     if( !p_region ) return;
363     if( p_region->picture.pf_release )
364         p_region->picture.pf_release( &p_region->picture );
365     free( p_region->fmt.p_palette );
366     if( p_region->p_cache ) __spu_DestroyRegion( p_this, p_region->p_cache );
367
368     free( p_region->psz_text );
369     free( p_region->psz_html );
370     //free( p_region->p_style ); FIXME --fenrir plugin does not allocate the memory for it. I think it might lead to segfault, video renderer can live longer than the decoder
371     free( p_region );
372 }
373
374 /**
375  * Display a subpicture
376  *
377  * Remove the reservation flag of a subpicture, which will cause it to be
378  * ready for display.
379  * \param p_spu the subpicture unit object
380  * \param p_subpic the subpicture to display
381  */
382 void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
383 {
384     /* Check if status is valid */
385     if( p_subpic->i_status != RESERVED_SUBPICTURE )
386     {
387         msg_Err( p_spu, "subpicture %p has invalid status #%d",
388                  p_subpic, p_subpic->i_status );
389     }
390
391     /* Remove reservation flag */
392     p_subpic->i_status = READY_SUBPICTURE;
393
394     if( p_subpic->i_channel == DEFAULT_CHAN )
395     {
396         p_subpic->i_channel = 0xFFFF;
397         spu_Control( p_spu, SPU_CHANNEL_CLEAR, DEFAULT_CHAN );
398         p_subpic->i_channel = DEFAULT_CHAN;
399     }
400 }
401
402 /**
403  * Allocate a subpicture in the spu heap.
404  *
405  * This function create a reserved subpicture in the spu heap.
406  * A null pointer is returned if the function fails. This method provides an
407  * already allocated zone of memory in the spu data fields. It needs locking
408  * since several pictures can be created by several producers threads.
409  * \param p_spu the subpicture unit in which to create the subpicture
410  * \return NULL on error, a reserved subpicture otherwise
411  */
412 subpicture_t *spu_CreateSubpicture( spu_t *p_spu )
413 {
414     int                 i_subpic;                        /* subpicture index */
415     subpicture_t *      p_subpic = NULL;            /* first free subpicture */
416
417     /* Get lock */
418     vlc_mutex_lock( &p_spu->subpicture_lock );
419
420     /*
421      * Look for an empty place
422      */
423     p_subpic = NULL;
424     for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
425     {
426         if( p_spu->p_subpicture[i_subpic].i_status == FREE_SUBPICTURE )
427         {
428             /* Subpicture is empty and ready for allocation */
429             p_subpic = &p_spu->p_subpicture[i_subpic];
430             p_spu->p_subpicture[i_subpic].i_status = RESERVED_SUBPICTURE;
431             break;
432         }
433     }
434
435     /* If no free subpicture could be found */
436     if( p_subpic == NULL )
437     {
438         msg_Err( p_spu, "subpicture heap is full" );
439         vlc_mutex_unlock( &p_spu->subpicture_lock );
440         return NULL;
441     }
442
443     /* Copy subpicture information, set some default values */
444     memset( p_subpic, 0, sizeof(subpicture_t) );
445     p_subpic->i_status   = RESERVED_SUBPICTURE;
446     p_subpic->b_absolute = VLC_TRUE;
447     p_subpic->b_pausable = VLC_FALSE;
448     p_subpic->b_fade     = VLC_FALSE;
449     p_subpic->i_alpha    = 0xFF;
450     p_subpic->p_region   = NULL;
451     p_subpic->pf_render  = NULL;
452     p_subpic->pf_destroy = NULL;
453     p_subpic->p_sys      = NULL;
454     vlc_mutex_unlock( &p_spu->subpicture_lock );
455
456     p_subpic->pf_create_region = __spu_CreateRegion;
457     p_subpic->pf_make_region = __spu_MakeRegion;
458     p_subpic->pf_destroy_region = __spu_DestroyRegion;
459
460     return p_subpic;
461 }
462
463 /**
464  * Remove a subpicture from the heap
465  *
466  * This function frees a previously reserved subpicture.
467  * It is meant to be used when the construction of a picture aborted.
468  * This function does not need locking since reserved subpictures are ignored
469  * by the spu.
470  */
471 void spu_DestroySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
472 {
473     /* Get lock */
474     vlc_mutex_lock( &p_spu->subpicture_lock );
475
476     /* There can be race conditions so we need to check the status */
477     if( p_subpic->i_status == FREE_SUBPICTURE )
478     {
479         vlc_mutex_unlock( &p_spu->subpicture_lock );
480         return;
481     }
482
483     /* Check if status is valid */
484     if( ( p_subpic->i_status != RESERVED_SUBPICTURE )
485            && ( p_subpic->i_status != READY_SUBPICTURE ) )
486     {
487         msg_Err( p_spu, "subpicture %p has invalid status %d",
488                          p_subpic, p_subpic->i_status );
489     }
490
491     while( p_subpic->p_region )
492     {
493         subpicture_region_t *p_region = p_subpic->p_region;
494         p_subpic->p_region = p_region->p_next;
495         spu_DestroyRegion( p_spu, p_region );
496     }
497
498     if( p_subpic->pf_destroy )
499     {
500         p_subpic->pf_destroy( p_subpic );
501     }
502
503     p_subpic->i_status = FREE_SUBPICTURE;
504
505     vlc_mutex_unlock( &p_spu->subpicture_lock );
506 }
507
508 /*****************************************************************************
509  * spu_RenderSubpictures: render a subpicture list
510  *****************************************************************************
511  * This function renders all sub picture units in the list.
512  *****************************************************************************/
513 void spu_RenderSubpictures( spu_t *p_spu, video_format_t *p_fmt,
514                             picture_t *p_pic_dst, picture_t *p_pic_src,
515                             subpicture_t *p_subpic,
516                             int i_scale_width_orig, int i_scale_height_orig )
517 {
518     int i_source_video_width;
519     int i_source_video_height;
520     subpicture_t *p_subpic_v = p_subpic;
521
522     /* Get lock */
523     vlc_mutex_lock( &p_spu->subpicture_lock );
524
525     for( p_subpic_v = p_subpic;
526             p_subpic_v != NULL && p_subpic_v->i_status != FREE_SUBPICTURE;
527             p_subpic_v = p_subpic_v->p_next )
528     {
529         if( p_subpic_v->pf_pre_render )
530         {
531             p_subpic_v->pf_pre_render( p_fmt, p_spu, p_subpic_v, mdate() );
532         }
533     }
534
535     if( i_scale_width_orig <= 0 )
536         i_scale_width_orig = 1;
537     if( i_scale_height_orig <= 0 )
538         i_scale_height_orig = 1;
539
540     i_source_video_width  = p_fmt->i_width  * 1000 / i_scale_width_orig;
541     i_source_video_height = p_fmt->i_height * 1000 / i_scale_height_orig;
542
543     /* Check i_status again to make sure spudec hasn't destroyed the subpic */
544     while( ( p_subpic != NULL ) && ( p_subpic->i_status != FREE_SUBPICTURE ) )
545     {
546         subpicture_region_t *p_region;
547         int pi_scale_width[ SCALE_SIZE ];
548         int pi_scale_height[ SCALE_SIZE ];
549         int pi_subpic_x[ SCALE_SIZE ];
550         int k;
551
552         /* If the source video and subtitles stream agree on the size of
553          * the video then disregard all further references to the subtitle
554          * stream.
555          */
556         if( ( i_source_video_height == p_subpic->i_original_picture_height ) &&
557             ( i_source_video_width  == p_subpic->i_original_picture_width ) )
558         {
559             p_subpic->i_original_picture_height = 0;
560             p_subpic->i_original_picture_width = 0;
561         }
562
563         for( k = 0; k < SCALE_SIZE ; k++ )
564             pi_subpic_x[ k ] = p_subpic->i_x;
565
566         if( p_subpic->pf_update_regions )
567         {
568             if ( p_subpic->p_region ) {
569                 spu_DestroyRegion( p_spu, p_subpic->p_region );
570             }
571             p_subpic->p_region = p_region = p_subpic->pf_update_regions( p_fmt, p_spu, p_subpic, mdate() );
572         }
573         else
574         {
575             p_region = p_subpic->p_region;
576         }
577
578         /* Load the blending module */
579         if( !p_spu->p_blend && p_region )
580         {
581             p_spu->p_blend = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
582             vlc_object_attach( p_spu->p_blend, p_spu );
583             p_spu->p_blend->fmt_out.video.i_x_offset =
584                 p_spu->p_blend->fmt_out.video.i_y_offset = 0;
585             p_spu->p_blend->fmt_out.video.i_aspect = p_fmt->i_aspect;
586             p_spu->p_blend->fmt_out.video.i_chroma = p_fmt->i_chroma;
587
588             /* The blend module will be loaded when needed with the real
589             * input format */
590             memset( &p_spu->p_blend->fmt_in, 0, sizeof(p_spu->p_blend->fmt_in) );
591             p_spu->p_blend->p_module = NULL;
592         }
593
594         /* Load the text rendering module; it is possible there is a
595          * text region somewhere in the subpicture other than the first
596          * element in the region list, so just load it anyway as we'll
597          * probably want it sooner or later. */
598         if( !p_spu->p_text && p_region )
599         {
600             char *psz_modulename = NULL;
601
602             p_spu->p_text = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
603             vlc_object_attach( p_spu->p_text, p_spu );
604
605             p_spu->p_text->fmt_out.video.i_width =
606                 p_spu->p_text->fmt_out.video.i_visible_width =
607                 p_fmt->i_width;
608             p_spu->p_text->fmt_out.video.i_height =
609                 p_spu->p_text->fmt_out.video.i_visible_height =
610                 p_fmt->i_height;
611
612             p_spu->p_text->pf_sub_buffer_new = spu_new_buffer;
613             p_spu->p_text->pf_sub_buffer_del = spu_del_buffer;
614
615             psz_modulename = var_CreateGetString( p_spu, "text-renderer" );
616             if( psz_modulename && *psz_modulename )
617             {
618                 p_spu->p_text->p_module =
619                     module_Need( p_spu->p_text, "text renderer",
620                                  psz_modulename, VLC_TRUE );
621             }
622             if( !p_spu->p_text->p_module )
623             {
624                 p_spu->p_text->p_module =
625                     module_Need( p_spu->p_text, "text renderer", 0, 0 );
626             }
627             free( psz_modulename );
628         }
629
630         if( p_spu->p_text )
631         {
632             subpicture_region_t *p_text_region = p_subpic->p_region;
633
634             /* Only overwrite the size fields if the region is still in
635              * pre-rendered TEXT format. We have to traverse the subregion
636              * list because if more than one subregion is present, the text
637              * region isn't guarentteed to be the first in the list, and
638              * only text regions use this flag. All of this effort assists
639              * with the rescaling of text that has been rendered at native
640              * resolution, rather than video resolution.
641              */
642             while( p_text_region &&
643                    ( p_text_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') ) )
644             {
645                 p_text_region = p_text_region->p_next;
646             }
647
648             if( p_text_region &&
649                 ( ( p_text_region->i_align & SUBPICTURE_RENDERED ) == 0 ) )
650             {
651                 if( (p_subpic->i_original_picture_height > 0) &&
652                     (p_subpic->i_original_picture_width  > 0) )
653                 {
654                     p_spu->p_text->fmt_out.video.i_width =
655                         p_spu->p_text->fmt_out.video.i_visible_width =
656                         p_subpic->i_original_picture_width;
657                     p_spu->p_text->fmt_out.video.i_height =
658                         p_spu->p_text->fmt_out.video.i_visible_height =
659                         p_subpic->i_original_picture_height;
660                 }
661                 else
662                 {
663                     p_spu->p_text->fmt_out.video.i_width =
664                         p_spu->p_text->fmt_out.video.i_visible_width =
665                         p_fmt->i_width;
666                     p_spu->p_text->fmt_out.video.i_height =
667                         p_spu->p_text->fmt_out.video.i_visible_height =
668                         p_fmt->i_height;
669                 }
670             }
671         }
672
673         pi_scale_width[ SCALE_DEFAULT ]  = i_scale_width_orig;
674         pi_scale_height[ SCALE_DEFAULT ] = i_scale_height_orig;
675
676         if( p_spu->p_text )
677         {
678             pi_scale_width[ SCALE_TEXT ]     = ( p_fmt->i_width * 1000 ) /
679                                           p_spu->p_text->fmt_out.video.i_width;
680             pi_scale_height[ SCALE_TEXT ]    = ( p_fmt->i_height * 1000 ) /
681                                           p_spu->p_text->fmt_out.video.i_height;
682         }
683         /* If we have an explicit size plane to render to, then turn off
684          * the fontsize rescaling.
685          */
686         if( (p_subpic->i_original_picture_height > 0) &&
687             (p_subpic->i_original_picture_width  > 0) )
688         {
689             i_scale_width_orig  = 1000;
690             i_scale_height_orig = 1000;
691         }
692
693         for( k = 0; k < SCALE_SIZE ; k++ )
694         {
695             /* Case of both width and height being specified has been dealt
696              * with above by instead rendering to an output pane of the
697              * explicit dimensions specified - we don't need to scale it.
698              */
699             if( (p_subpic->i_original_picture_height > 0) &&
700                 (p_subpic->i_original_picture_width <= 0) )
701             {
702                 pi_scale_height[ k ] = pi_scale_height[ k ] * i_source_video_height /
703                                  p_subpic->i_original_picture_height;
704                 pi_scale_width[ k ]  = pi_scale_width[ k ]  * i_source_video_height /
705                                  p_subpic->i_original_picture_height;
706             }
707         }
708
709         /* Set default subpicture aspect ratio */
710         if( p_region && p_region->fmt.i_aspect &&
711             ( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den ) )
712         {
713             p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
714             p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
715         }
716         if( p_region &&
717             ( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den ) )
718         {
719             p_region->fmt.i_sar_den = p_fmt->i_sar_den;
720             p_region->fmt.i_sar_num = p_fmt->i_sar_num;
721         }
722
723         /* Take care of the aspect ratio */
724         if( p_region &&
725             ( ( p_region->fmt.i_sar_num * p_fmt->i_sar_den ) !=
726               ( p_region->fmt.i_sar_den * p_fmt->i_sar_num ) ) )
727         {
728             for( k = 0; k < SCALE_SIZE ; k++ )
729             {
730                 pi_scale_width[ k ] = pi_scale_width[ k ] *
731                     (int64_t)p_region->fmt.i_sar_num * p_fmt->i_sar_den /
732                     p_region->fmt.i_sar_den / p_fmt->i_sar_num;
733                 pi_subpic_x[ k ] = p_subpic->i_x * pi_scale_width[ k ] / 1000;
734             }
735         }
736
737         /* Load the scaling module */
738         if( !p_spu->p_scale &&
739            ((((pi_scale_width[ SCALE_TEXT ]    > 0)     || (pi_scale_height[ SCALE_TEXT ]    > 0)) &&
740              ((pi_scale_width[ SCALE_TEXT ]    != 1000) || (pi_scale_height[ SCALE_TEXT ]    != 1000))) ||
741             (((pi_scale_width[ SCALE_DEFAULT ] > 0)     || (pi_scale_height[ SCALE_DEFAULT ] > 0)) &&
742              ((pi_scale_width[ SCALE_DEFAULT ] != 1000) || (pi_scale_height[ SCALE_DEFAULT ] != 1000)))) )
743         {
744             p_spu->p_scale = vlc_object_create( p_spu, VLC_OBJECT_FILTER );
745             vlc_object_attach( p_spu->p_scale, p_spu );
746             p_spu->p_scale->fmt_out.video.i_chroma =
747                 p_spu->p_scale->fmt_in.video.i_chroma =
748                     VLC_FOURCC('Y','U','V','P');
749             /* FIXME: We'll also be using it for YUVA and RGBA blending ... */
750
751             p_spu->p_scale->fmt_in.video.i_width =
752                 p_spu->p_scale->fmt_in.video.i_height = 32;
753             p_spu->p_scale->fmt_out.video.i_width =
754                 p_spu->p_scale->fmt_out.video.i_height = 16;
755
756             p_spu->p_scale->pf_vout_buffer_new = spu_new_video_buffer;
757             p_spu->p_scale->pf_vout_buffer_del = spu_del_video_buffer;
758             p_spu->p_scale->p_module =
759                 module_Need( p_spu->p_scale, "video filter2", 0, 0 );
760         }
761
762         while( p_region )
763         {
764             video_format_t orig_fmt = p_region->fmt;
765             vlc_bool_t b_rerender_text = VLC_FALSE;
766             int i_fade_alpha = 255;
767             int i_x_offset;
768             int i_y_offset;
769             int i_scale_idx   = SCALE_DEFAULT;
770             int i_inv_scale_x = 1000;
771             int i_inv_scale_y = 1000;
772
773             if( p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T') )
774             {
775                 if( p_spu->p_text && p_spu->p_text->p_module )
776                 {
777                     vlc_value_t  val;
778
779                     /* Setup 3 variables which can be used to render
780                      * time-dependent text (and effects). The first indicates
781                      * the total amount of time the text will be on screen,
782                      * the second the amount of time it has already been on
783                      * screen (can be a negative value as text is layed out
784                      * before it is rendered) and the third is a feedback
785                      * variable from the renderer - if the renderer sets it
786                      * then this particular text is time-dependent, eg. the
787                      * visual progress bar inside the text in karaoke and the
788                      * text needs to be rendered multiple times in order for
789                      * the effect to work - we therefore need to return the
790                      * region to its original state at the end of the loop,
791                      * instead of leaving it in YUVA or YUVP.
792                      * Any renderer which is unaware of how to render
793                      * time-dependent text can happily ignore the variables
794                      * and render the text the same as usual - it should at
795                      * least show up on screen, but the effect won't change
796                      * the text over time.
797                      */
798
799                     var_Create( p_spu->p_text, "spu-duration", VLC_VAR_TIME );
800                     val.i_time = p_subpic->i_stop - p_subpic->i_start;
801                     var_Set( p_spu->p_text, "spu-duration", val );
802
803                     var_Create( p_spu->p_text, "spu-elapsed", VLC_VAR_TIME );
804                     val.i_time = mdate() - p_subpic->i_start;
805                     var_Set( p_spu->p_text, "spu-elapsed", val );
806
807                     var_Create( p_spu->p_text, "text-rerender", VLC_VAR_BOOL );
808                     var_SetBool( p_spu->p_text, "text-rerender", VLC_FALSE );
809
810                     var_Create( p_spu->p_text, "scale", VLC_VAR_INTEGER );
811                     var_SetInteger( p_spu->p_text, "scale",
812                               __MIN(i_scale_width_orig, i_scale_height_orig) );
813
814                     if( p_spu->p_text->pf_render_html && p_region->psz_html )
815                     {
816                         p_spu->p_text->pf_render_html( p_spu->p_text,
817                                                        p_region, p_region );
818                     }
819                     else if( p_spu->p_text->pf_render_text )
820                     {
821                         p_spu->p_text->pf_render_text( p_spu->p_text,
822                                                        p_region, p_region );
823                     }
824                     b_rerender_text = var_GetBool( p_spu->p_text, "text-rerender" );
825
826                     var_Destroy( p_spu->p_text, "spu-duration" );
827                     var_Destroy( p_spu->p_text, "spu-elapsed" );
828                     var_Destroy( p_spu->p_text, "text-rerender" );
829                     var_Destroy( p_spu->p_text, "scale" );
830                 }
831                 p_region->i_align |= SUBPICTURE_RENDERED;
832             }
833
834             if( p_region->i_align & SUBPICTURE_RENDERED )
835             {
836                 i_scale_idx   = SCALE_TEXT;
837                 i_inv_scale_x = i_scale_width_orig;
838                 i_inv_scale_y = i_scale_height_orig;
839             }
840
841             i_x_offset = (p_region->i_x + pi_subpic_x[ i_scale_idx ]) * i_inv_scale_x / 1000;
842             i_y_offset = (p_region->i_y + p_subpic->i_y) * i_inv_scale_y / 1000;
843
844             /* Force palette if requested */
845             if( p_spu->b_force_palette &&
846                 ( VLC_FOURCC('Y','U','V','P') == p_region->fmt.i_chroma ) )
847             {
848                 memcpy( p_region->fmt.p_palette->palette,
849                         p_spu->palette, 16 );
850             }
851
852             /* Scale SPU if necessary */
853             if( p_region->p_cache &&
854                 ( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') ) )
855             {
856                 if( pi_scale_width[ i_scale_idx ] * p_region->fmt.i_width / 1000 !=
857                     p_region->p_cache->fmt.i_width ||
858                     pi_scale_height[ i_scale_idx ] * p_region->fmt.i_height / 1000 !=
859                     p_region->p_cache->fmt.i_height )
860                 {
861                     p_subpic->pf_destroy_region( VLC_OBJECT(p_spu),
862                                                  p_region->p_cache );
863                     p_region->p_cache = 0;
864                 }
865             }
866
867             if( ( ( pi_scale_width[ i_scale_idx ] != 1000 ) ||
868                   ( pi_scale_height[ i_scale_idx ] != 1000 ) ) &&
869                 ( ( pi_scale_width[ i_scale_idx ] > 0 ) ||
870                   ( pi_scale_height[ i_scale_idx ] > 0 ) ) &&
871                 p_spu->p_scale && !p_region->p_cache &&
872                 ( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') ) )
873             {
874                 picture_t *p_pic;
875
876                 p_spu->p_scale->fmt_in.video = p_region->fmt;
877                 p_spu->p_scale->fmt_out.video = p_region->fmt;
878
879                 p_region->p_cache =
880                     p_subpic->pf_create_region( VLC_OBJECT(p_spu),
881                         &p_spu->p_scale->fmt_out.video );
882                 if( p_spu->p_scale->fmt_out.video.p_palette )
883                     *p_spu->p_scale->fmt_out.video.p_palette =
884                         *p_region->fmt.p_palette;
885                 p_region->p_cache->p_next = p_region->p_next;
886
887                 vout_CopyPicture( p_spu, &p_region->p_cache->picture,
888                                   &p_region->picture );
889
890                 p_spu->p_scale->fmt_out.video.i_width =
891                     p_region->fmt.i_width * pi_scale_width[ i_scale_idx ] / 1000;
892                 p_spu->p_scale->fmt_out.video.i_visible_width =
893                     p_region->fmt.i_visible_width * pi_scale_width[ i_scale_idx ] / 1000;
894                 p_spu->p_scale->fmt_out.video.i_height =
895                     p_region->fmt.i_height * pi_scale_height[ i_scale_idx ] / 1000;
896                 p_spu->p_scale->fmt_out.video.i_visible_height =
897                     p_region->fmt.i_visible_height * pi_scale_height[ i_scale_idx ] / 1000;
898                 p_region->p_cache->fmt = p_spu->p_scale->fmt_out.video;
899                 p_region->p_cache->i_x = p_region->i_x * pi_scale_width[ i_scale_idx ] / 1000;
900                 p_region->p_cache->i_y = p_region->i_y * pi_scale_height[ i_scale_idx ] / 1000;
901                 p_region->p_cache->i_align = p_region->i_align;
902
903                 p_pic = p_spu->p_scale->pf_video_filter(
904                                  p_spu->p_scale, &p_region->p_cache->picture );
905                 if( p_pic )
906                 {
907                     picture_t p_pic_tmp = p_region->p_cache->picture;
908                     p_region->p_cache->picture = *p_pic;
909                     *p_pic = p_pic_tmp;
910                     free( p_pic );
911                 }
912             }
913
914             if( ( ( pi_scale_width[ i_scale_idx ] != 1000 ) ||
915                   ( pi_scale_height[ i_scale_idx ] != 1000 ) ) &&
916                 ( ( pi_scale_width[ i_scale_idx ] > 0 ) ||
917                   ( pi_scale_height[ i_scale_idx ] > 0 ) ) &&
918                 p_spu->p_scale && p_region->p_cache &&
919                 ( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') )  )
920             {
921                 p_region = p_region->p_cache;
922             }
923
924             if( p_region->i_align & SUBPICTURE_ALIGN_BOTTOM )
925             {
926                 i_y_offset = p_fmt->i_height - p_region->fmt.i_height -
927                     (p_subpic->i_y + p_region->i_y) * i_inv_scale_y / 1000;
928             }
929             else if ( !(p_region->i_align & SUBPICTURE_ALIGN_TOP) )
930             {
931                 i_y_offset = p_fmt->i_height / 2 - p_region->fmt.i_height / 2;
932             }
933
934             if( p_region->i_align & SUBPICTURE_ALIGN_RIGHT )
935             {
936                 i_x_offset = p_fmt->i_width - p_region->fmt.i_width -
937                     (pi_subpic_x[ i_scale_idx ] + p_region->i_x)
938                     * i_inv_scale_x / 1000;
939             }
940             else if ( !(p_region->i_align & SUBPICTURE_ALIGN_LEFT) )
941             {
942                 i_x_offset = p_fmt->i_width / 2 - p_region->fmt.i_width / 2;
943             }
944
945             if( p_subpic->b_absolute )
946             {
947                 i_x_offset = (p_region->i_x +
948                     pi_subpic_x[ i_scale_idx ] *
949                                      pi_scale_width[ i_scale_idx ] / 1000)
950                     * i_inv_scale_x / 1000;
951                 i_y_offset = (p_region->i_y +
952                     p_subpic->i_y * pi_scale_height[ i_scale_idx ] / 1000)
953                     * i_inv_scale_y / 1000;
954
955             }
956
957             i_x_offset = __MAX( i_x_offset, 0 );
958             i_y_offset = __MAX( i_y_offset, 0 );
959
960             if( ( p_spu->i_margin != 0 ) &&
961                 ( p_spu->b_force_crop == VLC_FALSE ) )
962             {
963                 int i_diff = 0;
964                 int i_low = (i_y_offset - p_spu->i_margin) * i_inv_scale_y / 1000;
965                 int i_high = i_low + p_region->fmt.i_height;
966
967                 /* crop extra margin to keep within bounds */
968                 if( i_low < 0 )
969                     i_diff = i_low;
970                 if( i_high > (int)p_fmt->i_height )
971                     i_diff = i_high - p_fmt->i_height;
972                 i_y_offset -= ( p_spu->i_margin * i_inv_scale_y / 1000 + i_diff );
973             }
974
975             if( p_subpic->b_fade )
976             {
977                 mtime_t i_fade_start = ( p_subpic->i_stop +
978                                          p_subpic->i_start ) / 2;
979                 mtime_t i_now = mdate();
980                 if( i_now >= i_fade_start && p_subpic->i_stop > i_fade_start )
981                 {
982                     i_fade_alpha = 255 * ( p_subpic->i_stop - i_now ) /
983                                    ( p_subpic->i_stop - i_fade_start );
984                 }
985             }
986
987             if( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') )
988             {
989                 if( p_spu->p_blend->fmt_in.video.i_chroma != p_region->fmt.i_chroma )
990                 {
991                     /* The chroma is not the same, we need to reload the blend module
992                      * XXX to match the old behaviour just test !p_spu->p_blend->fmt_in.video.i_chroma */
993                     if( p_spu->p_blend->p_module )
994                         module_Unneed( p_spu->p_blend, p_spu->p_blend->p_module );
995
996                     p_spu->p_blend->fmt_in.video = p_region->fmt;
997                     p_spu->p_blend->p_module = module_Need( p_spu->p_blend, "video blending", 0, 0 );
998                 }
999                 else
1000                 {
1001                     p_spu->p_blend->fmt_in.video = p_region->fmt;
1002                 }
1003
1004                 /* Force cropping if requested */
1005                 if( p_spu->b_force_crop )
1006                 {
1007                     video_format_t *p_fmt = &p_spu->p_blend->fmt_in.video;
1008                     int i_crop_x = p_spu->i_crop_x * pi_scale_width[ i_scale_idx ] / 1000
1009                                         * i_inv_scale_x / 1000;
1010                     int i_crop_y = p_spu->i_crop_y * pi_scale_height[ i_scale_idx ] / 1000
1011                                         * i_inv_scale_y / 1000;
1012                     int i_crop_width = p_spu->i_crop_width * pi_scale_width[ i_scale_idx ] / 1000
1013                                         * i_inv_scale_x / 1000;
1014                     int i_crop_height = p_spu->i_crop_height * pi_scale_height[ i_scale_idx ] / 1000
1015                                         * i_inv_scale_y / 1000;
1016
1017                     /* Find the intersection */
1018                     if( i_crop_x + i_crop_width <= i_x_offset ||
1019                         i_x_offset + (int)p_fmt->i_visible_width < i_crop_x ||
1020                         i_crop_y + i_crop_height <= i_y_offset ||
1021                         i_y_offset + (int)p_fmt->i_visible_height < i_crop_y )
1022                     {
1023                         /* No intersection */
1024                         p_fmt->i_visible_width = p_fmt->i_visible_height = 0;
1025                     }
1026                     else
1027                     {
1028                         int i_x, i_y, i_x_end, i_y_end;
1029                         i_x = __MAX( i_crop_x, i_x_offset );
1030                         i_y = __MAX( i_crop_y, i_y_offset );
1031                         i_x_end = __MIN( i_crop_x + i_crop_width,
1032                                        i_x_offset + (int)p_fmt->i_visible_width );
1033                         i_y_end = __MIN( i_crop_y + i_crop_height,
1034                                        i_y_offset + (int)p_fmt->i_visible_height );
1035
1036                         p_fmt->i_x_offset = i_x - i_x_offset;
1037                         p_fmt->i_y_offset = i_y - i_y_offset;
1038                         p_fmt->i_visible_width = i_x_end - i_x;
1039                         p_fmt->i_visible_height = i_y_end - i_y;
1040
1041                         i_x_offset = i_x;
1042                         i_y_offset = i_y;
1043                     }
1044                 }
1045
1046                 i_x_offset = __MAX( i_x_offset, 0 );
1047                 i_y_offset = __MAX( i_y_offset, 0 );
1048
1049                 /* Update the output picture size */
1050                 p_spu->p_blend->fmt_out.video.i_width =
1051                     p_spu->p_blend->fmt_out.video.i_visible_width =
1052                         p_fmt->i_width;
1053                 p_spu->p_blend->fmt_out.video.i_height =
1054                     p_spu->p_blend->fmt_out.video.i_visible_height =
1055                         p_fmt->i_height;
1056
1057                 if( p_spu->p_blend->p_module )
1058                 {
1059                     p_spu->p_blend->pf_video_blend( p_spu->p_blend, p_pic_dst,
1060                         p_pic_src, &p_region->picture, i_x_offset, i_y_offset,
1061                         i_fade_alpha * p_subpic->i_alpha / 255 );
1062                 }
1063                 else
1064                 {
1065                     msg_Err( p_spu, "blending %4.4s to %4.4s failed",
1066                              (char *)&p_spu->p_blend->fmt_out.video.i_chroma,
1067                              (char *)&p_spu->p_blend->fmt_out.video.i_chroma );
1068                 }
1069             }
1070
1071             if( b_rerender_text )
1072             {
1073                 /* Some forms of subtitles need to be re-rendered more than
1074                  * once, eg. karaoke. We therefore restore the region to its
1075                  * pre-rendered state, so the next time through everything is
1076                  * calculated again.
1077                  */
1078                 p_region->picture.pf_release( &p_region->picture );
1079                 memset( &p_region->picture, 0, sizeof( picture_t ) );
1080                 p_region->fmt = orig_fmt;
1081                 p_region->i_align &= ~SUBPICTURE_RENDERED;
1082             }
1083             p_region = p_region->p_next;
1084         }
1085
1086         p_subpic = p_subpic->p_next;
1087     }
1088
1089     vlc_mutex_unlock( &p_spu->subpicture_lock );
1090 }
1091
1092 /*****************************************************************************
1093  * spu_SortSubpictures: find the subpictures to display
1094  *****************************************************************************
1095  * This function parses all subpictures and decides which ones need to be
1096  * displayed. This operation does not need lock, since only READY_SUBPICTURE
1097  * are handled. If no picture has been selected, display_date will depend on
1098  * the subpicture.
1099  * We also check for ephemer DVD subpictures (subpictures that have
1100  * to be removed if a newer one is available), which makes it a lot
1101  * more difficult to guess if a subpicture has to be rendered or not.
1102  *****************************************************************************/
1103 subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
1104                                    vlc_bool_t b_paused )
1105 {
1106     int i_index, i_channel;
1107     subpicture_t *p_subpic = NULL;
1108     subpicture_t *p_ephemer;
1109     mtime_t      ephemer_date;
1110
1111     /* Run subpicture filters */
1112     for( i_index = 0; i_index < p_spu->i_filter; i_index++ )
1113     {
1114         subpicture_t *p_subpic_filter;
1115         p_subpic_filter = p_spu->pp_filter[i_index]->
1116             pf_sub_filter( p_spu->pp_filter[i_index], display_date );
1117         if( p_subpic_filter )
1118         {
1119             spu_DisplaySubpicture( p_spu, p_subpic_filter );
1120         }
1121     }
1122
1123     /* We get an easily parsable chained list of subpictures which
1124      * ends with NULL since p_subpic was initialized to NULL. */
1125     for( i_channel = 0; i_channel < p_spu->i_channel; i_channel++ )
1126     {
1127         p_ephemer = 0;
1128         ephemer_date = 0;
1129
1130         for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
1131         {
1132             if( p_spu->p_subpicture[i_index].i_channel != i_channel ||
1133                 p_spu->p_subpicture[i_index].i_status != READY_SUBPICTURE )
1134             {
1135                 continue;
1136             }
1137             if( display_date &&
1138                 display_date < p_spu->p_subpicture[i_index].i_start )
1139             {
1140                 /* Too early, come back next monday */
1141                 continue;
1142             }
1143
1144             if( p_spu->p_subpicture[i_index].i_start > ephemer_date )
1145                 ephemer_date = p_spu->p_subpicture[i_index].i_start;
1146
1147             if( display_date > p_spu->p_subpicture[i_index].i_stop &&
1148                 ( !p_spu->p_subpicture[i_index].b_ephemer ||
1149                   p_spu->p_subpicture[i_index].i_stop >
1150                   p_spu->p_subpicture[i_index].i_start ) &&
1151                 !( p_spu->p_subpicture[i_index].b_pausable &&
1152                    b_paused ) )
1153             {
1154                 /* Too late, destroy the subpic */
1155                 spu_DestroySubpicture( p_spu, &p_spu->p_subpicture[i_index] );
1156                 continue;
1157             }
1158
1159             /* If this is an ephemer subpic, add it to our list */
1160             if( p_spu->p_subpicture[i_index].b_ephemer )
1161             {
1162                 p_spu->p_subpicture[i_index].p_next = p_ephemer;
1163                 p_ephemer = &p_spu->p_subpicture[i_index];
1164
1165                 continue;
1166             }
1167
1168             p_spu->p_subpicture[i_index].p_next = p_subpic;
1169             p_subpic = &p_spu->p_subpicture[i_index];
1170         }
1171
1172         /* If we found ephemer subpictures, check if they have to be
1173          * displayed or destroyed */
1174         while( p_ephemer != NULL )
1175         {
1176             subpicture_t *p_tmp = p_ephemer;
1177             p_ephemer = p_ephemer->p_next;
1178
1179             if( p_tmp->i_start < ephemer_date )
1180             {
1181                 /* Ephemer subpicture has lived too long */
1182                 spu_DestroySubpicture( p_spu, p_tmp );
1183             }
1184             else
1185             {
1186                 /* Ephemer subpicture can still live a bit */
1187                 p_tmp->p_next = p_subpic;
1188                 p_subpic = p_tmp;
1189             }
1190         }
1191     }
1192
1193     return p_subpic;
1194 }
1195
1196 /*****************************************************************************
1197  * SpuClearChannel: clear an spu channel
1198  *****************************************************************************
1199  * This function destroys the subpictures which belong to the spu channel
1200  * corresponding to i_channel_id.
1201  *****************************************************************************/
1202 static void SpuClearChannel( spu_t *p_spu, int i_channel )
1203 {
1204     int          i_subpic;                               /* subpicture index */
1205     subpicture_t *p_subpic = NULL;                  /* first free subpicture */
1206
1207     vlc_mutex_lock( &p_spu->subpicture_lock );
1208
1209     for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
1210     {
1211         p_subpic = &p_spu->p_subpicture[i_subpic];
1212         if( p_subpic->i_status == FREE_SUBPICTURE
1213             || ( p_subpic->i_status != RESERVED_SUBPICTURE
1214                  && p_subpic->i_status != READY_SUBPICTURE ) )
1215         {
1216             continue;
1217         }
1218
1219         if( p_subpic->i_channel == i_channel )
1220         {
1221             while( p_subpic->p_region )
1222             {
1223                 subpicture_region_t *p_region = p_subpic->p_region;
1224                 p_subpic->p_region = p_region->p_next;
1225                 spu_DestroyRegion( p_spu, p_region );
1226             }
1227
1228             if( p_subpic->pf_destroy ) p_subpic->pf_destroy( p_subpic );
1229             p_subpic->i_status = FREE_SUBPICTURE;
1230         }
1231     }
1232
1233     vlc_mutex_unlock( &p_spu->subpicture_lock );
1234 }
1235
1236 /*****************************************************************************
1237  * spu_ControlDefault: default methods for the subpicture unit control.
1238  *****************************************************************************/
1239 static int spu_vaControlDefault( spu_t *p_spu, int i_query, va_list args )
1240 {
1241     int *pi, i;
1242
1243     switch( i_query )
1244     {
1245     case SPU_CHANNEL_REGISTER:
1246         pi = (int *)va_arg( args, int * );
1247         if( pi ) *pi = p_spu->i_channel++;
1248         break;
1249
1250     case SPU_CHANNEL_CLEAR:
1251         i = (int)va_arg( args, int );
1252         SpuClearChannel( p_spu, i );
1253         break;
1254
1255     default:
1256         msg_Dbg( p_spu, "control query not supported" );
1257         return VLC_EGENERIC;
1258     }
1259
1260     return VLC_SUCCESS;
1261 }
1262
1263 /*****************************************************************************
1264  * Object variables callbacks
1265  *****************************************************************************/
1266
1267 /*****************************************************************************
1268  * UpdateSPU: update subpicture settings
1269  *****************************************************************************
1270  * This function is called from CropCallback and at initialization time, to
1271  * retrieve crop information from the input.
1272  *****************************************************************************/
1273 static void UpdateSPU( spu_t *p_spu, vlc_object_t *p_object )
1274 {
1275     vlc_value_t val;
1276
1277     p_spu->b_force_palette = VLC_FALSE;
1278     p_spu->b_force_crop = VLC_FALSE;
1279
1280     if( var_Get( p_object, "highlight", &val ) || !val.b_bool ) return;
1281
1282     p_spu->b_force_crop = VLC_TRUE;
1283     var_Get( p_object, "x-start", &val );
1284     p_spu->i_crop_x = val.i_int;
1285     var_Get( p_object, "y-start", &val );
1286     p_spu->i_crop_y = val.i_int;
1287     var_Get( p_object, "x-end", &val );
1288     p_spu->i_crop_width = val.i_int - p_spu->i_crop_x;
1289     var_Get( p_object, "y-end", &val );
1290     p_spu->i_crop_height = val.i_int - p_spu->i_crop_y;
1291
1292     if( var_Get( p_object, "menu-palette", &val ) == VLC_SUCCESS )
1293     {
1294         memcpy( p_spu->palette, val.p_address, 16 );
1295         p_spu->b_force_palette = VLC_TRUE;
1296     }
1297
1298     msg_Dbg( p_object, "crop: %i,%i,%i,%i, palette forced: %i",
1299              p_spu->i_crop_x, p_spu->i_crop_y,
1300              p_spu->i_crop_width, p_spu->i_crop_height,
1301              p_spu->b_force_palette );
1302 }
1303
1304 /*****************************************************************************
1305  * CropCallback: called when the highlight properties are changed
1306  *****************************************************************************
1307  * This callback is called from the input thread when we need cropping
1308  *****************************************************************************/
1309 static int CropCallback( vlc_object_t *p_object, char const *psz_var,
1310                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1311 {
1312     (void)psz_var; (void)oldval; (void)newval;
1313     UpdateSPU( (spu_t *)p_data, p_object );
1314     return VLC_SUCCESS;
1315 }
1316
1317 /*****************************************************************************
1318  * Buffers allocation callbacks for the filters
1319  *****************************************************************************/
1320 static subpicture_t *sub_new_buffer( filter_t *p_filter )
1321 {
1322     filter_owner_sys_t *p_sys = p_filter->p_owner;
1323     subpicture_t *p_subpicture = spu_CreateSubpicture( p_sys->p_spu );
1324     if( p_subpicture ) p_subpicture->i_channel = p_sys->i_channel;
1325     return p_subpicture;
1326 }
1327
1328 static void sub_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
1329 {
1330     filter_owner_sys_t *p_sys = p_filter->p_owner;
1331     spu_DestroySubpicture( p_sys->p_spu, p_subpic );
1332 }
1333
1334 static subpicture_t *spu_new_buffer( filter_t *p_filter )
1335 {
1336     (void)p_filter;
1337     subpicture_t *p_subpic = (subpicture_t *)malloc(sizeof(subpicture_t));
1338     if( !p_subpic ) return NULL;
1339     memset( p_subpic, 0, sizeof(subpicture_t) );
1340     p_subpic->b_absolute = VLC_TRUE;
1341
1342     p_subpic->pf_create_region = __spu_CreateRegion;
1343     p_subpic->pf_make_region = __spu_MakeRegion;
1344     p_subpic->pf_destroy_region = __spu_DestroyRegion;
1345
1346     return p_subpic;
1347 }
1348
1349 static void spu_del_buffer( filter_t *p_filter, subpicture_t *p_subpic )
1350 {
1351     while( p_subpic->p_region )
1352     {
1353         subpicture_region_t *p_region = p_subpic->p_region;
1354         p_subpic->p_region = p_region->p_next;
1355         p_subpic->pf_destroy_region( VLC_OBJECT(p_filter), p_region );
1356     }
1357
1358     free( p_subpic );
1359 }
1360
1361 static picture_t *spu_new_video_buffer( filter_t *p_filter )
1362 {
1363     picture_t *p_picture = malloc( sizeof(picture_t) );
1364     if( !p_picture ) return NULL;
1365     if( vout_AllocatePicture( p_filter, p_picture,
1366                               p_filter->fmt_out.video.i_chroma,
1367                               p_filter->fmt_out.video.i_width,
1368                               p_filter->fmt_out.video.i_height,
1369                               p_filter->fmt_out.video.i_aspect )
1370         != VLC_SUCCESS )
1371     {
1372         free( p_picture );
1373         return NULL;
1374     }
1375
1376     p_picture->pf_release = RegionPictureRelease;
1377
1378     return p_picture;
1379 }
1380
1381 static void spu_del_video_buffer( filter_t *p_filter, picture_t *p_pic )
1382 {
1383     (void)p_filter;
1384     if( p_pic )
1385     {
1386         free( p_pic->p_data_orig );
1387         free( p_pic );
1388     }
1389 }
1390
1391 static int SubFilterCallback( vlc_object_t *p_object, char const *psz_var,
1392                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
1393 {
1394     VLC_UNUSED(p_object); VLC_UNUSED(oldval);
1395     VLC_UNUSED(newval); VLC_UNUSED(psz_var);
1396
1397     spu_t *p_spu = (spu_t *)p_data;
1398     vlc_mutex_lock( &p_spu->subpicture_lock );
1399     spu_DeleteChain( p_spu );
1400     spu_ParseChain( p_spu );
1401     vlc_mutex_unlock( &p_spu->subpicture_lock );
1402     return VLC_SUCCESS;
1403 }