1 /*****************************************************************************
2 * video_spu.h : DVD subpicture units functions
3 *****************************************************************************
4 * Copyright (C) 1999, 2000 VideoLAN
7 * Samuel "Sam" Hocevar <sam@via.ecp.fr>
8 * Henri Fallon <henri@via.ecp.fr>
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 *****************************************************************************/
38 #include "video_output.h"
39 #include "video_spu.h"
43 typedef struct vout_spu_s
48 /* drawing coordinates inside the spu */
57 static int NewLine ( vout_spu_t *p_vspu, int *i_id );
59 /* i = get_nibble(); */
60 #define GET_NIBBLE( i ) \
63 i_next = *p_from[i_id]; \
74 /* i = j + get_nibble(); */
75 #define ADD_NIBBLE( i, j ) \
78 i_next = *p_from[i_id]; \
81 i = (j) + (i_next >> 4); \
86 i = (j) + (i_next & 0xf); \
89 /*****************************************************************************
90 * vout_RenderSPU: draws an SPU on a picture
91 *****************************************************************************
93 *****************************************************************************/
94 void vout_RenderSPU( vout_buffer_t *p_buffer, subpicture_t *p_subpic,
95 int i_bytes_per_pixel, int i_bytes_per_line )
102 /* FIXME: we need a way to get this information from the stream */
103 #define TARGET_WIDTH 720
104 #define TARGET_HEIGHT 576
105 int i_x_scale = ( p_buffer->i_pic_width << 6 ) / TARGET_WIDTH;
106 int i_y_scale = ( p_buffer->i_pic_height << 6 ) / TARGET_HEIGHT;
108 /* FIXME: fake palette - the real one has to be sought in the .IFO */
109 static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x8888 };
111 boolean_t b_aligned = 1;
115 p_from[1] = p_subpic->p_data + p_subpic->type.spu.i_offset[1];
116 p_from[0] = p_subpic->p_data + p_subpic->type.spu.i_offset[0];
120 vspu.i_width = TARGET_WIDTH;
121 vspu.i_height = TARGET_HEIGHT;
122 vspu.p_data = p_buffer->p_data
123 /* add the picture coordinates and the SPU coordinates */
124 + ( p_buffer->i_pic_x + ((p_subpic->i_x * i_x_scale) >> 6))
126 + ( p_buffer->i_pic_y + ((p_subpic->i_y * i_y_scale) >> 6))
129 /* Do we need scaling ?
130 * This is mostly dupliucate code except a few lines.
131 * This test was put out of the loop to avoid testing it
134 if ( i_y_scale >= (1 << 6) )
136 while( p_from[0] < (byte_t *)p_subpic->p_data
137 + p_subpic->type.spu.i_offset[1] )
139 GET_NIBBLE( i_code );
143 found_code_with_scale:
145 if( ((i_code >> 2) + vspu.i_x + vspu.i_y * vspu.i_width)
146 > vspu.i_height * vspu.i_width )
148 intf_DbgMsg ( "video_spu: invalid draw request ! %d %d",
149 i_code >> 2, vspu.i_height * vspu.i_width
150 - ( (i_code >> 2) + vspu.i_x
151 + vspu.i_y * vspu.i_width ) );
156 if( (i_color = i_code & 0x3) )
158 u8 *p_target = &vspu.p_data[
159 i_bytes_per_pixel * ((vspu.i_x * i_x_scale) >> 6)
160 + i_bytes_per_line * ((vspu.i_y * i_y_scale) >> 6) ];
162 memset( p_target, p_palette[i_color],
163 ((((i_code - 1) * i_x_scale) >> 8) + 1)
164 * i_bytes_per_pixel );
166 /* here we need some horizontal scaling (unlikely )
167 * we only scale up to 2x, someone watching a DVD
168 * with more than 2x zoom must be braindead */
169 p_target += i_bytes_per_line;
171 memset( p_target, p_palette[i_color],
172 ((((i_code - 1) * i_x_scale) >> 8) + 1)
173 * i_bytes_per_pixel );
175 vspu.i_x += i_code >> 2;
178 if( vspu.i_x >= vspu.i_width )
180 /* byte-align the stream */
182 /* finish the line */
183 NewLine( &vspu, &i_id );
188 ADD_NIBBLE( i_code, (i_code << 4) );
189 if( i_code >= 0x10 ) /* 00 11 xx cc */
190 goto found_code_with_scale; /* 00 01 xx cc */
192 ADD_NIBBLE( i_code, (i_code << 4) );
193 if( i_code >= 0x040 ) /* 00 00 11 xx xx cc */
194 goto found_code_with_scale; /* 00 00 01 xx xx cc */
196 ADD_NIBBLE( i_code, (i_code << 4) );
197 if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
198 goto found_code_with_scale; /* 00 00 00 01 xx xx xx cc */
200 /* if the 14 first bits are 0, then it's a newline */
201 if( i_code <= 0x0003 )
203 if( NewLine( &vspu, &i_id ) < 0 )
211 /* we have a boo boo ! */
212 intf_DbgMsg( "video_spu: unknown code 0x%x "
213 "(dest %x side %x, x=%d, y=%d)",
214 i_code, p_from[i_id], i_id, vspu.i_x, vspu.i_y );
215 if( NewLine( &vspu, &i_id ) < 0 )
223 while( p_from[0] < (byte_t *)p_subpic->p_data
224 + p_subpic->type.spu.i_offset[1] )
226 GET_NIBBLE( i_code );
232 if( ((i_code >> 2) + vspu.i_x + vspu.i_y * vspu.i_width)
233 > vspu.i_height * vspu.i_width )
235 intf_DbgMsg ( "video_spu: invalid draw request ! %d %d",
236 i_code >> 2, vspu.i_height * vspu.i_width
237 - ( (i_code >> 2) + vspu.i_x
238 + vspu.i_y * vspu.i_width ) );
243 if( (i_color = i_code & 0x3) )
245 u8 *p_target = &vspu.p_data[
246 i_bytes_per_pixel * ((vspu.i_x * i_x_scale) >> 6)
247 + i_bytes_per_line * ((vspu.i_y * i_y_scale) >> 6) ];
249 memset( p_target, p_palette[i_color],
250 ((((i_code - 1) * i_x_scale) >> 8) + 1)
251 * i_bytes_per_pixel );
253 vspu.i_x += i_code >> 2;
256 if( vspu.i_x >= vspu.i_width )
258 /* byte-align the stream */
260 /* finish the line */
261 NewLine( &vspu, &i_id );
266 ADD_NIBBLE( i_code, (i_code << 4) );
267 if( i_code >= 0x10 ) /* 00 11 xx cc */
268 goto found_code; /* 00 01 xx cc */
270 ADD_NIBBLE( i_code, (i_code << 4) );
271 if( i_code >= 0x040 ) /* 00 00 11 xx xx cc */
272 goto found_code; /* 00 00 01 xx xx cc */
274 ADD_NIBBLE( i_code, (i_code << 4) );
275 if( i_code >= 0x0100 ) /* 00 00 00 11 xx xx xx cc */
276 goto found_code; /* 00 00 00 01 xx xx xx cc */
278 /* if the 14 first bits are 0, then it's a newline */
279 if( i_code <= 0x0003 )
281 if( NewLine( &vspu, &i_id ) < 0 )
289 /* we have a boo boo ! */
290 intf_DbgMsg( "video_spu: unknown code 0x%x "
291 "(dest %x side %x, x=%d, y=%d)",
292 i_code, p_from[i_id], i_id, vspu.i_x, vspu.i_y );
293 if( NewLine( &vspu, &i_id ) < 0 )
301 static int NewLine( vout_spu_t *p_vspu, int *i_id )
308 return( p_vspu->i_width - p_vspu->i_y );