1 /*****************************************************************************
2 * ogt.c : Overlay Graphics Text (SVCD subtitles) decoder thread
3 *****************************************************************************
4 * Copyright (C) 2003, 2004 VideoLAN
7 * Author: Rocky Bernstein
9 * Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10 * Samuel Hocevar <sam@zoy.org>
11 * Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
33 #include <vlc/decoder.h>
39 /*****************************************************************************
41 *****************************************************************************/
42 static int VCDSubOpen ( vlc_object_t * );
43 static int PacketizerOpen( vlc_object_t * );
46 set_description( _("Philips OGT (SVCD subtitle) decoder") );
47 set_capability( "decoder", 50 );
48 set_callbacks( VCDSubOpen, VCDSubClose );
50 add_integer ( MODULE_STRING "-debug", 0, NULL,
51 DEBUG_TEXT, DEBUG_LONGTEXT, VLC_TRUE );
53 add_integer ( MODULE_STRING "-horizontal-correct", 0, NULL,
54 HORIZONTAL_CORRECT, HORIZONTAL_CORRECT_LONGTEXT, VLC_FALSE );
56 add_integer ( MODULE_STRING "-vertical-correct", 0, NULL,
57 VERTICAL_CORRECT, VERTICAL_CORRECT_LONGTEXT, VLC_FALSE );
59 add_string( MODULE_STRING "-aspect-ratio", "", NULL,
60 SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT, VLC_TRUE );
62 add_integer( MODULE_STRING "-duration-scaling", 9, NULL,
63 DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT, VLC_TRUE );
66 set_description( _("Philips OGT (SVCD subtitle) packetizer") );
67 set_capability( "packetizer", 50 );
68 set_callbacks( PacketizerOpen, VCDSubClose );
71 /*****************************************************************************
73 *****************************************************************************/
75 static block_t *Reassemble ( decoder_t *, block_t ** );
76 static subpicture_t *Decode( decoder_t *, block_t ** );
77 static block_t *Packetize ( decoder_t *, block_t ** );
79 /*****************************************************************************
81 *****************************************************************************
82 * Tries to launch a decoder and return score so that the interface is able
84 *****************************************************************************/
86 VCDSubOpen( vlc_object_t *p_this )
88 decoder_t *p_dec = (decoder_t*)p_this;
91 if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'o','g','t',' ' ) )
97 p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
99 p_sys->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
100 p_sys->b_packetizer = VLC_FALSE;
101 p_sys->p_vout = NULL;
103 p_sys->subtitle_data = NULL;
105 VCDSubInitSubtitleBlock( p_sys );
107 es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'o','g','t',' ' ) );
110 p_dec->pf_decode_sub = Decode;
111 p_dec->pf_packetize = Packetize;
113 dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
118 /*****************************************************************************
120 *****************************************************************************
121 * Tries to launch a decoder and return score so that the interface is able
123 *****************************************************************************/
124 static int PacketizerOpen( vlc_object_t *p_this )
126 decoder_t *p_dec = (decoder_t*)p_this;
128 if( VCDSubOpen( p_this ) )
132 p_dec->p_sys->b_packetizer = VLC_TRUE;
137 /*****************************************************************************
139 *****************************************************************************/
140 static subpicture_t *
141 Decode ( decoder_t *p_dec, block_t **pp_block )
143 decoder_sys_t *p_sys = p_dec->p_sys;
144 block_t *p_spu = Reassemble( p_dec, pp_block );
145 vout_thread_t *p_last_vout = p_dec->p_sys->p_vout;
147 dbg_print( (DECODE_DBG_CALL) , "");
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 );
155 if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
157 if( p_last_vout != p_sys->p_vout )
159 spu_Control( p_sys->p_vout->p_spu, SPU_CHANNEL_REGISTER,
160 &p_sys->i_subpic_channel );
163 /* Parse and decode */
164 E_(ParsePacket)( p_dec );
166 vlc_object_release( p_sys->p_vout );
169 VCDSubInitSubtitleBlock ( p_sys );
175 /*****************************************************************************
177 *****************************************************************************/
179 Packetize( decoder_t *p_dec, block_t **pp_block )
181 decoder_sys_t *p_sys = p_dec->p_sys;
182 block_t *p_spu = Reassemble( p_dec, pp_block );
186 p_spu->i_dts = p_spu->i_pts;
189 VCDSubInitSubtitleBlock( p_sys );
191 return block_ChainGather( p_spu );
196 #define SPU_HEADER_LEN 5
198 /*****************************************************************************
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.
207 If everything is complete, we will return a block. Otherwise return
211 The format of the beginning of the subtitle packet that is used here.
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
220 *****************************************************************************/
222 Reassemble( decoder_t *p_dec, block_t **pp_block )
224 decoder_sys_t *p_sys = p_dec->p_sys;
227 uint16_t i_expected_image;
228 uint8_t i_packet, i_expected_packet;
230 if( pp_block == NULL || *pp_block == NULL )
237 if( p_block->i_buffer < SPU_HEADER_LEN )
239 msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
240 p_block->i_buffer, SPU_HEADER_LEN );
241 block_Release( p_block );
245 p_buffer = p_block->p_buffer;
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],
252 /* Attach to our input thread and see if subtitle is selected. */
254 vlc_object_t * p_input;
257 p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_PARENT );
259 if( !p_input ) return NULL;
261 if( var_Get( p_input, "spu-channel", &val ) )
263 vlc_object_release( p_input );
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]);
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] )
275 dbg_print( DECODE_DBG_PACKET, "subtitle not for us.\n");
280 if ( p_sys->state == SUBTITLE_BLOCK_EMPTY ) {
281 i_expected_image = p_sys->i_image+1;
282 i_expected_packet = 0;
284 i_expected_image = p_sys->i_image;
285 i_expected_packet = p_sys->i_packet+1;
290 if ( *p_buffer & 0x80 ) {
291 p_sys->state = SUBTITLE_BLOCK_COMPLETE;
292 i_packet = ( *p_buffer++ & 0x7F );
294 p_sys->state = SUBTITLE_BLOCK_PARTIAL;
295 i_packet = *p_buffer++;
298 p_sys->i_image = GETINT16(p_buffer);
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 );
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);
310 p_sys->i_packet = i_packet;
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);
318 /* FIXME - remove append_data and use chainappend */
319 VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - SPU_HEADER_LEN );
321 block_ChainAppend( &p_sys->p_block, p_block );
323 p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
325 if (p_sys->state == SUBTITLE_BLOCK_COMPLETE)
327 if( p_sys->i_spu != p_sys->i_spu_size )
329 msg_Warn( p_dec, "SPU packets size=%d should be %d",
330 p_sys->i_spu, p_sys->i_spu_size );
333 dbg_print( (DECODE_DBG_PACKET),
334 "subtitle packet complete, size=%d", p_sys->i_spu );
336 return p_sys->p_block;
344 * c-file-style: "gnu"
346 * indent-tabs-mode: nil