]> git.sesse.net Git - vlc/blob - modules/codec/ogt/cvd.c
* src/video_output/vout_subpictures.c : New OSD channels
[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     vout_thread_t *p_last_vout = p_dec->p_sys->p_vout;
149
150     dbg_print( (DECODE_DBG_CALL) , "");
151
152     if( p_spu )
153     {
154         p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
155         p_sys->i_pts = p_spu->i_pts;
156         block_ChainRelease( p_spu );
157
158         if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
159         {
160             if( p_last_vout != p_sys->p_vout )
161             {
162                 p_sys->i_subpic_channel =
163                     vout_RegisterOSDChannel( p_sys->p_vout );
164             }
165
166             /* Parse and decode */
167             E_(ParsePacket)( p_dec );
168
169             vlc_object_release( p_sys->p_vout );
170         }
171
172         VCDSubInitSubtitleBlock ( p_sys );
173     }
174
175 }
176
177 /*****************************************************************************
178  * Packetize:
179  *****************************************************************************/
180 static block_t *
181 Packetize( decoder_t *p_dec, block_t **pp_block )
182 {
183     decoder_sys_t *p_sys = p_dec->p_sys;
184     block_t       *p_spu = Reassemble( p_dec, pp_block );
185
186     if( p_spu )
187     {
188         p_spu->i_dts = p_spu->i_pts;
189         p_spu->i_length = 0;
190
191         VCDSubInitSubtitleBlock( p_sys );
192
193         return block_ChainGather( p_spu );
194     }
195     return NULL;
196 }
197
198 /* following functions are local */
199
200 #define SPU_HEADER_LEN 1
201
202 /*****************************************************************************
203  Reassemble:
204
205  Data for single screen subtitle may come in several non-contiguous
206  packets of a stream. This routine is called when the next packet in
207  the stream comes in. The job of this routine is to parse the header,
208  if this is the beginning, and combine the packets into one complete
209  subtitle unit.
210
211  If everything is complete, we will return a block. Otherwise return
212  NULL.
213
214  *****************************************************************************/
215 static block_t *
216 Reassemble( decoder_t *p_dec, block_t **pp_block )
217 {
218     decoder_sys_t *p_sys = p_dec->p_sys;
219     block_t *p_block;
220     uint8_t *p_buffer;
221
222     if( pp_block == NULL || *pp_block == NULL )
223     {
224         return NULL;
225     }
226     p_block = *pp_block;
227     *pp_block = NULL;
228
229     if( p_block->i_buffer < SPU_HEADER_LEN )
230     {
231       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
232                p_block->i_buffer, SPU_HEADER_LEN );
233       block_Release( p_block );
234       return NULL;
235     }
236
237     p_buffer = p_block->p_buffer;
238
239     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET),
240                "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
241                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
242                p_buffer[5], p_buffer[6],
243                p_block->i_buffer);
244
245
246     /* Attach to our input thread and see if subtitle is selected. */
247     {
248         vlc_object_t * p_input;
249         vlc_value_t val;
250
251         p_input = vlc_object_find( p_dec, VLC_OBJECT_INPUT, FIND_PARENT );
252
253         if( !p_input ) return NULL;
254
255         if( var_Get( p_input, "spu-channel", &val ) )
256         {
257           vlc_object_release( p_input );
258           return NULL;
259         }
260
261         vlc_object_release( p_input );
262
263         /* Number could be 0bd, 1bd, 2bd, 3bd for 0..3. If so
264            reduce it to 0..3.
265          */
266         if ( (val.i_int & 0xff) == 0xbd ) val.i_int >>= 8;
267
268         if( val.i_int == -1 || val.i_int != p_buffer[0] )
269           return NULL;
270     }
271
272
273     /* From the scant data on the format, there is only only way known
274        to detect the first packet in a subtitle.  The first packet
275        seems to have a valid PTS while later packets for the same
276        image don't. */
277
278     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 ) {
279       msg_Warn( p_dec,
280                 "first packet expected but no PTS present -- skipped\n");
281       return NULL;
282     }
283
284     if ( p_sys->subtitle_data_pos == 0 ) {
285       /* First packet in the subtitle block */
286       E_(ParseHeader)( p_dec, p_buffer, p_block );
287       VCDSubInitSubtitleData(p_sys);
288     }
289
290     /* FIXME - remove append_data and use chainappend */
291     VCDSubAppendData( p_dec, p_buffer + SPU_HEADER_LEN,
292                       p_block->i_buffer - SPU_HEADER_LEN );
293
294     block_ChainAppend( &p_sys->p_block, p_block );
295
296     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
297
298     if ( p_sys->subtitle_data_pos == p_sys->i_spu_size ) {
299       E_(ParseMetaInfo)( p_dec );
300       return p_sys->p_block;
301     } else {
302       /* Not last block in subtitle, so wait for another. */
303       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
304     }
305
306     return NULL;
307 }