]> git.sesse.net Git - vlc/blob - modules/codec/ogt/cvd.c
Omitted option -duration-scaling which caused plugin to stop working.
[vlc] / modules / codec / ogt / cvd.c
1 /*****************************************************************************
2  * cvd.c : CVD Subtitle decoder thread
3  *****************************************************************************
4  * Copyright (C) 2003, 2004 VideoLAN
5  * $Id: cvd.c,v 1.13 2004/01/23 08:36:48 rocky Exp $
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  DecoderOpen   ( 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( DecoderOpen, VCDSubClose );
49
50     add_integer ( MODULE_STRING "-debug", 0, NULL,
51                   N_("set debug mask for additional debugging."),
52                   N_(DEBUG_LONGTEXT), VLC_TRUE );
53
54     add_integer ( MODULE_STRING "-horizontal-correct", 0, NULL,
55                   HORIZONTAL_CORRECT, HORIZONTAL_CORRECT_LONGTEXT, VLC_FALSE );
56
57     add_integer ( MODULE_STRING "-vertical-correct", 0, NULL,
58                   VERTICAL_CORRECT, VERTICAL_CORRECT_LONGTEXT, VLC_FALSE );
59
60     add_string( MODULE_STRING "-aspect-ratio", "", NULL,
61                 SUB_ASPECT_RATIO_TEXT, SUB_ASPECT_RATIO_LONGTEXT, 
62                 VLC_TRUE );
63
64     add_integer( MODULE_STRING "-duration-scaling", 9, NULL,
65                  DURATION_SCALE_TEXT, DURATION_SCALE_LONGTEXT,
66                  VLC_TRUE );
67
68     add_submodule();
69     set_description( _("Chaoji VCD subtitle packetizer") );
70     set_capability( "packetizer", 50 );
71     set_callbacks( PacketizerOpen, VCDSubClose );
72 vlc_module_end();
73
74 /*****************************************************************************
75  * Local prototypes
76  *****************************************************************************/
77
78 static block_t *Reassemble( decoder_t *, block_t ** );
79 static void     Decode   ( decoder_t *, block_t ** );
80 static block_t *Packetize( decoder_t *, block_t ** );
81
82
83 /*****************************************************************************
84  * DecoderOpen
85  *****************************************************************************
86  * Tries to launch a decoder and return score so that the interface is able
87  * to chose.
88  *****************************************************************************/
89 static int
90 DecoderOpen( 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( DecoderOpen( 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 void
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
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             /* Parse and decode */
161             E_(ParsePacket)( p_dec );
162
163             vlc_object_release( p_sys->p_vout );
164         }
165
166         VCDSubInitSubtitleBlock ( p_sys );
167     }
168
169 }
170
171 /*****************************************************************************
172  * Packetize:
173  *****************************************************************************/
174 static block_t *
175 Packetize( decoder_t *p_dec, block_t **pp_block )
176 {
177     decoder_sys_t *p_sys = p_dec->p_sys;
178     block_t       *p_spu = Reassemble( p_dec, pp_block );
179
180     if( p_spu )
181     {
182         p_spu->i_dts = p_spu->i_pts;
183         p_spu->i_length = 0;
184
185         VCDSubInitSubtitleBlock( p_sys );
186
187         return block_ChainGather( p_spu );
188     }
189     return NULL;
190 }
191
192 /* following functions are local */
193
194 #define SPU_HEADER_LEN 1
195
196 /*****************************************************************************
197  Reassemble:
198
199  Data for single screen subtitle may come in several non-contiguous
200  packets of a stream. This routine is called when the next packet in
201  the stream comes in. The job of this routine is to parse the header,
202  if this is the beginning, and combine the packets into one complete
203  subtitle unit.
204
205  If everything is complete, we will return a block. Otherwise return
206  NULL.
207
208  *****************************************************************************/
209 static block_t *
210 Reassemble( decoder_t *p_dec, block_t **pp_block )
211 {
212     decoder_sys_t *p_sys = p_dec->p_sys;
213     block_t *p_block;
214     uint8_t *p_buffer;
215
216     if( pp_block == NULL || *pp_block == NULL )
217     {
218         return NULL;
219     }
220     p_block = *pp_block;
221     *pp_block = NULL;
222
223     if( p_block->i_buffer < SPU_HEADER_LEN )
224     {
225       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
226                p_block->i_buffer, SPU_HEADER_LEN );
227       block_Release( p_block );
228       return NULL;
229     }
230
231     p_buffer = p_block->p_buffer;
232
233     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
234                "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
235                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
236                p_buffer[5], p_buffer[6],
237                p_block->i_buffer);
238
239     if( config_GetInt( p_dec, "spu-channel" ) != p_buffer[0] )
240       return NULL;
241
242     /* From the scant data on the format, there is only only way known
243        to detect the first packet in a subtitle.  The first packet
244        seems to have a valid PTS while later packets for the same
245        image don't. */
246
247     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 ) {
248       msg_Warn( p_dec, 
249                 "first packet expected but no PTS present -- skipped\n");
250       return NULL;
251     }
252
253     if ( p_sys->subtitle_data_pos == 0 ) {
254       /* First packet in the subtitle block */
255       E_(ParseHeader)( p_dec, p_buffer, p_block );
256       VCDSubInitSubtitleData(p_sys);
257     }
258
259     /* FIXME - remove append_data and use chainappend */
260     VCDSubAppendData( p_dec, p_buffer + SPU_HEADER_LEN, 
261                       p_block->i_buffer - SPU_HEADER_LEN );
262
263     block_ChainAppend( &p_sys->p_block, p_block );
264
265     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
266
267     if ( p_sys->subtitle_data_pos == p_sys->i_spu_size ) {
268       E_(ParseMetaInfo)( p_dec );
269       return p_sys->p_block;
270     } else {
271       /* Not last block in subtitle, so wait for another. */
272       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
273     }
274
275     
276     return NULL;
277 }