]> git.sesse.net Git - vlc/blob - src/video_output/video_spu.c
* The Gtk+ interface is now built as a Debian package as well. The Gnome
[vlc] / src / video_output / video_spu.c
1 /*****************************************************************************
2  * video_spu.c : DVD subpicture units functions
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  *
6  * Authors: Samuel Hocevar <sam@zoy.org>
7  *          Henri Fallon <henri@via.ecp.fr>
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 "defs.h"
28
29 #include <stdio.h>
30
31 #include "config.h"
32 #include "common.h"
33 #include "threads.h"
34 #include "mtime.h"
35
36 #include "video.h"
37 #include "video_output.h"
38 #include "video_spu.h"
39
40 #include "intf_msg.h"
41
42 /* FIXME: fake palette - the real one has to be sought in the .IFO */
43 static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x8888 };
44
45 static __inline__ u8 GetNibble( u8 *p_source, int *pi_index )
46 {
47     if( *pi_index & 0x1 )
48     {
49         return( p_source[(*pi_index)++ >> 1] & 0xf );
50     }
51     else
52     {
53         return( p_source[(*pi_index)++ >> 1] >> 4 );
54     }
55 }
56
57 /*****************************************************************************
58  * vout_RenderSPU: draw an SPU on a picture
59  *****************************************************************************
60  * 
61  *****************************************************************************/
62 void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_spu,
63                      int i_bytes_per_pixel, int i_bytes_per_line )
64 {
65     int i_code = 0x00;
66     int i_id = 0;
67     int i_color;
68
69     /* SPU size */
70     int i_width = p_spu->i_width;
71     int i_height = p_spu->i_height;
72
73     /* Drawing coordinates inside the SPU */
74     int i_x = 0, i_y = 0;
75
76     /* FIXME: we need a way to get this information from the stream */
77     #define TARGET_WIDTH     720
78     #define TARGET_HEIGHT    576
79     int i_xscale = ( p_buffer->i_pic_width << 6 ) / TARGET_WIDTH;
80     int i_yscale = ( p_buffer->i_pic_height << 6 ) / TARGET_HEIGHT;
81
82     u8 *p_source = p_spu->p_data;
83     u8 *p_dest;
84     int pi_index[2];
85
86     pi_index[0] = ( p_spu->type.spu.i_offset[0] - 2 ) << 1;
87     pi_index[1] = ( p_spu->type.spu.i_offset[1] - 2 ) << 1;
88
89     p_dest = p_buffer->p_data
90                 /* add the picture coordinates and the SPU coordinates */
91                 + ( p_buffer->i_pic_x + ((p_spu->i_x * i_xscale) >> 6))
92                      * i_bytes_per_pixel
93                 + ( p_buffer->i_pic_y + ((p_spu->i_y * i_yscale) >> 6))
94                      * i_bytes_per_line;
95
96     while( pi_index[0] >> 1 < p_spu->type.spu.i_offset[1] )
97     {
98         i_code = GetNibble( p_source, pi_index + i_id );
99
100         if( i_code >= 0x04 )
101         {
102             found_code:
103
104             if( ((i_code >> 2) + i_x + i_y * i_width) > i_height * i_width )
105             {
106                 intf_DbgMsg ( "video_spu: invalid draw request ! %d %d",
107                               i_code >> 2, i_height * i_width
108                                - ( (i_code >> 2) + i_x + i_y * i_width ) );
109                 return;
110             }
111             else
112             {
113                 if( (i_color = i_code & 0x3) )
114                 {
115                     u8 *p_target = p_dest
116                         + i_bytes_per_pixel * ((i_x * i_xscale) >> 6)
117                         + i_bytes_per_line * ((i_y * i_yscale) >> 6);
118
119                     memset( p_target, p_palette[i_color],
120                             ((((i_code >> 2) * i_xscale) >> 6) + 1)
121                             * i_bytes_per_pixel );
122                 }
123                 i_x += i_code >> 2;
124             }
125
126             if( i_x >= i_width )
127             {
128                 /* byte-align the stream */
129                 if( pi_index[i_id] & 0x1 )
130                 {
131                     pi_index[i_id]++;
132                 }
133
134                 i_id = ~i_id & 0x1;
135
136                 i_y++;
137                 i_x = 0;
138
139                 if( i_width <= i_y )
140                 {
141                     return;
142                 }
143             }
144             continue;
145         }
146
147         i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
148
149         if( i_code >= 0x10 )   /* 00 11 xx cc */
150         {
151             goto found_code;   /* 00 01 xx cc */
152         }
153
154         i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
155         if( i_code >= 0x040 )  /* 00 00 11 xx xx cc */
156         {
157             goto found_code;   /* 00 00 01 xx xx cc */
158         }
159
160         i_code = ( i_code << 4 ) + GetNibble( p_source, pi_index + i_id );
161         if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
162         {
163             goto found_code;   /* 00 00 00 01 xx xx xx cc */
164         }
165
166         if( i_code & ~0x0003 )
167         {
168             /* we have a boo boo ! */
169             intf_ErrMsg( "video_spu: unknown code 0x%x "
170                          "(dest %x side %x, x=%d, y=%d)",
171                          i_code, p_source, i_id, i_x, i_y );
172             return;
173         }
174         else
175         {
176             /* if the 14 first bits are 0, then it's a new line */
177             if( pi_index[i_id] & 0x1 )
178             {
179                 pi_index[i_id]++;
180             }
181
182             i_id = ~i_id & 0x1;
183
184             i_y++;
185             i_x = 0;
186
187             if( i_width <= i_y )
188             {
189                 return;
190             }
191         }
192     }
193 }
194