Mercurial > mplayer.hg
annotate sub/sub_cc.c @ 32921:448517f556a5
Fix memory leak in appClearItem().
Mask wasn't freed.
Additionally: symbolic constants are used for initialization where possible,
the pressed default is btnDisabled now, gfree() is preferred to free() and
setting NULL, and statements are rearranged according to members in structure.
author | ib |
---|---|
date | Thu, 03 Mar 2011 11:43:01 +0000 |
parents | da2dc11d8436 |
children | 5367c50655c4 |
rev | line source |
---|---|
32458 | 1 /* |
2 * decoder for Closed Captions | |
3 * | |
4 * This decoder relies on MPlayer's OSD to display subtitles. | |
5 * Be warned that decoding is somewhat preliminary, though it basically works. | |
6 * | |
7 * Most notably, only the text information is decoded as of now, discarding | |
8 * color, background and position info (see source below). | |
9 * | |
10 * uses source from the xine closed captions decoder | |
11 * | |
12 * Copyright (C) 2002 Matteo Giani | |
13 * | |
14 * This file is part of MPlayer. | |
15 * | |
16 * MPlayer is free software; you can redistribute it and/or modify | |
17 * it under the terms of the GNU General Public License as published by | |
18 * the Free Software Foundation; either version 2 of the License, or | |
19 * (at your option) any later version. | |
20 * | |
21 * MPlayer is distributed in the hope that it will be useful, | |
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 * GNU General Public License for more details. | |
25 * | |
26 * You should have received a copy of the GNU General Public License along | |
27 * with MPlayer; if not, write to the Free Software Foundation, Inc., | |
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
29 */ | |
30 | |
31 #include <stdio.h> | |
32 #include <stdlib.h> | |
33 #include <string.h> | |
34 | |
35 #include "config.h" | |
32464
22888a8cb312
Do not use a path for including files in the same directory.
reimar
parents:
32458
diff
changeset
|
36 #include "sub_cc.h" |
32458 | 37 |
32464
22888a8cb312
Do not use a path for including files in the same directory.
reimar
parents:
32458
diff
changeset
|
38 #include "subreader.h" |
32458 | 39 |
40 #include "libvo/video_out.h" | |
32467 | 41 #include "sub.h" |
32458 | 42 |
43 | |
44 #define CC_MAX_LINE_LENGTH 64 | |
45 | |
46 static char chartbl[128]; | |
47 | |
48 static subtitle buf1,buf2; | |
49 static subtitle *fb,*bb; | |
50 | |
51 static unsigned int cursor_pos=0; | |
52 | |
53 static int initialized=0; | |
54 | |
55 #define CC_ROLLON 1 | |
56 #define CC_ROLLUP 2 | |
57 | |
58 static int cc_mode=CC_ROLLON; | |
59 static int cc_lines=4; ///< number of visible rows in CC roll-up mode, not used in CC roll-on mode | |
60 | |
61 static void build_char_table(void) | |
62 { | |
63 int i; | |
64 /* first the normal ASCII codes */ | |
65 for (i = 0; i < 128; i++) | |
66 chartbl[i] = (char) i; | |
67 /* now the special codes */ | |
68 chartbl[0x2a] = 'á'; | |
69 chartbl[0x5c] = 'é'; | |
70 chartbl[0x5e] = 'í'; | |
71 chartbl[0x5f] = 'ó'; | |
72 chartbl[0x60] = 'ú'; | |
73 chartbl[0x7b] = 'ç'; | |
74 chartbl[0x7c] = '÷'; | |
75 chartbl[0x7d] = 'Ñ'; | |
76 chartbl[0x7e] = 'ñ'; | |
77 chartbl[0x7f] = '¤'; /* FIXME: this should be a solid block */ | |
78 } | |
79 | |
80 static void clear_buffer(subtitle *buf) | |
81 { | |
82 int i; | |
83 buf->lines=0; | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
84 for (i = 0; i < SUB_MAX_TEXT; i++) { |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
85 free(buf->text[i]); |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
86 buf->text[i] = NULL; |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
87 } |
32458 | 88 } |
89 | |
90 | |
91 /** | |
92 \brief scroll buffer one line up | |
93 \param buf buffer to scroll | |
94 */ | |
95 static void scroll_buffer(subtitle* buf) | |
96 { | |
97 int i; | |
98 | |
99 while(buf->lines > cc_lines) | |
100 { | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
101 free(buf->text[0]); |
32458 | 102 |
32512 | 103 for(i = 0; i < buf->lines - 1; i++) buf->text[i] = buf->text[i+1]; |
32458 | 104 |
105 buf->text[buf->lines-1] = NULL; | |
106 buf->lines--; | |
107 } | |
108 } | |
109 | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
110 static int channel; |
32458 | 111 |
112 void subcc_init(void) | |
113 { | |
114 int i; | |
115 //printf("subcc_init(): initing...\n"); | |
116 build_char_table(); | |
117 for(i=0;i<SUB_MAX_TEXT;i++) {buf1.text[i]=buf2.text[i]=NULL;} | |
118 buf1.lines=buf2.lines=0; | |
119 fb=&buf1; | |
120 bb=&buf2; | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
121 channel = -1; |
32458 | 122 |
123 initialized=1; | |
124 } | |
125 | |
126 | |
127 static void display_buffer(subtitle *buf) | |
128 { | |
129 vo_sub = buf; | |
130 vo_osd_changed(OSDTYPE_SUBTITLE); | |
131 } | |
132 | |
133 | |
134 static void append_char(char c) | |
135 { | |
136 if(!bb->lines) {bb->lines++; cursor_pos=0;} | |
137 if(bb->text[bb->lines - 1]==NULL) | |
138 { | |
32513 | 139 bb->text[bb->lines - 1] = calloc(1, CC_MAX_LINE_LENGTH); |
32458 | 140 cursor_pos=0; |
141 } | |
142 | |
143 if(c=='\n') | |
144 { | |
145 if(cursor_pos>0 && bb->lines < SUB_MAX_TEXT) | |
146 { | |
147 bb->lines++;cursor_pos=0; | |
148 if(cc_mode==CC_ROLLUP){ //Carriage return - scroll buffer one line up | |
149 bb->text[bb->lines - 1]=calloc(1, CC_MAX_LINE_LENGTH); | |
150 scroll_buffer(bb); | |
151 } | |
152 } | |
153 } | |
154 else | |
155 { | |
156 if(cursor_pos==CC_MAX_LINE_LENGTH-1) | |
157 { | |
158 fprintf(stderr,"CC: append_char() reached CC_MAX_LINE_LENGTH!\n"); | |
159 return; | |
160 } | |
161 bb->text[bb->lines - 1][cursor_pos++]=c; | |
162 } | |
163 //In CC roll-up mode data should be shown immediately | |
164 if(cc_mode==CC_ROLLUP) display_buffer(bb); | |
165 } | |
166 | |
167 | |
168 static void swap_buffers(void) | |
169 { | |
170 subtitle *foo; | |
171 foo=fb; | |
172 fb=bb; | |
173 bb=foo; | |
174 } | |
175 | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
176 static int selected_channel(void) |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
177 { |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
178 return subcc_enabled - 1; |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
179 } |
32458 | 180 |
181 static void cc_decode_EIA608(unsigned short int data) | |
182 { | |
183 | |
184 static unsigned short int lastcode=0x0000; | |
32566 | 185 uint8_t c1 = data & 0x7f; |
186 uint8_t c2 = (data >> 8) & 0x7f; | |
32458 | 187 |
188 if (c1 & 0x60) { /* normal character, 0x20 <= c1 <= 0x7f */ | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
189 if (channel != (selected_channel() & 1)) |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
190 return; |
32458 | 191 append_char(chartbl[c1]); |
192 if(c2 & 0x60) /*c2 might not be a normal char even if c1 is*/ | |
193 append_char(chartbl[c2]); | |
194 } | |
195 else if (c1 & 0x10) // control code / special char | |
196 { | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
197 channel = (c1 & 0x08) >> 3; |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
198 if (channel != (selected_channel() & 1)) |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
199 return; |
32458 | 200 c1&=~0x08; |
201 if(data!=lastcode) | |
202 { | |
203 if(c2 & 0x40) { /*PAC, Preamble Address Code */ | |
204 append_char('\n'); /*FIXME properly interpret PACs*/ | |
205 } | |
206 else | |
207 switch(c1) | |
208 { | |
209 case 0x10: break; // ext attribute | |
210 case 0x11: | |
211 if((c2 & 0x30)==0x30) | |
212 { | |
213 //printf("[debug]:Special char (ignored)\n"); | |
214 /*cc_decode_special_char()*/; | |
215 } | |
216 else if (c2 & 0x20) | |
217 { | |
218 //printf("[debug]: midrow_attr (ignored)\n"); | |
219 /*cc_decode_midrow_attr()*/; | |
220 } | |
221 break; | |
222 case 0x14: | |
223 switch(c2) | |
224 { | |
225 case 0x00: //CC roll-on mode | |
226 cc_mode=CC_ROLLON; | |
227 break; | |
228 case 0x25: //CC roll-up, 2 rows | |
229 case 0x26: //CC roll-up, 3 rows | |
230 case 0x27: //CC roll-up, 4 rows | |
231 cc_lines=c2-0x23; | |
232 cc_mode=CC_ROLLUP; | |
233 break; | |
234 case 0x2C: display_buffer(NULL); //EDM | |
235 clear_buffer(fb); break; | |
236 case 0x2d: append_char('\n'); //carriage return | |
237 break; | |
238 case 0x2e: clear_buffer(bb); //ENM | |
239 break; | |
240 case 0x2f: swap_buffers(); //Swap buffers | |
241 display_buffer(fb); | |
242 clear_buffer(bb); | |
243 break; | |
244 } | |
245 break; | |
246 case 0x17: | |
247 if( c2>=0x21 && c2<=0x23) //TAB | |
248 { | |
249 break; | |
250 } | |
251 } | |
252 } | |
253 } | |
254 lastcode=data; | |
255 } | |
256 | |
32566 | 257 static void subcc_decode(const uint8_t *inputbuffer, unsigned int inputlength) |
32458 | 258 { |
259 /* The first number may denote a channel number. I don't have the | |
260 * EIA-708 standard, so it is hard to say. | |
261 * From what I could figure out so far, the general format seems to be: | |
262 * | |
263 * repeat | |
264 * | |
265 * 0xfe starts 2 byte sequence of unknown purpose. It might denote | |
32522 | 266 * field #2 in line 21 of the VBI. |
267 * Treating it identical of 0xff fixes | |
268 * http://samples.mplayerhq.hu/MPEG-VOB/ClosedCaptions/Starship_Troopers.vob | |
32458 | 269 * |
270 * 0xff starts 2 byte EIA-608 sequence, field #1 in line 21 of the VBI. | |
271 * Followed by a 3-code triplet that starts either with 0xff or | |
272 * 0xfe. In either case, the following triplet needs to be ignored | |
273 * for line 21, field 1. | |
274 * | |
275 * 0x00 is padding, followed by 2 more 0x00. | |
276 * | |
277 * 0x01 always seems to appear at the beginning, always seems to | |
278 * be followed by 0xf8, 8-bit number. | |
279 * The lower 7 bits of this 8-bit number seem to denote the | |
280 * number of code triplets that follow. | |
281 * The most significant bit denotes whether the Line 21 field 1 | |
282 * captioning information is at odd or even triplet offsets from this | |
283 * beginning triplet. 1 denotes odd offsets, 0 denotes even offsets. | |
284 * | |
285 * Most captions are encoded with odd offsets, so this is what we | |
286 * will assume. | |
287 * | |
288 * until end of packet | |
289 */ | |
32566 | 290 const uint8_t *current = inputbuffer; |
32458 | 291 unsigned int curbytes = 0; |
32566 | 292 uint8_t data1, data2; |
293 uint8_t cc_code; | |
32458 | 294 int odd_offset = 1; |
295 | |
296 while (curbytes < inputlength) { | |
32512 | 297 cc_code = current[0]; |
32458 | 298 |
299 if (inputlength - curbytes < 2) { | |
300 #ifdef LOG_DEBUG | |
301 fprintf(stderr, "Not enough data for 2-byte CC encoding\n"); | |
302 #endif | |
303 break; | |
304 } | |
305 | |
32512 | 306 data1 = current[1]; |
307 data2 = current[2]; | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
308 current += 3; curbytes += 3; |
32458 | 309 |
310 switch (cc_code) { | |
311 case 0xfe: | |
312 case 0xff: | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
313 odd_offset ^= 1; |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
314 if (odd_offset != selected_channel() >> 1) |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
315 break; |
32458 | 316 /* expect EIA-608 CC1/CC2 encoding */ |
317 // FIXME check parity! | |
318 // Parity check omitted assuming we are reading from a DVD and therefore | |
319 // we should encounter no "transmission errors". | |
320 cc_decode_EIA608(data1 | (data2 << 8)); | |
321 break; | |
322 | |
323 case 0x00: | |
324 /* This seems to be just padding */ | |
325 break; | |
326 | |
327 case 0x01: | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
328 odd_offset = data2 >> 7; |
32458 | 329 break; |
330 | |
331 default: | |
332 //#ifdef LOG_DEBUG | |
333 fprintf(stderr, "Unknown CC encoding: %x\n", cc_code); | |
334 //#endif | |
335 break; | |
336 } | |
337 } | |
338 } | |
339 | |
340 | |
32566 | 341 void subcc_process_data(const uint8_t *inputdata, unsigned int len) |
32458 | 342 { |
343 if(!subcc_enabled) return; | |
344 if(!initialized) subcc_init(); | |
345 | |
346 subcc_decode(inputdata, len); | |
347 } |