]> git.sesse.net Git - vlc/blob - modules/codec/kate.c
Remove most stray semi-colons in module descriptions
[vlc] / 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     video_format_t palette;
556     kate_tracker kin;
557     bool tracker_valid = false;
558
559     ret = kate_decode_packetin( &p_sys->k, p_kp );
560     if( ret < 0 )
561     {
562         msg_Err( p_dec, "Kate failed to decode packet: %d", ret );
563         return NULL;
564     }
565
566     ret = kate_decode_eventout( &p_sys->k, &ev );
567     if( ret < 0 )
568     {
569         msg_Err( p_dec, "Kate failed to retrieve event: %d", ret );
570         return NULL;
571     }
572     if( ret > 0 )
573     {
574         /* no event to go with this packet, this is normal */
575         return NULL;
576     }
577
578     /* we have an event */
579
580     /* Get a new spu */
581     p_spu = decoder_NewSubpicture( p_dec );
582     if( !p_spu )
583     {
584         msg_Err( p_dec, "Failed to allocate spu buffer" );
585         return NULL;
586     }
587
588     /* these may be 0 for "not specified" */
589     p_spu->i_original_picture_width = p_sys->ki.original_canvas_width;
590     p_spu->i_original_picture_height = p_sys->ki.original_canvas_height;
591
592     /* Create a new subpicture region */
593     memset( &fmt, 0, sizeof(video_format_t) );
594
595 #ifdef ENABLE_FORMATTING
596     if (p_sys->b_formatted)
597     {
598         ret = kate_tracker_init( &kin, &p_sys->ki, ev );
599         if( ret < 0)
600         {
601             msg_Err( p_dec, "failed to initialize kate tracker, event will be unformatted: %d", ret );
602         }
603         else
604         {
605             int w = 720, h = 576; /* give sensible defaults just in case we fail to get the actual size */
606             GetVideoSize(p_dec, &w, &h);
607             ret = kate_tracker_update(&kin, 0, w, h, 0, 0, w, h);
608             if( ret < 0)
609             {
610                 kate_tracker_clear(&kin);
611                 msg_Err( p_dec, "failed to update kate tracker, event will be unformatted: %d", ret );
612             }
613             else
614             {
615                 // TODO: parse tracker and set style, init fmt
616                 tracker_valid = true;
617             }
618         }
619     }
620 #endif
621
622 #ifdef ENABLE_BITMAPS
623     if (ev->bitmap && ev->bitmap->type==kate_bitmap_type_paletted && ev->palette) {
624
625         /* create a separate region for the bitmap */
626         memset( &fmt, 0, sizeof(video_format_t) );
627         fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
628         fmt.i_aspect = 0;
629         fmt.i_width = fmt.i_visible_width = ev->bitmap->width;
630         fmt.i_height = fmt.i_visible_height = ev->bitmap->height;
631         fmt.i_x_offset = fmt.i_y_offset = 0;
632         fmt.p_palette = &palette;
633         CreateKatePalette( fmt.p_palette, ev->palette );
634
635         p_bitmap_region = subpicture_region_New( &fmt );
636         if( !p_bitmap_region )
637         {
638             msg_Err( p_dec, "cannot allocate SPU region" );
639             decoder_DeleteSubpicture( p_dec, p_spu );
640             return NULL;
641         }
642
643         /* create the bitmap */
644         CreateKateBitmap( p_bitmap_region->p_picture, ev->bitmap );
645
646         msg_Dbg(p_dec, "Created bitmap, %zux%zu, %zu colors\n", ev->bitmap->width, ev->bitmap->height, ev->palette->ncolors);
647     }
648 #endif
649
650     /* text region */
651     fmt.i_chroma = VLC_FOURCC('T','E','X','T');
652     fmt.i_aspect = 0;
653     fmt.i_width = fmt.i_height = 0;
654     fmt.i_x_offset = fmt.i_y_offset = 0;
655     p_spu->p_region = subpicture_region_New( &fmt );
656     if( !p_spu->p_region )
657     {
658         msg_Err( p_dec, "cannot allocate SPU region" );
659         decoder_DeleteSubpicture( p_dec, p_spu );
660         return NULL;
661     }
662
663     SetupText( p_dec, p_spu, ev );
664
665     p_spu->i_start = p_block->i_pts;
666     p_spu->i_stop = p_block->i_pts + INT64_C(1000000)*ev->duration*p_sys->ki.gps_denominator/p_sys->ki.gps_numerator;
667     p_spu->b_ephemer = (p_block->i_length == 0);
668     p_spu->b_absolute = false;
669
670     /* default positioning */
671     p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
672     if (p_bitmap_region)
673     {
674         p_bitmap_region->i_align = SUBPICTURE_ALIGN_BOTTOM;
675     }
676     p_spu->p_region->i_x = 0;
677     p_spu->p_region->i_y = 10;
678
679     /* override if tracker info present */
680     if (tracker_valid)
681     {
682         if (kin.has.region)
683         {
684             p_spu->p_region->i_x = kin.region_x;
685             p_spu->p_region->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             break;
720         psz_name = psz_comment;
721         psz_value = strchr( psz_comment, '=' );
722         if( psz_value )
723         {
724             *psz_value = '\0';
725             psz_value++;
726             input_Control( p_input, INPUT_ADD_INFO, _("Kate comment"),
727                            psz_name, "%s", psz_value );
728         }
729         free( psz_comment );
730         i++;
731     }
732 }
733
734 /*****************************************************************************
735  * CloseDecoder: clean up the decoder
736  *****************************************************************************/
737 static void CloseDecoder( vlc_object_t *p_this )
738 {
739     decoder_t *p_dec = (decoder_t *)p_this;
740     decoder_sys_t *p_sys = p_dec->p_sys;
741
742     if (p_sys->b_ready)
743         kate_clear( &p_sys->k );
744     kate_info_clear( &p_sys->ki );
745     kate_comment_clear( &p_sys->kc );
746
747     free( p_sys );
748 }
749