Mercurial > mplayer.hg
comparison sub_cc.c @ 6784:b38e38b6f88f
DVD Closed Captioning support, patch by Matteo Giani <matgiani@ctonet.it>, small changes by me.
author | atmos4 |
---|---|
date | Thu, 25 Jul 2002 03:37:28 +0000 |
parents | |
children | a3b2f80f3a26 |
comparison
equal
deleted
inserted
replaced
6783:798e404931fe | 6784:b38e38b6f88f |
---|---|
1 /* | |
2 * sub_cc.c - Decoder for Closed Captions | |
3 * | |
4 * This decoder relies on MPlayer's OSD to display subtitles. | |
5 * Be warned that the decoding is somewhat preliminary, though it basically works. | |
6 * | |
7 * Most notably, only the text information is decoded as of now, discarding color, | |
8 * background and position info (see source below). | |
9 * | |
10 * by Matteo Giani | |
11 * | |
12 * uses source from the xine closed captions decoder | |
13 */ | |
14 | |
15 | |
16 #include <stdio.h> | |
17 #include <stdlib.h> | |
18 | |
19 #include "subreader.h" | |
20 | |
21 #include "libvo/video_out.h" | |
22 #include "libvo/sub.h" | |
23 | |
24 | |
25 #define CC_INPUTBUFFER_SIZE 256 | |
26 | |
27 #define CC_MAX_LINE_LENGTH 64 | |
28 | |
29 static char chartbl[128]; | |
30 | |
31 extern int subcc_enabled; | |
32 | |
33 subtitle buf1,buf2; | |
34 subtitle *fb,*bb; | |
35 | |
36 static unsigned int cursor_pos=0; | |
37 | |
38 static int inited=0; | |
39 static unsigned char inputbuffer[CC_INPUTBUFFER_SIZE]; | |
40 static unsigned int inputlength; | |
41 | |
42 static void build_char_table(void) | |
43 { | |
44 int i; | |
45 /* first the normal ASCII codes */ | |
46 for (i = 0; i < 128; i++) | |
47 chartbl[i] = (char) i; | |
48 /* now the special codes */ | |
49 chartbl[0x2a] = 'á'; | |
50 chartbl[0x5c] = 'é'; | |
51 chartbl[0x5e] = 'í'; | |
52 chartbl[0x5f] = 'ó'; | |
53 chartbl[0x60] = 'ú'; | |
54 chartbl[0x7b] = 'ç'; | |
55 chartbl[0x7c] = '÷'; | |
56 chartbl[0x7d] = 'Ñ'; | |
57 chartbl[0x7e] = 'ñ'; | |
58 chartbl[0x7f] = '¤'; /* FIXME: this should be a solid block */ | |
59 } | |
60 | |
61 void clear_buffer(subtitle *buf) | |
62 { | |
63 int i; | |
64 buf->lines=0; | |
65 for(i=0;i<SUB_MAX_TEXT;i++) if(buf->text[i]) {free(buf->text[i]);buf->text[i]=NULL;} | |
66 } | |
67 | |
68 | |
69 void subcc_init() | |
70 { | |
71 int i; | |
72 //printf("subcc_init(): initing...\n"); | |
73 build_char_table(); | |
74 for(i=0;i<SUB_MAX_TEXT;i++) {buf1.text[i]=buf2.text[i]=NULL;} | |
75 buf1.lines=buf2.lines=0; | |
76 fb=&buf1; | |
77 bb=&buf2; | |
78 | |
79 inited=1; | |
80 } | |
81 | |
82 static void append_char(char c) | |
83 { | |
84 if(!bb->lines) {bb->lines++; cursor_pos=0;} | |
85 if(bb->text[bb->lines - 1]==NULL) | |
86 { | |
87 bb->text[bb->lines - 1]=malloc(CC_MAX_LINE_LENGTH); | |
88 memset(bb->text[bb->lines - 1],0,CC_MAX_LINE_LENGTH); | |
89 cursor_pos=0; | |
90 } | |
91 | |
92 if(c=='\n') | |
93 { | |
94 if(cursor_pos>0) | |
95 bb->lines++;cursor_pos=0; | |
96 } | |
97 else | |
98 { | |
99 if(cursor_pos==CC_MAX_LINE_LENGTH-1) | |
100 { | |
101 printf("sub_cc.c: append_char() reached CC_MAX_LINE_LENGTH!\n"); | |
102 return; | |
103 } | |
104 bb->text[bb->lines - 1][cursor_pos++]=c; | |
105 } | |
106 } | |
107 | |
108 | |
109 static void swap_buffers() | |
110 { | |
111 subtitle *foo; | |
112 foo=fb; | |
113 fb=bb; | |
114 bb=foo; | |
115 } | |
116 | |
117 static void display_buffer(subtitle * buf) | |
118 { | |
119 vo_sub=buf; | |
120 vo_osd_changed(OSDTYPE_SUBTITLE); | |
121 } | |
122 | |
123 | |
124 static void cc_decode_EIA608(unsigned short int data) | |
125 { | |
126 | |
127 static unsigned short int lastcode=0x0000; | |
128 unsigned char c1 = data & 0x7f; | |
129 unsigned char c2 = (data >> 8) & 0x7f; | |
130 | |
131 if (c1 & 0x60) { /* normal character, 0x20 <= c1 <= 0x7f */ | |
132 append_char(chartbl[c1]); | |
133 if(c2 & 0x60) /*c2 might not be a normal char even if c1 is*/ | |
134 append_char(chartbl[c2]); | |
135 } | |
136 else if (c1 & 0x10) // control code / special char | |
137 { | |
138 int channel= (c1 & 0x08) >> 3; | |
139 c1&=~0x08; | |
140 if(data!=lastcode) | |
141 { | |
142 if(c2 & 0x40) { /*PAC, Preamble Address Code */ | |
143 append_char('\n'); /*FIXME properly interpret PACs*/ | |
144 } | |
145 else | |
146 switch(c1) | |
147 { | |
148 case 0x10: break; // ext attribute | |
149 case 0x11: | |
150 if((c2 & 0x30)==0x30) | |
151 { | |
152 //printf("[debug]:Special char (ignored)\n"); | |
153 /*cc_decode_special_char()*/; | |
154 } | |
155 else if (c2 & 0x20) | |
156 { | |
157 //printf("[debug]: midrow_attr (ignored)\n"); | |
158 /*cc_decode_midrow_attr()*/; | |
159 } | |
160 break; | |
161 case 0x14: | |
162 switch(c2) | |
163 { | |
164 case 0x2C: display_buffer(NULL); //EDM | |
165 clear_buffer(fb); break; | |
166 case 0x2d: append_char('\n'); //carriage return | |
167 break; | |
168 case 0x2e: clear_buffer(bb); //ENM | |
169 break; | |
170 case 0x2f: swap_buffers(); //Swap buffers | |
171 display_buffer(fb); | |
172 clear_buffer(bb); | |
173 break; | |
174 } | |
175 break; | |
176 case 0x17: | |
177 if( c2>=0x21 && c2<=0x23) //TAB | |
178 { | |
179 break; | |
180 } | |
181 } | |
182 } | |
183 } | |
184 lastcode=data; | |
185 } | |
186 | |
187 void subcc_decode() | |
188 { | |
189 /* The first number may denote a channel number. I don't have the | |
190 * EIA-708 standard, so it is hard to say. | |
191 * From what I could figure out so far, the general format seems to be: | |
192 * | |
193 * repeat | |
194 * | |
195 * 0xfe starts 2 byte sequence of unknown purpose. It might denote | |
196 * field #2 in line 21 of the VBI. We'll ignore it for the | |
197 * time being. | |
198 * | |
199 * 0xff starts 2 byte EIA-608 sequence, field #1 in line 21 of the VBI. | |
200 * Followed by a 3-code triplet that starts either with 0xff or | |
201 * 0xfe. In either case, the following triplet needs to be ignored | |
202 * for line 21, field 1. | |
203 * | |
204 * 0x00 is padding, followed by 2 more 0x00. | |
205 * | |
206 * 0x01 always seems to appear at the beginning, always seems to | |
207 * be followed by 0xf8, 8-bit number. | |
208 * The lower 7 bits of this 8-bit number seem to denote the | |
209 * number of code triplets that follow. | |
210 * The most significant bit denotes whether the Line 21 field 1 | |
211 * captioning information is at odd or even triplet offsets from this | |
212 * beginning triplet. 1 denotes odd offsets, 0 denotes even offsets. | |
213 * | |
214 * Most captions are encoded with odd offsets, so this is what we | |
215 * will assume. | |
216 * | |
217 * until end of packet | |
218 */ | |
219 unsigned char *current = inputbuffer; | |
220 unsigned int curbytes = 0; | |
221 unsigned char data1, data2; | |
222 unsigned char cc_code; | |
223 int odd_offset = 1; | |
224 | |
225 while (curbytes < inputlength) { | |
226 int skip = 2; | |
227 | |
228 cc_code = *(current); | |
229 | |
230 if (inputlength - curbytes < 2) { | |
231 #ifdef LOG_DEBUG | |
232 fprintf(stderr, "Not enough data for 2-byte CC encoding\n"); | |
233 #endif | |
234 break; | |
235 } | |
236 | |
237 data1 = *(current+1); | |
238 data2 = *(current + 2); | |
239 current++; curbytes++; | |
240 | |
241 switch (cc_code) { | |
242 case 0xfe: | |
243 /* expect 2 byte encoding (perhaps CC3, CC4?) */ | |
244 /* ignore for time being */ | |
245 skip = 2; | |
246 break; | |
247 | |
248 case 0xff: | |
249 /* expect EIA-608 CC1/CC2 encoding */ | |
250 // FIXME check parity! | |
251 // Parity check omitted assuming we are reading from a DVD and therefore | |
252 // we should encounter no "transmission errors". | |
253 cc_decode_EIA608(data1 | (data2 << 8)); | |
254 skip = 5; | |
255 break; | |
256 | |
257 case 0x00: | |
258 /* This seems to be just padding */ | |
259 skip = 2; | |
260 break; | |
261 | |
262 case 0x01: | |
263 odd_offset = data2 & 0x80; | |
264 if (odd_offset) | |
265 skip = 2; | |
266 else | |
267 skip = 5; | |
268 break; | |
269 | |
270 default: | |
271 //#ifdef LOG_DEBUG | |
272 fprintf(stderr, "Unknown CC encoding: %x\n", cc_code); | |
273 //#endif | |
274 skip = 2; | |
275 break; | |
276 } | |
277 current += skip; | |
278 curbytes += skip; | |
279 } | |
280 } | |
281 | |
282 | |
283 void subcc_process_data(unsigned char *inputdata,unsigned int len) | |
284 { | |
285 if(!subcc_enabled) return; | |
286 if(!inited) subcc_init(); | |
287 | |
288 memcpy(inputbuffer,inputdata,len); | |
289 inputlength=len; | |
290 subcc_decode(); | |
291 } | |
292 |