Mercurial > mplayer.hg
annotate sub/sub_cc.c @ 35553:29f2de5e63d6
Don't unconditionally reset playlist to first item after playback.
Only do so if the current item isn't the first one in the list.
This will continue displaying the file's media information.
author | ib |
---|---|
date | Mon, 10 Dec 2012 02:08:43 +0000 |
parents | 7abba31768ec |
children | d206960484fe |
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" | |
34756 | 36 #include "mp_msg.h" |
32464
22888a8cb312
Do not use a path for including files in the same directory.
reimar
parents:
32458
diff
changeset
|
37 #include "sub_cc.h" |
32458 | 38 |
32464
22888a8cb312
Do not use a path for including files in the same directory.
reimar
parents:
32458
diff
changeset
|
39 #include "subreader.h" |
32458 | 40 |
41 #include "libvo/video_out.h" | |
32467 | 42 #include "sub.h" |
32458 | 43 |
34756 | 44 #include "libavutil/avutil.h" |
45 | |
32458 | 46 |
47 #define CC_MAX_LINE_LENGTH 64 | |
48 | |
49 static char chartbl[128]; | |
50 | |
51 static subtitle buf1,buf2; | |
52 static subtitle *fb,*bb; | |
53 | |
54 static unsigned int cursor_pos=0; | |
55 | |
56 static int initialized=0; | |
35028
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
57 static int wtv_format; |
32458 | 58 |
59 #define CC_ROLLON 1 | |
60 #define CC_ROLLUP 2 | |
61 | |
62 static int cc_mode=CC_ROLLON; | |
63 static int cc_lines=4; ///< number of visible rows in CC roll-up mode, not used in CC roll-on mode | |
64 | |
65 static void build_char_table(void) | |
66 { | |
67 int i; | |
68 /* first the normal ASCII codes */ | |
69 for (i = 0; i < 128; i++) | |
70 chartbl[i] = (char) i; | |
71 /* now the special codes */ | |
34702 | 72 chartbl[0x2a] = 0xe1; /* Latin Small Letter A with acute */ |
73 chartbl[0x5c] = 0xe9; /* Latin Small Letter E with acute */ | |
74 chartbl[0x5e] = 0xed; /* Latin Small Letter I with acute */ | |
75 chartbl[0x5f] = 0xf3; /* Latin Small Letter O with acute */ | |
76 chartbl[0x60] = 0xfa; /* Latin Small Letter U with acute */ | |
77 chartbl[0x7b] = 0xe7; /* Latin Small Letter C with cedilla */ | |
78 chartbl[0x7c] = 0xf7; /* Division sign */ | |
79 chartbl[0x7d] = 0xd1; /* Latin Capital letter N with tilde */ | |
80 chartbl[0x7e] = 0xf1; /* Latin Small Letter N with tilde */ | |
81 chartbl[0x7f] = 0xa4; /* Currency sign FIXME: this should be a solid block */ | |
32458 | 82 } |
83 | |
84 static void clear_buffer(subtitle *buf) | |
85 { | |
86 int i; | |
87 buf->lines=0; | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
88 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
|
89 free(buf->text[i]); |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
90 buf->text[i] = NULL; |
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
91 } |
32458 | 92 } |
93 | |
94 | |
95 /** | |
96 \brief scroll buffer one line up | |
97 \param buf buffer to scroll | |
98 */ | |
99 static void scroll_buffer(subtitle* buf) | |
100 { | |
101 int i; | |
102 | |
103 while(buf->lines > cc_lines) | |
104 { | |
32511
b39155e98ac3
Remove some useless NULL pointer checks before invoking free() on the pointer.
diego
parents:
32467
diff
changeset
|
105 free(buf->text[0]); |
32458 | 106 |
32512 | 107 for(i = 0; i < buf->lines - 1; i++) buf->text[i] = buf->text[i+1]; |
32458 | 108 |
109 buf->text[buf->lines-1] = NULL; | |
110 buf->lines--; | |
111 } | |
112 } | |
113 | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
114 static int channel; |
32458 | 115 |
116 void subcc_init(void) | |
117 { | |
118 int i; | |
119 //printf("subcc_init(): initing...\n"); | |
120 build_char_table(); | |
121 for(i=0;i<SUB_MAX_TEXT;i++) {buf1.text[i]=buf2.text[i]=NULL;} | |
122 buf1.lines=buf2.lines=0; | |
123 fb=&buf1; | |
124 bb=&buf2; | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
125 channel = -1; |
32458 | 126 |
127 initialized=1; | |
35028
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
128 wtv_format = 0; |
32458 | 129 } |
130 | |
34761 | 131 void subcc_reset(void) |
132 { | |
35028
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
133 wtv_format = 0; |
34761 | 134 if (!initialized) |
135 return; | |
136 clear_buffer(&buf1); | |
137 clear_buffer(&buf2); | |
138 } | |
32458 | 139 |
140 static void display_buffer(subtitle *buf) | |
141 { | |
142 vo_sub = buf; | |
143 vo_osd_changed(OSDTYPE_SUBTITLE); | |
144 } | |
145 | |
146 | |
147 static void append_char(char c) | |
148 { | |
149 if(!bb->lines) {bb->lines++; cursor_pos=0;} | |
150 if(bb->text[bb->lines - 1]==NULL) | |
151 { | |
32513 | 152 bb->text[bb->lines - 1] = calloc(1, CC_MAX_LINE_LENGTH); |
32458 | 153 cursor_pos=0; |
154 } | |
155 | |
156 if(c=='\n') | |
157 { | |
158 if(cursor_pos>0 && bb->lines < SUB_MAX_TEXT) | |
159 { | |
160 bb->lines++;cursor_pos=0; | |
161 if(cc_mode==CC_ROLLUP){ //Carriage return - scroll buffer one line up | |
162 bb->text[bb->lines - 1]=calloc(1, CC_MAX_LINE_LENGTH); | |
163 scroll_buffer(bb); | |
164 } | |
165 } | |
166 } | |
167 else | |
168 { | |
169 if(cursor_pos==CC_MAX_LINE_LENGTH-1) | |
170 { | |
171 fprintf(stderr,"CC: append_char() reached CC_MAX_LINE_LENGTH!\n"); | |
172 return; | |
173 } | |
174 bb->text[bb->lines - 1][cursor_pos++]=c; | |
175 } | |
176 //In CC roll-up mode data should be shown immediately | |
177 if(cc_mode==CC_ROLLUP) display_buffer(bb); | |
178 } | |
179 | |
180 | |
181 static void swap_buffers(void) | |
182 { | |
183 subtitle *foo; | |
184 foo=fb; | |
185 fb=bb; | |
186 bb=foo; | |
187 } | |
188 | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
189 static int selected_channel(void) |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
190 { |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
191 return subcc_enabled - 1; |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
192 } |
32458 | 193 |
194 static void cc_decode_EIA608(unsigned short int data) | |
195 { | |
196 | |
197 static unsigned short int lastcode=0x0000; | |
32566 | 198 uint8_t c1 = data & 0x7f; |
199 uint8_t c2 = (data >> 8) & 0x7f; | |
32458 | 200 |
201 if (c1 & 0x60) { /* normal character, 0x20 <= c1 <= 0x7f */ | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
202 if (channel != (selected_channel() & 1)) |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
203 return; |
32458 | 204 append_char(chartbl[c1]); |
205 if(c2 & 0x60) /*c2 might not be a normal char even if c1 is*/ | |
206 append_char(chartbl[c2]); | |
207 } | |
208 else if (c1 & 0x10) // control code / special char | |
209 { | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
210 channel = (c1 & 0x08) >> 3; |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
211 if (channel != (selected_channel() & 1)) |
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
212 return; |
32458 | 213 c1&=~0x08; |
214 if(data!=lastcode) | |
215 { | |
216 if(c2 & 0x40) { /*PAC, Preamble Address Code */ | |
217 append_char('\n'); /*FIXME properly interpret PACs*/ | |
218 } | |
219 else | |
220 switch(c1) | |
221 { | |
222 case 0x10: break; // ext attribute | |
223 case 0x11: | |
224 if((c2 & 0x30)==0x30) | |
225 { | |
226 //printf("[debug]:Special char (ignored)\n"); | |
227 /*cc_decode_special_char()*/; | |
228 } | |
229 else if (c2 & 0x20) | |
230 { | |
231 //printf("[debug]: midrow_attr (ignored)\n"); | |
232 /*cc_decode_midrow_attr()*/; | |
233 } | |
234 break; | |
235 case 0x14: | |
236 switch(c2) | |
237 { | |
238 case 0x00: //CC roll-on mode | |
239 cc_mode=CC_ROLLON; | |
240 break; | |
241 case 0x25: //CC roll-up, 2 rows | |
242 case 0x26: //CC roll-up, 3 rows | |
243 case 0x27: //CC roll-up, 4 rows | |
244 cc_lines=c2-0x23; | |
245 cc_mode=CC_ROLLUP; | |
246 break; | |
247 case 0x2C: display_buffer(NULL); //EDM | |
248 clear_buffer(fb); break; | |
249 case 0x2d: append_char('\n'); //carriage return | |
250 break; | |
251 case 0x2e: clear_buffer(bb); //ENM | |
252 break; | |
253 case 0x2f: swap_buffers(); //Swap buffers | |
254 display_buffer(fb); | |
255 clear_buffer(bb); | |
256 break; | |
257 } | |
258 break; | |
259 case 0x17: | |
260 if( c2>=0x21 && c2<=0x23) //TAB | |
261 { | |
262 break; | |
263 } | |
264 } | |
265 } | |
266 } | |
267 lastcode=data; | |
268 } | |
269 | |
32566 | 270 static void subcc_decode(const uint8_t *inputbuffer, unsigned int inputlength) |
32458 | 271 { |
272 /* The first number may denote a channel number. I don't have the | |
273 * EIA-708 standard, so it is hard to say. | |
274 * From what I could figure out so far, the general format seems to be: | |
275 * | |
276 * repeat | |
277 * | |
278 * 0xfe starts 2 byte sequence of unknown purpose. It might denote | |
32522 | 279 * field #2 in line 21 of the VBI. |
280 * Treating it identical of 0xff fixes | |
281 * http://samples.mplayerhq.hu/MPEG-VOB/ClosedCaptions/Starship_Troopers.vob | |
32458 | 282 * |
283 * 0xff starts 2 byte EIA-608 sequence, field #1 in line 21 of the VBI. | |
284 * Followed by a 3-code triplet that starts either with 0xff or | |
285 * 0xfe. In either case, the following triplet needs to be ignored | |
286 * for line 21, field 1. | |
287 * | |
288 * 0x00 is padding, followed by 2 more 0x00. | |
289 * | |
290 * 0x01 always seems to appear at the beginning, always seems to | |
291 * be followed by 0xf8, 8-bit number. | |
292 * The lower 7 bits of this 8-bit number seem to denote the | |
293 * number of code triplets that follow. | |
294 * The most significant bit denotes whether the Line 21 field 1 | |
295 * captioning information is at odd or even triplet offsets from this | |
296 * beginning triplet. 1 denotes odd offsets, 0 denotes even offsets. | |
297 * | |
298 * Most captions are encoded with odd offsets, so this is what we | |
299 * will assume. | |
300 * | |
301 * until end of packet | |
302 */ | |
32566 | 303 const uint8_t *current = inputbuffer; |
32458 | 304 unsigned int curbytes = 0; |
32566 | 305 uint8_t data1, data2; |
306 uint8_t cc_code; | |
32458 | 307 int odd_offset = 1; |
308 | |
309 while (curbytes < inputlength) { | |
32512 | 310 cc_code = current[0]; |
32458 | 311 |
312 if (inputlength - curbytes < 2) { | |
313 #ifdef LOG_DEBUG | |
314 fprintf(stderr, "Not enough data for 2-byte CC encoding\n"); | |
315 #endif | |
316 break; | |
317 } | |
318 | |
32512 | 319 data1 = current[1]; |
320 data2 = current[2]; | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
321 current += 3; curbytes += 3; |
32458 | 322 |
35029 | 323 // 0xfe/0xff are both used on plain EIA-608 CC and |
324 // for extended EIA-708 (where 0xfc/0xfd is used for | |
325 // compatibility layer). | |
326 // Allow using channel bit 2 to select between which | |
327 // ones to look in. | |
32458 | 328 switch (cc_code) { |
35029 | 329 case 0xfc: |
330 case 0xfd: | |
32458 | 331 case 0xfe: |
332 case 0xff: | |
35029 | 333 if ((cc_code & 2) == (selected_channel() & 4) >> 1) |
334 break; | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
335 odd_offset ^= 1; |
35029 | 336 if (odd_offset != (selected_channel() & 2) >> 1) |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
337 break; |
32458 | 338 /* expect EIA-608 CC1/CC2 encoding */ |
339 // FIXME check parity! | |
340 // Parity check omitted assuming we are reading from a DVD and therefore | |
341 // we should encounter no "transmission errors". | |
342 cc_decode_EIA608(data1 | (data2 << 8)); | |
343 break; | |
344 | |
35029 | 345 case 0xfa: |
32458 | 346 case 0x00: |
347 /* This seems to be just padding */ | |
348 break; | |
349 | |
350 case 0x01: | |
32520
5e062dc4a04d
Add code to allow selecting the Close Captioning channel.
reimar
parents:
32513
diff
changeset
|
351 odd_offset = data2 >> 7; |
32458 | 352 break; |
353 | |
354 default: | |
355 //#ifdef LOG_DEBUG | |
356 fprintf(stderr, "Unknown CC encoding: %x\n", cc_code); | |
357 //#endif | |
358 break; | |
359 } | |
360 } | |
361 } | |
362 | |
34756 | 363 static const uint8_t mov_cc_signature_1[] = {0, 0, 0, 0xa, 'c', 'd', 'a', 't'}; |
364 static const uint8_t mov_cc_signature_2[] = {0, 0, 0, 0xa, 'c', 'd', 't', '2'}; | |
365 /** | |
366 * MOV uses a vastly more verbose representation for EIA 608 CC data than DVDs. | |
367 * This function handles that case. | |
368 */ | |
369 static void mov_subcc_decode(const uint8_t *data, unsigned len) | |
370 { | |
371 while (len >= 10) { | |
372 int channel = -1; | |
373 if (memcmp(data, mov_cc_signature_1, sizeof(mov_cc_signature_1)) == 0) { | |
374 channel = 0; | |
375 } else if (memcmp(data, mov_cc_signature_2, sizeof(mov_cc_signature_2)) == 0) { | |
376 channel = 1; | |
377 } else { | |
378 mp_msg(MSGT_OSD, MSGL_V, "Unknown MOV 608 CC formatting\n"); | |
379 data++; | |
380 len--; | |
381 continue; | |
382 } | |
383 if (channel == selected_channel() >> 1) | |
384 cc_decode_EIA608(data[8] | (data[9] << 8)); | |
385 data += 10; | |
386 len -= 10; | |
387 } | |
388 } | |
32458 | 389 |
32566 | 390 void subcc_process_data(const uint8_t *inputdata, unsigned int len) |
32458 | 391 { |
34756 | 392 int mov_mode = len >= 10 && |
393 memcmp(inputdata, mov_cc_signature_1, sizeof(mov_cc_signature_1)) == 0; | |
32458 | 394 if(!subcc_enabled) return; |
395 if(!initialized) subcc_init(); | |
396 | |
34756 | 397 if (mov_mode) { |
398 mov_subcc_decode(inputdata, len); | |
399 return; | |
400 } | |
35028
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
401 if (len & 1) wtv_format = 0; |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
402 if (len == 2) { |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
403 // EIA-608 compatibility part. |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
404 // Full EIA-708 parts have length >= 4 (multiple of 2). |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
405 cc_decode_EIA608(inputdata[0] | (inputdata[1] << 8)); |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
406 wtv_format = 1; |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
407 } |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
408 if (wtv_format) |
dd77d5a292df
Support closed-caption format as used in wtv format.
reimar
parents:
34761
diff
changeset
|
409 return; |
32458 | 410 subcc_decode(inputdata, len); |
411 } | |
34756 | 412 |
413 /** | |
34759 | 414 * This processes CC captions in the format as found in ATSC broadcasts. |
34756 | 415 * Like DVD CC it is stored inside the MPEG-frame userdata, but with two |
416 * differences: | |
417 * 1) It starts with "GA" instead of "CC" | |
418 * 2) It _must_ be reordered in the way the decoder reorders the video frames | |
419 * The latter makes things difficult and is the reason why there is no support | |
420 * for this yet beyond this function. | |
421 */ | |
422 void subcc_process_eia708(const uint8_t *data, int len) | |
423 { | |
424 int cc_count; | |
425 if (!subcc_enabled) | |
426 return; | |
427 if (!initialized) | |
428 subcc_init(); | |
429 if (len <= 5) | |
430 return; | |
431 if (data[0] != '9' || data[1] != '4' || data[2] != 3) { | |
432 mp_msg(MSGT_OSD, MSGL_ERR, "Unknown ATSC CC type " | |
433 "0x%"PRIx8" 0x%"PRIx8" 0x%"PRIx8"\n", | |
434 data[0], data[1], data[2]); | |
435 return; | |
436 } | |
437 // process_cc_data_flag | |
438 if (!(data[3] & 0x40)) | |
439 return; | |
440 cc_count = data[3] & 0x1f; | |
441 data += 5; | |
442 len -= 5; | |
443 cc_count = FFMIN(cc_count, len / 3); | |
444 while (cc_count--) { | |
445 // EAI-608 data | |
446 if ((data[0] & 0xfe) == 0xfc && (data[0] & 1) == selected_channel() >> 1) | |
447 cc_decode_EIA608(data[1] | (data[2] << 8)); | |
448 data += 3; | |
449 } | |
450 } |