]> git.sesse.net Git - vlc/blob - modules/codec/spudec/parse.c
* modules/codec/spudec/spudec.c, modules/codec/spudec/parse.c: fixed a couple
[vlc] / modules / codec / spudec / parse.c
1 /*****************************************************************************
2  * parse.c: SPU parser
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: parse.c,v 1.3 2002/10/31 09:40:26 gbazin Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>                                    /* memcpy(), memset() */
29
30 #include <vlc/vlc.h>
31 #include <vlc/vout.h>
32 #include <vlc/decoder.h>
33
34 #ifdef HAVE_UNISTD_H
35 #   include <unistd.h>                                           /* getpid() */
36 #endif
37
38 #ifdef WIN32                   /* getpid() for win32 is located in process.h */
39 #   include <process.h>
40 #endif
41
42 #include "spudec.h"
43
44 /*****************************************************************************
45  * Local prototypes.
46  *****************************************************************************/
47 static int  ParseControlSequences( spudec_thread_t *, subpicture_t * );
48 static int  ParseRLE             ( spudec_thread_t *, subpicture_t *, u8 * );
49
50 /*****************************************************************************
51  * AddNibble: read a nibble from a source packet and add it to our integer.
52  *****************************************************************************/
53 static inline unsigned int AddNibble( unsigned int i_code,
54                                       u8 *p_src, int *pi_index )
55 {
56     if( *pi_index & 0x1 )
57     {
58         return( i_code << 4 | ( p_src[(*pi_index)++ >> 1] & 0xf ) );
59     }
60     else
61     {
62         return( i_code << 4 | p_src[(*pi_index)++ >> 1] >> 4 );
63     }
64 }
65
66 /*****************************************************************************
67  * SyncPacket: get in sync with the stream
68  *****************************************************************************
69  * This function makes a few sanity checks and returns 0 if it looks like we
70  * are at the beginning of a subpicture packet.
71  *****************************************************************************/
72 int E_(SyncPacket)( spudec_thread_t *p_spudec )
73 {
74     /* Re-align the buffer on an 8-bit boundary */
75     RealignBits( &p_spudec->bit_stream );
76
77     /* The total SPU packet size, often bigger than a PS packet */
78     p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 );
79
80     /* The RLE stuff size (remove 4 because we just read 32 bits) */
81     p_spudec->i_rle_size = ShowBits( &p_spudec->bit_stream, 16 ) - 4;
82
83     /* If the values we got are a bit strange, skip packet */
84     if( !p_spudec->i_spu_size
85          || ( p_spudec->i_rle_size >= p_spudec->i_spu_size ) )
86     {
87         return VLC_EGENERIC;
88     }
89
90     RemoveBits( &p_spudec->bit_stream, 16 );
91
92     return VLC_SUCCESS;
93 }
94
95 /*****************************************************************************
96  * ParsePacket: parse an SPU packet and send it to the video output
97  *****************************************************************************
98  * This function parses the SPU packet and, if valid, sends it to the
99  * video output.
100  *****************************************************************************/
101 void E_(ParsePacket)( spudec_thread_t *p_spudec )
102 {
103     subpicture_t * p_spu;
104     u8           * p_src;
105     unsigned int   i_offset;
106     mtime_t        i_pts;
107
108     msg_Dbg( p_spudec->p_fifo, "trying to gather a 0x%.2x long subtitle",
109                                p_spudec->i_spu_size );
110
111     /* We cannot display a subpicture with no date */
112     NextPTS( &p_spudec->bit_stream, &i_pts, NULL );
113     if( i_pts == 0 )
114     {
115         msg_Warn( p_spudec->p_fifo, "subtitle without a date" );
116         return;
117     }
118
119     /* Allocate the subpicture internal data. */
120     p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE,
121                                    sizeof( subpicture_sys_t )
122                                     + p_spudec->i_rle_size * 4 );
123     /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
124      * expand the RLE stuff so that we won't need to read nibbles later
125      * on. This will speed things up a lot. Plus, we'll only need to do
126      * this stupid interlacing stuff once. */
127
128     if( p_spu == NULL )
129     {
130         return;
131     }
132
133     /* Fill the p_spu structure */
134     p_spu->pf_render = E_(RenderSPU);
135     p_spu->p_sys->p_data = (u8*)p_spu->p_sys + sizeof( subpicture_sys_t );
136     p_spu->p_sys->b_palette = VLC_FALSE;
137
138     p_spu->p_sys->pi_alpha[0] = 0x00;
139     p_spu->p_sys->pi_alpha[1] = 0x0f;
140     p_spu->p_sys->pi_alpha[2] = 0x0f;
141     p_spu->p_sys->pi_alpha[3] = 0x0f;
142
143     /* Get display time now. If we do it later, we may miss the PTS. */
144     p_spu->p_sys->i_pts = i_pts;
145
146     /* Allocate the temporary buffer we will parse */
147     p_src = malloc( p_spudec->i_rle_size );
148
149     if( p_src == NULL )
150     {
151         msg_Err( p_spudec->p_fifo, "out of memory" );
152         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
153         return;
154     }
155
156     /* Get RLE data */
157     for( i_offset = 0; i_offset < p_spudec->i_rle_size;
158          i_offset += SPU_CHUNK_SIZE )
159     {
160         GetChunk( &p_spudec->bit_stream, p_src + i_offset,
161                   ( i_offset + SPU_CHUNK_SIZE < p_spudec->i_rle_size ) ?
162                   SPU_CHUNK_SIZE : p_spudec->i_rle_size - i_offset );
163
164         /* Abort subtitle parsing if we were requested to stop */
165         if( p_spudec->p_fifo->b_die )
166         {
167             free( p_src );
168             vout_DestroySubPicture( p_spudec->p_vout, p_spu );
169             return;
170         }
171     }
172
173 #if 0
174     /* Dump the subtitle info */
175     intf_WarnHexDump( 5, p_spu->p_sys->p_data, p_spudec->i_rle_size );
176 #endif
177
178     /* Getting the control part */
179     if( ParseControlSequences( p_spudec, p_spu ) )
180     {
181         /* There was a parse error, delete the subpicture */
182         free( p_src );
183         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
184         return;
185     }
186
187     /* At this point, no more GetBit() command is needed, so we have all
188      * the data we need to tell whether the subtitle is valid. Thus we
189      * try to display it and we ignore b_die. */
190
191     if( ParseRLE( p_spudec, p_spu, p_src ) )
192     {
193         /* There was a parse error, delete the subpicture */
194         free( p_src );
195         vout_DestroySubPicture( p_spudec->p_vout, p_spu );
196         return;
197     }
198
199     msg_Dbg( p_spudec->p_fifo, "total size: 0x%x, RLE offsets: 0x%x 0x%x",
200              p_spudec->i_spu_size,
201              p_spu->p_sys->pi_offset[0], p_spu->p_sys->pi_offset[1] );
202
203     /* SPU is finished - we can ask the video output to display it */
204     vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
205
206     /* Clean up */
207     free( p_src );
208 }
209
210 /*****************************************************************************
211  * ParseControlSequences: parse all SPU control sequences
212  *****************************************************************************
213  * This is the most important part in SPU decoding. We get dates, palette
214  * information, coordinates, and so on. For more information on the
215  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
216  *****************************************************************************/
217 static int ParseControlSequences( spudec_thread_t *p_spudec,
218                                   subpicture_t * p_spu )
219 {
220     /* Our current index in the SPU packet */
221     int i_index = p_spudec->i_rle_size + 4;
222
223     /* The next start-of-control-sequence index and the previous one */
224     int i_next_seq = 0, i_cur_seq = 0;
225
226     /* Command and date */
227     u8 i_command = SPU_CMD_END;
228     mtime_t date = 0;
229
230     int i, pi_alpha[4];
231
232     /* Initialize the structure */
233     p_spu->i_start = p_spu->i_stop = 0;
234     p_spu->b_ephemer = VLC_FALSE;
235
236     do
237     {
238         /* If we just read a command sequence, read the next one;
239          * otherwise, go on with the commands of the current sequence. */
240         if( i_command == SPU_CMD_END )
241         {
242             /* Get the control sequence date */
243             date = GetBits( &p_spudec->bit_stream, 16 );
244  
245             /* Next offset */
246             i_cur_seq = i_index;
247             i_next_seq = GetBits( &p_spudec->bit_stream, 16 );
248  
249             /* Skip what we just read */
250             i_index += 4;
251         }
252  
253         i_command = GetBits( &p_spudec->bit_stream, 8 );
254         i_index++;
255  
256         switch( i_command )
257         {
258         case SPU_CMD_FORCE_DISPLAY: /* 00 (force displaying) */
259             p_spu->i_start = p_spu->p_sys->i_pts + ( date * 11000 );
260             p_spu->b_ephemer = VLC_TRUE;
261             break;
262
263         /* Convert the dates in seconds to PTS values */
264         case SPU_CMD_START_DISPLAY: /* 01 (start displaying) */
265             p_spu->i_start = p_spu->p_sys->i_pts + ( date * 11000 );
266             break;
267
268         case SPU_CMD_STOP_DISPLAY: /* 02 (stop displaying) */
269             p_spu->i_stop = p_spu->p_sys->i_pts + ( date * 11000 );
270             break;
271
272         case SPU_CMD_SET_PALETTE:
273
274             /* 03xxxx (palette) */
275             if( p_spudec->p_fifo->p_demux_data
276                  && *(int*)p_spudec->p_fifo->p_demux_data == 0xBeeF )
277             {
278                 u32 i_color;
279
280                 p_spu->p_sys->b_palette = VLC_TRUE;
281                 for( i = 0; i < 4 ; i++ )
282                 {
283                     i_color = ((u32*)((char*)p_spudec->p_fifo->
284                                 p_demux_data + sizeof(int)))[
285                                   GetBits(&p_spudec->bit_stream, 4) ];
286
287                     /* FIXME: this job should be done sooner */
288 #ifndef WORDS_BIGENDIAN
289                     p_spu->p_sys->pi_yuv[3-i][0] = (i_color>>16) & 0xff;
290                     p_spu->p_sys->pi_yuv[3-i][1] = (i_color>>0) & 0xff;
291                     p_spu->p_sys->pi_yuv[3-i][2] = (i_color>>8) & 0xff;
292 #else
293                     p_spu->p_sys->pi_yuv[3-i][0] = (i_color>>8) & 0xff;
294                     p_spu->p_sys->pi_yuv[3-i][1] = (i_color>>24) & 0xff;
295                     p_spu->p_sys->pi_yuv[3-i][2] = (i_color>>16) & 0xff;
296 #endif
297                 }
298             }
299             else
300             {
301                 RemoveBits( &p_spudec->bit_stream, 16 );
302             }
303             i_index += 2;
304
305             break;
306
307         case SPU_CMD_SET_ALPHACHANNEL: /* 04xxxx (alpha channel) */
308             pi_alpha[3] = GetBits( &p_spudec->bit_stream, 4 );
309             pi_alpha[2] = GetBits( &p_spudec->bit_stream, 4 );
310             pi_alpha[1] = GetBits( &p_spudec->bit_stream, 4 );
311             pi_alpha[0] = GetBits( &p_spudec->bit_stream, 4 );
312
313             /* Ignore blank alpha palette. Sometimes spurious blank
314              * alpha palettes are present - dunno why. */
315             if( pi_alpha[0] | pi_alpha[1] | pi_alpha[2] | pi_alpha[3] )
316             {
317                 p_spu->p_sys->pi_alpha[0] = pi_alpha[0];
318                 p_spu->p_sys->pi_alpha[1] = pi_alpha[1];
319                 p_spu->p_sys->pi_alpha[2] = pi_alpha[2];
320                 p_spu->p_sys->pi_alpha[3] = pi_alpha[3];
321             }
322             else
323             {
324                 msg_Warn( p_spudec->p_fifo, "ignoring blank alpha palette" );
325             }
326
327             i_index += 2;
328             break;
329
330         case SPU_CMD_SET_COORDINATES: /* 05xxxyyyxxxyyy (coordinates) */
331             p_spu->i_x = GetBits( &p_spudec->bit_stream, 12 );
332             p_spu->i_width = GetBits( &p_spudec->bit_stream, 12 )
333                               - p_spu->i_x + 1;
334
335             p_spu->i_y = GetBits( &p_spudec->bit_stream, 12 );
336             p_spu->i_height = GetBits( &p_spudec->bit_stream, 12 )
337                                - p_spu->i_y + 1;
338
339             i_index += 6;
340             break;
341
342         case SPU_CMD_SET_OFFSETS: /* 06xxxxyyyy (byte offsets) */
343             p_spu->p_sys->pi_offset[0] =
344                 GetBits( &p_spudec->bit_stream, 16 ) - 4;
345
346             p_spu->p_sys->pi_offset[1] =
347                 GetBits( &p_spudec->bit_stream, 16 ) - 4;
348
349             i_index += 4;
350             break;
351
352         case SPU_CMD_END: /* ff (end) */
353             break;
354
355         default: /* xx (unknown command) */
356             msg_Err( p_spudec->p_fifo, "unknown command 0x%.2x",
357                                        i_command );
358             return VLC_EGENERIC;
359         }
360
361         /* We need to check for quit commands here */
362         if( p_spudec->p_fifo->b_die )
363         {
364             return VLC_EGENERIC;
365         }
366
367     } while( i_command != SPU_CMD_END || i_index == i_next_seq );
368
369     /* Check that the next sequence index matches the current one */
370     if( i_next_seq != i_cur_seq )
371     {
372         msg_Err( p_spudec->p_fifo, "index mismatch (0x%.4x != 0x%.4x)",
373                                    i_next_seq, i_cur_seq );
374         return VLC_EGENERIC;
375     }
376
377     if( i_index > p_spudec->i_spu_size )
378     {
379         msg_Err( p_spudec->p_fifo, "uh-oh, we went too far (0x%.4x > 0x%.4x)",
380                                    i_index, p_spudec->i_spu_size );
381         return VLC_EGENERIC;
382     }
383
384     if( !p_spu->i_start )
385     {
386         msg_Err( p_spudec->p_fifo, "no `start display' command" );
387     }
388
389     if( !p_spu->i_stop && !p_spu->b_ephemer )
390     {
391         /* This subtitle will live for 5 seconds or until the next subtitle */
392         p_spu->i_stop = p_spu->i_start + 500 * 11000;
393         p_spu->b_ephemer = VLC_TRUE;
394     }
395
396     /* Get rid of padding bytes */
397     switch( p_spudec->i_spu_size - i_index )
398     {
399         /* Zero or one padding byte, quite usual */
400         case 1:
401             RemoveBits( &p_spudec->bit_stream, 8 );
402             i_index++;
403         case 0:
404             break;
405
406         /* More than one padding byte - this is very strange, but
407          * we can deal with it */
408         default:
409             msg_Warn( p_spudec->p_fifo,
410                       "%i padding bytes, we usually get 0 or 1 of them",
411                       p_spudec->i_spu_size - i_index );
412
413             while( i_index < p_spudec->i_spu_size )
414             {
415                 RemoveBits( &p_spudec->bit_stream, 8 );
416                 i_index++;
417             }
418
419             break;
420     }
421
422     /* Successfully parsed ! */
423     return VLC_SUCCESS;
424 }
425
426 /*****************************************************************************
427  * ParseRLE: parse the RLE part of the subtitle
428  *****************************************************************************
429  * This part parses the subtitle graphical data and stores it in a more
430  * convenient structure for later decoding. For more information on the
431  * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
432  *****************************************************************************/
433 static int ParseRLE( spudec_thread_t *p_spudec,
434                      subpicture_t * p_spu, u8 * p_src )
435 {
436     unsigned int i_code;
437
438     unsigned int i_width = p_spu->i_width;
439     unsigned int i_height = p_spu->i_height;
440     unsigned int i_x, i_y;
441
442     u16 *p_dest = (u16 *)p_spu->p_sys->p_data;
443
444     /* The subtitles are interlaced, we need two offsets */
445     unsigned int  i_id = 0;                   /* Start on the even SPU layer */
446     unsigned int  pi_table[ 2 ];
447     unsigned int *pi_offset;
448
449     vlc_bool_t b_empty_top = VLC_TRUE,
450                b_empty_bottom = VLC_FALSE;
451     unsigned int i_skipped_top = 0,
452                  i_skipped_bottom = 0;
453
454     /* Colormap statistics */
455     int i_border = -1;
456     int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0;
457
458     pi_table[ 0 ] = p_spu->p_sys->pi_offset[ 0 ] << 1;
459     pi_table[ 1 ] = p_spu->p_sys->pi_offset[ 1 ] << 1;
460
461     for( i_y = 0 ; i_y < i_height ; i_y++ )
462     {
463         pi_offset = pi_table + i_id;
464
465         for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
466         {
467             i_code = AddNibble( 0, p_src, pi_offset );
468
469             if( i_code < 0x04 )
470             {
471                 i_code = AddNibble( i_code, p_src, pi_offset );
472
473                 if( i_code < 0x10 )
474                 {
475                     i_code = AddNibble( i_code, p_src, pi_offset );
476
477                     if( i_code < 0x040 )
478                     {
479                         i_code = AddNibble( i_code, p_src, pi_offset );
480
481                         if( i_code < 0x0100 )
482                         {
483                             /* If the 14 first bits are set to 0, then it's a
484                              * new line. We emulate it. */
485                             if( i_code < 0x0004 )
486                             {
487                                 i_code |= ( i_width - i_x ) << 2;
488                             }
489                             else
490                             {
491                                 /* We have a boo boo ! */
492                                 msg_Err( p_spudec->p_fifo, "unknown RLE code "
493                                          "0x%.4x", i_code );
494                                 return VLC_EGENERIC;
495                             }
496                         }
497                     }
498                 }
499             }
500
501             if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
502             {
503                 msg_Err( p_spudec->p_fifo,
504                          "out of bounds, %i at (%i,%i) is out of %ix%i",
505                          i_code >> 2, i_x, i_y, i_width, i_height );
506                 return VLC_EGENERIC;
507             }
508
509             /* Try to find the border color */
510             if( p_spu->p_sys->pi_alpha[ i_code & 0x3 ] != 0x00 )
511             {
512                 i_border = i_code & 0x3;
513                 stats[i_border] += i_code >> 2;
514             }
515
516             if( (i_code >> 2) == i_width
517                  && p_spu->p_sys->pi_alpha[ i_code & 0x3 ] == 0x00 )
518             {
519                 if( b_empty_top )
520                 {
521                     /* This is a blank top line, we skip it */
522                     i_skipped_top++;
523                 }
524                 else
525                 {
526                     /* We can't be sure the current lines will be skipped,
527                      * so we store the code just in case. */
528                     *p_dest++ = i_code;
529
530                     b_empty_bottom = VLC_TRUE;
531                     i_skipped_bottom++;
532                 }
533             }
534             else
535             {
536                 /* We got a valid code, store it */
537                 *p_dest++ = i_code;
538
539                 /* Valid code means no blank line */
540                 b_empty_top = VLC_FALSE;
541                 b_empty_bottom = VLC_FALSE;
542                 i_skipped_bottom = 0;
543             }
544         }
545
546         /* Check that we didn't go too far */
547         if( i_x > i_width )
548         {
549             msg_Err( p_spudec->p_fifo, "i_x overflowed, %i > %i",
550                                        i_x, i_width );
551             return VLC_EGENERIC;
552         }
553
554         /* Byte-align the stream */
555         if( *pi_offset & 0x1 )
556         {
557             (*pi_offset)++;
558         }
559
560         /* Swap fields */
561         i_id = ~i_id & 0x1;
562     }
563
564     /* We shouldn't get any padding bytes */
565     if( i_y < i_height )
566     {
567         msg_Err( p_spudec->p_fifo, "padding bytes found in RLE sequence" );
568         msg_Err( p_spudec->p_fifo, "send mail to <sam@zoy.org> if you "
569                                    "want to help debugging this" );
570
571         /* Skip them just in case */
572         while( i_y < i_height )
573         {
574             *p_dest++ = i_width << 2;
575             i_y++;
576         }
577
578         return VLC_EGENERIC;
579     }
580
581     msg_Dbg( p_spudec->p_fifo, "valid subtitle, size: %ix%i, position: %i,%i",
582              p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
583
584     /* Crop if necessary */
585     if( i_skipped_top || i_skipped_bottom )
586     {
587         p_spu->i_y += i_skipped_top;
588         p_spu->i_height -= i_skipped_top + i_skipped_bottom;
589
590         msg_Dbg( p_spudec->p_fifo, "cropped to: %ix%i, position: %i,%i",
591                  p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
592     }
593
594     /* Handle color if no palette was found */
595     if( !p_spu->p_sys->b_palette )
596     {
597         int i, i_inner = -1, i_shade = -1;
598
599         /* Set the border color */
600         p_spu->p_sys->pi_yuv[i_border][0] = 0x00;
601         p_spu->p_sys->pi_yuv[i_border][1] = 0x80;
602         p_spu->p_sys->pi_yuv[i_border][2] = 0x80;
603         stats[i_border] = 0;
604
605         /* Find the inner colors */
606         for( i = 0 ; i < 4 && i_inner == -1 ; i++ )
607         {
608             if( stats[i] )
609             {
610                 i_inner = i;
611             }
612         }
613
614         for(       ; i < 4 && i_shade == -1 ; i++ )
615         {
616             if( stats[i] )
617             {
618                 if( stats[i] > stats[i_inner] )
619                 {
620                     i_shade = i_inner;
621                     i_inner = i;
622                 }
623                 else
624                 {
625                     i_shade = i;
626                 }
627             }
628         }
629
630         /* Set the inner color */
631         if( i_inner != -1 )
632         {
633             p_spu->p_sys->pi_yuv[i_inner][0] = 0xff;
634             p_spu->p_sys->pi_yuv[i_inner][1] = 0x80;
635             p_spu->p_sys->pi_yuv[i_inner][2] = 0x80;
636         }
637
638         /* Set the anti-aliasing color */
639         if( i_shade != -1 )
640         {
641             p_spu->p_sys->pi_yuv[i_shade][0] = 0x80;
642             p_spu->p_sys->pi_yuv[i_shade][1] = 0x80;
643             p_spu->p_sys->pi_yuv[i_shade][2] = 0x80;
644         }
645
646         msg_Dbg( p_spudec->p_fifo,
647                  "using custom palette (border %i, inner %i, shade %i)",
648                  i_border, i_inner, i_shade );
649     }
650
651     return VLC_SUCCESS;
652 }
653