]> git.sesse.net Git - vlc/blob - src/video_output/video_spu.c
1a98576a10786784da427adc37eab985e40e1f51
[vlc] / src / video_output / video_spu.c
1 /*****************************************************************************
2  * video_spu.h : DVD subpicture units functions
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  *
6  * Authors:
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this program; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, 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 "video_spu.h"
34
35 #include "intf_msg.h"
36
37 typedef struct spu_s
38 {
39     int i_id;
40     byte_t *p_data;
41
42     int x;
43     int y;
44     int width;
45     int height;
46
47 } spu_t;
48
49 static int NewLine  ( spu_t *p_spu, int *i_id );
50
51 /* i = get_nibble(); */
52 #define GET_NIBBLE( i ) \
53     if( b_aligned ) \
54     { \
55         i_next = *p_from[i_id]; \
56         /*printf("%.1x", i_next >> 4);*/ \
57         p_from[ i_id ]++; \
58         b_aligned = 0; \
59         i = i_next >> 4; \
60     } \
61     else \
62     { \
63         b_aligned = 1; \
64         /*printf("%.1x", i_next & 0xf);*/ \
65         i = i_next & 0xf; \
66     }
67
68 /* i = j + get_nibble(); */
69 #define ADD_NIBBLE( i, j ) \
70     if( b_aligned ) \
71     { \
72         i_next = *p_from[i_id]; \
73         /*printf("%.1x", i_next >> 4);*/ \
74         p_from[ i_id ]++; \
75         b_aligned = 0; \
76         i = (j) + (i_next >> 4); \
77     } \
78     else \
79     { \
80         b_aligned = 1; \
81         /*printf("%.1x", i_next & 0xf);*/ \
82         i = (j) + (i_next & 0xf); \
83     }
84
85 /*****************************************************************************
86  * vout_RenderSPU: draws an SPU on a picture
87  *****************************************************************************
88  * 
89  *****************************************************************************/
90 void vout_RenderSPU( byte_t *p_data, int p_offset[2],
91                      int i_x, int i_y, byte_t *p_pic,
92                      int i_bytes_per_pixel, int i_bytes_per_line )
93 {
94     int i_code = 0x00;
95     int i_next = 0;
96     int i_id = 0;
97     int i_color;
98     static int p_palette[4] = { 0x0000, 0xffff, 0x5555, 0x0000 };
99
100     boolean_t b_aligned = 1;
101     byte_t *p_from[2];
102     spu_t spu;
103
104     p_from[1] = p_data + p_offset[1];
105     p_from[0] = p_data + p_offset[0];
106
107     spu.x = 0;
108     spu.y = 0;
109     spu.width = 720;
110     spu.height = 576;
111     spu.p_data = p_pic + i_x * i_bytes_per_pixel + i_y * i_bytes_per_line;
112
113     while( p_from[0] < p_data + p_offset[1] )
114     {
115         GET_NIBBLE( i_code );
116
117         if( i_code >= 0x04 )
118         {
119             found_code:
120
121             if( ((i_code >> 2) + spu.x + spu.y * spu.width)
122                     > spu.height * spu.width )
123             {
124                 intf_DbgMsg ( "video_spu: invalid draw request ! %d %d\n",
125                               i_code >> 2, spu.height * spu.width
126                                - ( (i_code >> 2) + spu.x
127                                    + spu.y * spu.width ) );
128                 return;
129             }
130             else
131             {
132                 if( (i_color = i_code & 0x3) )
133                 {
134                     u8 *p_target = &spu.p_data[ 2 * 
135                                     ( spu.x + spu.y * spu.width ) ];
136                     memset( p_target, p_palette[i_color], 2 * (i_code >> 2) );
137                 }
138                 spu.x += i_code >> 2;
139             }
140
141             if( spu.x >= spu.width )
142             {
143                 /* byte-align the stream */
144                 b_aligned = 1;
145                 /* finish the line */
146                 NewLine( &spu, &i_id );
147             }
148             continue;
149         }
150
151         ADD_NIBBLE( i_code, (i_code << 4) );
152         if( i_code >= 0x10 )       /* 1x .. 3x */
153             goto found_code;
154
155         ADD_NIBBLE( i_code, (i_code << 4) );
156         if( i_code >= 0x40 )       /* 04x .. 0fx */
157             goto found_code;
158
159         ADD_NIBBLE( i_code, (i_code << 4) );
160         if( i_code >= 0x100 )      /* 01xx .. 03xx */
161             goto found_code;
162
163         /* 00xx - should only happen for 00 00 */
164         if( !b_aligned )
165         {
166             ADD_NIBBLE( i_code, (i_code << 4) );
167         }
168
169         if( i_code )
170         {
171             intf_DbgMsg( "video_spu: unknown code 0x%x "
172                          "(dest %x side %x, x=%d, y=%d)\n",
173                          i_code, p_from[i_id], i_id, spu.x, spu.y );
174             if( NewLine( &spu, &i_id ) < 0 )
175                 return;
176             continue;
177         }
178
179         /* aligned 00 00 */
180         if( NewLine( &spu, &i_id ) < 0 )
181             return;
182     }
183 }
184
185 static int NewLine( spu_t *p_spu, int *i_id )
186 {
187     *i_id = 1 - *i_id;
188
189     p_spu->x = 0;
190     p_spu->y++;
191
192     return( p_spu->width - p_spu->y );
193
194 }
195