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