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 if(priv
->mag
[magAddr
].pt
)
1104 free(priv
->mag
[magAddr
].pt
);
1105 priv
->mag
[magAddr
].pt
=NULL
;
1106 priv
->mag
[magAddr
].order
=0;
1110 if (!priv
->mag
[magAddr
].pt
)
1111 priv
->mag
[magAddr
].pt
= malloc(sizeof(tt_page
));
1113 if(priv
->primary_language
)
1114 priv
->mag
[magAddr
].pt
->primary_lang
=priv
->primary_language
;
1116 priv
->mag
[magAddr
].pt
->primary_lang
= (d
[7]>>1)&7;
1117 priv
->mag
[magAddr
].pt
->secondary_lang
=priv
->secondary_language
;
1118 priv
->mag
[magAddr
].pt
->subpagenum
=(d
[2]|(d
[3]<<4)|(d
[4]<<8)|(d
[5]<<12))&0x3f7f;
1119 priv
->mag
[magAddr
].pt
->pagenum
=(magAddr
<<8) | d
[0] | (d
[1]<<4);
1120 priv
->mag
[magAddr
].pt
->flags
=((d
[7]&1)<<7) | ((d
[3]&8)<<3) | ((d
[5]&12)<<2) | d
[6];
1122 memset(priv
->mag
[magAddr
].pt
->raw
, 0x00, VBI_COLUMNS
*VBI_ROWS
);
1123 priv
->mag
[magAddr
].order
=0;
1126 priv
->mag
[magAddr
].pt
->raw
[i
]=0x20;
1129 for(i
=8; i
<VBI_COLUMNS
; i
++){
1130 data
[i
]= fixParity
[data
[i
]];
1131 priv
->mag
[magAddr
].pt
->raw
[i
]=data
[i
];
1132 if(data
[i
]&0x80) //Error
1134 pll_add(priv
,1,err
);
1137 store_in_cache(priv
,magAddr
,0);
1143 * \brief decode teletext 8/30 Format 1 packet
1144 * \param priv private data structure
1145 * \param data raw teletext data (with not applied hamm correction yet)
1146 * \param magAddr teletext page's magazine address
1150 * 0 designation code
1152 * 3..6 initial subpage & magazine address
1155 * 10..12 julian date
1156 * 13..15 universal time
1157 * 20..40 network name
1159 * First 7 bytes are protected by Hamm 8/4 code.
1160 * Bytes 20-40 has odd parity check.
1162 * See subcaluse 9.8.1 of specification for details
1164 static int decode_pkt30(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
)
1170 d
[i
]= corrHamm48
[ data
[i
] ];
1179 for(i
=20; i
<40; i
++){
1180 data
[i
]= fixParity
[data
[i
]];
1181 if(data
[i
]&0x80)//Unrecoverable error
1183 pll_add(priv
,1,err
);
1187 if (d
[0]&0xe) //This is not 8/30 Format 1 packet
1190 priv
->initialpage
=d
[1] | d
[2]<<4 | (d
[6]&0xc)<<7 | (d
[4]&1)<<8;
1191 priv
->initialsubpage
=d
[3] | d
[4]<<4 | d
[5]<<8 | d
[6]<<12;
1192 priv
->networkid
=data
[7]<<8 | data
[8];
1194 priv
->timeoffset
=(data
[9]>>1)&0xf;
1196 priv
->timeoffset
=-priv
->timeoffset
;
1198 priv
->juliandate
=(data
[10]&0xf)<<16 | data
[11]<<8 | data
[12];
1199 priv
->juliandate
-=0x11111;
1201 priv
->universaltime
=data
[13]<<16 | data
[14]<<8 | data
[15];
1202 priv
->universaltime
-=0x111111;
1204 snprintf(priv
->networkname
,21,"%s",data
+20);
1210 * \brief decode packets 1..24 (teletext page header)
1211 * \param priv private data structure
1212 * \param data raw teletext data
1213 * \param magAddr teletext page's magazine address
1214 * \param rowAddr teletext page's row number
1217 * data buffer was shifted by 6 and now contains 40 bytes of display data:
1218 * this type of packet is not proptected by Hamm 8/4 code
1220 static void decode_pkt_page(priv_vbi_t
* priv
,unsigned char*data
,int magAddr
,int rowAddr
){
1222 if (!priv
->mag
[magAddr
].pt
)
1225 priv
->mag
[magAddr
].order
=rowAddr
;
1228 for(i
=0; i
<VBI_COLUMNS
; i
++){
1229 data
[i
]= fixParity
[ data
[i
] ];
1230 priv
->mag
[magAddr
].pt
->raw
[i
+rowAddr
*VBI_COLUMNS
]=data
[i
];
1231 if( data
[i
]&0x80) //HammError
1234 pll_add(priv
,1,err
);
1236 store_in_cache(priv
,magAddr
,rowAddr
);
1240 * \brief decode packets 27 (teletext links)
1241 * \param priv private data structure
1242 * \param data raw teletext data
1243 * \param magAddr teletext page's magazine address
1245 static int decode_pkt27(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
){
1248 if (!priv
->mag
[magAddr
].pt
)
1251 if ((data
[i
] = corrHamm48
[ data
[i
] ]) & 0x80){
1257 Not a X/27/0 Format 1 packet or
1258 flag "show links on row 24" is not set.
1260 if (data
[0] || !(data
[37] & 8))
1263 hpg
= (magAddr
<<8) ^ ((data
[4+i
*6]&0x8)<<5 | (data
[6+i
*6]&0xc)<<7);
1264 if (!hpg
) hpg
=0x800;
1265 priv
->mag
[magAddr
].pt
->links
[i
].pagenum
= (data
[1+i
*6] & 0xf) |
1266 ((data
[2+i
*6] & 0xf) << 4) | hpg
;
1267 priv
->mag
[magAddr
].pt
->links
[i
].subpagenum
= ((data
[3+i
*6] & 0xf) |
1268 (data
[4+i
*6] & 0xf) << 4 | (data
[5+i
*6] & 0xf) << 8 |
1269 (data
[6+i
*6] & 0xf) << 12) & 0x3f7f;
1271 put_to_cache(priv
,priv
->mag
[magAddr
].pt
,-1);
1276 * \brief Decode teletext X/28/0 Format 1 packet
1277 * \param priv private data structure
1278 * \param data raw teletext data
1280 * Primary G0 charset is transmitted in bits 14-8 of Triplet 1
1281 * See Table 32 of specification for details.
1283 * Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and
1284 * bits 18-15 of Triplet 1
1285 * See Table 33 of specification for details.
1288 static void decode_pkt28(priv_vbi_t
* priv
,unsigned char*data
){
1291 d
=corrHamm48
[ data
[0] ];
1292 if(d
) return; //this is not X/28/0 Format 1 packet or error occured
1294 t1
=corrHamm24(data
+1);
1295 t2
=corrHamm24(data
+4);
1301 priv
->primary_language
=(t1
>>7)&0x7f;
1302 priv
->secondary_language
=((t2
<<4) | (t1
>>14))&0x7f;
1303 if (priv
->secondary_language
==0x7f)
1304 //No secondary language required
1305 priv
->secondary_language
=priv
->primary_language
;
1306 else // Swapping bits 1 and 3
1307 priv
->secondary_language
=(priv
->secondary_language
&0x7a) |
1308 (priv
->secondary_language
&4)>>2 |
1309 (priv
->secondary_language
&1)<<2;
1311 mp_msg(MSGT_TELETEXT
,MSGL_DBG2
,"pkt28: language: primary=%02x secondary=0x%02x\n",
1312 priv
->primary_language
,priv
->secondary_language
);
1316 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1317 * \param priv private data structure
1318 * \param buf raw vbi data (one line of frame)
1319 * \param data output buffer for decoded bytes (at least 45 bytes long)
1321 * Used XawTV's algorithm. Signal phase is calculated with help of starting clock
1322 * run-in sequence (min/max values and bit distance values are calculated)
1324 static int decode_raw_line_runin(priv_vbi_t
* priv
,unsigned char* buf
,unsigned char* data
){
1325 const int magic
= 0x27; // reversed 1110010
1326 int dt
[256],hi
[6],lo
[6];
1330 unsigned char min
,max
;
1331 int thr
=0; //threshold
1337 for(i
=soc
;i
<eoc
;i
++)
1338 dt
[i
]=buf
[i
+priv
->bpb
/ONE_FIXP
]-buf
[i
]; // amplifies the edges best.
1340 for (i
=eoc
; i
<eoc
+16; i
+=2)
1341 dt
[i
]=100, dt
[i
+1]=-100;
1343 /* find 6 rising and falling edges */
1344 for (i
=soc
, x
=0; x
<6; ++x
)
1355 return 0; // not enough periods found
1357 i
=hi
[5]-hi
[1]; // length of 4 periods (8 bits)
1358 if (i
<priv
->bp8bl
|| i
>priv
->bp8bh
)
1360 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"vbi: wrong freq %d (%d,%d)\n",
1361 i
,priv
->bp8bl
,priv
->bp8bh
);
1362 return 0; // bad frequency
1364 /* AGC and sync-reference */
1365 min
=255, max
=0, sync
=0;
1366 for (i
=hi
[4]; i
<hi
[5]; ++i
)
1369 for (i
=lo
[4]; i
<lo
[5]; ++i
)
1375 // searching for '11'
1376 for(i
=priv
->pll_adj
*priv
->bpb
/10;i
<16*priv
->bpb
;i
+=priv
->bpb
)
1377 if(buf
[FIXP2INT(i
)]>thr
&& buf
[FIXP2INT(i
+priv
->bpb
)]>thr
)
1380 for(decoded
=1; decoded
<= (VBI_COLUMNS
+3)<<3;decoded
++){
1382 if(buf
[FIXP2INT(i
)]>thr
) r
|=0x80;
1383 if(!(decoded
& 0x07)){
1384 data
[(decoded
>>3) - 1]=r
;
1390 return 0; //magic not found
1396 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"thr:%d sync:%d ",thr
,sync
);
1402 //See comment in vbi_decode for a reason of commenting out this routine.
1405 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1406 * \param priv private data structure
1407 * \param buf raw vbi data (one line of frame)
1408 * \param data output buffer for decoded bytes (at least 45 bytes long)
1410 * Used Michael Niedermayer's algorithm.
1411 * Signal phase is calculated using correlation between given samples data and
1414 static int decode_raw_line_sine(priv_vbi_t
* priv
,unsigned char* buf
,unsigned char* data
){
1415 int i
,x
,r
,amp
,xFixp
;
1417 double sin_sum
=0, cos_sum
=0;
1419 for(x
=0; x
< FIXP2INT(10*priv
->bpb
); x
++)
1422 avg
/=FIXP2INT(10*priv
->bpb
);
1424 for(x
=0; x
<12; x
++){
1426 sin_sum
+= si
[x
]*(amp
-avg
);
1427 cos_sum
+= co
[x
]*(amp
-avg
);
1429 //this is always zero. Why ?
1430 xFixp
= atan(sin_sum
/cos_sum
)*priv
->bpb
/M_PI
;
1432 //Without this line the result is full of errors
1433 //and routine is unable to find magic sequence
1434 buf
+=FIXP2INT(10*priv
->bpb
);
1437 for(x
=FIXP2INT(xFixp
);x
<70;x
=FIXP2INT(xFixp
)){
1439 if(buf
[x
]>avg
) r
|=1;
1441 if(r
==0xAAE4) break;
1444 //this is not teletext
1445 if (r
!=0xaae4) return 0;
1447 //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes
1448 for(i
=1; i
<=(42<<3); i
++){
1466 * \brief decodes one vbi line from one video frame
1467 * \param priv private data structure
1468 * \param data buffer with raw vbi data in it
1470 static void vbi_decode_line(priv_vbi_t
*priv
, unsigned char *data
) {
1471 int d0
,d1
,magAddr
,pkt
;
1473 d0
= corrHamm48
[ data
[0] ];
1474 d1
= corrHamm48
[ data
[1] ];
1476 if(d0
&0x80 || d1
&0x80){
1478 mp_msg(MSGT_TELETEXT
,MSGL_V
,"vbi_decode_line: HammErr\n");
1483 pkt
=(d0
>>3)|(d1
<<1);
1484 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"vbi_decode_line:%x %x (mag:%x, pkt:%d)\n",
1487 decode_pkt0(priv
,data
+2,magAddr
); //skip MRGA
1488 }else if(pkt
>0 && pkt
<VBI_ROWS
){
1489 if(!priv
->mag
[magAddr
].pt
)
1491 decode_pkt_page(priv
,data
+2,magAddr
,pkt
);//skip MRGA
1493 decode_pkt27(priv
,data
+2,magAddr
);
1495 decode_pkt28(priv
,data
+2);
1497 decode_pkt30(priv
,data
+2,magAddr
);
1499 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"unsupported packet:%d\n",pkt
);
1504 * \brief decodes all vbi lines from one video frame
1505 * \param priv private data structure
1506 * \param buf buffer with raw vbi data in it
1508 * \note buffer size have to be at least priv->ptsp->bufsize bytes
1510 static void vbi_decode(priv_vbi_t
* priv
,unsigned char*buf
){
1511 unsigned char data
[64];
1512 unsigned char* linep
;
1514 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"vbi: vbi_decode\n");
1515 for(linep
=buf
; !priv
->cache_reset
&& linep
<buf
+priv
->ptsp
->bufsize
; linep
+=priv
->ptsp
->samples_per_line
,i
++){
1518 This routine is alternative implementation of raw VBI data decoding.
1519 Unfortunately, it detects only about 20% of incoming data,
1520 but Michael says that this algorithm is better, and he wants to fix it.
1522 if(decode_raw_line_sine(priv
,linep
,data
)<=0){
1524 if(decode_raw_line_runin(priv
,linep
,data
)<=0){
1525 continue; //this is not valid teletext line
1527 vbi_decode_line(priv
, data
);
1529 if (priv
->cache_reset
){
1530 pthread_mutex_lock(&(priv
->buffer_mutex
));
1531 priv
->cache_reset
--;
1532 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1538 * \brief decodes a vbi line from a DVB teletext stream
1539 * \param priv private data structure
1540 * \param buf buffer with DVB teletext data
1542 * No locking is done since this is only called from a single-threaded context
1544 static void vbi_decode_dvb(priv_vbi_t
*priv
, const uint8_t buf
[44]){
1548 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
, "vbi: vbi_decode_dvb\n");
1550 /* Reverse bit order, skipping the first two bytes (field parity, line
1551 offset and framing code). */
1552 for (i
= 0; i
< sizeof(data
); i
++)
1553 data
[i
] = av_reverse
[buf
[2 + i
]];
1555 vbi_decode_line(priv
, data
);
1556 if (priv
->cache_reset
)
1557 priv
->cache_reset
--;
1561 ---------------------------------------------------------------------------------
1563 ---------------------------------------------------------------------------------
1567 * \brief toggles teletext page displaying format
1568 * \param priv_vbi private data structure
1569 * \param flag new format
1571 * VBI_CONTROL_TRUE is success,
1572 * VBI_CONTROL_FALSE otherwise
1577 * 2 - opaque with black foreground color (only in bw mode)
1578 * 3 - transparent with black foreground color (only in bw mode)
1580 static int teletext_set_format(priv_vbi_t
* priv
, teletext_format flag
)
1584 mp_msg(MSGT_TELETEXT
,MSGL_DBG3
,"teletext_set_format_is called. mode:%d\n",flag
);
1585 pthread_mutex_lock(&(priv
->buffer_mutex
));
1591 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1592 return VBI_CONTROL_TRUE
;
1596 * \brief append just entered digit to editing page number
1597 * \param priv_vbi private data structure
1598 * \param dec decimal digit to append
1601 * '0'..'9' append digit
1602 * '-' remove last digit (backspace emulation)
1604 * This routine allows user to jump to arbitrary page.
1605 * It implements simple page number editing algorithm.
1607 * Subsystem can be on one of two modes: normal and page number edit mode.
1608 * Zero value of priv->pagenumdec means normal mode
1609 * Non-zero value means page number edit mode and equals to packed
1610 * decimal number of already entered part of page number.
1613 * Let's assume that current mode is normal (pagenumdec is zero), teletext page
1614 * 100 are displayed as usual. topmost left corner of page contains page number.
1615 * Then vbi_add_dec is sequentially called (through slave
1616 * command of course) with 1,4,-,2,3 * values of dec parameter.
1618 * +-----+------------+------------------+
1619 * | dec | pagenumdec | displayed number |
1620 * +-----+------------+------------------+
1622 * +-----+------------+------------------+
1623 * | 1 | 0x001 | __1 |
1624 * +-----+------------+------------------+
1625 * | 4 | 0x014 | _14 |
1626 * +-----+------------+------------------+
1627 * | - | 0x001 | __1 |
1628 * +-----+------------+------------------+
1629 * | 2 | 0x012 | _12 |
1630 * +-----+------------+------------------+
1631 * | 3 | 0x123 | 123 |
1632 * +-----+------------+------------------+
1634 * +-----+------------+------------------+
1636 * pagenumdec will automatically receive zero value after third digit of page
1637 * number is entered and current page will be switched to another one with
1638 * entered page number.
1640 static void vbi_add_dec(priv_vbi_t
* priv
, char *dec
)
1647 if ((*dec
<'0' || *dec
>'9') && *dec
!='-')
1649 if (!priv
->pagenumdec
) //first digit cannot be '0','9' or '-'
1650 if(*dec
=='-' || *dec
=='0' || *dec
=='9')
1652 pthread_mutex_lock(&(priv
->buffer_mutex
));
1653 count
=(priv
->pagenumdec
>>12)&0xf;
1657 priv
->pagenumdec
=((priv
->pagenumdec
>>4)&0xfff)|(count
<<12);
1664 (((priv
->pagenumdec
)<<4|(*dec
-'0'))&0xfff)|(count
<<12);
1666 priv
->pagenum
=priv
->pagenumdec
&0x7ff;
1667 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1671 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1676 * \brief Teletext control routine
1677 * \param priv_vbi private data structure
1678 * \param cmd command
1679 * \param arg command parameter (has to be not null)
1681 int teletext_control(void* p
, int cmd
, void *arg
)
1684 priv_vbi_t
* priv
=(priv_vbi_t
*)p
;
1687 if (!priv
&& cmd
!=TV_VBI_CONTROL_START
)
1688 return VBI_CONTROL_FALSE
;
1689 if (!arg
&& cmd
!=TV_VBI_CONTROL_STOP
&& cmd
!=TV_VBI_CONTROL_MARK_UNCHANGED
)
1690 return VBI_CONTROL_FALSE
;
1693 case TV_VBI_CONTROL_RESET
:
1696 struct tt_param
* tt_param
=arg
;
1697 pthread_mutex_lock(&(priv
->buffer_mutex
));
1700 priv
->pagenum
=steppage(0,tt_param
->page
&0x7ff,1);
1701 priv
->tformat
=tt_param
->format
;
1702 priv
->subpagenum
=0x3f7f;
1703 pll_reset(priv
,fine_tune
);
1704 if(tt_param
->lang
==-1){
1705 mp_tmsg(MSGT_TELETEXT
,MSGL_INFO
,"Supported Teletext languages:\n");
1706 for(i
=0; tt_languages
[i
].lang_code
; i
++){
1707 mp_msg(MSGT_TELETEXT
,MSGL_INFO
," %3d %s\n",
1708 tt_languages
[i
].lang_code
, tt_languages
[i
].lang_name
);
1710 mp_msg(MSGT_TELETEXT
,MSGL_INFO
," %3d %s\n",
1711 tt_languages
[i
].lang_code
, tt_languages
[i
].lang_name
);
1713 for(i
=0; tt_languages
[i
].lang_code
; i
++){
1714 if(tt_languages
[i
].lang_code
==tt_param
->lang
)
1717 if (priv
->primary_language
!=tt_languages
[i
].lang_code
){
1718 mp_tmsg(MSGT_TELETEXT
,MSGL_INFO
,"Selected default teletext language: %s\n",
1719 tt_languages
[i
].lang_name
);
1720 priv
->primary_language
=tt_languages
[i
].lang_code
;
1723 priv
->page_changed
=1;
1724 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1725 return VBI_CONTROL_TRUE
;
1727 case TV_VBI_CONTROL_START
:
1730 tt_stream_props
* ptsp
=*(tt_stream_props
**)arg
;
1733 return VBI_CONTROL_FALSE
;
1735 priv
=calloc(1,sizeof(priv_vbi_t
));
1737 priv
->ptsp
=malloc(sizeof(tt_stream_props
));
1738 memcpy(priv
->ptsp
,ptsp
,sizeof(tt_stream_props
));
1739 *(priv_vbi_t
**)arg
=priv
;
1741 priv
->subpagenum
=0x3f7f;
1742 pthread_mutex_init(&priv
->buffer_mutex
, NULL
);
1744 for(i
=0;i
<VBI_ROWS
*VBI_COLUMNS
;i
++)
1745 priv
->display_page
[i
]=tt_space
;
1747 priv
->mag
=calloc(8,sizeof(mag_t
));
1749 init_vbi_consts(priv
);
1750 pll_reset(priv
,fine_tune
);
1751 priv
->page_changed
=1;
1752 return VBI_CONTROL_TRUE
;
1754 case TV_VBI_CONTROL_STOP
:
1760 destroy_cache(priv
);
1761 priv
->page_changed
=1;
1762 pthread_mutex_destroy(&priv
->buffer_mutex
);
1764 return VBI_CONTROL_TRUE
;
1766 case TV_VBI_CONTROL_SET_MODE
:
1767 priv
->on
=(*(int*)arg
%2);
1768 priv
->page_changed
=1;
1769 return VBI_CONTROL_TRUE
;
1770 case TV_VBI_CONTROL_GET_MODE
:
1771 *(int*)arg
=priv
->on
;
1772 return VBI_CONTROL_TRUE
;
1773 case TV_VBI_CONTROL_SET_FORMAT
:
1774 priv
->page_changed
=1;
1775 return teletext_set_format(priv
, *(int *) arg
);
1776 case TV_VBI_CONTROL_GET_FORMAT
:
1777 pthread_mutex_lock(&(priv
->buffer_mutex
));
1778 *(int*)arg
=priv
->tformat
;
1779 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1780 return VBI_CONTROL_TRUE
;
1781 case TV_VBI_CONTROL_GET_HALF_PAGE
:
1783 return VBI_CONTROL_FALSE
;
1784 *(int *)arg
=priv
->zoom
;
1785 return VBI_CONTROL_TRUE
;
1786 case TV_VBI_CONTROL_SET_HALF_PAGE
:
1792 pthread_mutex_lock(&(priv
->buffer_mutex
));
1794 priv
->page_changed
=1;
1795 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1796 return VBI_CONTROL_TRUE
;
1798 case TV_VBI_CONTROL_GO_LINK
:
1800 int val
=*(int *) arg
;
1802 return VBI_CONTROL_FALSE
;
1803 pthread_mutex_lock(&(priv
->buffer_mutex
));
1804 if (!(pgc
= priv
->ptt_cache
[priv
->pagenum
])) {
1805 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1806 return VBI_CONTROL_FALSE
;
1808 if (!pgc
->links
[val
-1].pagenum
|| pgc
->links
[val
-1].pagenum
>0x7ff) {
1809 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1810 return VBI_CONTROL_FALSE
;
1812 priv
->pagenum
=pgc
->links
[val
-1].pagenum
;
1813 if(pgc
->links
[val
-1].subpagenum
!=0x3f7f)
1814 priv
->subpagenum
=pgc
->links
[val
-1].subpagenum
;
1816 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1817 priv
->page_changed
=1;
1818 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1819 return VBI_CONTROL_TRUE
;
1821 case TV_VBI_CONTROL_SET_PAGE
:
1823 int val
=*(int *) arg
;
1824 if(val
<100 || val
>0x899)
1825 return VBI_CONTROL_FALSE
;
1826 pthread_mutex_lock(&(priv
->buffer_mutex
));
1827 priv
->pagenum
=val
&0x7ff;
1828 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1830 priv
->page_changed
=1;
1831 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1832 return VBI_CONTROL_TRUE
;
1834 case TV_VBI_CONTROL_STEP_PAGE
:
1836 int direction
=*(int *) arg
;
1837 pthread_mutex_lock(&(priv
->buffer_mutex
));
1838 priv
->pagenum
=steppage(priv
->pagenum
, direction
,1);
1839 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1841 priv
->page_changed
=1;
1842 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1843 return VBI_CONTROL_TRUE
;
1845 case TV_VBI_CONTROL_GET_PAGE
:
1846 *(int*)arg
=((priv
->pagenum
+0x700)&0x7ff)+0x100;
1847 return VBI_CONTROL_TRUE
;
1848 case TV_VBI_CONTROL_SET_SUBPAGE
:
1849 pthread_mutex_lock(&(priv
->buffer_mutex
));
1851 priv
->subpagenum
=*(int*)arg
;
1852 if(priv
->subpagenum
<0)
1853 priv
->subpagenum
=0x3f7f;
1854 if(priv
->subpagenum
>=VBI_MAX_SUBPAGES
)
1855 priv
->subpagenum
=VBI_MAX_SUBPAGES
-1;
1856 priv
->page_changed
=1;
1857 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1858 return VBI_CONTROL_TRUE
;
1859 case TV_VBI_CONTROL_GET_SUBPAGE
:
1860 *(int*)arg
=priv
->subpagenum
;
1861 return VBI_CONTROL_TRUE
;
1862 case TV_VBI_CONTROL_ADD_DEC
:
1863 vbi_add_dec(priv
, *(char **) arg
);
1864 priv
->page_changed
=1;
1865 return VBI_CONTROL_TRUE
;
1866 case TV_VBI_CONTROL_DECODE_PAGE
:
1867 vbi_decode(priv
,*(unsigned char**)arg
);
1868 return VBI_CONTROL_TRUE
;
1869 case TV_VBI_CONTROL_DECODE_DVB
:
1870 vbi_decode_dvb(priv
, arg
);
1871 return VBI_CONTROL_TRUE
;
1872 case TV_VBI_CONTROL_GET_VBIPAGE
:
1874 return VBI_CONTROL_FALSE
;
1875 prepare_visible_page(priv
);
1876 *(void **)arg
=priv
->display_page
;
1877 return VBI_CONTROL_TRUE
;
1878 case TV_VBI_CONTROL_GET_NETWORKNAME
:
1879 *(void **)arg
=priv
->networkname
;
1880 return VBI_CONTROL_TRUE
;
1881 case TV_VBI_CONTROL_MARK_UNCHANGED
:
1882 priv
->page_changed
=0;
1883 priv
->last_rendered
=GetTimerMS();
1884 return VBI_CONTROL_TRUE
;
1885 case TV_VBI_CONTROL_IS_CHANGED
:
1886 if(GetTimerMS()-priv
->last_rendered
> 250) //forcing page update every 1/4 sec
1887 priv
->page_changed
=3; //mark that header update is enough
1888 *(int*)arg
=priv
->page_changed
;
1889 return VBI_CONTROL_TRUE
;
1891 return VBI_CONTROL_UNKNOWN
;