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