+ subpicture_region_t *p_region = calloc( 1, sizeof(*p_region ) );
+ if( !p_region )
+ return NULL;
+
+ p_region->fmt = *p_fmt;
+ p_region->fmt.p_palette = NULL;
+ if( p_fmt->i_chroma == VLC_FOURCC_YUVP )
+ {
+ p_region->fmt.p_palette = calloc( 1, sizeof(*p_region->fmt.p_palette) );
+ if( p_fmt->p_palette )
+ *p_region->fmt.p_palette = *p_fmt->p_palette;
+ }
+ p_region->i_alpha = 0xff;
+ p_region->p_next = NULL;
+ p_region->p_private = NULL;
+ p_region->psz_text = NULL;
+ p_region->p_style = NULL;
+ p_region->p_picture = NULL;
+
+ if( p_fmt->i_chroma == VLC_FOURCC_TEXT )
+ return p_region;
+
+ p_region->p_picture = picture_New( p_fmt->i_chroma, p_fmt->i_width, p_fmt->i_height,
+ p_fmt->i_aspect );
+ if( !p_region->p_picture )
+ {
+ free( p_fmt->p_palette );
+ free( p_region );
+ return NULL;
+ }
+
+ return p_region;
+}
+
+/* */
+void subpicture_region_Delete( subpicture_region_t *p_region )
+{
+ if( !p_region )
+ return;
+
+ if( p_region->p_private )
+ SpuRegionPrivateDestroy( p_region->p_private );
+
+ if( p_region->p_picture )
+ picture_Release( p_region->p_picture );
+
+ free( p_region->fmt.p_palette );
+
+ free( p_region->psz_text );
+ free( p_region->psz_html );
+ //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
+ free( p_region );
+}
+
+/* */
+void subpicture_region_ChainDelete( subpicture_region_t *p_head )
+{
+ while( p_head )
+ {
+ subpicture_region_t *p_next = p_head->p_next;
+
+ subpicture_region_Delete( p_head );
+
+ p_head = p_next;
+ }
+}
+
+/**
+ * This function create a new empty subpicture.
+ */
+static subpicture_t *subpicture_New( void )
+{
+ subpicture_t *p_subpic = calloc( 1, sizeof(*p_subpic) );
+ if( !p_subpic )
+ return NULL;
+
+ p_subpic->i_order = 0;
+ p_subpic->b_absolute = true;
+ p_subpic->b_fade = false;
+ p_subpic->b_subtitle = false;
+ p_subpic->i_alpha = 0xFF;
+ p_subpic->p_region = NULL;
+ p_subpic->pf_render = NULL;
+ p_subpic->pf_destroy = NULL;
+ p_subpic->p_sys = NULL;
+
+ return p_subpic;
+}
+
+static void subpicture_Delete( subpicture_t *p_subpic )
+{
+ subpicture_region_ChainDelete( p_subpic->p_region );
+ p_subpic->p_region = NULL;
+
+ if( p_subpic->pf_destroy )
+ {
+ p_subpic->pf_destroy( p_subpic );
+ }
+ free( p_subpic );
+}
+
+
+static void SpuHeapInit( spu_heap_t *p_heap )
+{
+ for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
+ {
+ spu_heap_entry_t *e = &p_heap->p_entry[i];
+
+ e->p_subpicture = NULL;
+ e->b_reject = false;
+ }
+}
+
+static int SpuHeapPush( spu_heap_t *p_heap, subpicture_t *p_subpic )
+{
+ for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
+ {
+ spu_heap_entry_t *e = &p_heap->p_entry[i];
+
+ if( e->p_subpicture )
+ continue;
+
+ e->p_subpicture = p_subpic;
+ e->b_reject = false;
+ return VLC_SUCCESS;
+ }
+ return VLC_EGENERIC;
+}
+
+static void SpuHeapDeleteAt( spu_heap_t *p_heap, int i_index )
+{
+ spu_heap_entry_t *e = &p_heap->p_entry[i_index];
+
+ if( e->p_subpicture )
+ subpicture_Delete( e->p_subpicture );
+
+ e->p_subpicture = NULL;
+}
+
+static int SpuHeapDeleteSubpicture( spu_heap_t *p_heap, subpicture_t *p_subpic )
+{
+ for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
+ {
+ spu_heap_entry_t *e = &p_heap->p_entry[i];
+
+ if( e->p_subpicture != p_subpic )
+ continue;
+
+ SpuHeapDeleteAt( p_heap, i );
+ return VLC_SUCCESS;
+ }
+ return VLC_EGENERIC;
+}
+
+static void SpuHeapClean( spu_heap_t *p_heap )
+{
+ for( int i = 0; i < VOUT_MAX_SUBPICTURES; i++ )
+ {
+ spu_heap_entry_t *e = &p_heap->p_entry[i];
+ if( e->p_subpicture )
+ subpicture_Delete( e->p_subpicture );
+ }
+}
+static subpicture_region_private_t *SpuRegionPrivateCreate( video_format_t *p_fmt )
+{
+ subpicture_region_private_t *p_private = malloc( sizeof(*p_private) );
+
+ if( !p_private )
+ return NULL;
+
+ p_private->fmt = *p_fmt;
+ if( p_fmt->p_palette )
+ {
+ p_private->fmt.p_palette = malloc( sizeof(*p_private->fmt.p_palette) );
+ if( p_private->fmt.p_palette )
+ *p_private->fmt.p_palette = *p_fmt->p_palette;
+ }
+ p_private->p_picture = NULL;
+
+ return p_private;
+}
+static void SpuRegionPrivateDestroy( subpicture_region_private_t *p_private )
+{
+ if( p_private->p_picture )
+ picture_Release( p_private->p_picture );
+ free( p_private->fmt.p_palette );
+ free( p_private );
+}
+
+/* */
+static void SpuRenderCreateAndLoadText( spu_t *p_spu );
+static void SpuRenderCreateAndLoadScale( spu_t *p_spu );
+static void FilterRelease( filter_t *p_filter );