]> git.sesse.net Git - vlc/blob - modules/codec/cvdsub.c
macosx: fixed menubar appearance in fullscreen mode by partially reverting [46c93c9cc...
[vlc] / modules / codec / cvdsub.c
1 /*****************************************************************************
2  * cvd.c : CVD Subtitle decoder
3  *****************************************************************************
4  * Copyright (C) 2003, 2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Rocky Bernstein
8  *          Gildas Bazin <gbazin@videolan.org>
9  *          Julio Sanchez Fernandez (http://subhandler.sourceforge.net)
10  *          Laurent Aimar <fenrir@via.ecp.fr>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_vout.h>
37 #include <vlc_codec.h>
38
39 #include "vlc_bits.h"
40
41 #define DEBUG_CVDSUB 1
42
43 /*****************************************************************************
44  * Module descriptor.
45  *****************************************************************************/
46 static int  DecoderOpen   ( vlc_object_t * );
47 static int  PacketizerOpen( vlc_object_t * );
48 static void DecoderClose  ( vlc_object_t * );
49
50 vlc_module_begin ()
51     set_description( N_("CVD subtitle decoder") )
52     set_capability( "decoder", 50 )
53     set_callbacks( DecoderOpen, DecoderClose )
54
55     add_submodule ()
56     set_description( N_("Chaoji VCD subtitle packetizer") )
57     set_capability( "packetizer", 50 )
58     set_callbacks( PacketizerOpen, DecoderClose )
59 vlc_module_end ()
60
61 /*****************************************************************************
62  * Local prototypes
63  *****************************************************************************/
64 static subpicture_t *Decode( decoder_t *, block_t ** );
65 static block_t *Packetize  ( decoder_t *, block_t ** );
66 static block_t *Reassemble ( decoder_t *, block_t * );
67 static void ParseMetaInfo  ( decoder_t *, block_t * );
68 static void ParseHeader    ( decoder_t *, block_t * );
69 static subpicture_t *DecodePacket( decoder_t *, block_t * );
70 static void RenderImage( decoder_t *, block_t *, subpicture_region_t * );
71
72 #define SUBTITLE_BLOCK_EMPTY 0
73 #define SUBTITLE_BLOCK_PARTIAL 1
74 #define SUBTITLE_BLOCK_COMPLETE 2
75
76 struct decoder_sys_t
77 {
78   int      b_packetizer;
79
80   int      i_state;    /* data-gathering state for this subtitle */
81
82   block_t  *p_spu;   /* Bytes of the packet. */
83
84   size_t   i_spu_size;     /* goal for subtitle_data_pos while gathering,
85                              size of used subtitle_data later */
86
87   uint16_t i_image_offset;      /* offset from subtitle_data to compressed
88                                    image data */
89   size_t i_image_length;           /* size of the compressed image data */
90   size_t first_field_offset;       /* offset of even raster lines */
91   size_t second_field_offset;      /* offset of odd raster lines */
92   size_t metadata_offset;          /* offset to data describing the image */
93   size_t metadata_length;          /* length of metadata */
94
95   mtime_t i_duration;   /* how long to display the image, 0 stands
96                            for "until next subtitle" */
97
98   uint16_t i_x_start, i_y_start; /* position of top leftmost pixel of
99                                     image when displayed */
100   uint16_t i_width, i_height;    /* dimensions in pixels of image */
101
102   uint8_t p_palette[4][4];       /* Palette of colors used in subtitle */
103   uint8_t p_palette_highlight[4][4];
104 };
105
106 /*****************************************************************************
107  * DecoderOpen: open/initialize the cvdsub decoder.
108  *****************************************************************************/
109 static int DecoderOpen( vlc_object_t *p_this )
110 {
111     decoder_t     *p_dec = (decoder_t*)p_this;
112     decoder_sys_t *p_sys;
113
114     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'c','v','d',' ' ) )
115     {
116         return VLC_EGENERIC;
117     }
118
119     p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) );
120     if( !p_sys )
121         return VLC_ENOMEM;
122
123     p_sys->b_packetizer  = false;
124
125     p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
126     p_sys->p_spu   = NULL;
127
128     p_dec->pf_decode_sub = Decode;
129     p_dec->pf_packetize  = Packetize;
130
131     p_dec->fmt_out.i_cat = SPU_ES;
132     p_dec->fmt_out.i_codec = VLC_FOURCC('Y','U','V','P');
133
134     return VLC_SUCCESS;
135 }
136
137 /*****************************************************************************
138  * PacketizerOpen: open/initialize the cvdsub packetizer.
139  *****************************************************************************/
140 static int PacketizerOpen( vlc_object_t *p_this )
141 {
142     decoder_t *p_dec = (decoder_t*)p_this;
143
144     if( DecoderOpen( p_this ) != VLC_SUCCESS ) return VLC_EGENERIC;
145
146     p_dec->p_sys->b_packetizer = true;
147
148     return VLC_SUCCESS;
149 }
150
151 /*****************************************************************************
152  * DecoderClose: closes the cvdsub decoder/packetizer.
153  *****************************************************************************/
154 void DecoderClose( vlc_object_t *p_this )
155 {
156     decoder_t     *p_dec = (decoder_t*)p_this;
157     decoder_sys_t *p_sys = p_dec->p_sys;
158
159     if( p_sys->p_spu ) block_ChainRelease( p_sys->p_spu );
160     free( p_sys );
161 }
162
163 /*****************************************************************************
164  * Decode:
165  *****************************************************************************/
166 static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
167 {
168     block_t *p_block, *p_spu;
169
170     if( pp_block == NULL || *pp_block == NULL ) return NULL;
171
172     p_block = *pp_block;
173     *pp_block = NULL;
174
175     if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
176
177     /* Parse and decode */
178     return DecodePacket( p_dec, p_spu );
179 }
180
181 /*****************************************************************************
182  * Packetize:
183  *****************************************************************************/
184 static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
185 {
186     block_t *p_block, *p_spu;
187
188     if( pp_block == NULL || *pp_block == NULL ) return NULL;
189
190     p_block = *pp_block;
191     *pp_block = NULL;
192
193     if( !(p_spu = Reassemble( p_dec, p_block )) ) return NULL;
194
195     p_spu->i_dts = p_spu->i_pts;
196     p_spu->i_length = 0;
197
198     return p_spu;
199 }
200
201
202 /*****************************************************************************
203  Reassemble:
204
205  Data for single screen subtitle may come in several non-contiguous
206  packets of a stream. This routine is called when the next packet in
207  the stream comes in. The job of this routine is to parse the header,
208  if this is the beginning, and combine the packets into one complete
209  subtitle unit.
210
211  If everything is complete, we will return a block. Otherwise return
212  NULL.
213
214  *****************************************************************************/
215 #define SPU_HEADER_LEN 1
216
217 static block_t *Reassemble( decoder_t *p_dec, block_t *p_block )
218 {
219     decoder_sys_t *p_sys = p_dec->p_sys;
220     uint8_t *p_buffer;
221
222     if( p_block->i_buffer < SPU_HEADER_LEN )
223     {
224         msg_Dbg( p_dec, "invalid packet header (size %zu < %u)" ,
225                  p_block->i_buffer, SPU_HEADER_LEN );
226         block_Release( p_block );
227         return NULL;
228     }
229
230     p_buffer = p_block->p_buffer;
231
232     /* From the scant data on the format, there is only only way known
233      * to detect the first packet in a subtitle.  The first packet
234      * seems to have a valid PTS while later packets for the same
235      * image don't. */
236     if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY && p_block->i_pts == 0 )
237     {
238         msg_Warn( p_dec, "first packet expected but no PTS present");
239         return NULL;
240     }
241
242     p_block->p_buffer += SPU_HEADER_LEN;
243     p_block->i_buffer -= SPU_HEADER_LEN;
244
245     /* First packet in the subtitle block */
246     if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY ) ParseHeader( p_dec, p_block );
247
248     block_ChainAppend( &p_sys->p_spu, p_block );
249     p_sys->p_spu = block_ChainGather( p_sys->p_spu );
250
251     if( p_sys->p_spu->i_buffer >= p_sys->i_spu_size )
252     {
253         block_t *p_spu = p_sys->p_spu;
254
255         if( p_spu->i_buffer != p_sys->i_spu_size )
256         {
257             msg_Warn( p_dec, "SPU packets size=%zu should be %zu",
258                       p_spu->i_buffer, p_sys->i_spu_size );
259         }
260
261         msg_Dbg( p_dec, "subtitle packet complete, size=%zuu", p_spu->i_buffer);
262
263         ParseMetaInfo( p_dec, p_spu );
264
265         p_sys->i_state = SUBTITLE_BLOCK_EMPTY;
266         p_sys->p_spu = 0;
267         return p_spu;
268     }
269     else
270     {
271         /* Not last block in subtitle, so wait for another. */
272         p_sys->i_state = SUBTITLE_BLOCK_PARTIAL;
273     }
274
275     return NULL;
276 }
277
278 /*
279   We do not have information on the subtitle format used on CVD's
280   except the submux sample code and a couple of samples of dubious
281   origin. Thus, this is the result of reading some code whose
282   correctness is not known and some experimentation.
283
284   CVD subtitles are different in several ways from SVCD OGT subtitles.
285   Image comes first and metadata is at the end.  So that the metadata
286   can be found easily, the subtitle packet starts with two bytes
287   (everything is big-endian again) that give the total size of the
288   subtitle data and the offset to the metadata - i.e. size of the
289   image data plus the four bytes at the beginning.
290
291   Image data comes interlaced is run-length encoded.  Each field is a
292   four-bit nibble. Each nibble contains a two-bit repeat count and a
293   two-bit color number so that up to three pixels can be described in
294   four bits.  The function of a 0 repeat count is unknown; it might be
295   used for RLE extension.  However when the full nibble is zero, the
296   rest of the line is filled with the color value in the next nibble.
297   It is unknown what happens if the color value is greater than three.
298   The rest seems to use a 4-entries palette.  It is not impossible
299   that the fill-line complete case above is not as described and the
300   zero repeat count means fill line.  The sample code never produces
301   this, so it may be untested.
302 */
303
304 static void ParseHeader( decoder_t *p_dec, block_t *p_block )
305 {
306     decoder_sys_t *p_sys = p_dec->p_sys;
307     uint8_t *p = p_block->p_buffer;
308
309     p_sys->i_spu_size = (p[0] << 8) + p[1] + 4; p += 2;
310
311     /* FIXME: check data sanity */
312     p_sys->metadata_offset = (p[0] <<  8) +   p[1]; p +=2;
313     p_sys->metadata_length = p_sys->i_spu_size - p_sys->metadata_offset;
314
315     p_sys->i_image_offset = 4;
316     p_sys->i_image_length = p_sys->metadata_offset - p_sys->i_image_offset;
317
318 #ifdef DEBUG_CVDSUB
319     msg_Dbg( p_dec, "total size: %zu  image size: %zu",
320              p_sys->i_spu_size, p_sys->i_image_length );
321 #endif
322 }
323
324 /*
325   We parse the metadata information here.
326
327   Although metadata information does not have to come in a fixed field
328   order, every metadata field consists of a tag byte followed by
329   parameters. In all cases known, the size including tag byte is
330   exactly four bytes in length.
331 */
332
333 #define ExtractXY(x, y) x = ((p[1]&0x0f)<<6) + (p[2]>>2); \
334                         y = ((p[2]&0x03)<<8) + p[3];
335
336 static void ParseMetaInfo( decoder_t *p_dec, block_t *p_spu  )
337 {
338     /* Last packet in subtitle block. */
339
340     decoder_sys_t *p_sys = p_dec->p_sys;
341     uint8_t       *p     = p_spu->p_buffer + p_sys->metadata_offset;
342     uint8_t       *p_end = p + p_sys->metadata_length;
343
344     for( ; p < p_end; p += 4 )
345     {
346         switch( p[0] )
347         {
348         case 0x04: /* subtitle duration in 1/90000ths of a second */
349             p_sys->i_duration = (p[1]<<16) + (p[2]<<8) + p[3];
350
351 #ifdef DEBUG_CVDSUB
352             msg_Dbg( p_dec, "subtitle display duration %lu secs",
353                      (long unsigned int)(p_sys->i_duration / 90000) );
354 #endif
355             p_sys->i_duration *= 100 / 9;
356             break;
357
358         case 0x0c: /* unknown */
359 #ifdef DEBUG_CVDSUB
360             msg_Dbg( p_dec, "subtitle command unknown 0x%0x 0x%0x 0x%0x 0x%0x",
361                      (int)p[0], (int)p[1], (int)p[2], (int)p[3] );
362 #endif
363             break;
364
365         case 0x17: /* coordinates of subtitle upper left x, y position */
366             ExtractXY(p_sys->i_x_start, p_sys->i_y_start);
367
368 #ifdef DEBUG_CVDSUB
369             msg_Dbg( p_dec, "start position (%d,%d)",
370                      p_sys->i_x_start, p_sys->i_y_start );
371 #endif
372             break;
373
374         case 0x1f: /* coordinates of subtitle bottom right x, y position */
375         {
376             int lastx;
377             int lasty;
378             ExtractXY(lastx, lasty);
379             p_sys->i_width  = lastx - p_sys->i_x_start + 1;
380             p_sys->i_height = lasty - p_sys->i_y_start + 1;
381
382 #ifdef DEBUG_CVDSUB
383             msg_Dbg( p_dec, "end position (%d,%d), w x h: %dx%d",
384                      lastx, lasty, p_sys->i_width, p_sys->i_height );
385 #endif
386             break;
387         }
388
389         case 0x24:
390         case 0x25:
391         case 0x26:
392         case 0x27:
393         {
394             uint8_t v = p[0] - 0x24;
395
396 #ifdef DEBUG_CVDSUB
397             /* Primary Palette */
398             msg_Dbg( p_dec, "primary palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
399                      (int)v, (int)p[1], (int)p[2], (int)p[3] );
400 #endif
401
402             p_sys->p_palette[v][0] = p[1]; /* Y */
403             p_sys->p_palette[v][1] = p[3]; /* Cr / V */
404             p_sys->p_palette[v][2] = p[2]; /* Cb / U */
405             break;
406         }
407
408         case 0x2c:
409         case 0x2d:
410         case 0x2e:
411         case 0x2f:
412         {
413             uint8_t v = p[0] - 0x2c;
414
415 #ifdef DEBUG_CVDSUB
416             msg_Dbg( p_dec,"highlight palette %d (y,u,v): (0x%0x,0x%0x,0x%0x)",
417                      (int)v, (int)p[1], (int)p[2], (int)p[3] );
418 #endif
419
420             /* Highlight Palette */
421             p_sys->p_palette_highlight[v][0] = p[1]; /* Y */
422             p_sys->p_palette_highlight[v][1] = p[3]; /* Cr / V */
423             p_sys->p_palette_highlight[v][2] = p[2]; /* Cb / U */
424             break;
425         }
426
427         case 0x37:
428             /* transparency for primary palette */
429             p_sys->p_palette[0][3] = (p[3] & 0x0f) << 4;
430             p_sys->p_palette[1][3] = (p[3] >> 4) << 4;
431             p_sys->p_palette[2][3] = (p[2] & 0x0f) << 4;
432             p_sys->p_palette[3][3] = (p[2] >> 4) << 4;
433
434 #ifdef DEBUG_CVDSUB
435             msg_Dbg( p_dec, "transparency for primary palette 0..3: "
436                      "0x%0x 0x%0x 0x%0x 0x%0x",
437                      (int)p_sys->p_palette[0][3], (int)p_sys->p_palette[1][3],
438                      (int)p_sys->p_palette[2][3], (int)p_sys->p_palette[3][3]);
439 #endif
440             break;
441
442         case 0x3f:
443             /* transparency for highlight palette */
444             p_sys->p_palette_highlight[0][3] = (p[2] & 0x0f) << 4;
445             p_sys->p_palette_highlight[1][3] = (p[2] >> 4) << 4;
446             p_sys->p_palette_highlight[2][3] = (p[1] & 0x0f) << 4;
447             p_sys->p_palette_highlight[3][3] = (p[1] >> 4) << 4;
448
449 #ifdef DEBUG_CVDSUB
450             msg_Dbg( p_dec, "transparency for highlight palette 0..3: "
451                      "0x%0x 0x%0x 0x%0x 0x%0x",
452                      (int)p_sys->p_palette_highlight[0][3],
453                      (int)p_sys->p_palette_highlight[1][3],
454                      (int)p_sys->p_palette_highlight[2][3],
455                      (int)p_sys->p_palette_highlight[3][3] );
456 #endif
457             break;
458
459         case 0x47:
460             /* offset to start of even rows of interlaced image, we correct
461              * to make it relative to i_image_offset (usually 4) */
462             p_sys->first_field_offset =
463                 (p[2] << 8) + p[3] - p_sys->i_image_offset;
464 #ifdef DEBUG_CVDSUB
465             msg_Dbg( p_dec, "1st_field_offset %zu",
466                      p_sys->first_field_offset );
467 #endif
468             break;
469
470         case 0x4f:
471             /* offset to start of odd rows of interlaced image, we correct
472              * to make it relative to i_image_offset (usually 4) */
473             p_sys->second_field_offset =
474                 (p[2] << 8) + p[3] - p_sys->i_image_offset;
475 #ifdef DEBUG_CVDSUB
476             msg_Dbg( p_dec, "2nd_field_offset %zu",
477                      p_sys->second_field_offset);
478 #endif
479             break;
480
481         default:
482 #ifdef DEBUG_CVDSUB
483             msg_Warn( p_dec, "unknown sequence in control header "
484                       "0x%0x 0x%0x 0x%0x 0x%0x", p[0], p[1], p[2], p[3]);
485 #endif
486         }
487     }
488 }
489
490 /*****************************************************************************
491  * DecodePacket: parse and decode an SPU packet
492  *****************************************************************************
493  * This function parses and decodes an SPU packet and, if valid, returns a
494  * subpicture.
495  *****************************************************************************/
496 static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data )
497 {
498     decoder_sys_t *p_sys = p_dec->p_sys;
499     subpicture_t  *p_spu;
500     subpicture_region_t *p_region;
501     video_format_t fmt;
502     video_palette_t palette;
503     int i;
504
505     /* Allocate the subpicture internal data. */
506     p_spu = decoder_NewSubpicture( p_dec );
507     if( !p_spu ) return NULL;
508
509     p_spu->i_start = p_data->i_pts;
510     p_spu->i_stop  = p_data->i_pts + p_sys->i_duration;
511     p_spu->b_ephemer = true;
512
513     /* Create new SPU region */
514     memset( &fmt, 0, sizeof(video_format_t) );
515     fmt.i_chroma = VLC_FOURCC('Y','U','V','P');
516     fmt.i_aspect = VOUT_ASPECT_FACTOR;
517     fmt.i_width = fmt.i_visible_width = p_sys->i_width;
518     fmt.i_height = fmt.i_visible_height = p_sys->i_height;
519     fmt.i_x_offset = fmt.i_y_offset = 0;
520     fmt.p_palette = &palette;
521     fmt.p_palette->i_entries = 4;
522     for( i = 0; i < fmt.p_palette->i_entries; i++ )
523     {
524         fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0];
525         fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1];
526         fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2];
527         fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3];
528     }
529
530     p_region = subpicture_region_New( &fmt );
531     if( !p_region )
532     {
533         msg_Err( p_dec, "cannot allocate SPU region" );
534         decoder_DeleteSubpicture( p_dec, p_spu );
535         return NULL;
536     }
537
538     p_spu->p_region = p_region;
539     p_region->i_x = p_sys->i_x_start;
540     p_region->i_x = p_region->i_x * 3 / 4; /* FIXME: use aspect ratio for x? */
541     p_region->i_y = p_sys->i_y_start;
542
543     RenderImage( p_dec, p_data, p_region );
544
545     return p_spu;
546 }
547
548 /*****************************************************************************
549  * ParseImage: parse and render the image part of the subtitle
550  *****************************************************************************
551  This part parses the subtitle graphical data and renders it.
552
553  Image data comes interlaced and is run-length encoded (RLE). Each
554  field is a four-bit nibbles that is further subdivided in a two-bit
555  repeat count and a two-bit color number - up to three pixels can be
556  described in four bits.  What a 0 repeat count means is unknown.  It
557  might be used for RLE extension.  There is a special case of a 0
558  repeat count though.  When the full nibble is zero, the rest of the
559  line is filled with the color value in the next nibble.  It is
560  unknown what happens if the color value is greater than three.  The
561  rest seems to use a 4-entries palette.  It is not impossible that the
562  fill-line complete case above is not as described and the zero repeat
563  count means fill line.  The sample code never produces this, so it
564  may be untested.
565
566  However we'll transform this so that that the RLE is expanded and
567  interlacing will also be removed. On output each pixel entry will by
568  a 4-bit alpha (filling 8 bits), and 8-bit y, u, and v entry.
569
570  *****************************************************************************/
571 static void RenderImage( decoder_t *p_dec, block_t *p_data,
572                          subpicture_region_t *p_region )
573 {
574     decoder_sys_t *p_sys = p_dec->p_sys;
575     uint8_t *p_dest = p_region->p_picture->Y_PIXELS;
576     int i_field;            /* The subtitles are interlaced */
577     int i_row, i_column;    /* scanline row/column number */
578     uint8_t i_color, i_count;
579     bs_t bs;
580
581     bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset,
582              p_data->i_buffer - p_sys->i_image_offset );
583
584     for( i_field = 0; i_field < 2; i_field++ )
585     {
586         for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 )
587         {
588             for( i_column = 0; i_column < p_sys->i_width; i_column++ )
589             {
590                 uint8_t i_val = bs_read( &bs, 4 );
591
592                 if( i_val == 0 )
593                 {
594                     /* Fill the rest of the line with next color */
595                     i_color = bs_read( &bs, 4 );
596
597                     memset( &p_dest[i_row * p_region->p_picture->Y_PITCH +
598                                     i_column], i_color,
599                             p_sys->i_width - i_column );
600                     i_column = p_sys->i_width;
601                     continue;
602                 }
603                 else
604                 {
605                     /* Normal case: get color and repeat count */
606                     i_count = (i_val >> 2);
607                     i_color = i_val & 0x3;
608
609                     i_count = __MIN( i_count, p_sys->i_width - i_column );
610
611                     memset( &p_dest[i_row * p_region->p_picture->Y_PITCH +
612                                     i_column], i_color, i_count );
613                     i_column += i_count - 1;
614                     continue;
615                 }
616             }
617
618             bs_align( &bs );
619         }
620     }
621 }