]> git.sesse.net Git - vlc/blob - modules/codec/ogt/cvd.c
First cut at CVD subtitle unit assembly and initial parsing.
[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.2 2003/12/28 11:26: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 1
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 static block_t *
205 Reassemble( decoder_t *p_dec, block_t **pp_block )
206 {
207     decoder_sys_t *p_sys = p_dec->p_sys;
208     block_t *p_block;
209     uint8_t *p_buffer;
210
211     if( pp_block == NULL || *pp_block == NULL )
212     {
213         return NULL;
214     }
215     p_block = *pp_block;
216     *pp_block = NULL;
217
218     if( p_block->i_buffer < SPU_HEADER_LEN )
219     {
220       msg_Dbg( p_dec, "invalid packet header (size %d < %d)" ,
221                p_block->i_buffer, SPU_HEADER_LEN );
222       block_Release( p_block );
223       return NULL;
224     }
225
226     p_buffer = p_block->p_buffer;
227
228     dbg_print( (DECODE_DBG_CALL|DECODE_DBG_PACKET), 
229                "header: 0x%02x 0x%02x 0x%02x 0x%02x, 0x%02x, 0x%02x, size: %i",
230                p_buffer[1], p_buffer[2], p_buffer[3], p_buffer[4],
231                p_buffer[5], p_buffer[6],
232                p_block->i_buffer);
233
234     /* There is little data on the format, but it does not seem to have a
235        good way to detect the first packet in the subtitle.  It seems,
236        however, that it has a valid pts while later packets for the same
237        image don't */
238
239     if ( p_sys->state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 ) {
240       msg_Warn( p_dec, 
241                 "first packet expected but no PTS present -- skipped\n");
242       return NULL;
243     }
244
245     if ( p_sys->subtitle_data_pos == 0 ) {
246       /* First packet in the subtitle block */
247       E_(ParseHeader)( p_dec, p_buffer, p_block );
248       VCDSubInitSubtitleData(p_sys);
249     }
250
251     /* FIXME - remove append_data and use chainappend */
252     VCDSubAppendData( p_dec, p_buffer, p_block->i_buffer - 1 );
253
254     block_ChainAppend( &p_sys->p_block, p_block );
255
256     p_sys->i_spu += p_block->i_buffer - SPU_HEADER_LEN;
257
258     if ( p_sys->subtitle_data_pos == p_sys->i_spu_size ) {
259       /* last packet in subtitle block. */
260
261       uint8_t *p     = p_sys->subtitle_data + p_sys->metadata_offset+1;
262       uint8_t *p_end = p + p_sys->metadata_length;
263
264       dbg_print( (DECODE_DBG_PACKET),
265                  "subtitle packet complete, size=%d", p_sys->i_spu );
266
267       p_sys->state = SUBTITLE_BLOCK_COMPLETE;
268       p_sys->i_image++;
269
270
271       for ( ; p < p_end; p += 4 ) {
272
273         switch ( p[0] ) {
274           
275         case 0x04:      /* Display duration in 1/90000ths of a second */
276
277           p_sys->i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
278           
279           dbg_print( DECODE_DBG_PACKET, 
280                      "subtitle display duration %u", p_sys->i_duration);
281           break;
282           
283         case 0x0c:      /* Unknown */
284           dbg_print( DECODE_DBG_PACKET, 
285                      "subtitle command unknown 0x%0x 0x%0x 0x%0x 0x%0x\n",
286                     p[0], p[1], p[2], p[3]);
287           break;
288           
289         case 0x17:      /* Position */
290           p_sys->i_x_start = ((p[1]&0x0f)<<6) + (p[2]>>2);
291           p_sys->i_y_start = ((p[2]&0x03)<<8) + p[3];
292           dbg_print( DECODE_DBG_PACKET, 
293                      "start position (%d,%d): %.2x %.2x %.2x", 
294                      p_sys->i_x_start, p_sys->i_y_start,
295                      p[1], p[2], p[3] );
296           break;
297           
298         case 0x1f:      /* Coordinates of the image bottom right */
299           {
300             int lastx = ((p[1]&0x0f)<<6) + (p[2]>>2);
301             int lasty = ((p[2]&0x03)<<8) + p[3];
302             p_sys->i_width  = lastx - p_sys->i_x_start + 1;
303             p_sys->i_height = lasty - p_sys->i_y_start + 1;
304             dbg_print( DECODE_DBG_PACKET, 
305                        "end position: (%d,%d): %.2x %.2x %.2x, w x h: %d x %d",
306                        lastx, lasty, p[1], p[2], p[3], 
307                        p_sys->i_width, p_sys->i_height );
308             break;
309           }
310           
311           
312         case 0x24:
313         case 0x25:
314         case 0x26:
315         case 0x27: 
316           {
317             uint8_t v = p[0]-0x24;
318             
319             /* Primary Palette */
320             dbg_print( DECODE_DBG_PACKET,
321                        "primary palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
322                        v, p[1], p[2], p[3]);
323             
324             p_sys->pi_palette[v].s.y = p[1];
325             p_sys->pi_palette[v].s.u = p[2];
326             p_sys->pi_palette[v].s.v = p[3];
327             break;
328           }
329           
330           
331         case 0x2c:
332         case 0x2d:
333         case 0x2e:
334         case 0x2f:
335           {
336             uint8_t v = p[0]-0x2c;
337             
338             dbg_print( DECODE_DBG_PACKET,
339                        "highlight palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
340                        v, p[1], p[2], p[3]);
341             
342             /* Highlight Palette */
343             p_sys->pi_palette_highlight[v].s.y = p[1];
344             p_sys->pi_palette_highlight[v].s.u = p[2];
345             p_sys->pi_palette_highlight[v].s.v = p[3];
346             break;
347           }
348
349         case 0x37:
350           /* transparency for primary palette */
351           p_sys->pi_palette[0].s.t = p[3] & 0x0f;
352           p_sys->pi_palette[1].s.t = p[3] >> 4;
353           p_sys->pi_palette[2].s.t = p[2] & 0x0f;
354           p_sys->pi_palette[3].s.t = p[2] >> 4;
355
356           dbg_print( DECODE_DBG_PACKET,
357                      "transparancy for primary palette (y,u,v): "
358                      "0x%0x 0x%0x 0x%0x",
359                      p[1], p[2], p[3]);
360
361           break;
362
363         case 0x3f:
364           /* transparency for highlight palette */
365           p_sys->pi_palette_highlight[0].s.t = p[2] & 0x0f;
366           p_sys->pi_palette_highlight[1].s.t = p[2] >> 4;
367           p_sys->pi_palette_highlight[2].s.t = p[1] & 0x0f;
368           p_sys->pi_palette_highlight[3].s.t = p[1] >> 4;
369
370           dbg_print( DECODE_DBG_PACKET,
371                      "transparancy for highlight palette (y,u,v): "
372                      "0x%0x 0x%0x 0x%0x",
373                      p[1], p[2], p[3]);
374
375           break;
376           
377         case 0x47:
378           /* offset to first field data, we correct to make it relative
379              to comp_image_offset (usually 4) */
380           p_sys->first_field_offset =
381             (p[2] << 8) + p[3] - p_sys->comp_image_offset;
382           dbg_print( DECODE_DBG_PACKET, 
383                      "first_field_offset %d", p_sys->first_field_offset);
384           break;
385           
386         case 0x4f:
387           /* offset to second field data, we correct to make it relative to
388              comp_image_offset (usually 4) */
389           p_sys->second_field_offset =
390             (p[2] << 8) + p[3] - p_sys->comp_image_offset;
391           dbg_print( DECODE_DBG_PACKET, 
392                      "second_field_offset %d", p_sys->second_field_offset);
393           break;
394           
395         default:
396           msg_Warn( p_dec, 
397                     "unknown sequence in control header " 
398                     "0x%0x 0x%0x 0x%0x 0x%0x",
399                     p[0], p[1], p[2], p[3]);
400           
401           p_sys->subtitle_data_pos = 0;
402         }
403       }
404       return p_sys->p_block;
405     } else {
406       /* Not last block in subtitle, so wait for another. */
407       p_sys->state = SUBTITLE_BLOCK_PARTIAL;
408     }
409
410     
411     return NULL;
412 }