]> git.sesse.net Git - vlc/blob - modules/codec/ogt/cvd.c
* when you use object_find you need to do a object_release as well
[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         var_Get( p_input, "spu-channel", &val );
249         vlc_object_release( p_input );
250
251         /* Number could be 0bd, 1bd, 2bd, 3bd for 0..3. If so 
252            reduce it to 0..3.
253          */
254         if ( (val.i_int & 0xff) == 0xbd ) val.i_int >>= 8;
255         
256         if( val.i_int == -1 || val.i_int != p_buffer[0] )
257           return NULL;
258     }
259
260
261     /* From the scant data on the format, there is only only way known
262        to detect the first packet in a subtitle.  The first packet
263        seems to have a valid PTS while later packets for the same
264        image don't. */
265
266     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 ) {
267       msg_Warn( p_dec, 
268                 "first packet expected but no PTS present -- skipped\n");
269       return NULL;
270     }
271
272     if ( p_sys->subtitle_data_pos == 0 ) {
273       /* First packet in the subtitle block */
274       E_(ParseHeader)( p_dec, p_buffer, p_block );
275       VCDSubInitSubtitleData(p_sys);
276     }
277
278     /* FIXME - remove append_data and use chainappend */
279     VCDSubAppendData( p_dec, p_buffer + SPU_HEADER_LEN, 
280                       p_block->i_buffer - SPU_HEADER_LEN );
281
282     block_ChainAppend( &p_sys->p_block, p_block );
283
284     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
285
286     if ( p_sys->subtitle_data_pos == p_sys->i_spu_size ) {
287       E_(ParseMetaInfo)( p_dec );
288       return p_sys->p_block;
289     } else {
290       /* Not last block in subtitle, so wait for another. */
291       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
292     }
293
294     
295     return NULL;
296 }