1 /*****************************************************************************
2 * spudec.c : spu decoder thread
3 *****************************************************************************
4 * Copyright (C) 2000-2001 VideoLAN
5 * $Id: spudec.c,v 1.1 2002/08/04 17:23:42 sam Exp $
7 * Authors: Samuel Hocevar <sam@zoy.org>
8 * Rudolf Cornelissen <rag.cornelissen@inter.nl.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
29 #include <string.h> /* memcpy(), memset() */
33 #include <vlc/decoder.h>
36 # include <unistd.h> /* getpid() */
39 #ifdef WIN32 /* getpid() for win32 is located in process.h */
45 /*****************************************************************************
47 *****************************************************************************/
48 static int OpenDecoder ( vlc_object_t * );
49 static int RunDecoder ( decoder_fifo_t * );
50 static int InitThread ( spudec_thread_t * );
51 static void EndThread ( spudec_thread_t * );
53 static int SyncPacket ( spudec_thread_t * );
54 static void ParsePacket ( spudec_thread_t * );
55 static int ParseControlSequences( spudec_thread_t *, subpicture_t * );
56 static int ParseRLE ( spudec_thread_t *, subpicture_t *, u8 * );
57 static void RenderSPU ( vout_thread_t *, picture_t *,
58 const subpicture_t * );
59 /*****************************************************************************
61 *****************************************************************************/
63 set_description( _("DVD subtitles decoder module") );
64 set_capability( "decoder", 50 );
65 set_callbacks( OpenDecoder, NULL );
68 /*****************************************************************************
69 * OpenDecoder: probe the decoder and return score
70 *****************************************************************************
71 * Tries to launch a decoder and return score so that the interface is able
73 *****************************************************************************/
74 static int OpenDecoder( vlc_object_t *p_this )
76 decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;
78 if( p_fifo->i_fourcc == VLC_FOURCC('s','p','u',' ') )
80 p_fifo->pf_run = RunDecoder;
87 /*****************************************************************************
88 * RunDecoder: this function is called just after the thread is created
89 *****************************************************************************/
90 static int RunDecoder( decoder_fifo_t * p_fifo )
92 spudec_thread_t * p_spudec;
94 /* Allocate the memory needed to store the thread's structure */
95 p_spudec = (spudec_thread_t *)malloc( sizeof(spudec_thread_t) );
97 if ( p_spudec == NULL )
99 msg_Err( p_fifo, "out of memory" );
100 DecoderError( p_fifo );
105 * Initialize the thread properties
107 p_spudec->p_vout = NULL;
108 p_spudec->p_fifo = p_fifo;
111 * Initialize thread and free configuration
113 p_spudec->p_fifo->b_error = InitThread( p_spudec );
116 * Main loop - it is not executed if an error occured during
119 while( (!p_spudec->p_fifo->b_die) && (!p_spudec->p_fifo->b_error) )
121 if( !SyncPacket( p_spudec ) )
123 ParsePacket( p_spudec );
130 if( p_spudec->p_fifo->b_error )
132 DecoderError( p_spudec->p_fifo );
135 EndThread( p_spudec );
140 EndThread( p_spudec );
144 /* following functions are local */
146 /*****************************************************************************
147 * InitThread: initialize spu decoder thread
148 *****************************************************************************
149 * This function is called from RunThread and performs the second step of the
150 * initialization. It returns 0 on success. Note that the thread's flag are not
151 * modified inside this function.
152 *****************************************************************************/
153 static int InitThread( spudec_thread_t *p_spudec )
155 /* Find an available video output */
158 if( p_spudec->p_fifo->b_die || p_spudec->p_fifo->b_error )
163 p_spudec->p_vout = vlc_object_find( p_spudec->p_fifo, VLC_OBJECT_VOUT,
166 if( p_spudec->p_vout )
171 msleep( VOUT_OUTMEM_SLEEP );
175 InitBitstream( &p_spudec->bit_stream, p_spudec->p_fifo, NULL, NULL );
177 /* Mark thread as running and return */
181 /*****************************************************************************
182 * EndThread: thread destruction
183 *****************************************************************************
184 * This function is called when the thread ends after a sucessful
186 *****************************************************************************/
187 static void EndThread( spudec_thread_t *p_spudec )
189 if( p_spudec->p_vout != NULL
190 && p_spudec->p_vout->p_subpicture != NULL )
192 subpicture_t * p_subpic;
195 for( i_subpic = 0; i_subpic < VOUT_MAX_SUBPICTURES; i_subpic++ )
197 p_subpic = &p_spudec->p_vout->p_subpicture[i_subpic];
199 if( p_subpic != NULL &&
200 ( ( p_subpic->i_status == RESERVED_SUBPICTURE )
201 || ( p_subpic->i_status == READY_SUBPICTURE ) ) )
203 vout_DestroySubPicture( p_spudec->p_vout, p_subpic );
207 vlc_object_release( p_spudec->p_vout );
213 /*****************************************************************************
214 * SyncPacket: get in sync with the stream
215 *****************************************************************************
216 * This function makes a few sanity checks and returns 0 if it looks like we
217 * are at the beginning of a subpicture packet.
218 *****************************************************************************/
219 static int SyncPacket( spudec_thread_t *p_spudec )
221 /* Re-align the buffer on an 8-bit boundary */
222 RealignBits( &p_spudec->bit_stream );
224 /* The total SPU packet size, often bigger than a PS packet */
225 p_spudec->i_spu_size = GetBits( &p_spudec->bit_stream, 16 );
227 /* The RLE stuff size (remove 4 because we just read 32 bits) */
228 p_spudec->i_rle_size = ShowBits( &p_spudec->bit_stream, 16 ) - 4;
230 /* If the values we got are a bit strange, skip packet */
231 if( !p_spudec->i_spu_size
232 || ( p_spudec->i_rle_size >= p_spudec->i_spu_size ) )
237 RemoveBits( &p_spudec->bit_stream, 16 );
242 /*****************************************************************************
243 * ParsePacket: parse an SPU packet and send it to the video output
244 *****************************************************************************
245 * This function parses the SPU packet and, if valid, sends it to the
247 *****************************************************************************/
248 static void ParsePacket( spudec_thread_t *p_spudec )
250 subpicture_t * p_spu;
252 unsigned int i_offset;
254 msg_Dbg( p_spudec->p_fifo, "trying to gather a 0x%.2x long subtitle",
255 p_spudec->i_spu_size );
257 /* We cannot display a subpicture with no date */
258 if( p_spudec->p_fifo->p_first->i_pts == 0 )
260 msg_Warn( p_spudec->p_fifo, "subtitle without a date" );
264 /* Allocate the subpicture internal data. */
265 p_spu = vout_CreateSubPicture( p_spudec->p_vout, MEMORY_SUBPICTURE,
266 sizeof( subpicture_sys_t )
267 + p_spudec->i_rle_size * 4 );
268 /* Rationale for the "p_spudec->i_rle_size * 4": we are going to
269 * expand the RLE stuff so that we won't need to read nibbles later
270 * on. This will speed things up a lot. Plus, we'll only need to do
271 * this stupid interlacing stuff once. */
278 /* Fill the p_spu structure */
279 p_spu->pf_render = RenderSPU;
280 p_spu->p_sys->p_data = (u8*)p_spu->p_sys + sizeof( subpicture_sys_t );
281 p_spu->p_sys->b_palette = 0;
283 /* Get display time now. If we do it later, we may miss the PTS. */
284 p_spu->p_sys->i_pts = p_spudec->p_fifo->p_first->i_pts;
286 /* Allocate the temporary buffer we will parse */
287 p_src = malloc( p_spudec->i_rle_size );
291 msg_Err( p_spudec->p_fifo, "out of memory" );
292 vout_DestroySubPicture( p_spudec->p_vout, p_spu );
297 for( i_offset = 0; i_offset < p_spudec->i_rle_size;
298 i_offset += SPU_CHUNK_SIZE )
300 GetChunk( &p_spudec->bit_stream, p_src + i_offset,
301 ( i_offset + SPU_CHUNK_SIZE < p_spudec->i_rle_size ) ?
302 SPU_CHUNK_SIZE : p_spudec->i_rle_size - i_offset );
304 /* Abort subtitle parsing if we were requested to stop */
305 if( p_spudec->p_fifo->b_die )
308 vout_DestroySubPicture( p_spudec->p_vout, p_spu );
314 /* Dump the subtitle info */
315 intf_WarnHexDump( 5, p_spu->p_sys->p_data, p_spudec->i_rle_size );
318 /* Getting the control part */
319 if( ParseControlSequences( p_spudec, p_spu ) )
321 /* There was a parse error, delete the subpicture */
323 vout_DestroySubPicture( p_spudec->p_vout, p_spu );
327 /* At this point, no more GetBit() command is needed, so we have all
328 * the data we need to tell whether the subtitle is valid. Thus we
329 * try to display it and we ignore b_die. */
331 if( ParseRLE( p_spudec, p_spu, p_src ) )
333 /* There was a parse error, delete the subpicture */
335 vout_DestroySubPicture( p_spudec->p_vout, p_spu );
339 msg_Dbg( p_spudec->p_fifo, "total size: 0x%x, RLE offsets: 0x%x 0x%x",
340 p_spudec->i_spu_size,
341 p_spu->p_sys->pi_offset[0], p_spu->p_sys->pi_offset[1] );
343 /* SPU is finished - we can ask the video output to display it */
344 vout_DisplaySubPicture( p_spudec->p_vout, p_spu );
350 /*****************************************************************************
351 * ParseControlSequences: parse all SPU control sequences
352 *****************************************************************************
353 * This is the most important part in SPU decoding. We get dates, palette
354 * information, coordinates, and so on. For more information on the
355 * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
356 *****************************************************************************/
357 static int ParseControlSequences( spudec_thread_t *p_spudec,
358 subpicture_t * p_spu )
360 /* Our current index in the SPU packet */
361 int i_index = p_spudec->i_rle_size + 4;
363 /* The next start-of-control-sequence index and the previous one */
364 int i_next_seq, i_cur_seq;
366 /* Command time and date */
372 /* XXX: temporary variables */
373 vlc_bool_t b_force_display = 0;
375 /* Initialize the structure */
376 p_spu->i_start = p_spu->i_stop = 0;
377 p_spu->b_ephemer = 0;
381 /* Get the control sequence date */
382 i_date = GetBits( &p_spudec->bit_stream, 16 );
386 i_next_seq = GetBits( &p_spudec->bit_stream, 16 );
388 /* Skip what we just read */
393 i_command = GetBits( &p_spudec->bit_stream, 8 );
398 case SPU_CMD_FORCE_DISPLAY:
400 /* 00 (force displaying) */
401 p_spu->i_start = p_spu->p_sys->i_pts + ( i_date * 11000 );
406 /* Convert the dates in seconds to PTS values */
407 case SPU_CMD_START_DISPLAY:
409 /* 01 (start displaying) */
410 p_spu->i_start = p_spu->p_sys->i_pts + ( i_date * 11000 );
414 case SPU_CMD_STOP_DISPLAY:
416 /* 02 (stop displaying) */
417 p_spu->i_stop = p_spu->p_sys->i_pts + ( i_date * 11000 );
421 case SPU_CMD_SET_PALETTE:
423 /* 03xxxx (palette) */
424 if( p_spudec->p_fifo->p_demux_data &&
425 *(int*)p_spudec->p_fifo->p_demux_data == 0xBeeF )
429 p_spu->p_sys->b_palette = 1;
430 for( i = 0; i < 4 ; i++ )
432 i_color = ((u32*)((char*)p_spudec->p_fifo->
433 p_demux_data + sizeof(int)))[
434 GetBits(&p_spudec->bit_stream, 4) ];
436 /* FIXME: this job should be done sooner */
437 #ifndef WORDS_BIGENDIAN
438 p_spu->p_sys->pi_yuv[3-i][0] = (i_color>>16) & 0xff;
439 p_spu->p_sys->pi_yuv[3-i][1] = (i_color>>0) & 0xff;
440 p_spu->p_sys->pi_yuv[3-i][2] = (i_color>>8) & 0xff;
442 p_spu->p_sys->pi_yuv[3-i][0] = (i_color>>8) & 0xff;
443 p_spu->p_sys->pi_yuv[3-i][1] = (i_color>>24) & 0xff;
444 p_spu->p_sys->pi_yuv[3-i][2] = (i_color>>16) & 0xff;
450 RemoveBits( &p_spudec->bit_stream, 16 );
456 case SPU_CMD_SET_ALPHACHANNEL:
458 /* 04xxxx (alpha channel) */
459 pi_alpha[3] = GetBits( &p_spudec->bit_stream, 4 );
460 pi_alpha[2] = GetBits( &p_spudec->bit_stream, 4 );
461 pi_alpha[1] = GetBits( &p_spudec->bit_stream, 4 );
462 pi_alpha[0] = GetBits( &p_spudec->bit_stream, 4 );
464 /* Ignore blank alpha palette. Sometimes spurious blank
465 * alpha palettes are present - dunno why. */
466 if( pi_alpha[0] | pi_alpha[1] | pi_alpha[2] | pi_alpha[3] )
468 p_spu->p_sys->pi_alpha[0] = pi_alpha[0];
469 p_spu->p_sys->pi_alpha[1] = pi_alpha[1];
470 p_spu->p_sys->pi_alpha[2] = pi_alpha[2];
471 p_spu->p_sys->pi_alpha[3] = pi_alpha[3];
475 msg_Warn( p_spudec->p_fifo,
476 "ignoring blank alpha palette" );
483 case SPU_CMD_SET_COORDINATES:
485 /* 05xxxyyyxxxyyy (coordinates) */
486 p_spu->i_x = GetBits( &p_spudec->bit_stream, 12 );
487 p_spu->i_width = GetBits( &p_spudec->bit_stream, 12 )
490 p_spu->i_y = GetBits( &p_spudec->bit_stream, 12 );
491 p_spu->i_height = GetBits( &p_spudec->bit_stream, 12 )
498 case SPU_CMD_SET_OFFSETS:
500 /* 06xxxxyyyy (byte offsets) */
501 p_spu->p_sys->pi_offset[0] =
502 GetBits( &p_spudec->bit_stream, 16 ) - 4;
504 p_spu->p_sys->pi_offset[1] =
505 GetBits( &p_spudec->bit_stream, 16 ) - 4;
518 /* xx (unknown command) */
519 msg_Err( p_spudec->p_fifo, "unknown command 0x%.2x",
524 /* We need to check for quit commands here */
525 if( p_spudec->p_fifo->b_die )
530 } while( i_command != SPU_CMD_END );
532 } while( i_index == i_next_seq );
534 /* Check that the next sequence index matches the current one */
535 if( i_next_seq != i_cur_seq )
537 msg_Err( p_spudec->p_fifo, "index mismatch (0x%.4x != 0x%.4x)",
538 i_next_seq, i_cur_seq );
542 if( i_index > p_spudec->i_spu_size )
544 msg_Err( p_spudec->p_fifo, "uh-oh, we went too far (0x%.4x > 0x%.4x)",
545 i_index, p_spudec->i_spu_size );
549 if( !p_spu->i_start )
551 msg_Err( p_spudec->p_fifo, "no `start display' command" );
556 /* This subtitle will live for 5 seconds or until the next subtitle */
557 p_spu->i_stop = p_spu->i_start + 500 * 11000;
558 p_spu->b_ephemer = 1;
561 /* Get rid of padding bytes */
562 switch( p_spudec->i_spu_size - i_index )
564 /* Zero or one padding byte, quite usual */
566 RemoveBits( &p_spudec->bit_stream, 8 );
571 /* More than one padding byte - this is very strange, but
572 * we can deal with it */
574 msg_Warn( p_spudec->p_fifo,
575 "%i padding bytes, we usually get 0 or 1 of them",
576 p_spudec->i_spu_size - i_index );
578 while( i_index < p_spudec->i_spu_size )
580 RemoveBits( &p_spudec->bit_stream, 8 );
587 if( b_force_display )
589 msg_Err( p_spudec->p_fifo, "\"force display\" command" );
590 msg_Err( p_spudec->p_fifo, "send mail to <sam@zoy.org> if you "
591 "want to help debugging this" );
594 /* Successfully parsed ! */
598 /*****************************************************************************
599 * ParseRLE: parse the RLE part of the subtitle
600 *****************************************************************************
601 * This part parses the subtitle graphical data and stores it in a more
602 * convenient structure for later decoding. For more information on the
603 * subtitles format, see http://sam.zoy.org/doc/dvd/subtitles/index.html
604 *****************************************************************************/
605 static int ParseRLE( spudec_thread_t *p_spudec,
606 subpicture_t * p_spu, u8 * p_src )
610 unsigned int i_width = p_spu->i_width;
611 unsigned int i_height = p_spu->i_height;
612 unsigned int i_x, i_y;
614 u16 *p_dest = (u16 *)p_spu->p_sys->p_data;
616 /* The subtitles are interlaced, we need two offsets */
617 unsigned int i_id = 0; /* Start on the even SPU layer */
618 unsigned int pi_table[ 2 ];
619 unsigned int *pi_offset;
621 vlc_bool_t b_empty_top = 1,
623 unsigned int i_skipped_top = 0,
624 i_skipped_bottom = 0;
626 /* Colormap statistics */
628 int stats[4]; stats[0] = stats[1] = stats[2] = stats[3] = 0;
630 pi_table[ 0 ] = p_spu->p_sys->pi_offset[ 0 ] << 1;
631 pi_table[ 1 ] = p_spu->p_sys->pi_offset[ 1 ] << 1;
633 for( i_y = 0 ; i_y < i_height ; i_y++ )
635 pi_offset = pi_table + i_id;
637 for( i_x = 0 ; i_x < i_width ; i_x += i_code >> 2 )
639 i_code = AddNibble( 0, p_src, pi_offset );
643 i_code = AddNibble( i_code, p_src, pi_offset );
647 i_code = AddNibble( i_code, p_src, pi_offset );
651 i_code = AddNibble( i_code, p_src, pi_offset );
653 if( i_code < 0x0100 )
655 /* If the 14 first bits are set to 0, then it's a
656 * new line. We emulate it. */
657 if( i_code < 0x0004 )
659 i_code |= ( i_width - i_x ) << 2;
663 /* We have a boo boo ! */
664 msg_Err( p_spudec->p_fifo, "unknown RLE code "
673 if( ( (i_code >> 2) + i_x + i_y * i_width ) > i_height * i_width )
675 msg_Err( p_spudec->p_fifo,
676 "out of bounds, %i at (%i,%i) is out of %ix%i",
677 i_code >> 2, i_x, i_y, i_width, i_height );
681 /* Try to find the border color */
682 if( p_spu->p_sys->pi_alpha[ i_code & 0x3 ] != 0x00 )
684 i_border = i_code & 0x3;
685 stats[i_border] += i_code >> 2;
688 if( (i_code >> 2) == i_width
689 && p_spu->p_sys->pi_alpha[ i_code & 0x3 ] == 0x00 )
693 /* This is a blank top line, we skip it */
698 /* We can't be sure the current lines will be skipped,
699 * so we store the code just in case. */
708 /* We got a valid code, store it */
711 /* Valid code means no blank line */
714 i_skipped_bottom = 0;
718 /* Check that we didn't go too far */
721 msg_Err( p_spudec->p_fifo, "i_x overflowed, %i > %i",
726 /* Byte-align the stream */
727 if( *pi_offset & 0x1 )
736 /* We shouldn't get any padding bytes */
739 msg_Err( p_spudec->p_fifo, "padding bytes found in RLE sequence" );
740 msg_Err( p_spudec->p_fifo, "send mail to <sam@zoy.org> if you "
741 "want to help debugging this" );
743 /* Skip them just in case */
744 while( i_y < i_height )
746 *p_dest++ = i_width << 2;
753 msg_Dbg( p_spudec->p_fifo, "valid subtitle, size: %ix%i, position: %i,%i",
754 p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
756 /* Crop if necessary */
757 if( i_skipped_top || i_skipped_bottom )
759 p_spu->i_y += i_skipped_top;
760 p_spu->i_height -= i_skipped_top + i_skipped_bottom;
762 msg_Dbg( p_spudec->p_fifo, "cropped to: %ix%i, position: %i,%i",
763 p_spu->i_width, p_spu->i_height, p_spu->i_x, p_spu->i_y );
766 /* Handle color if no palette was found */
767 if( !p_spu->p_sys->b_palette )
769 int i, i_inner = -1, i_shade = -1;
771 /* Set the border color */
772 p_spu->p_sys->pi_yuv[i_border][0] = 0x00;
773 p_spu->p_sys->pi_yuv[i_border][1] = 0x80;
774 p_spu->p_sys->pi_yuv[i_border][2] = 0x80;
777 /* Find the inner colors */
778 for( i = 0 ; i < 4 && i_inner == -1 ; i++ )
786 for( ; i < 4 && i_shade == -1 ; i++ )
790 if( stats[i] > stats[i_inner] )
802 /* Set the inner color */
805 p_spu->p_sys->pi_yuv[i_inner][0] = 0xff;
806 p_spu->p_sys->pi_yuv[i_inner][1] = 0x80;
807 p_spu->p_sys->pi_yuv[i_inner][2] = 0x80;
810 /* Set the anti-aliasing color */
813 p_spu->p_sys->pi_yuv[i_shade][0] = 0x80;
814 p_spu->p_sys->pi_yuv[i_shade][1] = 0x80;
815 p_spu->p_sys->pi_yuv[i_shade][2] = 0x80;
818 msg_Dbg( p_spudec->p_fifo,
819 "using custom palette (border %i, inner %i, shade %i)",
820 i_border, i_inner, i_shade );
826 /*****************************************************************************
827 * RenderSPU: draw an SPU on a picture
828 *****************************************************************************
829 * This is a fast implementation of the subpicture drawing code. The data
830 * has been preprocessed once, so we don't need to parse the RLE buffer again
831 * and again. Most sanity checks are already done so that this routine can be
832 * as fast as possible.
833 *****************************************************************************/
834 static void RenderSPU( vout_thread_t *p_vout, picture_t *p_pic,
835 const subpicture_t *p_spu )
837 /* Common variables */
841 u8 *p_destptr = (u8 *)p_dest;
842 u16 *p_source = (u16 *)p_spu->p_sys->p_data;
845 int i_len, i_color, i_colprecomp, i_destalpha;
849 int i_xscale, i_yscale, i_width, i_height, i_ytmp, i_yreal, i_ynext;
851 switch( p_vout->output.i_chroma )
853 /* I420 target, no scaling */
854 case VLC_FOURCC('I','4','2','0'):
855 case VLC_FOURCC('I','Y','U','V'):
856 case VLC_FOURCC('Y','V','1','2'):
858 p_dest = p_pic->Y_PIXELS + p_spu->i_x + p_spu->i_width
859 + p_pic->Y_PITCH * ( p_spu->i_y + p_spu->i_height );
861 /* Draw until we reach the bottom of the subtitle */
862 for( i_y = p_spu->i_height * p_pic->Y_PITCH ;
864 i_y -= p_pic->Y_PITCH )
866 /* Draw until we reach the end of the line */
867 for( i_x = p_spu->i_width ; i_x ; )
869 /* Get the RLE part, then draw the line */
870 i_color = *p_source & 0x3;
871 i_len = *p_source++ >> 2;
873 switch( p_spu->p_sys->pi_alpha[ i_color ] )
879 memset( p_dest - i_x - i_y,
880 p_spu->p_sys->pi_yuv[i_color][0], i_len );
884 /* To be able to divide by 16 (>>4) we add 1 to the alpha.
885 * This means Alpha 0 won't be completely transparent, but
886 * that's handled in a special case above anyway. */
887 i_colprecomp = p_spu->p_sys->pi_yuv[i_color][0]
888 * (p_spu->p_sys->pi_alpha[ i_color ] + 1);
889 i_destalpha = 15 - p_spu->p_sys->pi_alpha[ i_color ];
891 for ( p_destptr = p_dest - i_x - i_y;
892 p_destptr < p_dest - i_x - i_y + i_len;
895 *p_destptr = ( i_colprecomp +
896 *p_destptr * i_destalpha ) >> 4;
907 /* RV16 target, scaling */
908 case VLC_FOURCC('R','V','1','6'):
910 /* XXX: this is a COMPLETE HACK, memcpy is unable to do u16s anyway */
911 /* FIXME: get this from the DVD */
912 for( i_color = 0; i_color < 4; i_color++ )
914 p_clut16[i_color] = 0x1111
915 * ( (u16)p_spu->p_sys->pi_yuv[i_color][0] >> 4 );
918 i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width;
919 i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height;
921 i_width = p_spu->i_width * i_xscale;
922 i_height = p_spu->i_height * i_yscale;
924 p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 2
925 /* Add the picture coordinates and the SPU coordinates */
926 + ( (p_spu->i_x * i_xscale) >> 6 ) * 2
927 + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
929 /* Draw until we reach the bottom of the subtitle */
930 for( i_y = 0 ; i_y < i_height ; )
935 /* Check whether we need to draw one line or more than one */
936 if( i_ytmp + 1 >= ( i_y >> 6 ) )
938 /* Just one line : we precalculate i_y >> 6 */
939 i_yreal = p_pic->p->i_pitch * i_ytmp;
941 /* Draw until we reach the end of the line */
942 for( i_x = i_width ; i_x ; )
944 /* Get the RLE part, then draw the line */
945 i_color = *p_source & 0x3;
947 switch( p_spu->p_sys->pi_alpha[ i_color ] )
950 i_x -= i_xscale * ( *p_source++ >> 2 );
954 i_len = i_xscale * ( *p_source++ >> 2 );
955 memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
957 2 * ( ( i_len >> 6 ) + 1 ) );
962 /* FIXME: we should do transparency */
963 i_len = i_xscale * ( *p_source++ >> 2 );
964 memset( p_dest - 2 * ( i_x >> 6 ) + i_yreal,
966 2 * ( ( i_len >> 6 ) + 1 ) );
975 i_yreal = p_pic->p->i_pitch * i_ytmp;
976 i_ynext = p_pic->p->i_pitch * i_y >> 6;
978 /* Draw until we reach the end of the line */
979 for( i_x = i_width ; i_x ; )
981 /* Get the RLE part, then draw as many lines as needed */
982 i_color = *p_source & 0x3;
984 switch( p_spu->p_sys->pi_alpha[ i_color ] )
987 i_x -= i_xscale * ( *p_source++ >> 2 );
991 i_len = i_xscale * ( *p_source++ >> 2 );
992 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
993 i_ytmp += p_pic->p->i_pitch )
995 memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp,
997 2 * ( ( i_len >> 6 ) + 1 ) );
1003 /* FIXME: we should do transparency */
1004 i_len = i_xscale * ( *p_source++ >> 2 );
1005 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
1006 i_ytmp += p_pic->p->i_pitch )
1008 memset( p_dest - 2 * ( i_x >> 6 ) + i_ytmp,
1009 p_clut16[ i_color ],
1010 2 * ( ( i_len >> 6 ) + 1 ) );
1021 /* RV32 target, scaling */
1022 case VLC_FOURCC('R','V','2','4'):
1023 case VLC_FOURCC('R','V','3','2'):
1025 /* XXX: this is a COMPLETE HACK, memcpy is unable to do u32s anyway */
1026 /* FIXME: get this from the DVD */
1027 for( i_color = 0; i_color < 4; i_color++ )
1029 p_clut32[i_color] = 0x11111111
1030 * ( (u16)p_spu->p_sys->pi_yuv[i_color][0] >> 4 );
1033 i_xscale = ( p_vout->output.i_width << 6 ) / p_vout->render.i_width;
1034 i_yscale = ( p_vout->output.i_height << 6 ) / p_vout->render.i_height;
1036 i_width = p_spu->i_width * i_xscale;
1037 i_height = p_spu->i_height * i_yscale;
1039 p_dest = p_pic->p->p_pixels + ( i_width >> 6 ) * 4
1040 /* Add the picture coordinates and the SPU coordinates */
1041 + ( (p_spu->i_x * i_xscale) >> 6 ) * 4
1042 + ( (p_spu->i_y * i_yscale) >> 6 ) * p_pic->p->i_pitch;
1044 /* Draw until we reach the bottom of the subtitle */
1045 for( i_y = 0 ; i_y < i_height ; )
1050 /* Check whether we need to draw one line or more than one */
1051 if( i_ytmp + 1 >= ( i_y >> 6 ) )
1053 /* Just one line : we precalculate i_y >> 6 */
1054 i_yreal = p_pic->p->i_pitch * i_ytmp;
1056 /* Draw until we reach the end of the line */
1057 for( i_x = i_width ; i_x ; )
1059 /* Get the RLE part, then draw the line */
1060 i_color = *p_source & 0x3;
1062 switch( p_spu->p_sys->pi_alpha[ i_color ] )
1065 i_x -= i_xscale * ( *p_source++ >> 2 );
1069 i_len = i_xscale * ( *p_source++ >> 2 );
1070 memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
1071 p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
1076 /* FIXME: we should do transparency */
1077 i_len = i_xscale * ( *p_source++ >> 2 );
1078 memset( p_dest - 4 * ( i_x >> 6 ) + i_yreal,
1079 p_clut32[ i_color ], 4 * ( ( i_len >> 6 ) + 1 ) );
1088 i_yreal = p_pic->p->i_pitch * i_ytmp;
1089 i_ynext = p_pic->p->i_pitch * i_y >> 6;
1091 /* Draw until we reach the end of the line */
1092 for( i_x = i_width ; i_x ; )
1094 /* Get the RLE part, then draw as many lines as needed */
1095 i_color = *p_source & 0x3;
1097 switch( p_spu->p_sys->pi_alpha[ i_color ] )
1100 i_x -= i_xscale * ( *p_source++ >> 2 );
1104 i_len = i_xscale * ( *p_source++ >> 2 );
1105 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
1106 i_ytmp += p_pic->p->i_pitch )
1108 memset( p_dest - 4 * ( i_x >> 6 ) + i_ytmp,
1109 p_clut32[ i_color ],
1110 4 * ( ( i_len >> 6 ) + 1 ) );
1116 /* FIXME: we should do transparency */
1117 i_len = i_xscale * ( *p_source++ >> 2 );
1118 for( i_ytmp = i_yreal ; i_ytmp < i_ynext ;
1119 i_ytmp += p_pic->p->i_pitch )
1121 memset( p_dest - 4 * ( i_x >> 6 ) + i_ytmp,
1122 p_clut32[ i_color ],
1123 4 * ( ( i_len >> 6 ) + 1 ) );
1134 /* NVidia overlay, no scaling */
1135 case VLC_FOURCC('Y','U','Y','2'):
1137 p_dest = p_pic->p->p_pixels +
1138 (p_spu->i_x + p_spu->i_width +
1139 p_vout->output.i_width * ( p_spu->i_y + p_spu->i_height )) * 2;
1140 /* Draw until we reach the bottom of the subtitle */
1141 for( i_y = p_spu->i_height * p_vout->output.i_width;
1143 i_y -= p_vout->output.i_width )
1145 /* Draw until we reach the end of the line */
1146 for( i_x = p_spu->i_width ; i_x ; )
1148 /* Get the RLE part, then draw the line */
1149 i_color = *p_source & 0x3;
1151 switch( p_spu->p_sys->pi_alpha[ i_color ] )
1154 i_x -= *p_source++ >> 2;
1158 i_len = *p_source++ >> 2;
1159 for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
1163 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2,
1164 p_spu->p_sys->pi_yuv[i_color][0], 1);
1166 if (!(i_cnt & 0x01))
1169 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 1,
1171 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 3,
1179 /* FIXME: we should do transparency */
1180 i_len = *p_source++ >> 2;
1181 for( i_cnt = 0; i_cnt < i_len; i_cnt++ )
1185 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2,
1186 p_spu->p_sys->pi_yuv[i_color][0], 1);
1188 if (!(i_cnt & 0x01))
1191 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 1,
1193 memset( p_dest - i_x * 2 - i_y * 2 + i_cnt * 2 + 3,
1207 msg_Err( p_vout, "unknown chroma, can't render SPU" );