root/src/video_output/vout_subpictures.c

Revision c4f35e50483d9a019cf8b665bb60a836071b96e0, 58.2 kB (checked in by Laurent Aimar <fenrir@videolan.org>, 2 months ago)

Fixed SSA subtitles pause.

I have modified spu_RenderSubpictures to take a b_paused argument.
The calls to pf_pre_render/pf_update_regions could have been moved to

spu_SortSubpicture and might have been cleaner BUT the way used keeps
all time consumming tasks inside spu_RenderSubpictures.

  • Property mode set to 100644
<
Line 
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_common.h>
34 #include <vlc_vout.h>
35 #include <vlc_block.h>
36 #include <vlc_filter.h>
37 #include <vlc_osd.h>
38 #include "../libvlc.h"
39
40 #include <assert.h>
41 #include <limits.h>
42
43 /*****************************************************************************
44  * Local prototypes
45  *****************************************************************************/
46 #define VLC_FOURCC_YUVP VLC_FOURCC('Y','U','V','P')
47 #define VLC_FOURCC_YUVA VLC_FOURCC('Y','U','V','A')
48 #define VLC_FOURCC_RGBA VLC_FOURCC('R','G','B','A')
49 #define VLC_FOURCC_TEXT VLC_FOURCC('T','E','X','T')
50
51 /* */
52 typedef struct
53 {
54     subpicture_t *p_subpicture;
55     bool          b_reject;
56 } spu_heap_entry_t;
57
58 typedef struct
59 {
60     spu_heap_entry_t p_entry[VOUT_MAX_SUBPICTURES];
61
62 } spu_heap_t;
63
64 static void SpuHeapInit( spu_heap_t * );
65 static int  SpuHeapPush( spu_heap_t *, subpicture_t * );
66 static void SpuHeapDeleteAt( spu_heap_t *, int i_index );
67 static int  SpuHeapDeleteSubpicture( spu_heap_t *, subpicture_t * );
68 static void SpuHeapClean( spu_heap_t *p_heap );
69
70 struct spu_private_t
71 {
72     vlc_mutex_t lock;   /* lock to protect all followings fields */
73
74     spu_heap_t heap;
75
76     int i_channel;             /**< number of subpicture channels registered */
77     filter_t *p_blend;                            /**< alpha blending module */
78     filter_t *p_text;                              /**< text renderer module */
79     filter_t *p_scale_yuvp;                     /**< scaling module for YUVP */
80     filter_t *p_scale;                    /**< scaling module (all but YUVP) */
81     bool b_force_crop;                     /**< force cropping of subpicture */
82     int i_crop_x, i_crop_y, i_crop_width, i_crop_height;       /**< cropping */
83
84     int i_margin;                        /**< force position of a subpicture */
85     bool b_force_palette;             /**< force palette of subpicture */
86     uint8_t palette[4][4];                               /**< forced palette */
87
88     /* Subpiture filters */
89     filter_chain_t *p_chain;
90
91     /* */
92     mtime_t i_last_sort_date;
93 };
94
95 /* */
96 struct subpicture_region_private_t
97 {
98     video_format_t fmt;
99     picture_t      *p_picture;
100 };
101 static subpicture_region_private_t *SpuRegionPrivateNew( video_format_t * );
102 static void SpuRegionPrivateDelete( subpicture_region_private_t * );
103
104 /* */
105 typedef struct
106 {
107     int w;
108     int h;
109 } spu_scale_t;
110 static spu_scale_t spu_scale_create( int w, int h );
111 static spu_scale_t spu_scale_unit(void );
112 static spu_scale_t spu_scale_createq( int wn, int wd, int hn, int hd );
113 static int spu_scale_w( int v, const spu_scale_t s );
114 static int spu_scale_h( int v, const spu_scale_t s );
115 static int spu_invscale_w( int v, const spu_scale_t s );
116 static int spu_invscale_h( int v, const spu_scale_t s );
117
118 typedef struct
119 {
120     int i_x;
121     int i_y;
122     int i_width;
123     int i_height;
124
125     spu_scale_t scale;
126 } spu_area_t;
127
128 static spu_area_t spu_area_create( int x, int y, int w, int h, spu_scale_t );
129 static spu_area_t spu_area_scaled( spu_area_t );
130 static spu_area_t spu_area_unscaled( spu_area_t, spu_scale_t );
131 static bool spu_area_overlap( spu_area_t, spu_area_t );
132
133
134 /* Subpicture rendered flag
135  * FIXME ? it could be moved to private ? */
136 #define SUBPICTURE_RENDERED  (0x1000)
137 #if SUBPICTURE_RENDERED < SUBPICTURE_ALIGN_MASK
138 #   error SUBPICTURE_RENDERED too low
139 #endif
140
141 #define SCALE_UNIT (1000)
142
143 static void SubpictureChain( subpicture_t **pp_head, subpicture_t *p_subpic );
144 static int SubpictureCmp( const void *s0, const void *s1 );
145
146 static void SpuRenderRegion( spu_t *,
147                              picture_t *p_pic_dst, spu_area_t *,
148                              subpicture_t *, subpicture_region_t *,
149                              const spu_scale_t scale_size,
150                              const video_format_t *p_fmt,
151                              const spu_area_t *p_subtitle_area, int i_subtitle_area );
152
153 static void UpdateSPU   ( spu_t *, vlc_object_t * );
154 static int  CropCallback( vlc_object_t *, char const *,
155                           vlc_value_t, vlc_value_t, void * );
156
157 static int SpuControl( spu_t *, int, va_list );
158
159 static void SpuClearChannel( spu_t *p_spu, int i_channel, bool b_locked );
160
161 /* Buffer allocation for SPU filter (blend, scale, ...) */
162 static subpicture_t *spu_new_buffer( filter_t * );
163 static void spu_del_buffer( filter_t *, subpicture_t * );
164 static picture_t *spu_new_video_buffer( filter_t * );
165 static void spu_del_video_buffer( filter_t *, picture_t * );
166
167 static int spu_ParseChain( spu_t * );
168
169 /* Buffer aloccation fir SUB filter */
170 static int SubFilterCallback( vlc_object_t *, char const *,
171                               vlc_value_t, vlc_value_t, void * );
172
173 static int SubFilterAllocationInit( filter_t *, void * );
174 static void SubFilterAllocationClean( filter_t * );
175
176 /* */
177 static void SpuRenderCreateAndLoadText( spu_t * );
178 static void SpuRenderCreateAndLoadScale( spu_t * );
179 static void SpuRenderCreateBlend( spu_t *, vlc_fourcc_t i_chroma, int i_aspect );
180 static void FilterRelease( filter_t *p_filter );
181
182 /*****************************************************************************
183  * Public API
184  *****************************************************************************/
185 /**
186  * Creates the subpicture unit
187  *
188  * \param p_this the parent object which creates the subpicture unit
189  */
190 spu_t *__spu_Create( vlc_object_t *p_this )
191 {
192     spu_t *p_spu;
193     spu_private_t *p_sys;
194  
195     p_spu = vlc_custom_create( p_this, sizeof(spu_t) + sizeof(spu_private_t),
196                                VLC_OBJECT_GENERIC, "subpicture" );
197
198     if( !p_spu )
199         return NULL;
200
201     /* Initialize spu fields */
202     p_spu->pf_control = SpuControl;
203     p_spu->p = p_sys = (spu_private_t*)&p_spu[1];
204
205     /* Initialize private fields */
206     vlc_mutex_init( &p_sys->lock );
207
208     SpuHeapInit( &p_sys->heap );
209
210     p_sys->p_blend = NULL;
211     p_sys->p_text = NULL;
212     p_sys->p_scale = NULL;
213     p_sys->p_scale_yuvp = NULL;
214
215     /* Register the default subpicture channel */
216     p_sys->i_channel = 2;
217
218     vlc_object_attach( p_spu, p_this );
219
220     p_sys->p_chain = filter_chain_New( p_spu, "sub filter", false,
221                                        SubFilterAllocationInit,
222                                        SubFilterAllocationClean,
223                                        p_spu );
224
225     /* Load text and scale module */
226     SpuRenderCreateAndLoadText( p_spu );
227     SpuRenderCreateAndLoadScale( p_spu );
228
229     /* */
230     p_sys->i_last_sort_date = -1;
231
232     return p_spu;
233 }
234
235 /**
236  * Initialise the subpicture unit
237  *
238  * \param p_spu the subpicture unit object
239  */
240 int spu_Init( spu_t *p_spu )
241 {
242     spu_private_t *p_sys = p_spu->p;
243
244     /* If the user requested a sub margin, we force the position. */
245     p_sys->i_margin = var_CreateGetInteger( p_spu, "sub-margin" );
246
247     var_Create( p_spu, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
248     var_AddCallback( p_spu, "sub-filter", SubFilterCallback, p_spu );
249
250     spu_ParseChain( p_spu );
251
252     return VLC_SUCCESS;
253 }
254
255 int spu_ParseChain( spu_t *p_spu )
256 {
257     char *psz_parser = var_GetString( p_spu, "sub-filter" );
258     int i_ret;
259
260     if( !psz_parser )
261         return VLC_EGENERIC;
262
263     i_ret = filter_chain_AppendFromString( p_spu->p->p_chain, psz_parser );
264
265     free( psz_parser );
266
267     return i_ret;
268 }
269
270 /**
271  * Destroy the subpicture unit
272  *
273  * \param p_this the parent object which destroys the subpicture unit
274  */
275 void spu_Destroy( spu_t *p_spu )
276 {
277     spu_private_t *p_sys = p_spu->p;
278
279     if( p_sys->p_blend )
280         FilterRelease( p_sys->p_blend );
281
282     if( p_sys->p_text )
283         FilterRelease( p_sys->p_text );
284
285     if( p_sys->p_scale_yuvp )
286         FilterRelease( p_sys->p_scale_yuvp );
287
288     if( p_sys->p_scale )
289         FilterRelease( p_sys->p_scale );
290
291     filter_chain_Delete( p_sys->p_chain );
292
293     /* Destroy all remaining subpictures */
294     SpuHeapClean( &p_sys->heap );
295
296     vlc_mutex_destroy( &p_sys->lock );
297
298     vlc_object_release( p_spu );
299 }
300
301 /**
302  * Attach/Detach the SPU from any input
303  *
304  * \param p_this the object in which to destroy the subpicture unit
305  * \param b_attach to select attach or detach
306  */
307 void spu_Attach( spu_t *p_spu, vlc_object_t *p_this, bool b_attach )
308 {
309     vlc_object_t *p_input;
310
311     p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT );
312     if( !p_input ) return;
313
314     if( b_attach )
315     {
316         UpdateSPU( p_spu, VLC_OBJECT(p_input) );
317         var_AddCallback( p_input, "highlight", CropCallback, p_spu );
318         vlc_object_release( p_input );
319     }
320     else
321     {
322         /* Delete callback */
323         var_DelCallback( p_input, "highlight", CropCallback, p_spu );
324         vlc_object_release( p_input );
325     }
326 }
327
328 /**
329  * Display a subpicture
330  *
331  * Remove the reservation flag of a subpicture, which will cause it to be
332  * ready for display.
333  * \param p_spu the subpicture unit object
334  * \param p_subpic the subpicture to display
335  */
336 void spu_DisplaySubpicture( spu_t *p_spu, subpicture_t *p_subpic )
337 {
338     spu_private_t *p_sys = p_spu->p;
339
340     /* DEFAULT_CHAN always reset itself */
341     if( p_subpic->i_channel == DEFAULT_CHAN )
342         SpuClearChannel( p_spu, DEFAULT_CHAN, false );
343
344     /* p_private is for spu only and cannot be non NULL here */
345     for( subpicture_region_t *r = p_subpic->p_region; r != NULL; r = r->p_next )
346         assert( r->p_private == NULL );
347
348     /* */
349     vlc_mutex_lock( &p_sys->lock );
350     if( SpuHeapPush( &p_sys->heap, p_subpic ) )
351     {
352         vlc_mutex_unlock( &p_sys->lock );
353         msg_Err( p_spu, "subpicture heap full" );
354         subpicture_Delete( p_subpic );
355         return;
356     }
357     vlc_mutex_unlock( &p_sys->lock );
358 }
359
360 /**
361  * This function renders all sub picture units in the list.
362  */
363 void spu_RenderSubpictures( spu_t *p_spu,
364                             picture_t *p_pic_dst, const video_format_t *p_fmt_dst,
365                             subpicture_t *p_subpic_list,
366                             const video_format_t *p_fmt_src, bool b_paused )
367 {
368     spu_private_t *p_sys = p_spu->p;
369
370     const int i_source_video_width  = p_fmt_src->i_width;
371     const int i_source_video_height = p_fmt_src->i_height;
372     const mtime_t i_current_date = mdate();
373
374     unsigned int i_subpicture;
375     subpicture_t *pp_subpicture[VOUT_MAX_SUBPICTURES];
376
377     unsigned int i_subtitle_region_count;
378     spu_area_t p_subtitle_area_buffer[VOUT_MAX_SUBPICTURES];
379     spu_area_t *p_subtitle_area;
380     int i_subtitle_area;
381
382     vlc_mutex_lock( &p_sys->lock );
383
384     /* Preprocess subpictures */
385     i_subpicture = 0;
386     i_subtitle_region_count = 0;
387     for( subpicture_t * p_subpic = p_subpic_list;
388             p_subpic != NULL;
389                 p_subpic = p_subpic->p_next )
390     {
391         /* */
392         if( !b_paused && p_subpic->pf_pre_render )
393             p_subpic->pf_pre_render( p_spu, p_subpic, p_fmt_dst );
394
395         if( !b_paused && p_subpic->pf_update_regions )
396         {
397             video_format_t fmt_org = *p_fmt_dst;
398             fmt_org.i_width =
399             fmt_org.i_visible_width = i_source_video_width;
400             fmt_org.i_height =
401             fmt_org.i_visible_height = i_source_video_height;
402
403             p_subpic->pf_update_regions( p_spu, p_subpic, &fmt_org, i_current_date );
404         }
405
406         /* */
407         if( p_subpic->b_subtitle )
408         {
409             for( subpicture_region_t *r = p_subpic->p_region; r != NULL; r = r->p_next )
410                 i_subtitle_region_count++;
411         }
412
413         /* */
414         pp_subpicture[i_subpicture++] = p_subpic;
415     }
416
417     /* Be sure we have at least 1 picture to process */
418     if( i_subpicture <= 0 )
419     {
420         vlc_mutex_unlock( &p_sys->lock );
421         return;
422     }
423
424     /* Now order subpicture array
425      * XXX The order is *really* important for overlap subtitles positionning */
426     qsort( pp_subpicture, i_subpicture, sizeof(*pp_subpicture), SubpictureCmp );
427
428     /* Allocate area array for subtitle overlap */
429     i_subtitle_area = 0;
430     p_subtitle_area = p_subtitle_area_buffer;
431     if( i_subtitle_region_count > sizeof(p_subtitle_area_buffer)/sizeof(*p_subtitle_area_buffer) )
432         p_subtitle_area = calloc( i_subtitle_region_count, sizeof(*p_subtitle_area) );
433
434     /* Create the blending module */
435     if( !p_sys->p_blend )
436         SpuRenderCreateBlend( p_spu, p_fmt_dst->i_chroma, p_fmt_dst->i_aspect );
437
438     /* Process all subpictures and regions (in the right order) */
439     for( unsigned int i_index = 0; i_index < i_subpicture; i_index++ )
440     {
441         subpicture_t *p_subpic = pp_subpicture[i_index];
442         subpicture_region_t *p_region;
443
444         if( !p_subpic->p_region )
445             continue;
446
447         /* FIXME when possible use a better rendering size than source size
448          * (max of display size and source size for example) FIXME */
449         int i_render_width  = p_subpic->i_original_picture_width;
450         int i_render_height = p_subpic->i_original_picture_height;
451         if( !i_render_width || !i_render_height )
452         {
453             if( i_render_width != 0 || i_render_height != 0 )
454                 msg_Err( p_spu, "unsupported original picture size %dx%d",
455                          i_render_width, i_render_height );
456
457             p_subpic->i_original_picture_width  = i_render_width = i_source_video_width;
458             p_subpic->i_original_picture_height = i_render_height = i_source_video_height;
459         }
460
461         if( p_sys->p_text )
462         {
463             p_sys->p_text->fmt_out.video.i_width          =
464             p_sys->p_text->fmt_out.video.i_visible_width  = i_render_width;
465
466             p_sys->p_text->fmt_out.video.i_height         =
467             p_sys->p_text->fmt_out.video.i_visible_height = i_render_height;
468         }
469
470         /* Compute scaling from picture to source size */
471         spu_scale_t scale = spu_scale_createq( i_source_video_width,  i_render_width,
472                                                i_source_video_height, i_render_height );
473
474         /* Update scaling from source size to display size(p_fmt_dst) */
475         scale.w = scale.w * p_fmt_dst->i_width  / i_source_video_width;
476         scale.h = scale.h * p_fmt_dst->i_height / i_source_video_height;
477
478         /* Set default subpicture aspect ratio
479          * FIXME if we only handle 1 aspect ratio per picture, why is it set per
480          * region ? */
481         p_region = p_subpic->p_region;
482         if( !p_region->fmt.i_sar_num || !p_region->fmt.i_sar_den )
483         {
484             if( p_region->fmt.i_aspect != 0 )
485             {
486                 p_region->fmt.i_sar_den = p_region->fmt.i_aspect;
487                 p_region->fmt.i_sar_num = VOUT_ASPECT_FACTOR;
488             }
489             else
490             {
491                 p_region->fmt.i_sar_den = p_fmt_dst->i_sar_den;
492                 p_region->fmt.i_sar_num = p_fmt_dst->i_sar_num;
493             }
494         }
495
496         /* Take care of the aspect ratio */
497         if( p_region->fmt.i_sar_num * p_fmt_dst->i_sar_den !=
498             p_region->fmt.i_sar_den * p_fmt_dst->i_sar_num )
499         {
500             /* FIXME FIXME what about region->i_x/i_y ? */
501             scale.w = scale.w *
502                 (int64_t)p_region->fmt.i_sar_num * p_fmt_dst->i_sar_den /
503                 p_region->fmt.i_sar_den / p_fmt_dst->i_sar_num;
504         }
505
506         /* Render all regions
507          * We always transform non absolute subtitle into absolute one on the
508          * first rendering to allow good subtitle overlap support.
509          */
510         for( p_region = p_subpic->p_region; p_region != NULL; p_region = p_region->p_next )
511         {
512             spu_area_t area;
513
514             /* Check scale validity */
515             if( scale.w <= 0 || scale.h <= 0 )
516                 continue;
517
518             /* */
519             SpuRenderRegion( p_spu, p_pic_dst, &area,
520                              p_subpic, p_region, scale, p_fmt_dst,
521                              p_subtitle_area, i_subtitle_area );
522
523             if( p_subpic->b_subtitle )
524             {
525                 area = spu_area_unscaled( area, scale );
526                 if( !p_subpic->b_absolute && area.i_width > 0 && area.i_height > 0 )
527                 {
528                     p_region->i_x = area.i_x;
529                     p_region->i_y = area.i_y;
530                 }
531                 if( p_subtitle_area )
532                     p_subtitle_area[i_subtitle_area++] = area;
533             }
534         }
535         if( p_subpic->b_subtitle )
536             p_subpic->b_absolute = true;
537     }
538
539     /* */
540     if( p_subtitle_area != p_subtitle_area_buffer )
541         free( p_subtitle_area );
542
543     vlc_mutex_unlock( &p_sys->lock );
544 }
545
546 /*****************************************************************************
547  * spu_SortSubpictures: find the subpictures to display
548  *****************************************************************************
549  * This function parses all subpictures and decides which ones need to be
550  * displayed. If no picture has been selected, display_date will depend on
551  * the subpicture.
552  * We also check for ephemer DVD subpictures (subpictures that have
553  * to be removed if a newer one is available), which makes it a lot
554  * more difficult to guess if a subpicture has to be rendered or not.
555  *****************************************************************************/
556 subpicture_t *spu_SortSubpictures( spu_t *p_spu, mtime_t display_date,
557                                    bool b_paused, bool b_subtitle_only )
558 {
559     spu_private_t *p_sys = p_spu->p;
560     int i_channel;
561     subpicture_t *p_subpic = NULL;
562
563     /* Run subpicture filters */
564     filter_chain_SubFilter( p_sys->p_chain, display_date );
565
566     vlc_mutex_lock( &p_sys->lock );
567
568     /* We get an easily parsable chained list of subpictures which
569      * ends with NULL since p_subpic was initialized to NULL. */
570     for( i_channel = 0; i_channel < p_sys->i_channel; i_channel++ )
571     {
572         subpicture_t *p_available_subpic[VOUT_MAX_SUBPICTURES];
573         bool         pb_available_late[VOUT_MAX_SUBPICTURES];
574         int          i_available = 0;
575
576         mtime_t      start_date = display_date;
577         mtime_t      ephemer_date = 0;
578         int i_index;
579
580         /* Select available pictures */
581         for( i_index = 0; i_index < VOUT_MAX_SUBPICTURES; i_index++ )
582         {
583             spu_heap_entry_t *p_entry = &p_sys->heap.p_entry[i_index];
584             subpicture_t *p_current = p_entry->p_subpicture;
585             bool b_stop_valid;
586             bool b_late;
587
588             if( !p_current || p_entry->b_reject )
589             {
590                 if( p_entry->b_reject )
591                     SpuHeapDeleteAt( &p_sys->heap, i_index );
592                 continue;
593             }
594
595             if( p_current->i_channel != i_channel ||
596                 ( b_subtitle_only && !p_current->b_subtitle ) )
597             {
598                 continue;
599             }
600             if( display_date &&
601                 display_date < p_current->i_start )
602             {
603                 /* Too early, come back next monday */
604                 continue;
605             }
606
607             if( p_current->i_start > ephemer_date )
608                 ephemer_date = p_current->i_start;
609
610             b_stop_valid = ( !p_current->b_ephemer || p_current->i_stop > p_current->i_start ) &&
611                            ( !p_current->b_subtitle || !b_paused ); /* XXX Assume that subtitle are pausable */
612
613             b_late = b_stop_valid && p_current->i_stop <= display_date;
614
615             /* start_date will be used for correct automatic overlap support
616              * in case picture that should not be displayed anymore (display_time)
617              * overlap with a picture to be displayed (p_current->i_start)  */
618             if( !b_late && !p_current->b_ephemer )
619                 start_date = p_current->i_start;
620
621             /* */
622             p_available_subpic[i_available] = p_current;
623             pb_available_late[i_available] = b_late;
624             i_available++;
625         }
626
627         /* Only forced old picture display at the transition */
628         if( start_date < p_sys->i_last_sort_date )
629             start_date = p_sys->i_last_sort_date;
630         if( start_date <= 0 )
631             start_date = INT64_MAX;
632
633         /* Select pictures to be displayed */
634         for( i_index = 0; i_index < i_available; i_index++ )
635         {
636             subpicture_t *p_current = p_available_subpic[i_index];
637             bool b_late = pb_available_late[i_index];
638
639             if( ( b_late && p_current->i_stop <= __MAX( start_date, p_sys->i_last_sort_date ) ) ||
640                 ( p_current->b_ephemer && p_current->i_start < ephemer_date ) )
641             {
642                 /* Destroy late and obsolete ephemer subpictures */
643                 SpuHeapDeleteSubpicture( &p_sys->heap, p_current );
644             }
645             else
646             {
647                 SubpictureChain( &p_subpic, p_current );
648             }
649         }
650     }
651
652     p_sys->i_last_sort_date = display_date;
653     vlc_mutex_unlock( &p_sys->lock );
654
655     return p_subpic;
656 }
657
658 /*****************************************************************************
659  * subpicture_t allocation
660  *****************************************************************************/
661 subpicture_t *subpicture_New( void )
662 {
663     subpicture_t *p_subpic = calloc( 1, sizeof(*p_subpic) );
664     if( !p_subpic )
665         return NULL;
666
667     p_subpic->i_order    = 0;
668     p_subpic->b_absolute = true;
669     p_subpic->b_fade     = false;
670     p_subpic->b_subtitle = false;
671     p_subpic->i_alpha    = 0xFF;
672     p_subpic->p_region   = NULL;
673     p_subpic->pf_render  = NULL;
674     p_subpic->pf_destroy = NULL;
675     p_subpic->p_sys      = NULL;
676
677     return p_subpic;
678 }
679
680 void subpicture_Delete( subpicture_t *p_subpic )
681 {
682     subpicture_region_ChainDelete( p_subpic->p_region );
683     p_subpic->p_region = NULL;
684
685     if( p_subpic->pf_destroy )
686     {
687         p_subpic->pf_destroy( p_subpic );
688     }
689     free( p_subpic );
690 }
691
692 static void SubpictureChain( subpicture_t **pp_head, subpicture_t *p_subpic )
693 {
694     p_subpic->p_next = *pp_head;
695
696     *pp_head = p_subpic;
697 }
698
699 /*****************************************************************************
700  * subpicture_region_t allocation
701  *****************************************************************************/
702 subpicture_region_t *subpicture_region_New( const video_format_t *p_fmt )
703 {
704     subpicture_region_t *p_region = calloc( 1, sizeof(*p_region ) );
705     if( !p_region )
706         return NULL;
707
708     p_region->fmt = *p_fmt;
709     p_region->fmt.p_palette = NULL;
710     if( p_fmt->i_chroma == VLC_FOURCC_YUVP )
711     {
712         p_region->fmt.p_palette = calloc( 1, sizeof(*p_region->fmt.p_palette) );
713         if( p_fmt->p_palette )
714             *p_region->fmt.p_palette = *p_fmt->p_palette;
715     }
716     p_region->i_alpha = 0xff;
717     p_region->p_next = NULL;
718     p_region->p_private = NULL;
719     p_region->psz_text = NULL;
720     p_region->p_style = NULL;
721     p_region->p_picture = NULL;
722
723     if( p_fmt->i_chroma == VLC_FOURCC_TEXT )
724         return p_region;
725
726     p_region->p_picture = picture_New( p_fmt->i_chroma, p_fmt->i_width, p_fmt->i_height,
727                                        p_fmt->i_aspect );
728     if( !p_region->p_picture )
729     {
730         free( p_fmt->p_palette );
731         free( p_region );
732         return NULL;
733     }
734
735     return p_region;
736 }
737
738 /* */
739 void subpicture_region_Delete( subpicture_region_t *p_region )
740 {
741     if( !p_region )
742         return;
743
744     if( p_region->p_private )
745         SpuRegionPrivateDelete( p_region->p_private );
746
747     if( p_region->p_picture )
748         picture_Release( p_region->p_picture );
749
750     free( p_region->fmt.p_palette );
751
752     free( p_region->psz_text );
753     free( p_region->psz_html );
754     //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
755     free( p_region );
756 }
757
758 /* */
759 void subpicture_region_ChainDelete( subpicture_region_t *p_head )
760 {
761     while( p_head )
762     {
763         subpicture_region_t *p_next = p_head->p_next;
764
765         subpicture_region_Delete( p_head );
766
767         p_head = p_next;
768     }
769 }
770
771
772
773 /*****************************************************************************
774  * heap managment
775  *****************************************************************************/
776 static void SpuHeapInit( spu_heap_t *p_heap )
777 {
778     for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
779     {
780         spu_heap_entry_t *e = &p_heap->p_entry[i];
781
782         e->p_subpicture = NULL;
783         e->b_reject = false;
784     }
785 }
786
787 static int SpuHeapPush( spu_heap_t *p_heap, subpicture_t *p_subpic )
788 {
789     for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
790     {
791         spu_heap_entry_t *e = &p_heap->p_entry[i];
792
793         if( e->p_subpicture )
794             continue;
795
796         e->p_subpicture = p_subpic;
797         e->b_reject = false;
798         return VLC_SUCCESS;
799     }
800     return VLC_EGENERIC;
801 }
802
803 static void SpuHeapDeleteAt( spu_heap_t *p_heap, int i_index )
804 {
805     spu_heap_entry_t *e = &p_heap->p_entry[i_index];
806
807     if( e->p_subpicture )
808         subpicture_Delete( e->p_subpicture );
809
810     e->p_subpicture = NULL;
811 }
812
813 static int SpuHeapDeleteSubpicture( spu_heap_t *p_heap, subpicture_t *p_subpic )
814 {
815     for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
816     {
817         spu_heap_entry_t *e = &p_heap->p_entry[i];
818
819         if( e->p_subpicture != p_subpic )
820             continue;
821
822         SpuHeapDeleteAt( p_heap, i );
823         return VLC_SUCCESS;
824     }
825     return VLC_EGENERIC;
826 }
827
828 static void SpuHeapClean( spu_heap_t *p_heap )
829 {
830     for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
831     {
832         spu_heap_entry_t *e = &p_heap->p_entry[i];
833         if( e->p_subpicture )
834             subpicture_Delete( e->p_subpicture );
835     }
836 }
837
838 static subpicture_region_private_t *SpuRegionPrivateNew( video_format_t *p_fmt )
839 {
840     subpicture_region_private_t *p_private = malloc( sizeof(*p_private) );
841
842     if( !p_private )
843         return NULL;
844
845     p_private->fmt = *p_fmt;
846     if( p_fmt->p_palette )
847     {
848         p_private->fmt.p_palette = malloc( sizeof(*p_private->fmt.p_palette) );
849         if( p_private->fmt.p_palette )
850             *p_private->fmt.p_palette = *p_fmt->p_palette;
851     }
852     p_private->p_picture = NULL;
853
854     return p_private;
855 }
856 static void SpuRegionPrivateDelete( subpicture_region_private_t *p_private )
857 {
858     if( p_private->p_picture )
859         picture_Release( p_private->p_picture );
860     free( p_private->fmt.p_palette );
861     free( p_private );
862 }
863
864 static void FilterRelease( filter_t *p_filter )
865 {
866     if( p_filter->p_module )
867         module_unneed( p_filter, p_filter->p_module );
868
869     vlc_object_detach( p_filter );
870     vlc_object_release( p_filter );
871 }
872
873 static void SpuRenderCreateBlend( spu_t *p_spu, vlc_fourcc_t i_chroma, int i_aspect )
874 {
875     filter_t *p_blend;
876
877     assert( !p_spu->p->p_blend );
878
879     p_spu->p->p_blend =
880     p_blend        = vlc_custom_create( p_spu, sizeof(filter_t),
881                                         VLC_OBJECT_GENERIC, "blend" );
882     if( !p_blend )
883         return;
884
885     es_format_Init( &p_blend->fmt_in, VIDEO_ES, 0 );
886
887     es_format_Init( &p_blend->fmt_out, VIDEO_ES, 0 );
888     p_blend->fmt_out.video.i_x_offset = 0;
889     p_blend->fmt_out.video.i_y_offset = 0;
890     p_blend->fmt_out.video.i_chroma = i_chroma;
891     p_blend->fmt_out.video.i_aspect = i_aspect;
892
893     /* The blend module will be loaded when needed with the real
894     * input format */
895     p_blend->p_module = NULL;
896
897     /* */
898     vlc_object_attach( p_blend, p_spu );
899 }
900 static void SpuRenderUpdateBlend( spu_t *p_spu, int i_out_width, int i_out_height,
901                                   const video_format_t *p_in_fmt )
902 {
903     filter_t *p_blend = p_spu->p->p_blend;
904
905     assert( p_blend );
906
907     /* */
908     if( p_blend->p_module && p_blend->fmt_in.video.i_chroma != p_in_fmt->i_chroma )
909     {
910         /* The chroma is not the same, we need to reload the blend module
911          * XXX to match the old behaviour just test !p_blend->fmt_in.video.i_chroma */
912         module_unneed( p_blend, p_blend->p_module );
913         p_blend->p_module = NULL;
914     }
915
916     /* */
917     p_blend->fmt_in.video = *p_in_fmt;
918
919     /* */
920     p_blend->fmt_out.video.i_width =
921     p_blend->fmt_out.video.i_visible_width = i_out_width;
922     p_blend->fmt_out.video.i_height =
923     p_blend->fmt_out.video.i_visible_height = i_out_height;
924
925     /* */
926     if( !p_blend->p_module )
927         p_blend->p_module = module_need( p_blend, "video blending", 0, 0 );
928 }
929 static void SpuRenderCreateAndLoadText( spu_t *p_spu )
930 {
931     filter_t *p_text;
932
933     assert( !p_spu->p->p_text );
934
935     p_spu->p->p_text =
936     p_text        = vlc_custom_create( p_spu, sizeof(filter_t),
937                                        VLC_OBJECT_GENERIC, "spu text" );
938     if( !p_text )