Work towards handling all planes in subtites, generalizing for CVD, and
[vlc.git] / modules / codec / ogt / ogt.c
1 /*****************************************************************************
2  * ogt.c : Overlay Graphics Text (SVCD subtitles) decoder thread
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
5  * $Id: ogt.c,v 1.5 2003/12/28 02:01:11 rocky Exp $
6  *
7  * Authors: Rocky Bernstein
8  *   based on code from:
9  *       Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10  *       Samuel Hocevar <sam@zoy.org>
11  *       Laurent Aimar <fenrir@via.ecp.fr>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <vlc/vlc.h>
32 #include <vlc/vout.h>
33 #include <vlc/decoder.h>
34
35 #include "subtitle.h"
36 #include "ogt.h"
37
38 #define DEBUG_LONGTEXT N_( \
39     "This integer when viewed in binary is a debugging mask\n" \
40     "external call          1\n" \
41     "all calls              2\n" \
42     "packet assembly info   4\n" \
43     "image bitmaps          8\n" \
44     "image transformations 16\n" \
45     "rendering information 32\n" \
46     "misc info             64\n" )
47
48
49 /*****************************************************************************
50  * Module descriptor.
51  *****************************************************************************/
52 static int  DecoderOpen   ( vlc_object_t * );
53 static int  PacketizerOpen( vlc_object_t * );
54
55 static void Close  ( vlc_object_t * );
56
57 vlc_module_begin();
58     set_description( _("Philips OGT (SVCD subtitle) decoder") );
59     set_capability( "decoder", 50 );
60     set_callbacks( DecoderOpen, Close );
61
62     add_integer ( MODULE_STRING "-debug", 0, NULL,
63                   N_("set debug mask for additional debugging."),
64                   N_(DEBUG_LONGTEXT), VLC_TRUE );
65
66     add_submodule();
67     set_description( _("Philips OGT (SVCD subtitle) packetizer") );
68     set_capability( "packetizer", 50 );
69     set_callbacks( PacketizerOpen, Close );
70 vlc_module_end();
71
72 /*****************************************************************************
73  * Local prototypes
74  *****************************************************************************/
75 static void     InitSubtitleBlock( decoder_sys_t * p_sys );
76 static vout_thread_t *FindVout( decoder_t *);
77
78 static block_t *Reassemble( decoder_t *, block_t ** );
79
80 static void     Decode   ( decoder_t *, block_t ** );
81 static block_t *Packetize( decoder_t *, block_t ** );
82
83
84 /*****************************************************************************
85  * DecoderOpen
86  *****************************************************************************
87  * Tries to launch a decoder and return score so that the interface is able
88  * to chose.
89  *****************************************************************************/
90 static int
91 DecoderOpen( vlc_object_t *p_this )
92 {
93     decoder_t     *p_dec = (decoder_t*)p_this;
94     decoder_sys_t *p_sys;
95
96     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'o','g','t',' ' ) )
97     {
98         return VLC_EGENERIC;
99     }
100
101
102     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
103
104     p_sys->i_debug       = config_GetInt( p_this, MODULE_STRING "-debug" );
105     p_sys->b_packetizer  = VLC_FALSE;
106     p_sys->p_vout        = NULL;
107     p_sys->i_image       = -1;
108     p_sys->subtitle_data = NULL;
109
110     InitSubtitleBlock( p_sys );
111
112     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'o','g','t',' ' ) );
113
114
115     p_dec->pf_decode_sub = Decode;
116     p_dec->pf_packetize  = Packetize;
117
118     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
119
120     return VLC_SUCCESS;
121 }
122
123 /*****************************************************************************
124  * PacketizerOpen
125  *****************************************************************************
126  * Tries to launch a decoder and return score so that the interface is able
127  * to chose.
128  *****************************************************************************/
129 static int PacketizerOpen( vlc_object_t *p_this )
130 {
131     decoder_t *p_dec = (decoder_t*)p_this;
132
133     if( DecoderOpen( p_this ) )
134     {
135         return VLC_EGENERIC;
136     }
137     p_dec->p_sys->b_packetizer = VLC_TRUE;
138
139     return VLC_SUCCESS;
140 }
141
142 /*****************************************************************************
143  * Close:
144  *****************************************************************************/
145 static void Close( vlc_object_t *p_this )
146 {
147     decoder_t     *p_dec = (decoder_t*)p_this;
148     decoder_sys_t *p_sys = p_dec->p_sys;
149
150     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
151
152     if( !p_sys->b_packetizer )
153     {
154         /* FIXME check if it's ok to not lock vout */
155         if( p_sys->p_vout != NULL && p_sys->p_vout->p_subpicture != NULL )
156         {
157             subpicture_t *  p_subpic;
158             int             i_subpic;
159
160             for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
161             {
162                 p_subpic = &p_sys->p_vout->p_subpicture[i_subpic];
163
164                 if( p_subpic != NULL &&
165                     ( ( p_subpic->i_status == RESERVED_SUBPICTURE ) ||
166                       ( p_subpic->i_status == READY_SUBPICTURE ) ) )
167                 {
168                     vout_DestroySubPicture( p_sys->p_vout, p_subpic );
169                 }
170             }
171         }
172     }
173
174     if( p_sys->p_block )
175     {
176         block_ChainRelease( p_sys->p_block );
177     }
178
179     free( p_sys );
180 }
181
182 /*****************************************************************************
183  * Decode:
184  *****************************************************************************/
185 static void
186 Decode ( decoder_t *p_dec, block_t **pp_block )
187 {
188     decoder_sys_t *p_sys = p_dec->p_sys;
189     block_t       *p_spu = Reassemble( p_dec, pp_block );
190
191     dbg_print( (DECODE_DBG_CALL) , "");
192
193     if( p_spu )
194     {
195         p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
196         p_sys->i_pts = p_spu->i_pts;
197         block_ChainRelease( p_spu );
198
199         if( ( p_sys->p_vout = FindVout( p_dec ) ) )
200         {
201             /* Parse and decode */
202             E_(ParsePacket)( p_dec );
203
204             vlc_object_release( p_sys->p_vout );
205         }
206
207         InitSubtitleBlock ( p_sys );
208     }
209
210 }
211
212 /*****************************************************************************
213  * Packetize:
214  *****************************************************************************/
215 static block_t *
216 Packetize( decoder_t *p_dec, block_t **pp_block )
217 {
218     decoder_sys_t *p_sys = p_dec->p_sys;
219     block_t       *p_spu = Reassemble( p_dec, pp_block );
220
221     if( p_spu )
222     {
223         p_spu->i_dts = p_spu->i_pts;
224         p_spu->i_length = 0;
225
226         InitSubtitleBlock( p_sys );
227
228         return block_ChainGather( p_spu );
229     }
230     return NULL;
231 }
232
233 /* following functions are local */
234
235 static void 
236 InitSubtitleData(decoder_sys_t *p_sys)
237 {
238   if ( p_sys->subtitle_data ) {
239     if ( p_sys->subtitle_data_size < p_sys->i_spu_size ) {
240       p_sys->subtitle_data = realloc(p_sys->subtitle_data,
241                                     p_sys->i_spu_size);
242       p_sys->subtitle_data_size = p_sys->i_spu_size;
243     }
244   } else {
245     p_sys->subtitle_data = malloc(p_sys->i_spu_size);
246     p_sys->subtitle_data_size = p_sys->i_spu_size;
247     /* FIXME: wrong place to get p_sys */
248     p_sys->i_image = 0;
249   }
250   p_sys->subtitle_data_pos = 0;
251 }
252
253 static void 
254 AppendData ( decoder_t *p_dec, uint8_t *buffer, uint32_t buf_len )
255 {
256   decoder_sys_t *p_sys = p_dec->p_sys;
257   int chunk_length = buf_len;
258
259   if ( chunk_length > p_sys->i_spu_size - p_sys->subtitle_data_pos ) {
260     msg_Warn( p_dec, "too much data (%d) expecting at most %u",
261               chunk_length, p_sys->i_spu_size - p_sys->subtitle_data_pos );
262
263     chunk_length = p_sys->i_spu_size - p_sys->subtitle_data_pos;
264   }
265
266   if ( chunk_length > 0 ) {
267     memcpy(p_sys->subtitle_data + p_sys->subtitle_data_pos,
268            buffer, chunk_length);
269     p_sys->subtitle_data_pos += chunk_length;
270     dbg_print(DECODE_DBG_PACKET, "%d bytes appended, pointer now %d",
271               chunk_length, p_sys->subtitle_data_pos);
272   }
273 }
274
275 /*****************************************************************************
276  InitSubtitleBlock:
277
278 Initialize so the next packet will start off a new one.
279
280  *****************************************************************************/
281 static void 
282 InitSubtitleBlock( decoder_sys_t * p_sys ) 
283 {
284   p_sys->i_spu_size = 0;
285   p_sys->state      = SUBTITLE_BLOCK_EMPTY;
286   p_sys->i_spu      = 0;
287   p_sys->p_block    = NULL;
288   p_sys->subtitle_data_pos = 0;
289
290 }
291
292 #define SPU_HEADER_LEN 5
293
294 /*****************************************************************************
295  Reassemble:
296
297  The data for single screen subtitle may come in one of many
298  non-contiguous packets of a stream. This routine is called when the
299  next packet in the stream comes in. The job of this routine is to
300  parse the header, if this is the beginning, and combine the packets
301  into one complete subtitle unit.
302
303  If everything is complete, we will return a block. Otherwise return
304  NULL.
305
306
307  The format of the beginning of the subtitle packet that is used here.
308
309    size    description
310    -------------------------------------------
311    byte    subtitle channel (0..7) in bits 0-3
312    byte    subtitle packet number of this subtitle image 0-N,
313            if the subtitle packet is complete, the top bit of the byte is 1.
314    uint16  subtitle image number
315
316  *****************************************************************************/
317 static block_t *
318 Reassemble( decoder_t *p_dec, block_t **pp_block )
319 {
320     decoder_sys_t *p_sys = p_dec->p_sys;
321     block_t *p_block;
322     uint8_t *p_buffer;
323     uint16_t i_expected_image;
324     uint8_t  i_packet, i_expected_packet;
325
326     if( pp_block == NULL || *pp_block == NULL )
327     {
328         return NULL;
329     }
330     p_block = *pp_block;
331     *pp_block = NULL;
332
333     if( p_block->i_buffer < SPU_HEADER_LEN )
334     {
335       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
336                p_block->i_buffer, SPU_HEADER_LEN );
337       block_Release( p_block );
338       return NULL;
339     }
340
341     p_buffer = p_block->p_buffer;
342
343     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
344                "header: 0x%02x 0x%02x 0x%02x 0x%02x, size: %i",
345                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
346                p_block->i_buffer);
347
348     if( config_GetInt( p_dec, "spu-channel" ) != p_buffer[1] )
349       return NULL;
350
351     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY ) {
352       i_expected_image  = p_sys->i_image+1;
353       i_expected_packet = 0;
354     } else {
355       i_expected_image  = p_sys->i_image;
356       i_expected_packet = p_sys->i_packet+1;
357     }
358
359     p_buffer += 2;
360
361     if ( *p_buffer & 0x80 ) {
362       p_sys->state = SUBTITLE_BLOCK_COMPLETE;
363       i_packet     = ( *p_buffer++ & 0x7F );
364     } else {
365       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
366       i_packet     = *p_buffer++;
367     }
368
369     p_sys->i_image = GETINT16(p_buffer);
370
371     if ( p_sys->i_image != i_expected_image ) {
372       msg_Warn( p_dec, "expecting subtitle image %u but found %u",
373                 i_expected_image, p_sys->i_image );
374     }
375
376     if ( i_packet != i_expected_packet ) {
377       msg_Warn( p_dec, "expecting subtitle image packet %u but found %u",
378                 i_expected_packet, i_packet);
379     }
380
381     p_sys->i_packet = i_packet;
382
383     if ( p_sys->i_packet == 0 ) {
384       /* First packet in the subtitle block */
385       E_(ParseHeader)( p_dec, p_buffer, p_block );
386       InitSubtitleData(p_sys);
387     }
388
389     /* FIXME - remove append_data and use chainappend */
390     AppendData( p_dec, p_buffer, p_block->i_buffer - 5 );
391
392     block_ChainAppend( &p_sys->p_block, p_block );
393
394     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
395
396     if (p_sys->state == SUBTITLE_BLOCK_COMPLETE)
397     {
398       if( p_sys->i_spu != p_sys->i_spu_size )
399         {
400           msg_Warn( p_dec, "SPU packets size=%d should be %d",
401                    p_sys->i_spu, p_sys->i_spu_size );
402         }
403
404       dbg_print( (DECODE_DBG_PACKET),
405                  "subtitle packet complete, size=%d", p_sys->i_spu );
406
407       return p_sys->p_block;
408     }
409     return NULL;
410 }
411
412 /*****************************************************************************
413  * FindVout: Find a vout or wait for one to be created.
414  *****************************************************************************/
415 static vout_thread_t *FindVout( decoder_t *p_dec )
416 {
417     vout_thread_t *p_vout = NULL;
418
419     /* Find an available video output */
420     do
421     {
422         if( p_dec->b_die || p_dec->b_error )
423         {
424             break;
425         }
426
427         p_vout = vlc_object_find( p_dec, VLC_OBJECT_VOUT, FIND_ANYWHERE );
428         if( p_vout )
429         {
430             break;
431         }
432
433         msleep( VOUT_OUTMEM_SLEEP );
434     }
435     while( 1 );
436
437     return p_vout;
438 }
439