Removed b_pausable flag in favour of b_subtitle.
[vlc.git] / modules / codec / kate.c
1 /*****************************************************************************
2  * kate.c : a decoder for the kate bitstream format
3  *****************************************************************************
4  * Copyright (C) 2000-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Vincent Penquerc'h <ogg.k.ogg.k@googlemail.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_input.h>
34 #include <vlc_codec.h>
35 #include <vlc_osd.h>
36
37 #include <kate/kate.h>
38
39 /* #define ENABLE_PACKETIZER */
40 #define ENABLE_FORMATTING
41 #define ENABLE_BITMAPS
42
43 /*****************************************************************************
44  * decoder_sys_t : decoder descriptor
45  *****************************************************************************/
46 struct decoder_sys_t
47 {
48 #ifdef ENABLE_PACKETIZER
49     /* Module mode */
50     bool b_packetizer;
51 #endif
52
53     /*
54      * Input properties
55      */
56     int i_num_headers;
57     int i_headers;
58
59     /*
60      * Kate properties
61      */
62     bool           b_ready;
63     kate_info      ki;
64     kate_comment   kc;
65     kate_state     k;
66
67     /*
68      * Common properties
69      */
70     mtime_t i_pts;
71
72     /*
73      * Options
74      */
75 #ifdef ENABLE_FORMATTING
76     bool   b_formatted;
77 #endif
78 };
79
80 /*****************************************************************************
81  * Local prototypes
82  *****************************************************************************/
83 static int  OpenDecoder   ( vlc_object_t * );
84 static void CloseDecoder  ( vlc_object_t * );
85 #ifdef ENABLE_PACKETIZER
86 static int OpenPacketizer( vlc_object_t *p_this );
87 #endif
88
89 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block );
90 static int ProcessHeaders( decoder_t *p_dec );
91 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
92                             block_t **pp_block );
93 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp,
94                             block_t *p_block );
95 static void ParseKateComments( decoder_t * );
96
97 #define DEFAULT_NAME "Default"
98 #define MAX_LINE 8192
99
100 /*****************************************************************************
101  * Module descriptor.
102  *****************************************************************************/
103
104 #ifdef ENABLE_FORMATTING
105 #define FORMAT_TEXT N_("Formatted Subtitles")
106 #define FORMAT_LONGTEXT N_("Kate streams allow for text formatting. " \
107  "VLC partly implements this, but you can choose to disable all formatting.")
108 #endif
109
110
111 vlc_module_begin();
112     set_shortname( N_("Kate"));
113     set_description( N_("Kate text subtitles decoder") );
114     set_capability( "decoder", 50 );
115     set_callbacks( OpenDecoder, CloseDecoder );
116     set_category( CAT_INPUT );
117     set_subcategory( SUBCAT_INPUT_SCODEC );
118     add_shortcut( "kate" );
119
120 #ifdef ENABLE_PACKETIZER
121     add_submodule();
122     set_description( N_("Kate text subtitles packetizer") );
123     set_capability( "packetizer", 100 );
124     set_callbacks( OpenPacketizer, CloseDecoder );
125     add_shortcut( "kate" );
126 #endif
127
128 #ifdef ENABLE_FORMATTING
129     add_bool( "kate-formatted", true, NULL, FORMAT_TEXT, FORMAT_LONGTEXT,
130               true );
131 #endif
132 vlc_module_end();
133
134 /*****************************************************************************
135  * OpenDecoder: probe the decoder and return score
136  *****************************************************************************
137  * Tries to launch a decoder and return score so that the interface is able
138  * to chose.
139  *****************************************************************************/
140 static int OpenDecoder( vlc_object_t *p_this )
141 {
142     decoder_t     *p_dec = (decoder_t*)p_this;
143     decoder_sys_t *p_sys;
144
145     msg_Dbg( p_dec, "kate: OpenDecoder");
146
147     if( p_dec->fmt_in.i_codec != VLC_FOURCC('k','a','t','e') )
148     {
149         return VLC_EGENERIC;
150     }
151
152     /* Set callbacks */
153     p_dec->pf_decode_sub = (subpicture_t *(*)(decoder_t *, block_t **))
154         DecodeBlock;
155     p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
156         DecodeBlock;
157
158     /* Allocate the memory needed to store the decoder's structure */
159     if( ( p_dec->p_sys = p_sys =
160           (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
161         return VLC_ENOMEM;
162
163     /* init of p_sys */
164 #ifdef ENABLE_PACKETIZER
165     p_sys->b_packetizer = false;
166 #endif
167     p_sys->b_ready = false;
168     p_sys->i_pts = 0;
169
170     kate_comment_init( &p_sys->kc );
171     kate_info_init( &p_sys->ki );
172
173     p_sys->i_num_headers = 0;
174     p_sys->i_headers = 0;
175
176     /* retrieve options */
177 #ifdef ENABLE_FORMATTING
178     p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" );
179 #endif
180
181     return VLC_SUCCESS;
182 }
183
184 #ifdef ENABLE_PACKETIZER
185 static int OpenPacketizer( vlc_object_t *p_this )
186 {
187     decoder_t *p_dec = (decoder_t*)p_this;
188
189     int i_ret = OpenDecoder( p_this );
190
191     if( i_ret == VLC_SUCCESS )
192     {
193         p_dec->p_sys->b_packetizer = true;
194         p_dec->fmt_out.i_codec = VLC_FOURCC( 'k', 'a', 't', 'e' );
195     }
196
197     return i_ret;
198 }
199 #endif
200
201 /****************************************************************************
202  * DecodeBlock: the whole thing
203  ****************************************************************************
204  * This function must be fed with kate packets.
205  ****************************************************************************/
206 static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
207 {
208     decoder_sys_t *p_sys = p_dec->p_sys;
209     block_t *p_block;
210     kate_packet kp;
211
212     if( !pp_block || !*pp_block )
213         return NULL;
214
215     p_block = *pp_block;
216     if( p_block->i_rate != 0 )
217         p_block->i_length = p_block->i_length * p_block->i_rate / INPUT_RATE_DEFAULT;
218
219     /* Block to Kate packet */
220     kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer);
221
222     if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
223     {
224         /* Headers already available as extra data */
225         p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
226         p_sys->i_headers = p_sys->i_num_headers;
227     }
228     else if( kp.nbytes && (p_sys->i_headers==0 || p_sys->i_headers < p_sys->ki.num_headers ))
229     {
230         /* Backup headers as extra data */
231         uint8_t *p_extra;
232
233         p_dec->fmt_in.p_extra =
234             realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra + kp.nbytes + 2 );
235         p_extra = (void*)(((unsigned char*)p_dec->fmt_in.p_extra) + p_dec->fmt_in.i_extra);
236         *(p_extra++) = kp.nbytes >> 8;
237         *(p_extra++) = kp.nbytes & 0xFF;
238
239         memcpy( p_extra, kp.data, kp.nbytes );
240         p_dec->fmt_in.i_extra += kp.nbytes + 2;
241
242         block_Release( *pp_block );
243         p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0];
244         p_sys->i_headers++;
245         return NULL;
246     }
247
248     if( p_sys->i_headers == p_sys->i_num_headers && p_sys->i_num_headers>0 )
249     {
250         if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
251         {
252             p_sys->i_headers = 0;
253             p_dec->fmt_in.i_extra = 0;
254             block_Release( *pp_block );
255             return NULL;
256         }
257         else p_sys->i_headers++;
258     }
259
260     return ProcessPacket( p_dec, &kp, pp_block );
261 }
262
263 /*****************************************************************************
264  * ProcessHeaders: process Kate headers.
265  *****************************************************************************/
266 static int ProcessHeaders( decoder_t *p_dec )
267 {
268     decoder_sys_t *p_sys = p_dec->p_sys;
269     kate_packet kp;
270     uint8_t *p_extra;
271     int i_extra;
272     int headeridx;
273     int ret;
274
275     if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
276
277     p_extra = p_dec->fmt_in.p_extra;
278     i_extra = p_dec->fmt_in.i_extra;
279
280     /* skip number of headers */
281     ++p_extra;
282     --i_extra;
283
284     /* Take care of the initial Kate header */
285     kp.nbytes = *(p_extra++) << 8;
286     kp.nbytes |= (*(p_extra++) & 0xFF);
287     kp.data = p_extra;
288     p_extra += kp.nbytes;
289     i_extra -= (kp.nbytes + 2);
290     if( i_extra < 0 )
291     {
292         msg_Err( p_dec, "header data corrupted");
293         return VLC_EGENERIC;
294     }
295
296     ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
297     if( ret < 0 )
298     {
299         msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", ret );
300         return VLC_EGENERIC;
301     }
302
303     msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d",
304              p_sys->ki.language, p_sys->ki.category,
305              (double)p_sys->ki.gps_numerator/p_sys->ki.gps_denominator,
306              p_sys->ki.granule_shift);
307
308     /* parse all remaining header packets */
309     for (headeridx=1; headeridx<p_sys->ki.num_headers; ++headeridx)
310     {
311         kp.nbytes = *(p_extra++) << 8;
312         kp.nbytes |= (*(p_extra++) & 0xFF);
313         kp.data = p_extra;
314         p_extra += kp.nbytes;
315         i_extra -= (kp.nbytes + 2);
316         if( i_extra < 0 )
317         {
318             msg_Err( p_dec, "header %d data corrupted", headeridx);
319             return VLC_EGENERIC;
320         }
321
322         ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp );
323         if( ret < 0 )
324         {
325             msg_Err( p_dec, "Kate header %d is corrupted: %d", headeridx, ret);
326             return VLC_EGENERIC;
327         }
328
329         /* header 1 is comments */
330         if( headeridx == 1 )
331         {
332             ParseKateComments( p_dec );
333         }
334     }
335
336 #ifdef ENABLE_PACKETIZER
337     if( !p_sys->b_packetizer )
338 #endif
339     {
340         /* We have all the headers, initialize decoder */
341         msg_Dbg( p_dec, "we have all headers, initialize libkate for decoding" );
342         ret = kate_decode_init( &p_sys->k, &p_sys->ki );
343         if (ret < 0)
344         {
345             msg_Err( p_dec, "Kate failed to initialize for decoding: %d", ret );
346             return VLC_EGENERIC;
347         }
348         p_sys->b_ready = true;
349     }
350 #ifdef ENABLE_PACKETIZER
351     else
352     {
353         p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
354         p_dec->fmt_out.p_extra =
355             realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
356         memcpy( p_dec->fmt_out.p_extra,
357                 p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
358     }
359 #endif
360
361     return VLC_SUCCESS;
362 }
363
364 /*****************************************************************************
365  * ProcessPacket: processes a kate packet.
366  *****************************************************************************/
367 static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp,
368                             block_t **pp_block )
369 {
370     decoder_sys_t *p_sys = p_dec->p_sys;
371     block_t *p_block = *pp_block;
372     subpicture_t *p_buf = NULL;
373
374     /* Date management */
375     if( p_block->i_pts > 0 && p_block->i_pts != p_sys->i_pts )
376     {
377         p_sys->i_pts = p_block->i_pts;
378     }
379
380     *pp_block = NULL; /* To avoid being fed the same packet again */
381
382 #ifdef ENABLE_PACKETIZER
383     if( p_sys->b_packetizer )
384     {
385         /* Date management */
386         p_block->i_dts = p_block->i_pts = p_sys->i_pts;
387
388         if( p_sys->i_headers >= p_sys->i_num_headers )
389             p_block->i_length = p_sys->i_pts - p_block->i_pts;
390         else
391             p_block->i_length = 0;
392
393         p_buf = p_block;
394     }
395     else
396 #endif
397     {
398         if( p_sys->i_headers >= p_sys->i_num_headers )
399             p_buf = DecodePacket( p_dec, p_kp, p_block );
400         else
401             p_buf = NULL;
402
403         if( p_block ) block_Release( p_block );
404     }
405
406     return p_buf;
407 }
408
409 #ifdef ENABLE_BITMAPS
410 /* nicked off blend.c */
411 static inline void rgb_to_yuv( uint8_t *y, uint8_t *u, uint8_t *v,
412                                int r, int g, int b )
413 {
414     *y = ( ( (  66 * r + 129 * g +  25 * b + 128 ) >> 8 ) + 16 );
415     *u =   ( ( -38 * r -  74 * g + 112 * b + 128 ) >> 8 ) + 128 ;
416     *v =   ( ( 112 * r -  94 * g -  18 * b + 128 ) >> 8 ) + 128 ;
417 }
418 #endif
419
420 /*
421   This retrieves the size of the video.
422   The best case is when the original video size is known, as we can then
423   scale images to match. In this case, since VLC autoscales, we want to
424   return the original size and let VLC scale everything.
425   if the original size is not known, then VLC can't resize, so we return
426   the size of the incoming video. If sizes in the Kate stream are in
427   relative units, it works fine. If they are absolute, you get what you
428   ask for. Images aren't rescaled.
429 */
430 static void GetVideoSize( decoder_t *p_dec, int *w, int *h )
431 {
432     /* searching for vout to get its size is frowned upon, so we don't and
433        use a default size if the original canvas size is not specified. */
434 #if 1
435     decoder_sys_t *p_sys = p_dec->p_sys;
436     if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
437     {
438         *w = p_sys->ki.original_canvas_width;
439         *h = p_sys->ki.original_canvas_height;
440         msg_Dbg( p_dec, "original canvas %zu %zu\n",
441                  p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
442     }
443     else
444     {
445         /* nothing, leave defaults */
446         msg_Dbg( p_dec, "original canvas size unknown\n");
447     }
448 #else
449     /* keep this just in case it might be allowed one day ;) */
450     vout_thread_t *p_vout;
451     p_vout = vlc_object_find( (vlc_object_t*)p_dec, VLC_OBJECT_VOUT, FIND_CHILD );
452     if( p_vout )
453     {
454         decoder_sys_t *p_sys = p_dec->p_sys;
455         if( p_sys->ki.original_canvas_width > 0 && p_sys->ki.original_canvas_height > 0 )
456         {
457             *w = p_sys->ki.original_canvas_width;
458             *h = p_sys->ki.original_canvas_height;
459         }
460         else
461         {
462             *w = p_vout->fmt_in.i_width;
463             *h = p_vout->fmt_in.i_height;
464         }
465         msg_Dbg( p_dec, "video: in %d %d, out %d %d, original canvas %zu %zu\n",
466                  p_vout->fmt_in.i_width, p_vout->fmt_in.i_height,
467                  p_vout->fmt_out.i_width, p_vout->fmt_out.i_height,
468                  p_sys->ki.original_canvas_width, p_sys->ki.original_canvas_height );
469         vlc_object_release( p_vout );
470     }
471 #endif
472 }
473
474 #ifdef ENABLE_BITMAPS
475
476 static void CreateKateBitmap( picture_t *pic, const kate_bitmap *bitmap )
477 {
478     size_t y;
479
480     for( y=0; y<bitmap->height; ++y )
481     {
482         uint8_t *dest = pic->Y_PIXELS+pic->Y_PITCH*y;
483         const uint8_t *src = bitmap->pixels+y*bitmap->width;
484         memcpy( dest, src, bitmap->width );
485     }
486 }
487
488 static void CreateKatePalette( video_palette_t *fmt_palette, const kate_palette *palette )
489 {
490     size_t n;
491
492     fmt_palette->i_entries = palette->ncolors;
493     for( n=0; n<palette->ncolors; ++n )
494     {
495         rgb_to_yuv(
496             &fmt_palette->palette[n][0], &fmt_palette->palette[n][1], &fmt_palette->palette[n][2],
497             palette->colors[n].r, palette->colors[n].g, palette->colors[n].b
498         );
499         fmt_palette->palette[n][3] = palette->colors[n].a;
500     }
501 }
502
503 #endif
504
505 static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event *ev )
506 {
507     decoder_sys_t *p_sys = p_dec->p_sys;
508
509     if( ev->text_encoding != kate_utf8 )
510     {
511         msg_Warn( p_dec, "Text isn't UTF-8, unsupported, ignored" );
512         return;
513     }
514
515     switch( ev->text_markup_type )
516     {
517         case kate_markup_none:
518             p_spu->p_region->psz_text = strdup( ev->text ); /* no leak, this actually gets killed by the core */
519             break;
520         case kate_markup_simple:
521             if( p_sys->b_formatted )
522             {
523                 /* the HTML renderer expects a top level text tag pair */
524                 char *buffer = NULL;
525                 if( asprintf( &buffer, "<text>%s</text>", ev->text ) >= 0 )
526                 {
527                     p_spu->p_region->psz_html = buffer;
528                 }
529                 break;
530             }
531             /* if not formatted, we fall through */
532         default:
533             /* we don't know about this one, so remove markup and display as text */
534             {
535                 char *copy = strdup( ev->text );
536                 size_t len0 = strlen( copy ) + 1;
537                 kate_text_remove_markup( ev->text_encoding, copy, &len0 );
538                 p_spu->p_region->psz_text = copy;
539             }
540             break;
541     }
542 }
543
544 /*****************************************************************************
545  * DecodePacket: decodes a Kate packet.
546  *****************************************************************************/
547 static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t *p_block )
548 {
549     decoder_sys_t *p_sys = p_dec->p_sys;
550     const kate_event *ev = NULL;
551     subpicture_t *p_spu = NULL;
552     subpicture_region_t *p_bitmap_region = NULL;
553     int ret;
554     video_format_t fmt;
555     kate_tracker kin;
556     bool tracker_valid = false;
557
558     ret = kate_decode_packetin( &p_sys->k, p_kp );
559     if( ret < 0 )
560     {
561         msg_Err( p_dec, "Kate failed to decode packet: %d", ret );
562         return NULL;
563     }
564
565     ret = kate_decode_eventout( &p_sys->k, &ev );
566     if( ret < 0 )
567     {
568         msg_Err( p_dec, "Kate failed to retrieve event: %d", ret );
569         return NULL;
570     }
571     if( ret > 0 )
572     {
573         /* no event to go with this packet, this is normal */
574         return NULL;
575     }
576
577     /* we have an event */
578
579     /* Get a new spu */
580     p_spu = p_dec->pf_spu_buffer_new( p_dec );
581     if( !p_spu )
582     {
583         msg_Err( p_dec, "Failed to allocate spu buffer" );
584         return NULL;
585     }
586
587     /* these may be 0 for "not specified" */
588     p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
589     p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
590
591     /* Create a new subpicture region */
592     memset( &fmt, 0, sizeof(video_format_t) );
593
594 #ifdef ENABLE_FORMATTING
595     if (p_sys->b_formatted)
596     {
597         ret = kate_tracker_init( &kin, &p_sys->ki, ev );
598         if( ret < 0)
599         {
600             msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", ret );
601         }
602         else
603         {
604             int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
605             GetVideoSize(p_dec, &w, &h);
606             ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
607             if( ret < 0)
608             {
609                 kate_tracker_clear(&kin);
610                 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", ret );
611             }
612             else
613             {
614                 // TODO: parse tracker and set style, init fmt
615                 tracker_valid = true;
616             }
617         }
618     }
619 #endif
620
621 #ifdef ENABLE_BITMAPS
622     if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
623         /* create a separate region for the bitmap */
624         memset( &fmt, 0, sizeof(video_format_t) );
625         fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
626         fmt.i_aspect = 0;
627         fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
628         fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
629         fmt.i_x_offset = fmt.i_y_offset = 0;
630
631         p_bitmap_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
632         if( !p_bitmap_region )
633         {
634             msg_Err( p_dec, "cannot allocate SPU region" );
635             p_dec->pf_spu_buffer_del( p_dec, p_spu );
636             return NULL;
637         }
638
639         /* create the palette */
640         CreateKatePalette( fmt.p_palette, ev->palette );
641
642         /* create the bitmap */
643         CreateKateBitmap( &p_bitmap_region->picture, ev->bitmap );
644
645         msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors\n", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
646     }
647 #endif
648
649     /* text region */
650     fmt.i_chroma = VLC_FOURCC('T','E','X','T');
651     fmt.i_aspect = 0;
652     fmt.i_width = fmt.i_height = 0;
653     fmt.i_x_offset = fmt.i_y_offset = 0;
654     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt );
655     if( !p_spu->p_region )
656     {
657         msg_Err( p_dec, "cannot allocate SPU region" );
658         p_dec->pf_spu_buffer_del( p_dec, p_spu );
659         return NULL;
660     }
661
662     SetupText( p_dec, p_spu, ev );
663
664     p_spu->i_start = p_block->i_pts;
665     p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
666     p_spu->b_ephemer = (p_block->i_length == 0);
667     p_spu->b_absolute = false;
668
669     /* default positioning */
670     p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
671     if (p_bitmap_region)
672     {
673         p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
674     }
675     p_spu->i_x = 0;
676     p_spu->i_y = 10;
677
678     /* override if tracker info present */
679     if (tracker_valid)
680     {
681         p_spu->i_flags = 0;
682         if (kin.has.region)
683         {
684             p_spu->i_x = kin.region_x;
685             p_spu->i_y = kin.region_y;
686             p_spu->b_absolute = true;
687         }
688
689         kate_tracker_clear(&kin);
690     }
691
692 #ifdef ENABLE_BITMAPS
693     /* if we have a bitmap, chain it before the text */
694     if (p_bitmap_region)
695     {
696         p_bitmap_region->p_next = p_spu->p_region;
697         p_spu->p_region = p_bitmap_region;
698     }
699 #endif
700
701     return p_spu;
702 }
703
704 /*****************************************************************************
705  * ParseKateComments: FIXME should be done in demuxer
706  *****************************************************************************/
707 static void ParseKateComments( decoder_t *p_dec )
708 {
709     input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
710     char *psz_name, *psz_value, *psz_comment;
711     int i = 0;
712
713     if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;
714
715     while ( i < p_dec->p_sys->kc.comments )
716     {
717         psz_comment = strdup( p_dec->p_sys->kc.user_comments[i] );
718         if( !psz_comment )
719         {
720             msg_Warn( p_dec, "out of memory" );
721             break;
722         }
723         psz_name = psz_comment;
724         psz_value = strchr( psz_comment, '=' );
725         if( psz_value )
726         {
727             *psz_value = '\0';
728             psz_value++;
729             input_Control( p_input, INPUT_ADD_INFO, _("Kate comment"),
730                            psz_name, "%s", psz_value );
731         }
732         free( psz_comment );
733         i++;
734     }
735 }
736
737 /*****************************************************************************
738  * CloseDecoder: clean up the decoder
739  *****************************************************************************/
740 static void CloseDecoder( vlc_object_t *p_this )
741 {
742     decoder_t *p_dec = (decoder_t *)p_this;
743     decoder_sys_t *p_sys = p_dec->p_sys;
744
745     if (p_sys->b_ready)
746         kate_clear( &p_sys->k );
747     kate_info_clear( &p_sys->ki );
748     kate_comment_clear( &p_sys->kc );
749
750     free( p_sys );
751 }
752