4 * Copyright (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>
6 * This file is part of MPlayer.
8 * MPlayer 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.
13 * MPlayer 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
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * Based on Attila Otvos' teletext patch, Michael Niedermayer's
24 * proof-of-concept teletext capture utility and some parts
25 * (decode_raw_line_runin,pll_add,pll_reset) of MythTV project.
26 * Code for calculating [soc:eoc] is based on aletv of Edgar Toernig.
28 * Teletext system is described in
29 * ETS 300 706 "Enhanced Teletext specification" : May 1997
30 * http://www.themm.net/~mihu/linux/saa7146/specs/ets_300706e01p.pdf
32 * Some implementation details:
33 * How to port teletext to another tvi_* driver (see tvi_v4l2.c for example):
35 * 1. Implement TVI_CONTROL_VBI_INIT (initialize driver-related vbi subsystem,
36 * start grabbing thread)
37 * input data: vbi device name.
38 * (driver should also call TV_VBI_CONTROL_START for common vbi subsystem initialization
39 * with pointer to initialized tt_stream_properties structure.
40 * After ioctl call variable will contain pointer to initialized priv_vbi_t structure.
42 * 2. After receiving next chunk of raw vbi data call TV_VBI_CONTROL_DECODE_PAGE
43 * ioctl with pointer to data buffer
44 * 3. pass all other VBI related ioctl cmds to teletext_control routine
46 * Page displaying process consist of following stages:
48 * ---grabbing stage---
49 * 0. stream/tvi_*.c: vbi_grabber(...)
50 * getting vbi data from video device
51 * ---decoding stage---
52 * 1. libmpcodecs/dec_teletext.c: decode_raw_line_runin(...) or decode_raw_line_sine(...)
53 * decode raw vbi data into sliced 45(?) bytes long packets
54 * 2. libmpcodecs/dec_teletext.c: decode_pkt0(...), decode_pkt_page(...)
55 * packets processing (header analyzing, storing complete page in cache,
56 * only raw member of tt_char is filled at this stage)
57 * 3. libmpcodecs/dec_teletext.c: decode_page(...)
58 * page decoding. filling unicode,gfx,ctl,etc members of tt_char structure
59 * with appropriate values according to teletext control chars, converting
61 * ---rendering stage---
62 * 4. libmpcodecs/dec_teletext.c: prepare_visible_page(...)
63 * processing page. adding number of just received by background process
64 * teletext page, adding current time,etc.
65 * 5. libvo/sub.c: vo_update_text_teletext(...)
66 * rendering displayable osd with text and graphics
71 * is better quality on poor signal possible ?
74 * slave command for dumping pages
75 * fix bcd<->dec as suggested my Michael
78 * wrong colors in debug dump
79 * blinking when visible page was just updated
92 // pthreads are needed for async updates from v4l(2)
93 // FIXME: try to avoid using pthread calls when running only a single
94 // thread as e.g. with DVB teletext
97 #define pthread_mutex_init(m, p)
98 #define pthread_mutex_destroy(m)
99 #define pthread_mutex_lock(m)
100 #define pthread_mutex_unlock(m)
103 #include "dec_teletext.h"
105 #include "libmpcodecs/img_format.h"
106 #include "libavutil/common.h"
107 #include "input/input.h"
108 #include "osdep/timer.h"
110 //#define DEBUG_DUMP 1
112 /// page magazine entry structure
113 typedef struct mag_s
{
119 int on
; ///< teletext on/off
120 int pagenum
; ///< seek page number
121 int subpagenum
; ///< seek subpage
122 int curr_pagenum
; ///< current page number
123 int pagenumdec
; ///< set page num with dec
125 teletext_format tformat
; ///< see teletext_format enum
126 teletext_zoom zoom
; ///< see teletext_zoom enum
127 mag_t
* mag
; ///< pages magazine (has 8 entities)
128 int primary_language
; ///< primary character set
129 int secondary_language
; ///< secondary character set
130 /// Currently displayed page (with additional info, e.g current time)
131 tt_char display_page
[VBI_ROWS
*VBI_COLUMNS
];
132 /// number of raw bytes between two subsequent encoded bits
134 /// clock run-in sequence will be searched in buffer in [soc:eoc] bytes range
137 /// minimum number of raw vbi bytes wich can be decoded into 8 data bits
139 /// maximum number of raw vbi bytes wich can be decoded into 8 data bits
148 /// vbi stream properties (buffer size,bytes per line, etc)
149 tt_stream_props
* ptsp
;
151 pthread_mutex_t buffer_mutex
;
155 unsigned char* ptt_cache_first_subpage
;
157 unsigned char initialpage
;
158 unsigned int initialsubpage
;
159 unsigned int networkid
;
160 int timeoffset
; // timeoffset=realoffset*2
161 unsigned int juliandate
;
162 unsigned int universaltime
;
163 unsigned char networkname
[21];
165 /// "page changed" flag: 0-unchanged, 1-entire page, 3-only header
170 static unsigned char fixParity
[256];
172 static const tt_char tt_space
={0x20,7,0,0,0,0,0,0,0x20};
173 static const tt_char tt_error
={'?',1,0,0,0,0,0,0,'?'}; // Red '?' on black background
174 static double si
[12];
175 static double co
[12];
177 #define VBI_FORMAT(priv) (*(priv->ptsp))
180 #define ONE_FIXP (1<<FIXP_SH)
181 #define FIXP2INT(a) ((a)>>FIXP_SH)
182 #define ANY2FIXP(a) ((int)((a)*ONE_FIXP))
184 static const unsigned char corrHamm48
[256]={
185 0x01, 0xff, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff,
186 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07,
187 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00,
188 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff,
189 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07,
190 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x07,
191 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff,
192 0x06, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07,
193 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09,
194 0x02, 0x02, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff,
195 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff,
196 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03,
197 0x04, 0xff, 0xff, 0x05, 0x04, 0x04, 0x04, 0xff,
198 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07,
199 0xff, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, 0x05,
200 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff,
201 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09,
202 0x0a, 0xff, 0xff, 0x0b, 0x0a, 0x0a, 0x0a, 0xff,
203 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff,
204 0xff, 0x0b, 0x0b, 0x0b, 0x0a, 0xff, 0xff, 0x0b,
205 0x0c, 0x0c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff,
206 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07,
207 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x0d, 0x0d,
208 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff,
209 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x09,
210 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09,
211 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09,
212 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff,
213 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09,
214 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0e, 0x0f, 0xff,
215 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff,
216 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x0e, 0xff, 0x0e };
228 // conversion table for chars 0x20-0x7F (UTF8)
229 // TODO: add another languages
230 static const unsigned int lang_chars
[LANGS
][0x60]={
233 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
234 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
235 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
236 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
237 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
238 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
239 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
240 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
241 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
242 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
243 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
244 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
247 //Cyrillic-1 (Serbian/Croatian)
248 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
249 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
250 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
251 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
252 0x0427,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
253 0x0425,0x0418,0x0408,0x041a,0x041b,0x041c,0x041d,0x041e,
254 0x041f,0x040c,0x0420,0x0421,0x0422,0x0423,0x0412,0x0403,
255 0x0409,0x040a,0x0417,0x040b,0x0416,0x0402,0x0428,0x040f,
256 0x0447,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
257 0x0445,0x0438,0x0428,0x043a,0x043b,0x043c,0x043d,0x043e,
258 0x043f,0x042c,0x0440,0x0441,0x0442,0x0443,0x0432,0x0423,
259 0x0429,0x042a,0x0437,0x042b,0x0436,0x0422,0x0448,0x042f
262 //Cyrillic-2 (Russian/Bulgarian)
263 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
264 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
265 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
266 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
267 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
268 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
269 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
270 0x042c,0x042a,0x0417,0x0428,0x042d,0x0429,0x0427,0x042b,
271 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
272 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
273 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
274 0x044c,0x044a,0x0437,0x0448,0x044d,0x0449,0x0447,0x044b
277 //Cyrillic-3 (Ukrainian)
278 0x20,0x21,0x22,0x23,0x24,0x25,0xef,0x27,
279 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
280 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
281 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
282 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
283 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
284 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
285 0x042c,0x49,0x0417,0x0428,0x042d,0x0429,0x0427,0xcf,
286 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
287 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
288 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
289 0x044c,0x69,0x0437,0x0448,0x044d,0x0449,0x0447,0xFF
293 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
294 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
295 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
296 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
297 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
298 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
299 0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
300 0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
301 0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
302 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
303 0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
304 0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,0x03cf
309 * Latin National Option Sub-Sets
310 * see Table 36 of ETS specification for details.
312 * 00: £ $ @ « ½ » ¬ # ¼ ¦ ¾ ÷ English
313 * 01: é ï à ë ê ù î # è â ô û ç French
314 * 02: # ¤ É Ä Ö Å Ü _ é ä ö å ü Swedish/Finnish/Hungarian
315 * 03: # ů č ť ž ý í ř é á ě ú š Czech/Slovak
316 * 04: # $ § Ä Ö Ü ^ _ ° ä ö ü ß German
317 * 05: ç $ ¡ á é í ó ú ¿ ü ñ è à Portuguese/Spanish
318 * 06: £ $ é ° ç » ¬ # ù à ò è ì Italian
321 static const unsigned int latin_subchars
[8][13]={
323 {0xa3,0x24,0x40,0xab,0xbd,0xbb,0xac,0x23,0xad,0xbc,0xa6,0xbe,0xf7},
325 {0xe9,0xef,0xe0,0xeb,0xea,0xf9,0xee,0x23,0xe8,0xe2,0xf4,0xfb,0xe7},
326 // Swedish/Finnish/Hungarian
327 {0x23,0xa4,0xc9,0xc4,0xd6,0xc5,0xdc,0x5f,0xe9,0xe4,0xf6,0xe5,0xfc},
329 {0x23,0x16f,0x10d,0x165,0x17e,0xfd,0xed,0x159,0xe9,0xe1,0x11b,0xfa,0x161},
331 {0x23,0x24,0xa7,0xc4,0xd6,0xdc,0x5e,0x5f,0xb0,0xe4,0xf6,0xfc,0xdf},
332 // Portuguese/Spanish
333 {0xe7,0x24,0xa1,0xe1,0xe9,0xed,0xf3,0xfa,0xbf,0xfc,0xf1,0xe8,0xe0},
335 {0xa3,0x24,0xe9,0xb0,0xe7,0xbb,0xac,0x23,0xf9,0xe0,0xf2,0xe8,0xec},
337 {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e}
341 * List of supported languages.
343 * lang_code bits for primary Language:
344 * bits 7-4 corresponds to bits 14-11 of 28 packet's first triplet
345 * bits 3-1 corresponds to bits C12-C14 of packet 0 (lang)
347 * lang_code bits for secondary Language:
348 * bits 7-5 corresponds to bits 3-1 of 28 packet's second triplet
349 * bits 4,2 corresponds to bits 18,16 of 28 packet's first triplet
350 * bits 3,1 corresponds to bits 15,17 of 28 packet's first triplet
352 * For details see Tables 32 and 33 of specification (subclause 15.2)
355 unsigned char lang_code
;
356 unsigned char charset
;
357 const char* lang_name
;
358 } const tt_languages
[]=
360 { 0x01, LATIN
, "French"},
361 { 0x02, LATIN
, "Swedish/Finnish/Hungarian"},
362 { 0x03, LATIN
, "Czech/Slovak"},
363 { 0x04, LATIN
, "German"},
364 { 0x05, LATIN
, "Portuguese/Spanish"},
365 { 0x06, LATIN
, "Italian"},
367 { 0x08, LATIN
, "Polish"},
368 { 0x09, LATIN
, "French"},
369 { 0x0a, LATIN
, "Swedish/Finnish/Hungarian"},
370 { 0x0b, LATIN
, "Czech/Slovak"},
371 { 0x0c, LATIN
, "German"},
372 { 0x0e, LATIN
, "Italian"},
374 { 0x10, LATIN
, "English"},
375 { 0x11, LATIN
, "French"},
376 { 0x12, LATIN
, "Swedish/Finnish/Hungarian"},
377 { 0x13, LATIN
, "Turkish"},
378 { 0x14, LATIN
, "German"},
379 { 0x15, LATIN
, "Portuguese/Spanish"},
380 { 0x16, LATIN
, "Italian"},
382 { 0x1d, LATIN
, "Serbian/Croatian/Slovenian (Latin)"},
384 { 0x20, CYRILLIC1
, "Serbian/Croatian (Cyrillic)"},
385 { 0x21, CYRILLIC2
, "Russian, Bulgarian"},
386 { 0x22, LATIN
, "Estonian"},
387 { 0x23, LATIN
, "Czech/Slovak"},
388 { 0x24, LATIN
, "German"},
389 { 0x25, CYRILLIC3
, "Ukrainian"},
390 { 0x26, LATIN
, "Lettish/Lithuanian"},
392 { 0x33, LATIN
, "Turkish"},
393 { 0x37, GREEK
, "Greek"},
395 { 0x40, LATIN
, "English"},
396 { 0x41, LATIN
, "French"},
397 // { 0x47, ARABIC, "Arabic"},
399 // { 0x55, HEBREW, "Hebrew"},
400 // { 0x57, ARABIC, "Arabic"},
402 { 0x00, LATIN
, "English"},
406 * \brief 24/18 Hamming code decoding
407 * \param data bytes with hamming code (array must be at least 3 bytes long)
408 * \return -1 if multiple bit error occured, D1-DI data bits - otherwise
410 * \note Bits must be correctly ordered, that is for 24/18 (lowest bit first)
411 * P1 P2 D1 P3 D2 D3 D4 P4 D5 D6 D7 D8 D9 DA DB P5 DC DD DE DF DG DH DI P6
413 static int corrHamm24(unsigned char *data
){
414 unsigned char syndrom
=0;
415 int cw
=data
[0] | (data
[1]<<8) | (data
[2]<<16);
419 syndrom
^=((cw
>>i
)&1)*(i
+33);
421 syndrom
^=(cw
>>11)&32;
424 if(syndrom
< 32 || syndrom
> 55)
426 cw
^= 1<<((syndrom
&31)-1);
436 * \brief converts language bits to charset index
437 * \param lang language bits
438 * \return charset index in lang_chars array
440 static int lang2charset (int lang
){
442 for(i
=0;tt_languages
[i
].lang_code
;i
++)
443 if(tt_languages
[i
].lang_code
==lang
)
446 return tt_languages
[i
].charset
;
450 * \brief convert chars from curent teletext codepage into MPlayer charset
451 * \param p raw teletext char to decode
452 * \param charset index on lang_chars
453 * \param lang index in substitution array (latin charset only)
457 * routine will analyze raw member of given tt_char structure and
458 * fill unicode member of the same struct with appropriate utf8 code.
460 static unsigned int conv2uni(unsigned int p
,int charset
,int lang
)
463 if(p
<0x80 && p
>=0x20){
466 if (p
>=0x23 && p
<=0x24){
467 return latin_subchars
[lang
][p
-0x23];
469 return latin_subchars
[lang
][2];
470 }else if (p
>=0x5b && p
<=0x60){
471 return latin_subchars
[lang
][p
-0x5b+3];
472 }else if (p
>=0x7b && p
<=0x7e){
473 return latin_subchars
[lang
][p
-0x7b+9];
476 return lang_chars
[charset
][p
-0x20];
481 static void init_vbi_consts(priv_vbi_t
* priv
){
484 for(i
=0; i
<256; i
++){
489 fixParity
[i
]= i
^ (j
&0x80) ^ 0x80;
492 for(i
=0,ang
=0; i
<12; i
++,ang
+=M_PI
/priv
->bpb
){
497 priv
->bpb
=(priv
->ptsp
->sampling_rate
/6937500.0)*ONE_FIXP
+0.5;
498 priv
->soc
=FFMAX(9.2e-6*priv
->ptsp
->sampling_rate
-priv
->ptsp
->offset
, 0);
499 priv
->eoc
=FFMIN(12.9e-6*priv
->ptsp
->sampling_rate
-priv
->ptsp
->offset
,
500 priv
->ptsp
->samples_per_line
-43*8*priv
->bpb
/ONE_FIXP
);
501 if (priv
->eoc
- priv
->soc
<16*priv
->bpb
/ONE_FIXP
){ // invalid [soc:eoc]
505 priv
->bp8bl
=0.97*8*priv
->bpb
/ONE_FIXP
; // -3% tolerance
506 priv
->bp8bh
=1.03*8*priv
->bpb
/ONE_FIXP
; // +3% tolerance
509 * \brief calculate increased/decreased by given value page number
510 * \param curr current page number in hexadecimal for
511 * \param direction decimal value (can be negative) to add to value
513 * \return new page number in hexadecimal form
515 * VBI page numbers are represented in special hexadecimal form, e.g.
516 * page with number 123 (as seen by user) internally has number 0x123.
517 * and equation 0x123+8 should be equal to 0x131 instead of regular 0x12b.
520 * Page numbers 0xYYY (where Y is not belongs to (0..9).
521 * Page number belongs to [0x000,0x799] or [0x100:0x899] (first 0 can be
524 static int steppage(int p
, int direction
, int skip_hidden
)
527 p
=(p
&15)+((p
>>4)&15)*10+(p
>>8)*100;
531 p
=(p
%10)+((p
/10)%10)*16+(p
/100)*256;
538 ------------------------------------------------------------------
540 ------------------------------------------------------------------
544 * \brief add/update entry in cache
545 * \param priv private data structure
546 * \param pg page to store in cache
547 * \param line line to update (value below 0 means update entire page)
549 static void put_to_cache(priv_vbi_t
* priv
,tt_page
* pg
,int line
){
550 tt_page
* pgc
; //page in cache
555 count
=VBI_ROWS
*VBI_COLUMNS
;
556 }else if(line
<VBI_ROWS
){
558 count
=(line
+1)*VBI_COLUMNS
;
562 pthread_mutex_lock(&(priv
->buffer_mutex
));
564 if(!priv
->ptt_cache
[pg
->pagenum
]){
565 priv
->ptt_cache
[pg
->pagenum
]=calloc(1,sizeof(tt_page
));
566 pgc
=priv
->ptt_cache
[pg
->pagenum
];
568 pgc
=priv
->ptt_cache
[pg
->pagenum
];
569 while(pgc
->next_subpage
&& pgc
->subpagenum
!=pg
->subpagenum
)
570 pgc
=pgc
->next_subpage
;
572 if(pgc
->subpagenum
!=pg
->subpagenum
){
573 pgc
->next_subpage
=calloc(1,sizeof(tt_page
));
574 pgc
=pgc
->next_subpage
;
577 pgc
->pagenum
=pg
->pagenum
;
578 pgc
->subpagenum
=pg
->subpagenum
;
579 pgc
->primary_lang
=pg
->primary_lang
;
580 pgc
->secondary_lang
=pg
->secondary_lang
;
581 pgc
->flags
=pg
->flags
;
583 pgc
->links
[j
]=pg
->links
[j
];
584 //instead of copying entire page into cache, copy only undamaged
587 if(!(pg
->raw
[i
]&0x80))
588 pgc
->raw
[i
]=pg
->raw
[i
];
590 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"char error. pg:%x, c[%d]=0x%x\n",
591 pg
->pagenum
,i
,pg
->raw
[i
]);
594 pthread_mutex_unlock(&(priv
->buffer_mutex
));
598 * \brief get any subpage number of given page
599 * \param priv private data structure
600 * \param pagenum page number to search subpages in
602 * \return subpage number of first found subpage which belongs to
605 * \note page itself is subpage too (and usually has subpage number 0)
607 static inline int get_subpagenum_from_cache(priv_vbi_t
* priv
, int pagenum
){
608 if (!priv
->ptt_cache
[pagenum
])
611 return priv
->ptt_cache
[pagenum
]->subpagenum
;
615 * \brief get page from cache by it page and subpage number
616 * \param priv private data structure
617 * \param pagenum page number
618 * \param subpagenum subpage number
620 * \return pointer to tt_page structure if requested page is found
623 static inline tt_page
* get_from_cache(priv_vbi_t
* priv
, int pagenum
,int subpagenum
){
624 tt_page
* tp
=priv
->ptt_cache
[pagenum
];
626 while(tp
&& tp
->subpagenum
!=subpagenum
)
632 * \brief clears cache
633 * \param priv private data structure
635 * Deletes all tt_page structures from cache and frees allocated memory.
636 * Only zero-filled array of pointers remains in memory
638 static void clear_cache(priv_vbi_t
* priv
){
643 Skip next 5 buffers to avoid mixing teletext pages from different
644 channels during channel switch
647 for(i
=0;i
<VBI_MAX_PAGES
;i
++){
648 while(priv
->ptt_cache
[i
]){
649 tp
=priv
->ptt_cache
[i
];
650 priv
->ptt_cache
[i
]=tp
->next_subpage
;
654 priv
->initialsubpage
=priv
->networkid
=0;
656 priv
->juliandate
=priv
->universaltime
=0;
657 memset(priv
->networkname
,0,21);
661 * \brief cache initialization
662 * \param priv private data structure
664 * \note Has to be called before any cache operations!
666 static void init_cache(priv_vbi_t
* priv
){
667 priv
->ptt_cache
=calloc(VBI_MAX_PAGES
,sizeof(tt_page
*));
671 * \brief destroys cache
672 * \param priv private data structure
674 * Frees all memory allocated for cache (including array of pointers).
675 * It is safe to call this routine multiple times
677 static void destroy_cache(priv_vbi_t
* priv
){
680 free(priv
->ptt_cache
);
681 priv
->ptt_cache
=NULL
;
686 ------------------------------------------------------------------
688 ------------------------------------------------------------------
691 * \brief converts raw teletext page into useful format (1st rendering stage)
692 * \param pg page to decode
693 * \param raw raw data to decode page from
694 * \param primary_lang primary language code
695 * \param secondary_lang secondary language code
697 * Routine fills tt_char structure of each teletext_page character with proper
698 * info about foreground and background colors, character
699 * type (graphics/control/text).
701 static void decode_page(tt_char
* p
,unsigned char* raw
,int primary_lang
,int secondary_lang
,int flags
)
704 int prim_charset
=lang2charset(primary_lang
);
705 int sec_charset
=lang2charset(secondary_lang
);
707 for(row
=0;row
<VBI_ROWS
;row
++) {
718 tt_char tt_held
=tt_space
;
719 for(col
=0;col
<VBI_COLUMNS
;col
++){
720 int i
=row
*VBI_COLUMNS
+col
;
723 if(c
&0x80){ //damaged char
727 if((flags
&TT_PGFL_SUBTITLE
) || (flags
&TT_PGFL_NEWFLASH
))
731 p
[i
].gfx
=gfx
?(separated
?2:1):0;
733 p
[i
].ctl
=(c
&0x60)==0?1:0;
738 if ((c
&0x60)==0){ //control chars
739 if(c
>=0x08 && c
<=0x09){//Flash/Steady
746 }else if(c
>=0x0a && c
<=0x0b){
748 }else if(c
>=0x0c && c
<=0x0f){
749 }else if (c
<=0x17){ //colors
756 }else if (c
<=0x1a){ //Contiguous/Separated gfx
759 prim_lang
=!prim_lang
;
761 bg_color
=(c
&1)?fg_color
:0;
763 }else{ //Hold/Release Graphics
772 p
[i
].unicode
=p
[i
].gfx
?0:' ';
781 if (p
[i
].unicode
>0x3f) p
[i
].unicode
-=0x20;
785 p
[i
].unicode
=conv2uni(c
,prim_charset
,primary_lang
&7);
787 p
[i
].unicode
=conv2uni(c
,sec_charset
,secondary_lang
&7);
797 * \brief prepares current page for displaying
798 * \param priv_vbi private data structure
800 * Routine adds some useful info (time and page number of page, grabbed by
801 * background thread to top line of current page). Displays "No teletext"
802 * string if no vbi data available.
804 #define PRINT_HEX(dp,i,h) dp[i].unicode=((h)&0xf)>9?'A'+((h)&0xf)-10:'0'+((h)&0xf)
805 static void prepare_visible_page(priv_vbi_t
* priv
){
806 tt_page
*pg
,*curr_pg
;
810 pthread_mutex_lock(&(priv
->buffer_mutex
));
811 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"dec_teletext: prepare_visible_page pg:0x%x, sub:0x%x\n",
812 priv
->pagenum
,priv
->subpagenum
);
813 if(priv
->subpagenum
==0x3f7f) //no page yet
814 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
816 pg
=get_from_cache(priv
,priv
->pagenum
,priv
->subpagenum
);
817 mp_dbg(MSGT_TELETEXT
,MSGL_DBG3
,"dec_teletext: prepare_vibible_page2 pg:0x%x, sub:0x%x\n",
818 priv
->pagenum
,priv
->subpagenum
);
820 curr_pg
=get_from_cache(priv
,priv
->curr_pagenum
,
821 get_subpagenum_from_cache(priv
,priv
->curr_pagenum
));
822 if (!pg
&& !curr_pg
){
824 for(i
=0;i
<VBI_COLUMNS
&& *p
;i
++){
825 GET_UTF8(priv
->display_page
[i
].unicode
,*p
++,break;);
827 for(;i
<VBI_ROWS
*VBI_COLUMNS
;i
++)
828 priv
->display_page
[i
]=tt_space
;
829 pthread_mutex_unlock(&(priv
->buffer_mutex
));
833 if (!pg
|| !pg
->active
){
834 for(i
=0;i
<VBI_ROWS
*VBI_COLUMNS
;i
++){
835 priv
->display_page
[i
]=tt_space
;
838 decode_page(priv
->display_page
,pg
->raw
,pg
->primary_lang
,pg
->secondary_lang
,pg
->flags
);
839 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"page #%x was decoded!\n",pg
->pagenum
);
842 PRINT_HEX(priv
->display_page
,0,(priv
->curr_pagenum
&0x700)?priv
->curr_pagenum
>>8:8);
843 PRINT_HEX(priv
->display_page
,1,priv
->curr_pagenum
>>4);
844 PRINT_HEX(priv
->display_page
,2,priv
->curr_pagenum
);
845 priv
->display_page
[3].unicode
=' ';
846 priv
->display_page
[4].unicode
=' ';
847 switch(priv
->pagenumdec
>>12){
849 priv
->display_page
[5].unicode
='_';
850 priv
->display_page
[6].unicode
='_';
851 PRINT_HEX(priv
->display_page
,7,priv
->pagenumdec
);
854 priv
->display_page
[5].unicode
='_';
855 PRINT_HEX(priv
->display_page
,6,priv
->pagenumdec
>>4);
856 PRINT_HEX(priv
->display_page
,7,priv
->pagenumdec
);
859 PRINT_HEX(priv
->display_page
,5,(priv
->pagenum
&0x700)?priv
->pagenum
>>8:8);
860 PRINT_HEX(priv
->display_page
,6,priv
->pagenum
>>4);
861 PRINT_HEX(priv
->display_page
,7,priv
->pagenum
);
863 if(priv
->subpagenum
!=0x3f7f){
864 priv
->display_page
[8].unicode
='.';
865 PRINT_HEX(priv
->display_page
,9,priv
->subpagenum
>>4);
866 PRINT_HEX(priv
->display_page
,10,priv
->subpagenum
);
868 priv
->display_page
[8].unicode
=' ';
869 priv
->display_page
[9].unicode
=' ';
870 priv
->display_page
[10].unicode
=' ';
872 priv
->display_page
[11].unicode
=' ';
873 for(i
=VBI_COLUMNS
;i
>VBI_TIME_LINEPOS
||
874 ((curr_pg
->raw
[i
]&0x60) && curr_pg
->raw
[i
]!=0x20 && i
>11);
876 if(curr_pg
->raw
[i
]&0x60)
877 priv
->display_page
[i
].unicode
=curr_pg
->raw
[i
];
879 priv
->display_page
[i
].unicode
=' ';
880 pthread_mutex_unlock(&(priv
->buffer_mutex
));
883 ------------------------------------------------------------------
885 ------------------------------------------------------------------
889 * \brief renders teletext page into given file
890 * \param pt page to render
891 * \param f opened file descriptor
892 * \param pagenum which page to render
893 * \param colored use colors not implemented yet)
895 * Text will be UTF8 encoded
897 static void render2text(tt_page
* pt
,FILE* f
,int colored
){
900 unsigned char buf
[8];
903 tt_char dp
[VBI_ROWS
*VBI_COLUMNS
];
909 fprintf(f
,"+========================================+\n");
910 fprintf(f
,"| lang:%d pagenum:0x%x subpagenum:%d flags:0x%x|\n",
915 fprintf(f
,"+----------------------------------------+\n");
917 decode_page(dp
,pt
->raw
,pt
->primary_lang
,pt
->secondary_lang
,pt
->flags
);
918 for(i
=0;i
<VBI_ROWS
;i
++){
920 if(colored
) fprintf(f
,"\033[40m");
921 for(j
=0;j
<VBI_COLUMNS
;j
++)
923 u
=dp
[i
*VBI_COLUMNS
+j
].unicode
;
924 if(dp
[i
*VBI_COLUMNS
+j
].fg
<= 7)
925 c1
=30+dp
[i
*VBI_COLUMNS
+j
].fg
;
928 if(dp
[i
*VBI_COLUMNS
+j
].bg
<= 7)
929 b1
=40+dp
[i
*VBI_COLUMNS
+j
].bg
;
932 if (b1
!=bkg
&& colored
){
933 fprintf(f
,"\033[%dm",b1
);
936 if(c1
!=color
&& colored
){
937 fprintf(f
,"\033[%dm",c1
);
940 if(dp
[i
*VBI_COLUMNS
+j
].gfx
){
944 PUT_UTF8(u
,tmp
,if(pos
<7) buf
[pos
++]=tmp
;);
950 if (colored
) fprintf(f
,"\033[0m");
955 fprintf(f
,"+====================raw=================+\n");
956 for(i
=0;i
<VBI_ROWS
;i
++){
957 for(j
=0;j
<VBI_COLUMNS
;j
++)
958 fprintf(f
,"%02x ",dp
[i
*VBI_COLUMNS
+j
].raw
);
961 fprintf(f
,"+====================lng=================+\n");
962 for(i
=0;i
<VBI_ROWS
;i
++){
963 for(j
=0;j
<VBI_COLUMNS
;j
++)
964 fprintf(f
,"%02x ",dp
[i
*VBI_COLUMNS
+j
].lng
);
967 fprintf(f
,"+========================================+\n");
971 * \brief dump page into pgXXX.txt file in vurrent directory
972 * \param pt page to dump
974 * \note XXX in filename is page number
975 * \note use only for debug purposes
977 static void dump_page(tt_page
* pt
)
981 snprintf(name
,99,"pg%x.txt",pt
->pagenum
);
990 * \brief checks whether page is ready and copies it into cache array if so
991 * \param priv private data structure
992 * \param magAddr page's magazine address (0-7)
994 static void store_in_cache(priv_vbi_t
* priv
, int magAddr
, int line
){
995 mp_msg(MSGT_TELETEXT
,MSGL_DBG2
,"store_in_cache(%d): pagenum:%x\n",
996 priv
->mag
[magAddr
].order
,
997 priv
->mag
[magAddr
].pt
->pagenum
);
999 put_to_cache(priv
,priv
->mag
[magAddr
].pt
,line
);
1000 priv
->curr_pagenum
=priv
->mag
[magAddr
].pt
->pagenum
;
1003 dump_page(get_from_cache(priv
,
1004 priv
->mag
[magAddr
].pt
->pagenum
,
1005 priv
->mag
[magAddr
].pt
->subpagenum
));
1011 ------------------------------------------------------------------
1013 ------------------------------------------------------------------
1015 #define PLL_SAMPLES 4
1017 #define PLL_ADJUST 4
1020 * \brief adjust current phase for better signal decoding
1021 * \param n count of bytes processed (?)
1022 * \param err count of error bytes (?)
1024 * \remarks code was got from MythTV project
1026 static void pll_add(priv_vbi_t
* priv
,int n
,int err
){
1029 if(err
>PLL_ERROR
*2/3)
1033 if(priv
->pll_cnt
<PLL_SAMPLES
)
1035 if(priv
->pll_err
>PLL_ERROR
)
1037 if(priv
->pll_err
>priv
->pll_lerr
)
1038 priv
->pll_dir
= -priv
->pll_dir
;
1039 priv
->pll_lerr
=priv
->pll_err
;
1040 priv
->pll_adj
+=priv
->pll_dir
;
1041 if (priv
->pll_adj
<-PLL_ADJUST
|| priv
->pll_adj
>PLL_ADJUST
)
1047 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"vbi: pll_adj=%2d\n",priv
->pll_adj
);
1054 * \brief reset error correction
1055 * \param priv private data structure
1056 * \param fine_tune shift value for adjusting
1058 * \remarks code was got from MythTV project
1060 static void pll_reset(priv_vbi_t
* priv
,int fine_tune
){
1061 priv
->pll_fixed
=fine_tune
>= -PLL_ADJUST
&& fine_tune
<= PLL_ADJUST
;
1069 priv
->pll_adj
=fine_tune
;
1071 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"pll_reset (fixed@%2d)\n",priv
->pll_adj
);
1073 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"pll_reset (auto)\n");
1077 * \brief decode packet 0 (teletext page header)
1078 * \param priv private data structure
1079 * \param data raw teletext data (with not applied hamm correction yet)
1080 * \param magAddr teletext page's magazine address
1083 * data buffer was shifted by 6 and now contains:
1086 * 6..7 control codes
1087 * 8..39 display data
1089 * only first 8 bytes protected by Hamm 8/4 code
1091 static int decode_pkt0(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
)
1096 if (magAddr
<0 || magAddr
>7)
1099 d
[i
]= corrHamm48
[ data
[i
] ];
1103 free(priv
->mag
[magAddr
].pt
);
1104 priv
->mag
[magAddr
].pt
=NULL
;
1105 priv
->mag
[magAddr
].order
=0;
1109 if (!priv
->mag
[magAddr
].pt
)
1110 priv
->mag
[magAddr
].pt
= malloc(sizeof(tt_page
));
1112 if(priv
->primary_language
)
1113 priv
->mag
[magAddr
].pt
->primary_lang
=priv
->primary_language
;
1115 priv
->mag
[magAddr
].pt
->primary_lang
= (d
[7]>>1)&7;
1116 priv
->mag
[magAddr
].pt
->secondary_lang
=priv
->secondary_language
;
1117 priv
->mag
[magAddr
].pt
->subpagenum
=(d
[2]|(d
[3]<<4)|(d
[4]<<8)|(d
[5]<<12))&0x3f7f;
1118 priv
->mag
[magAddr
].pt
->pagenum
=(magAddr
<<8) | d
[0] | (d
[1]<<4);
1119 priv
->mag
[magAddr
].pt
->flags
=((d
[7]&1)<<7) | ((d
[3]&8)<<3) | ((d
[5]&12)<<2) | d
[6];
1121 memset(priv
->mag
[magAddr
].pt
->raw
, 0x00, VBI_COLUMNS
*VBI_ROWS
);
1122 priv
->mag
[magAddr
].order
=0;
1125 priv
->mag
[magAddr
].pt
->raw
[i
]=0x20;
1128 for(i
=8; i
<VBI_COLUMNS
; i
++){
1129 data
[i
]= fixParity
[data
[i
]];
1130 priv
->mag
[magAddr
].pt
->raw
[i
]=data
[i
];
1131 if(data
[i
]&0x80) //Error
1133 pll_add(priv
,1,err
);
1136 store_in_cache(priv
,magAddr
,0);
1142 * \brief decode teletext 8/30 Format 1 packet
1143 * \param priv private data structure
1144 * \param data raw teletext data (with not applied hamm correction yet)
1145 * \param magAddr teletext page's magazine address
1149 * 0 designation code
1151 * 3..6 initial subpage & magazine address
1154 * 10..12 julian date
1155 * 13..15 universal time
1156 * 20..40 network name
1158 * First 7 bytes are protected by Hamm 8/4 code.
1159 * Bytes 20-40 has odd parity check.
1161 * See subcaluse 9.8.1 of specification for details
1163 static int decode_pkt30(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
)
1169 d
[i
]= corrHamm48
[ data
[i
] ];
1178 for(i
=20; i
<40; i
++){
1179 data
[i
]= fixParity
[data
[i
]];
1180 if(data
[i
]&0x80)//Unrecoverable error
1182 pll_add(priv
,1,err
);
1186 if (d
[0]&0xe) //This is not 8/30 Format 1 packet
1189 priv
->initialpage
=d
[1] | d
[2]<<4 | (d
[6]&0xc)<<7 | (d
[4]&1)<<8;
1190 priv
->initialsubpage
=d
[3] | d
[4]<<4 | d
[5]<<8 | d
[6]<<12;
1191 priv
->networkid
=data
[7]<<8 | data
[8];
1193 priv
->timeoffset
=(data
[9]>>1)&0xf;
1195 priv
->timeoffset
=-priv
->timeoffset
;
1197 priv
->juliandate
=(data
[10]&0xf)<<16 | data
[11]<<8 | data
[12];
1198 priv
->juliandate
-=0x11111;
1200 priv
->universaltime
=data
[13]<<16 | data
[14]<<8 | data
[15];
1201 priv
->universaltime
-=0x111111;
1203 snprintf(priv
->networkname
,21,"%s",data
+20);
1209 * \brief decode packets 1..24 (teletext page header)
1210 * \param priv private data structure
1211 * \param data raw teletext data
1212 * \param magAddr teletext page's magazine address
1213 * \param rowAddr teletext page's row number
1216 * data buffer was shifted by 6 and now contains 40 bytes of display data:
1217 * this type of packet is not proptected by Hamm 8/4 code
1219 static void decode_pkt_page(priv_vbi_t
* priv
,unsigned char*data
,int magAddr
,int rowAddr
){
1221 if (!priv
->mag
[magAddr
].pt
)
1224 priv
->mag
[magAddr
].order
=rowAddr
;
1227 for(i
=0; i
<VBI_COLUMNS
; i
++){
1228 data
[i
]= fixParity
[ data
[i
] ];
1229 priv
->mag
[magAddr
].pt
->raw
[i
+rowAddr
*VBI_COLUMNS
]=data
[i
];
1230 if( data
[i
]&0x80) //HammError
1233 pll_add(priv
,1,err
);
1235 store_in_cache(priv
,magAddr
,rowAddr
);
1239 * \brief decode packets 27 (teletext links)
1240 * \param priv private data structure
1241 * \param data raw teletext data
1242 * \param magAddr teletext page's magazine address
1244 static int decode_pkt27(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
){
1247 if (!priv
->mag
[magAddr
].pt
)
1250 if ((data
[i
] = corrHamm48
[ data
[i
] ]) & 0x80){
1256 Not a X/27/0 Format 1 packet or
1257 flag "show links on row 24" is not set.
1259 if (data
[0] || !(data
[37] & 8))
1262 hpg
= (magAddr
<<8) ^ ((data
[4+i
*6]&0x8)<<5 | (data
[6+i
*6]&0xc)<<7);
1263 if (!hpg
) hpg
=0x800;
1264 priv
->mag
[magAddr
].pt
->links
[i
].pagenum
= (data
[1+i
*6] & 0xf) |
1265 ((data
[2+i
*6] & 0xf) << 4) | hpg
;
1266 priv
->mag
[magAddr
].pt
->links
[i
].subpagenum
= ((data
[3+i
*6] & 0xf) |
1267 (data
[4+i
*6] & 0xf) << 4 | (data
[5+i
*6] & 0xf) << 8 |
1268 (data
[6+i
*6] & 0xf) << 12) & 0x3f7f;
1270 put_to_cache(priv
,priv
->mag
[magAddr
].pt
,-1);
1275 * \brief Decode teletext X/28/0 Format 1 packet
1276 * \param priv private data structure
1277 * \param data raw teletext data
1279 * Primary G0 charset is transmitted in bits 14-8 of Triplet 1
1280 * See Table 32 of specification for details.
1282 * Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and
1283 * bits 18-15 of Triplet 1
1284 * See Table 33 of specification for details.
1287 static void decode_pkt28(priv_vbi_t
* priv
,unsigned char*data
){
1290 d
=corrHamm48
[ data
[0] ];
1291 if(d
) return; //this is not X/28/0 Format 1 packet or error occured
1293 t1
=corrHamm24(data
+1);
1294 t2
=corrHamm24(data
+4);
1300 priv
->primary_language
=(t1
>>7)&0x7f;
1301 priv
->secondary_language
=((t2
<<4) | (t1
>>14))&0x7f;
1302 if (priv
->secondary_language
==0x7f)
1303 //No secondary language required
1304 priv
->secondary_language
=priv
->primary_language
;
1305 else // Swapping bits 1 and 3
1306 priv
->secondary_language
=(priv
->secondary_language
&0x7a) |
1307 (priv
->secondary_language
&4)>>2 |
1308 (priv
->secondary_language
&1)<<2;
1310 mp_msg(MSGT_TELETEXT
,MSGL_DBG2
,"pkt28: language: primary=%02x secondary=0x%02x\n",
1311 priv
->primary_language
,priv
->secondary_language
);
1315 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1316 * \param priv private data structure
1317 * \param buf raw vbi data (one line of frame)
1318 * \param data output buffer for decoded bytes (at least 45 bytes long)
1320 * Used XawTV's algorithm. Signal phase is calculated with help of starting clock
1321 * run-in sequence (min/max values and bit distance values are calculated)
1323 static int decode_raw_line_runin(priv_vbi_t
* priv
,unsigned char* buf
,unsigned char* data
){
1324 const int magic
= 0x27; // reversed 1110010
1325 int dt
[256],hi
[6],lo
[6];
1329 unsigned char min
,max
;
1330 int thr
=0; //threshold
1336 for(i
=soc
;i
<eoc
;i
++)
1337 dt
[i
]=buf
[i
+priv
->bpb
/ONE_FIXP
]-buf
[i
]; // amplifies the edges best.
1339 for (i
=eoc
; i
<eoc
+16; i
+=2)
1340 dt
[i
]=100, dt
[i
+1]=-100;
1342 /* find 6 rising and falling edges */
1343 for (i
=soc
, x
=0; x
<6; ++x
)
1354 return 0; // not enough periods found
1356 i
=hi
[5]-hi
[1]; // length of 4 periods (8 bits)
1357 if (i
<priv
->bp8bl
|| i
>priv
->bp8bh
)
1359 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"vbi: wrong freq %d (%d,%d)\n",
1360 i
,priv
->bp8bl
,priv
->bp8bh
);
1361 return 0; // bad frequency
1363 /* AGC and sync-reference */
1364 min
=255, max
=0, sync
=0;
1365 for (i
=hi
[4]; i
<hi
[5]; ++i
)
1368 for (i
=lo
[4]; i
<lo
[5]; ++i
)
1374 // searching for '11'
1375 for(i
=priv
->pll_adj
*priv
->bpb
/10;i
<16*priv
->bpb
;i
+=priv
->bpb
)
1376 if(buf
[FIXP2INT(i
)]>thr
&& buf
[FIXP2INT(i
+priv
->bpb
)]>thr
)
1379 for(decoded
=1; decoded
<= (VBI_COLUMNS
+3)<<3;decoded
++){
1381 if(buf
[FIXP2INT(i
)]>thr
) r
|=0x80;
1382 if(!(decoded
& 0x07)){
1383 data
[(decoded
>>3) - 1]=r
;
1389 return 0; //magic not found
1395 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"thr:%d sync:%d ",thr
,sync
);
1401 //See comment in vbi_decode for a reason of commenting out this routine.
1404 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1405 * \param priv private data structure
1406 * \param buf raw vbi data (one line of frame)
1407 * \param data output buffer for decoded bytes (at least 45 bytes long)
1409 * Used Michael Niedermayer's algorithm.
1410 * Signal phase is calculated using correlation between given samples data and
1413 static int decode_raw_line_sine(priv_vbi_t
* priv
,unsigned char* buf
,unsigned char* data
){
1414 int i
,x
,r
,amp
,xFixp
;
1416 double sin_sum
=0, cos_sum
=0;
1418 for(x
=0; x
< FIXP2INT(10*priv
->bpb
); x
++)
1421 avg
/=FIXP2INT(10*priv
->bpb
);
1423 for(x
=0; x
<12; x
++){
1425 sin_sum
+= si
[x
]*(amp
-avg
);
1426 cos_sum
+= co
[x
]*(amp
-avg
);
1428 //this is always zero. Why ?
1429 xFixp
= atan(sin_sum
/cos_sum
)*priv
->bpb
/M_PI
;
1431 //Without this line the result is full of errors
1432 //and routine is unable to find magic sequence
1433 buf
+=FIXP2INT(10*priv
->bpb
);
1436 for(x
=FIXP2INT(xFixp
);x
<70;x
=FIXP2INT(xFixp
)){
1438 if(buf
[x
]>avg
) r
|=1;
1440 if(r
==0xAAE4) break;
1443 //this is not teletext
1444 if (r
!=0xaae4) return 0;
1446 //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes
1447 for(i
=1; i
<=(42<<3); i
++){
1465 * \brief decodes one vbi line from one video frame
1466 * \param priv private data structure
1467 * \param data buffer with raw vbi data in it
1469 static void vbi_decode_line(priv_vbi_t
*priv
, unsigned char *data
) {
1470 int d0
,d1
,magAddr
,pkt
;
1472 d0
= corrHamm48
[ data
[0] ];
1473 d1
= corrHamm48
[ data
[1] ];
1475 if(d0
&0x80 || d1
&0x80){
1477 mp_msg(MSGT_TELETEXT
,MSGL_V
,"vbi_decode_line: HammErr\n");
1482 pkt
=(d0
>>3)|(d1
<<1);
1483 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"vbi_decode_line:%x %x (mag:%x, pkt:%d)\n",
1486 decode_pkt0(priv
,data
+2,magAddr
); //skip MRGA
1487 }else if(pkt
>0 && pkt
<VBI_ROWS
){
1488 if(!priv
->mag
[magAddr
].pt
)
1490 decode_pkt_page(priv
,data
+2,magAddr
,pkt
);//skip MRGA
1492 decode_pkt27(priv
,data
+2,magAddr
);
1494 decode_pkt28(priv
,data
+2);
1496 decode_pkt30(priv
,data
+2,magAddr
);
1498 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"unsupported packet:%d\n",pkt
);
1503 * \brief decodes all vbi lines from one video frame
1504 * \param priv private data structure
1505 * \param buf buffer with raw vbi data in it
1507 * \note buffer size have to be at least priv->ptsp->bufsize bytes
1509 static void vbi_decode(priv_vbi_t
* priv
,unsigned char*buf
){
1510 unsigned char data
[64];
1511 unsigned char* linep
;
1513 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"vbi: vbi_decode\n");
1514 for(linep
=buf
; !priv
->cache_reset
&& linep
<buf
+priv
->ptsp
->bufsize
; linep
+=priv
->ptsp
->samples_per_line
,i
++){
1517 This routine is alternative implementation of raw VBI data decoding.
1518 Unfortunately, it detects only about 20% of incoming data,
1519 but Michael says that this algorithm is better, and he wants to fix it.
1521 if(decode_raw_line_sine(priv
,linep
,data
)<=0){
1523 if(decode_raw_line_runin(priv
,linep
,data
)<=0){
1524 continue; //this is not valid teletext line
1526 vbi_decode_line(priv
, data
);
1528 if (priv
->cache_reset
){
1529 pthread_mutex_lock(&(priv
->buffer_mutex
));
1530 priv
->cache_reset
--;
1531 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1537 * \brief decodes a vbi line from a DVB teletext stream
1538 * \param priv private data structure
1539 * \param buf buffer with DVB teletext data
1541 * No locking is done since this is only called from a single-threaded context
1543 static void vbi_decode_dvb(priv_vbi_t
*priv
, const uint8_t buf
[44]){
1547 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
, "vbi: vbi_decode_dvb\n");
1549 /* Reverse bit order, skipping the first two bytes (field parity, line
1550 offset and framing code). */
1551 for (i
= 0; i
< sizeof(data
); i
++)
1552 data
[i
] = av_reverse
[buf
[2 + i
]];
1554 vbi_decode_line(priv
, data
);
1555 if (priv
->cache_reset
)
1556 priv
->cache_reset
--;
1560 ---------------------------------------------------------------------------------
1562 ---------------------------------------------------------------------------------
1566 * \brief toggles teletext page displaying format
1567 * \param priv_vbi private data structure
1568 * \param flag new format
1570 * VBI_CONTROL_TRUE is success,
1571 * VBI_CONTROL_FALSE otherwise
1576 * 2 - opaque with black foreground color (only in bw mode)
1577 * 3 - transparent with black foreground color (only in bw mode)
1579 static int teletext_set_format(priv_vbi_t
* priv
, teletext_format flag
)
1583 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"teletext_set_format_is called. mode:%d\n",flag
);
1584 pthread_mutex_lock(&(priv
->buffer_mutex
));
1590 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1591 return VBI_CONTROL_TRUE
;
1595 * \brief append just entered digit to editing page number
1596 * \param priv_vbi private data structure
1597 * \param dec decimal digit to append
1600 * '0'..'9' append digit
1601 * '-' remove last digit (backspace emulation)
1603 * This routine allows user to jump to arbitrary page.
1604 * It implements simple page number editing algorithm.
1606 * Subsystem can be on one of two modes: normal and page number edit mode.
1607 * Zero value of priv->pagenumdec means normal mode
1608 * Non-zero value means page number edit mode and equals to packed
1609 * decimal number of already entered part of page number.
1612 * Let's assume that current mode is normal (pagenumdec is zero), teletext page
1613 * 100 are displayed as usual. topmost left corner of page contains page number.
1614 * Then vbi_add_dec is sequentially called (through slave
1615 * command of course) with 1,4,-,2,3 * values of dec parameter.
1617 * +-----+------------+------------------+
1618 * | dec | pagenumdec | displayed number |
1619 * +-----+------------+------------------+
1621 * +-----+------------+------------------+
1622 * | 1 | 0x001 | __1 |
1623 * +-----+------------+------------------+
1624 * | 4 | 0x014 | _14 |
1625 * +-----+------------+------------------+
1626 * | - | 0x001 | __1 |
1627 * +-----+------------+------------------+
1628 * | 2 | 0x012 | _12 |
1629 * +-----+------------+------------------+
1630 * | 3 | 0x123 | 123 |
1631 * +-----+------------+------------------+
1633 * +-----+------------+------------------+
1635 * pagenumdec will automatically receive zero value after third digit of page
1636 * number is entered and current page will be switched to another one with
1637 * entered page number.
1639 static void vbi_add_dec(priv_vbi_t
* priv
, char *dec
)
1646 if ((*dec
<'0' || *dec
>'9') && *dec
!='-')
1648 if (!priv
->pagenumdec
) //first digit cannot be '0','9' or '-'
1649 if(*dec
=='-' || *dec
=='0' || *dec
=='9')
1651 pthread_mutex_lock(&(priv
->buffer_mutex
));
1652 count
=(priv
->pagenumdec
>>12)&0xf;
1656 priv
->pagenumdec
=((priv
->pagenumdec
>>4)&0xfff)|(count
<<12);
1663 (((priv
->pagenumdec
)<<4|(*dec
-'0'))&0xfff)|(count
<<12);
1665 priv
->pagenum
=priv
->pagenumdec
&0x7ff;
1666 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1670 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1675 * \brief Teletext control routine
1676 * \param priv_vbi private data structure
1677 * \param cmd command
1678 * \param arg command parameter (has to be not null)
1680 int teletext_control(void* p
, int cmd
, void *arg
)
1683 priv_vbi_t
* priv
=(priv_vbi_t
*)p
;
1686 if (!priv
&& cmd
!=TV_VBI_CONTROL_START
)
1687 return VBI_CONTROL_FALSE
;
1688 if (!arg
&& cmd
!=TV_VBI_CONTROL_STOP
&& cmd
!=TV_VBI_CONTROL_MARK_UNCHANGED
)
1689 return VBI_CONTROL_FALSE
;
1692 case TV_VBI_CONTROL_RESET
:
1695 struct tt_param
* tt_param
=arg
;
1696 pthread_mutex_lock(&(priv
->buffer_mutex
));
1699 priv
->pagenum
=steppage(0,tt_param
->page
&0x7ff,1);
1700 priv
->tformat
=tt_param
->format
;
1701 priv
->subpagenum
=0x3f7f;
1702 pll_reset(priv
,fine_tune
);
1703 if(tt_param
->lang
==-1){
1704 mp_tmsg(MSGT_TELETEXT
,MSGL_INFO
,"Supported Teletext languages:\n");
1705 for(i
=0; tt_languages
[i
].lang_code
; i
++){
1706 mp_msg(MSGT_TELETEXT
,MSGL_INFO
," %3d %s\n",
1707 tt_languages
[i
].lang_code
, tt_languages
[i
].lang_name
);
1709 mp_msg(MSGT_TELETEXT
,MSGL_INFO
," %3d %s\n",
1710 tt_languages
[i
].lang_code
, tt_languages
[i
].lang_name
);
1712 for(i
=0; tt_languages
[i
].lang_code
; i
++){
1713 if(tt_languages
[i
].lang_code
==tt_param
->lang
)
1716 if (priv
->primary_language
!=tt_languages
[i
].lang_code
){
1717 mp_tmsg(MSGT_TELETEXT
,MSGL_INFO
,"Selected default teletext language: %s\n",
1718 tt_languages
[i
].lang_name
);
1719 priv
->primary_language
=tt_languages
[i
].lang_code
;
1722 priv
->page_changed
=1;
1723 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1724 return VBI_CONTROL_TRUE
;
1726 case TV_VBI_CONTROL_START
:
1729 tt_stream_props
* ptsp
=*(tt_stream_props
**)arg
;
1732 return VBI_CONTROL_FALSE
;
1734 priv
=calloc(1,sizeof(priv_vbi_t
));
1736 priv
->ptsp
=malloc(sizeof(tt_stream_props
));
1737 memcpy(priv
->ptsp
,ptsp
,sizeof(tt_stream_props
));
1738 *(priv_vbi_t
**)arg
=priv
;
1740 priv
->subpagenum
=0x3f7f;
1741 pthread_mutex_init(&priv
->buffer_mutex
, NULL
);
1743 for(i
=0;i
<VBI_ROWS
*VBI_COLUMNS
;i
++)
1744 priv
->display_page
[i
]=tt_space
;
1746 priv
->mag
=calloc(8,sizeof(mag_t
));
1748 init_vbi_consts(priv
);
1749 pll_reset(priv
,fine_tune
);
1750 priv
->page_changed
=1;
1751 return VBI_CONTROL_TRUE
;
1753 case TV_VBI_CONTROL_STOP
:
1757 destroy_cache(priv
);
1758 priv
->page_changed
=1;
1759 pthread_mutex_destroy(&priv
->buffer_mutex
);
1761 return VBI_CONTROL_TRUE
;
1763 case TV_VBI_CONTROL_SET_MODE
:
1764 priv
->on
=(*(int*)arg
%2);
1765 priv
->page_changed
=1;
1766 return VBI_CONTROL_TRUE
;
1767 case TV_VBI_CONTROL_GET_MODE
:
1768 *(int*)arg
=priv
->on
;
1769 return VBI_CONTROL_TRUE
;
1770 case TV_VBI_CONTROL_SET_FORMAT
:
1771 priv
->page_changed
=1;
1772 return teletext_set_format(priv
, *(int *) arg
);
1773 case TV_VBI_CONTROL_GET_FORMAT
:
1774 pthread_mutex_lock(&(priv
->buffer_mutex
));
1775 *(int*)arg
=priv
->tformat
;
1776 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1777 return VBI_CONTROL_TRUE
;
1778 case TV_VBI_CONTROL_GET_HALF_PAGE
:
1780 return VBI_CONTROL_FALSE
;
1781 *(int *)arg
=priv
->zoom
;
1782 return VBI_CONTROL_TRUE
;
1783 case TV_VBI_CONTROL_SET_HALF_PAGE
:
1789 pthread_mutex_lock(&(priv
->buffer_mutex
));
1791 priv
->page_changed
=1;
1792 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1793 return VBI_CONTROL_TRUE
;
1795 case TV_VBI_CONTROL_GO_LINK
:
1797 int val
=*(int *) arg
;
1799 return VBI_CONTROL_FALSE
;
1800 pthread_mutex_lock(&(priv
->buffer_mutex
));
1801 if (!(pgc
= priv
->ptt_cache
[priv
->pagenum
])) {
1802 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1803 return VBI_CONTROL_FALSE
;
1805 if (!pgc
->links
[val
-1].pagenum
|| pgc
->links
[val
-1].pagenum
>0x7ff) {
1806 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1807 return VBI_CONTROL_FALSE
;
1809 priv
->pagenum
=pgc
->links
[val
-1].pagenum
;
1810 if(pgc
->links
[val
-1].subpagenum
!=0x3f7f)
1811 priv
->subpagenum
=pgc
->links
[val
-1].subpagenum
;
1813 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1814 priv
->page_changed
=1;
1815 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1816 return VBI_CONTROL_TRUE
;
1818 case TV_VBI_CONTROL_SET_PAGE
:
1820 int val
=*(int *) arg
;
1821 if(val
<100 || val
>0x899)
1822 return VBI_CONTROL_FALSE
;
1823 pthread_mutex_lock(&(priv
->buffer_mutex
));
1824 priv
->pagenum
=val
&0x7ff;
1825 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1827 priv
->page_changed
=1;
1828 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1829 return VBI_CONTROL_TRUE
;
1831 case TV_VBI_CONTROL_STEP_PAGE
:
1833 int direction
=*(int *) arg
;
1834 pthread_mutex_lock(&(priv
->buffer_mutex
));
1835 priv
->pagenum
=steppage(priv
->pagenum
, direction
,1);
1836 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1838 priv
->page_changed
=1;
1839 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1840 return VBI_CONTROL_TRUE
;
1842 case TV_VBI_CONTROL_GET_PAGE
:
1843 *(int*)arg
=((priv
->pagenum
+0x700)&0x7ff)+0x100;
1844 return VBI_CONTROL_TRUE
;
1845 case TV_VBI_CONTROL_SET_SUBPAGE
:
1846 pthread_mutex_lock(&(priv
->buffer_mutex
));
1848 priv
->subpagenum
=*(int*)arg
;
1849 if(priv
->subpagenum
<0)
1850 priv
->subpagenum
=0x3f7f;
1851 if(priv
->subpagenum
>=VBI_MAX_SUBPAGES
)
1852 priv
->subpagenum
=VBI_MAX_SUBPAGES
-1;
1853 priv
->page_changed
=1;
1854 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1855 return VBI_CONTROL_TRUE
;
1856 case TV_VBI_CONTROL_GET_SUBPAGE
:
1857 *(int*)arg
=priv
->subpagenum
;
1858 return VBI_CONTROL_TRUE
;
1859 case TV_VBI_CONTROL_ADD_DEC
:
1860 vbi_add_dec(priv
, *(char **) arg
);
1861 priv
->page_changed
=1;
1862 return VBI_CONTROL_TRUE
;
1863 case TV_VBI_CONTROL_DECODE_PAGE
:
1864 vbi_decode(priv
,*(unsigned char**)arg
);
1865 return VBI_CONTROL_TRUE
;
1866 case TV_VBI_CONTROL_DECODE_DVB
:
1867 vbi_decode_dvb(priv
, arg
);
1868 return VBI_CONTROL_TRUE
;
1869 case TV_VBI_CONTROL_GET_VBIPAGE
:
1871 return VBI_CONTROL_FALSE
;
1872 prepare_visible_page(priv
);
1873 *(void **)arg
=priv
->display_page
;
1874 return VBI_CONTROL_TRUE
;
1875 case TV_VBI_CONTROL_GET_NETWORKNAME
:
1876 *(void **)arg
=priv
->networkname
;
1877 return VBI_CONTROL_TRUE
;
1878 case TV_VBI_CONTROL_MARK_UNCHANGED
:
1879 priv
->page_changed
=0;
1880 priv
->last_rendered
=GetTimerMS();
1881 return VBI_CONTROL_TRUE
;
1882 case TV_VBI_CONTROL_IS_CHANGED
:
1883 if(GetTimerMS()-priv
->last_rendered
> 250) //forcing page update every 1/4 sec
1884 priv
->page_changed
=3; //mark that header update is enough
1885 *(int*)arg
=priv
->page_changed
;
1886 return VBI_CONTROL_TRUE
;
1888 return VBI_CONTROL_UNKNOWN
;