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