]> git.sesse.net Git - vlc/blob - modules/codec/ogt/cvd.c
04423495f3da51afea99cad0856b3f4bc4ef4974
[vlc] / modules / codec / ogt / cvd.c
1 /*****************************************************************************
2  * cvd.c : CVD Subtitle decoder thread
3  *****************************************************************************
4  * Copyright (C) 2003, 2004 VideoLAN
5  * $Id$
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 "cvd.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( _("CVD 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, 
61                 VLC_TRUE );
62
63     add_integer( MODULE_STRING "-duration-scaling", 3, NULL,
64                  DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT,
65                  VLC_TRUE );
66
67     add_submodule();
68     set_description( _("Chaoji VCD subtitle packetizer") );
69     set_capability( "packetizer", 50 );
70     set_callbacks( PacketizerOpen, VCDSubClose );
71 vlc_module_end();
72
73 /*****************************************************************************
74  * Local prototypes
75  *****************************************************************************/
76
77 static block_t *Reassemble( decoder_t *, block_t ** );
78 static void     Decode   ( decoder_t *, block_t ** );
79 static block_t *Packetize( decoder_t *, block_t ** );
80
81
82 /*****************************************************************************
83  * VCDSubOpen
84  *****************************************************************************
85  * Tries to launch a decoder and return score so that the interface is able
86  * to chose.
87  *****************************************************************************/
88 static int
89 VCDSubOpen( vlc_object_t *p_this )
90 {
91     decoder_t     *p_dec = (decoder_t*)p_this;
92     decoder_sys_t *p_sys;
93
94     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'c','v','d',' ' ) )
95     {
96         return VLC_EGENERIC;
97     }
98
99
100     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
101
102     p_sys->i_debug       = config_GetInt( p_this, MODULE_STRING "-debug" );
103     p_sys->b_packetizer  = VLC_FALSE;
104     p_sys->p_vout        = NULL;
105     p_sys->i_image       = -1;
106     p_sys->subtitle_data = NULL;
107
108     VCDSubInitSubtitleBlock( p_sys );
109
110     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'c','v','d',' ' ) );
111
112
113     p_dec->pf_decode_sub = Decode;
114     p_dec->pf_packetize  = Packetize;
115
116     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
117
118     return VLC_SUCCESS;
119 }
120
121 /*****************************************************************************
122  * PacketizerOpen
123  *****************************************************************************
124  * Tries to launch a decoder and return score so that the interface is able
125  * to chose.
126  *****************************************************************************/
127 static int PacketizerOpen( vlc_object_t *p_this )
128 {
129     decoder_t *p_dec = (decoder_t*)p_this;
130
131     if( VCDSubOpen( p_this ) )
132     {
133         return VLC_EGENERIC;
134     }
135     p_dec->p_sys->b_packetizer = VLC_TRUE;
136
137     return VLC_SUCCESS;
138 }
139
140 /*****************************************************************************
141  * Decode:
142  *****************************************************************************/
143 static void
144 Decode ( decoder_t *p_dec, block_t **pp_block )
145 {
146     decoder_sys_t *p_sys = p_dec->p_sys;
147     block_t       *p_spu = Reassemble( p_dec, pp_block );
148
149     dbg_print( (DECODE_DBG_CALL) , "");
150
151     if( p_spu )
152     {
153         p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
154         p_sys->i_pts = p_spu->i_pts;
155         block_ChainRelease( p_spu );
156
157         if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
158         {
159             /* Parse and decode */
160             E_(ParsePacket)( p_dec );
161
162             vlc_object_release( p_sys->p_vout );
163         }
164
165         VCDSubInitSubtitleBlock ( p_sys );
166     }
167
168 }
169
170 /*****************************************************************************
171  * Packetize:
172  *****************************************************************************/
173 static block_t *
174 Packetize( decoder_t *p_dec, block_t **pp_block )
175 {
176     decoder_sys_t *p_sys = p_dec->p_sys;
177     block_t       *p_spu = Reassemble( p_dec, pp_block );
178
179     if( p_spu )
180     {
181         p_spu->i_dts = p_spu->i_pts;
182         p_spu->i_length = 0;
183
184         VCDSubInitSubtitleBlock( p_sys );
185
186         return block_ChainGather( p_spu );
187     }
188     return NULL;
189 }
190
191 /* following functions are local */
192
193 #define SPU_HEADER_LEN 1
194
195 /*****************************************************************************
196  Reassemble:
197
198  Data for single screen subtitle may come in several non-contiguous
199  packets of a stream. This routine is called when the next packet in
200  the stream comes in. The job of this routine is to parse the header,
201  if this is the beginning, and combine the packets into one complete
202  subtitle unit.
203
204  If everything is complete, we will return a block. Otherwise return
205  NULL.
206
207  *****************************************************************************/
208 static block_t *
209 Reassemble( decoder_t *p_dec, block_t **pp_block )
210 {
211     decoder_sys_t *p_sys = p_dec->p_sys;
212     block_t *p_block;
213     uint8_t *p_buffer;
214
215     if( pp_block == NULL || *pp_block == NULL )
216     {
217         return NULL;
218     }
219     p_block = *pp_block;
220     *pp_block = NULL;
221
222     if( p_block->i_buffer < SPU_HEADER_LEN )
223     {
224       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
225                p_block->i_buffer, SPU_HEADER_LEN );
226       block_Release( p_block );
227       return NULL;
228     }
229
230     p_buffer = p_block->p_buffer;
231
232     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
233                "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
234                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
235                p_buffer[5], p_buffer[6],
236                p_block->i_buffer);
237
238
239     /* Attach to our input thread and see if subtitle is selected. */
240     {
241         vlc_object_t * p_input;
242         vlc_value_t val;
243       
244         p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_PARENT );
245
246         if( !p_input ) return NULL;
247
248         if( var_Get( p_input, "spu-channel", &val ) ) {
249           vlc_object_release( p_input );
250           return NULL;
251         }
252         
253         vlc_object_release( p_input );
254
255         /* Number could be 0bd, 1bd, 2bd, 3bd for 0..3. If so 
256            reduce it to 0..3.
257          */
258         if ( (val.i_int & 0xff) == 0xbd ) val.i_int >>= 8;
259         
260         if( val.i_int == -1 || val.i_int != p_buffer[0] )
261           return NULL;
262     }
263
264
265     /* From the scant data on the format, there is only only way known
266        to detect the first packet in a subtitle.  The first packet
267        seems to have a valid PTS while later packets for the same
268        image don't. */
269
270     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 ) {
271       msg_Warn( p_dec, 
272                 "first packet expected but no PTS present -- skipped\n");
273       return NULL;
274     }
275
276     if ( p_sys->subtitle_data_pos == 0 ) {
277       /* First packet in the subtitle block */
278       E_(ParseHeader)( p_dec, p_buffer, p_block );
279       VCDSubInitSubtitleData(p_sys);
280     }
281
282     /* FIXME - remove append_data and use chainappend */
283     VCDSubAppendData( p_dec, p_buffer + SPU_HEADER_LEN, 
284                       p_block->i_buffer - SPU_HEADER_LEN );
285
286     block_ChainAppend( &p_sys->p_block, p_block );
287
288     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
289
290     if ( p_sys->subtitle_data_pos == p_sys->i_spu_size ) {
291       E_(ParseMetaInfo)( p_dec );
292       return p_sys->p_block;
293     } else {
294       /* Not last block in subtitle, so wait for another. */
295       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
296     }
297
298     
299     return NULL;
300 }