]> git.sesse.net Git - vlc/blob - modules/codec/ogt/cvd.c
Start work on CVD subtitles.
[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.1 2003/12/28 04:51:52 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 #define DEBUG_LONGTEXT N_( \
40     "This integer when viewed in binary is a debugging mask\n" \
41     "external call          1\n" \
42     "all calls              2\n" \
43     "packet assembly info   4\n" \
44     "image bitmaps          8\n" \
45     "image transformations 16\n" \
46     "misc info             32\n" )
47
48 /*****************************************************************************
49  * Module descriptor.
50  *****************************************************************************/
51 static int  DecoderOpen   ( vlc_object_t * );
52 static int  PacketizerOpen( vlc_object_t * );
53
54 vlc_module_begin();
55     set_description( _("CVD subtitle decoder") );
56     set_capability( "decoder", 50 );
57     set_callbacks( DecoderOpen, VCDSubClose );
58
59     add_integer ( MODULE_STRING "-debug", 0, NULL,
60                   N_("set debug mask for additional debugging."),
61                   N_(DEBUG_LONGTEXT), VLC_TRUE );
62
63     add_submodule();
64     set_description( _("Chaoji VCD subtitle packetizer") );
65     set_capability( "packetizer", 50 );
66     set_callbacks( PacketizerOpen, VCDSubClose );
67 vlc_module_end();
68
69 /*****************************************************************************
70  * Local prototypes
71  *****************************************************************************/
72
73 static block_t *Reassemble( decoder_t *, block_t ** );
74 static void     Decode   ( decoder_t *, block_t ** );
75 static block_t *Packetize( decoder_t *, block_t ** );
76
77
78 /*****************************************************************************
79  * DecoderOpen
80  *****************************************************************************
81  * Tries to launch a decoder and return score so that the interface is able
82  * to chose.
83  *****************************************************************************/
84 static int
85 DecoderOpen( vlc_object_t *p_this )
86 {
87     decoder_t     *p_dec = (decoder_t*)p_this;
88     decoder_sys_t *p_sys;
89
90     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'c','v','d',' ' ) )
91     {
92         return VLC_EGENERIC;
93     }
94
95
96     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
97
98     p_sys->i_debug       = config_GetInt( p_this, MODULE_STRING "-debug" );
99     p_sys->b_packetizer  = VLC_FALSE;
100     p_sys->p_vout        = NULL;
101     p_sys->i_image       = -1;
102     p_sys->subtitle_data = NULL;
103
104     VCDSubInitSubtitleBlock( p_sys );
105
106     es_format_Init( &p_dec->fmt_out, SPU_ES, VLC_FOURCC( 'c','v','d',' ' ) );
107
108
109     p_dec->pf_decode_sub = Decode;
110     p_dec->pf_packetize  = Packetize;
111
112     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_EXT) , "");
113
114     return VLC_SUCCESS;
115 }
116
117 /*****************************************************************************
118  * PacketizerOpen
119  *****************************************************************************
120  * Tries to launch a decoder and return score so that the interface is able
121  * to chose.
122  *****************************************************************************/
123 static int PacketizerOpen( vlc_object_t *p_this )
124 {
125     decoder_t *p_dec = (decoder_t*)p_this;
126
127     if( DecoderOpen( p_this ) )
128     {
129         return VLC_EGENERIC;
130     }
131     p_dec->p_sys->b_packetizer = VLC_TRUE;
132
133     return VLC_SUCCESS;
134 }
135
136 /*****************************************************************************
137  * Decode:
138  *****************************************************************************/
139 static void
140 Decode ( decoder_t *p_dec, block_t **pp_block )
141 {
142     decoder_sys_t *p_sys = p_dec->p_sys;
143     block_t       *p_spu = Reassemble( p_dec, pp_block );
144
145     dbg_print( (DECODE_DBG_CALL) , "");
146
147     if( p_spu )
148     {
149         p_sys->i_spu = block_ChainExtract( p_spu, p_sys->buffer, 65536 );
150         p_sys->i_pts = p_spu->i_pts;
151         block_ChainRelease( p_spu );
152
153         if( ( p_sys->p_vout = VCDSubFindVout( p_dec ) ) )
154         {
155             /* Parse and decode */
156             E_(ParsePacket)( p_dec );
157
158             vlc_object_release( p_sys->p_vout );
159         }
160
161         VCDSubInitSubtitleBlock ( p_sys );
162     }
163
164 }
165
166 /*****************************************************************************
167  * Packetize:
168  *****************************************************************************/
169 static block_t *
170 Packetize( decoder_t *p_dec, block_t **pp_block )
171 {
172     decoder_sys_t *p_sys = p_dec->p_sys;
173     block_t       *p_spu = Reassemble( p_dec, pp_block );
174
175     if( p_spu )
176     {
177         p_spu->i_dts = p_spu->i_pts;
178         p_spu->i_length = 0;
179
180         VCDSubInitSubtitleBlock( p_sys );
181
182         return block_ChainGather( p_spu );
183     }
184     return NULL;
185 }
186
187 /* following functions are local */
188
189 #define SPU_HEADER_LEN 5
190
191 /*****************************************************************************
192  Reassemble:
193
194  The data for single screen subtitle may come in one of many
195  non-contiguous packets of a stream. This routine is called when the
196  next packet in the stream comes in. The job of this routine is to
197  parse the header, if this is the beginning, and combine the packets
198  into one complete subtitle unit.
199
200  If everything is complete, we will return a block. Otherwise return
201  NULL.
202
203
204  The format of the beginning of the subtitle packet that is used here.
205
206    size    description
207    -------------------------------------------
208    byte    subtitle channel (0..7) in bits 0-3
209    byte    subtitle packet number of this subtitle image 0-N,
210            if the subtitle packet is complete, the top bit of the byte is 1.
211    uint16  subtitle image number
212
213  *****************************************************************************/
214 static block_t *
215 Reassemble( decoder_t *p_dec, block_t **pp_block )
216 {
217     decoder_sys_t *p_sys = p_dec->p_sys;
218     block_t *p_block;
219     uint8_t *p_buffer;
220     uint16_t i_expected_image;
221     uint8_t  i_packet, i_expected_packet;
222
223     if( pp_block == NULL || *pp_block == NULL )
224     {
225         return NULL;
226     }
227     p_block = *pp_block;
228     *pp_block = NULL;
229
230     if( p_block->i_buffer < SPU_HEADER_LEN )
231     {
232       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
233                p_block->i_buffer, SPU_HEADER_LEN );
234       block_Release( p_block );
235       return NULL;
236     }
237
238     p_buffer = p_block->p_buffer;
239
240     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
241                "header: 0x%02x 0x%02x 0x%02x 0x%02x, size: %i",
242                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
243                p_block->i_buffer);
244
245     if( config_GetInt( p_dec, "spu-channel" ) != p_buffer[1] )
246       return NULL;
247
248     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY ) {
249       i_expected_image  = p_sys->i_image+1;
250       i_expected_packet = 0;
251     } else {
252       i_expected_image  = p_sys->i_image;
253       i_expected_packet = p_sys->i_packet+1;
254     }
255
256     p_buffer += 2;
257
258     if ( *p_buffer & 0x80 ) {
259       p_sys->state = SUBTITLE_BLOCK_COMPLETE;
260       i_packet     = ( *p_buffer++ & 0x7F );
261     } else {
262       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
263       i_packet     = *p_buffer++;
264     }
265
266     p_sys->i_image = GETINT16(p_buffer);
267
268     if ( p_sys->i_image != i_expected_image ) {
269       msg_Warn( p_dec, "expecting subtitle image %u but found %u",
270                 i_expected_image, p_sys->i_image );
271     }
272
273     if ( i_packet != i_expected_packet ) {
274       msg_Warn( p_dec, "expecting subtitle image packet %u but found %u",
275                 i_expected_packet, i_packet);
276     }
277
278     p_sys->i_packet = i_packet;
279
280     if ( p_sys->i_packet == 0 ) {
281       /* First packet in the subtitle block */
282       E_(ParseHeader)( p_dec, p_buffer, p_block );
283       VCDSubInitSubtitleData(p_sys);
284     }
285
286     /* FIXME - remove append_data and use chainappend */
287     VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - 5 );
288
289     block_ChainAppend( &p_sys->p_block, p_block );
290
291     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
292
293     if (p_sys->state == SUBTITLE_BLOCK_COMPLETE)
294     {
295       if( p_sys->i_spu != p_sys->i_spu_size )
296         {
297           msg_Warn( p_dec, "SPU packets size=%d should be %d",
298                    p_sys->i_spu, p_sys->i_spu_size );
299         }
300
301       dbg_print( (DECODE_DBG_PACKET),
302                  "subtitle packet complete, size=%d", p_sys->i_spu );
303
304       return p_sys->p_block;
305     }
306     return NULL;
307 }