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