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