36d8993f92f38d91a784db36335a8a45f70f57da
[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.7 2004/01/01 13:55:17 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 #include "common.h"
38
39 #define DEBUG_LONGTEXT N_( \
40     "This integer when viewed in binary is a debugging mask\n" \
41     "external call          1\n" \
42     "all calls              2\n" \
43     "packet assembly info   4\n" \
44     "image bitmaps          8\n" \
45     "image transformations 16\n" \
46     "rendering information 32\n" \
47     "misc info             64\n" )
48
49
50 /*****************************************************************************
51  * Module descriptor.
52  *****************************************************************************/
53 static int  DecoderOpen   ( vlc_object_t * );
54 static int  PacketizerOpen( vlc_object_t * );
55
56 vlc_module_begin();
57     set_description( _("Philips OGT (SVCD subtitle) decoder") );
58     set_capability( "decoder", 50 );
59     set_callbacks( DecoderOpen, VCDSubClose );
60
61     add_integer ( MODULE_STRING "-debug", 0, NULL,
62                   N_("set debug mask for additional debugging."),
63                   N_(DEBUG_LONGTEXT), VLC_TRUE );
64
65     add_submodule();
66     set_description( _("Philips OGT (SVCD subtitle) packetizer") );
67     set_capability( "packetizer", 50 );
68     set_callbacks( PacketizerOpen, VCDSubClose );
69 vlc_module_end();
70
71 /*****************************************************************************
72  * Local prototypes
73  *****************************************************************************/
74
75 static block_t *Reassemble( decoder_t *, block_t ** );
76 static void     Decode   ( decoder_t *, block_t ** );
77 static block_t *Packetize( decoder_t *, block_t ** );
78
79
80 /*****************************************************************************
81  * DecoderOpen
82  *****************************************************************************
83  * Tries to launch a decoder and return score so that the interface is able
84  * to chose.
85  *****************************************************************************/
86 static int
87 DecoderOpen( vlc_object_t *p_this )
88 {
89     decoder_t     *p_dec = (decoder_t*)p_this;
90     decoder_sys_t *p_sys;
91
92     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'o','g','t',' ' ) )
93     {
94         return VLC_EGENERIC;
95     }
96
97
98     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
99
100     p_sys->i_debug       = config_GetInt( p_this, MODULE_STRING "-debug" );
101     p_sys->b_packetizer  = VLC_FALSE;
102     p_sys->p_vout        = NULL;
103     p_sys->i_image       = -1;
104     p_sys->subtitle_data = NULL;
105
106     VCDSubInitSubtitleBlock( p_sys );
107
108     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'o','g','t',' ' ) );
109
110
111     p_dec->pf_decode_sub = Decode;
112     p_dec->pf_packetize  = Packetize;
113
114     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
115
116     return VLC_SUCCESS;
117 }
118
119 /*****************************************************************************
120  * PacketizerOpen
121  *****************************************************************************
122  * Tries to launch a decoder and return score so that the interface is able
123  * to chose.
124  *****************************************************************************/
125 static int PacketizerOpen( vlc_object_t *p_this )
126 {
127     decoder_t *p_dec = (decoder_t*)p_this;
128
129     if( DecoderOpen( p_this ) )
130     {
131         return VLC_EGENERIC;
132     }
133     p_dec->p_sys->b_packetizer = VLC_TRUE;
134
135     return VLC_SUCCESS;
136 }
137
138 /*****************************************************************************
139  * Decode:
140  *****************************************************************************/
141 static void
142 Decode ( decoder_t *p_dec, block_t **pp_block )
143 {
144     decoder_sys_t *p_sys = p_dec->p_sys;
145     block_t       *p_spu = Reassemble( p_dec, pp_block );
146
147     dbg_print( (DECODE_DBG_CALL) , "");
148
149     if( p_spu )
150     {
151         p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
152         p_sys->i_pts = p_spu->i_pts;
153         block_ChainRelease( p_spu );
154
155         if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
156         {
157             /* Parse and decode */
158             E_(ParsePacket)( p_dec );
159
160             vlc_object_release( p_sys->p_vout );
161         }
162
163         VCDSubInitSubtitleBlock ( p_sys );
164     }
165
166 }
167
168 /*****************************************************************************
169  * Packetize:
170  *****************************************************************************/
171 static block_t *
172 Packetize( decoder_t *p_dec, block_t **pp_block )
173 {
174     decoder_sys_t *p_sys = p_dec->p_sys;
175     block_t       *p_spu = Reassemble( p_dec, pp_block );
176
177     if( p_spu )
178     {
179         p_spu->i_dts = p_spu->i_pts;
180         p_spu->i_length = 0;
181
182         VCDSubInitSubtitleBlock( p_sys );
183
184         return block_ChainGather( p_spu );
185     }
186     return NULL;
187 }
188
189 #define SPU_HEADER_LEN 5
190
191 /*****************************************************************************
192  Reassemble:
193
194  The data for single screen subtitle may come in one of many
195  non-contiguous packets of a stream. This routine is called when the
196  next packet in the stream comes in. The job of this routine is to
197  parse the header, if this is the beginning, and combine the packets
198  into one complete subtitle unit.
199
200  If everything is complete, we will return a block. Otherwise return
201  NULL.
202
203
204  The format of the beginning of the subtitle packet that is used here.
205
206    size    description
207    -------------------------------------------
208    byte    subtitle channel (0..7) in bits 0-3
209    byte    subtitle packet number of this subtitle image 0-N,
210            if the subtitle packet is complete, the top bit of the byte is 1.
211    uint16  subtitle image number
212
213  *****************************************************************************/
214 static block_t *
215 Reassemble( decoder_t *p_dec, block_t **pp_block )
216 {
217     decoder_sys_t *p_sys = p_dec->p_sys;
218     block_t *p_block;
219     uint8_t *p_buffer;
220     uint16_t i_expected_image;
221     uint8_t  i_packet, i_expected_packet;
222
223     if( pp_block == NULL || *pp_block == NULL )
224     {
225         return NULL;
226     }
227     p_block = *pp_block;
228     *pp_block = NULL;
229
230     if( p_block->i_buffer < SPU_HEADER_LEN )
231     {
232       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
233                p_block->i_buffer, SPU_HEADER_LEN );
234       block_Release( p_block );
235       return NULL;
236     }
237
238     p_buffer = p_block->p_buffer;
239
240     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
241                "header: 0x%02x 0x%02x 0x%02x 0x%02x, size: %i",
242                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
243                p_block->i_buffer);
244
245     if( config_GetInt( p_dec, "spu-channel" ) != p_buffer[1] )
246       return NULL;
247
248     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY ) {
249       i_expected_image  = p_sys->i_image+1;
250       i_expected_packet = 0;
251     } else {
252       i_expected_image  = p_sys->i_image;
253       i_expected_packet = p_sys->i_packet+1;
254     }
255
256     p_buffer += 2;
257
258     if ( *p_buffer & 0x80 ) {
259       p_sys->state = SUBTITLE_BLOCK_COMPLETE;
260       i_packet     = ( *p_buffer++ & 0x7F );
261     } else {
262       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
263       i_packet     = *p_buffer++;
264     }
265
266     p_sys->i_image = GETINT16(p_buffer);
267
268     if ( p_sys->i_image != i_expected_image ) {
269       msg_Warn( p_dec, "expecting subtitle image %u but found %u",
270                 i_expected_image, p_sys->i_image );
271     }
272
273     if ( i_packet != i_expected_packet ) {
274       msg_Warn( p_dec, "expecting subtitle image packet %u but found %u",
275                 i_expected_packet, i_packet);
276     }
277
278     p_sys->i_packet = i_packet;
279
280     if ( p_sys->i_packet == 0 ) {
281       /* First packet in the subtitle block */
282       E_(ParseHeader)( p_dec, p_buffer, p_block );
283       VCDSubInitSubtitleData(p_sys);
284     }
285
286     /* FIXME - remove append_data and use chainappend */
287     VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - SPU_HEADER_LEN );
288
289     block_ChainAppend( &p_sys->p_block, p_block );
290
291     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
292
293     if (p_sys->state == SUBTITLE_BLOCK_COMPLETE)
294     {
295       if( p_sys->i_spu != p_sys->i_spu_size )
296         {
297           msg_Warn( p_dec, "SPU packets size=%d should be %d",
298                    p_sys->i_spu, p_sys->i_spu_size );
299         }
300
301       dbg_print( (DECODE_DBG_PACKET),
302                  "subtitle packet complete, size=%d", p_sys->i_spu );
303
304       return p_sys->p_block;
305     }
306     return NULL;
307 }