]> git.sesse.net Git - vlc/blob - modules/codec/ogt/ogt.c
* src/video_output/vout_subpictures.c : New OSD channels
[vlc] / modules / codec / ogt / ogt.c
1 /*****************************************************************************
2  * ogt.c : Overlay Graphics Text (SVCD subtitles) decoder thread
3  *****************************************************************************
4  * Copyright (C) 2003, 2004 VideoLAN
5  * $Id$
6  *
7  * Author: 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 /*****************************************************************************
40  * Module descriptor.
41  *****************************************************************************/
42 static int  VCDSubOpen   ( vlc_object_t * );
43 static int  PacketizerOpen( vlc_object_t * );
44
45 vlc_module_begin();
46     set_description( _("Philips OGT (SVCD subtitle) decoder") );
47     set_capability( "decoder", 50 );
48     set_callbacks( VCDSubOpen, VCDSubClose );
49
50     add_integer ( MODULE_STRING "-debug", 0, NULL,
51                   DEBUG_TEXT, DEBUG_LONGTEXT, VLC_TRUE );
52
53     add_integer ( MODULE_STRING "-horizontal-correct", 0, NULL,
54                   HORIZONTAL_CORRECT, HORIZONTAL_CORRECT_LONGTEXT, VLC_FALSE );
55
56     add_integer ( MODULE_STRING "-vertical-correct", 0, NULL,
57                   VERTICAL_CORRECT, VERTICAL_CORRECT_LONGTEXT, VLC_FALSE );
58
59     add_string( MODULE_STRING "-aspect-ratio", "", NULL,
60                 SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT, VLC_TRUE );
61
62     add_integer( MODULE_STRING "-duration-scaling", 9, NULL,
63                  DURATION_SCALE_TEXT, DURATION_SCALE_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  * VCDSubOpen
82  *****************************************************************************
83  * Tries to launch a decoder and return score so that the interface is able
84  * to chose.
85  *****************************************************************************/
86 static int
87 VCDSubOpen( 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( VCDSubOpen( 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     vout_thread_t *p_last_vout = p_dec->p_sys->p_vout;
147
148     dbg_print( (DECODE_DBG_CALL) , "");
149
150     if( p_spu )
151     {
152         p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
153         p_sys->i_pts = p_spu->i_pts;
154         block_ChainRelease( p_spu );
155
156         if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
157         {
158             if( p_last_vout != p_sys->p_vout )
159             {
160                 p_sys->i_subpic_channel =
161                     vout_RegisterOSDChannel( p_sys->p_vout );
162             }
163
164             /* Parse and decode */
165             E_(ParsePacket)( p_dec );
166
167             vlc_object_release( p_sys->p_vout );
168         }
169
170         VCDSubInitSubtitleBlock ( p_sys );
171     }
172
173 }
174
175 /*****************************************************************************
176  * Packetize:
177  *****************************************************************************/
178 static block_t *
179 Packetize( decoder_t *p_dec, block_t **pp_block )
180 {
181     decoder_sys_t *p_sys = p_dec->p_sys;
182     block_t       *p_spu = Reassemble( p_dec, pp_block );
183
184     if( p_spu )
185     {
186         p_spu->i_dts = p_spu->i_pts;
187         p_spu->i_length = 0;
188
189         VCDSubInitSubtitleBlock( p_sys );
190
191         return block_ChainGather( p_spu );
192     }
193     return NULL;
194 }
195
196 #define SPU_HEADER_LEN 5
197
198 /*****************************************************************************
199  Reassemble:
200
201  The data for single screen subtitle may come in one of many
202  non-contiguous packets of a stream. This routine is called when the
203  next packet in the stream comes in. The job of this routine is to
204  parse the header, if this is the beginning, and combine the packets
205  into one complete subtitle unit.
206
207  If everything is complete, we will return a block. Otherwise return
208  NULL.
209
210
211  The format of the beginning of the subtitle packet that is used here.
212
213    size    description
214    -------------------------------------------
215    byte    subtitle channel (0..7) in bits 0-3
216    byte    subtitle packet number of this subtitle image 0-N,
217            if the subtitle packet is complete, the top bit of the byte is 1.
218    uint16  subtitle image number
219
220  *****************************************************************************/
221 static block_t *
222 Reassemble( decoder_t *p_dec, block_t **pp_block )
223 {
224     decoder_sys_t *p_sys = p_dec->p_sys;
225     block_t *p_block;
226     uint8_t *p_buffer;
227     uint16_t i_expected_image;
228     uint8_t  i_packet, i_expected_packet;
229
230     if( pp_block == NULL || *pp_block == NULL )
231     {
232         return NULL;
233     }
234     p_block = *pp_block;
235     *pp_block = NULL;
236
237     if( p_block->i_buffer < SPU_HEADER_LEN )
238     {
239       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
240                p_block->i_buffer, SPU_HEADER_LEN );
241       block_Release( p_block );
242       return NULL;
243     }
244
245     p_buffer = p_block->p_buffer;
246
247     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET),
248                "header: 0x%02x 0x%02x 0x%02x 0x%02x, size: %i",
249                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
250                p_block->i_buffer);
251
252     /* Attach to our input thread and see if subtitle is selected. */
253     {
254         vlc_object_t * p_input;
255         vlc_value_t val;
256
257         p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_PARENT );
258
259         if( !p_input ) return NULL;
260
261         if( var_Get( p_input, "spu-channel", &val ) )
262         {
263             vlc_object_release( p_input );
264           return NULL;
265         }
266
267         vlc_object_release( p_input );
268         dbg_print( (DECODE_DBG_PACKET),
269                    "val.i_int %x p_buffer[i] %x", val.i_int, p_buffer[1]);
270
271         /* The dummy ES that the menu selection uses has an 0x70 at
272            the head which we need to strip off. */
273         if( val.i_int == -1 || (val.i_int & 0x03) != p_buffer[1] )
274         {
275             dbg_print( DECODE_DBG_PACKET, "subtitle not for us.\n");
276             return NULL;
277         }
278     }
279
280     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY ) {
281       i_expected_image  = p_sys->i_image+1;
282       i_expected_packet = 0;
283     } else {
284       i_expected_image  = p_sys->i_image;
285       i_expected_packet = p_sys->i_packet+1;
286     }
287
288     p_buffer += 2;
289
290     if ( *p_buffer & 0x80 ) {
291       p_sys->state = SUBTITLE_BLOCK_COMPLETE;
292       i_packet     = ( *p_buffer++ & 0x7F );
293     } else {
294       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
295       i_packet     = *p_buffer++;
296     }
297
298     p_sys->i_image = GETINT16(p_buffer);
299
300     if ( p_sys->i_image != i_expected_image ) {
301       msg_Warn( p_dec, "expecting subtitle image %u but found %u",
302                 i_expected_image, p_sys->i_image );
303     }
304
305     if ( i_packet != i_expected_packet ) {
306       msg_Warn( p_dec, "expecting subtitle image packet %u but found %u",
307                 i_expected_packet, i_packet);
308     }
309
310     p_sys->i_packet = i_packet;
311
312     if ( p_sys->i_packet == 0 ) {
313       /* First packet in the subtitle block */
314       E_(ParseHeader)( p_dec, p_buffer, p_block );
315       VCDSubInitSubtitleData(p_sys);
316     }
317
318     /* FIXME - remove append_data and use chainappend */
319     VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - SPU_HEADER_LEN );
320
321     block_ChainAppend( &p_sys->p_block, p_block );
322
323     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
324
325     if (p_sys->state == SUBTITLE_BLOCK_COMPLETE)
326     {
327       if( p_sys->i_spu != p_sys->i_spu_size )
328         {
329           msg_Warn( p_dec, "SPU packets size=%d should be %d",
330                    p_sys->i_spu, p_sys->i_spu_size );
331         }
332
333       dbg_print( (DECODE_DBG_PACKET),
334                  "subtitle packet complete, size=%d", p_sys->i_spu );
335
336       return p_sys->p_block;
337     }
338     return NULL;
339 }
340
341 \f
342 /*
343  * Local variables:
344  *  c-file-style: "gnu"
345  *  tab-width: 8
346  *  indent-tabs-mode: nil
347  * End:
348  */