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. stream/tvi_vbi.c: decode_raw_line_runin(...) or decode_raw_line_sine(...)
53 * decode raw vbi data into sliced 45(?) bytes long packets
54 * 2. stream/tvi_vbi.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. stream/tvi_vbi.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. stream/tvi_vbi.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 ?
75 * slave command for dumping pages
76 * fix bcd<->dec as suggested my Michael
79 * wrong colors in debug dump
80 * blinking when visible page was just updated
97 #include "libmpcodecs/img_format.h"
98 #include "libavutil/common.h"
99 #include "input/input.h"
100 #include "osdep/timer.h"
102 //#define DEBUG_DUMP 1
104 /// page magazine entry structure
105 typedef struct mag_s
{
111 int on
; ///< teletext on/off
112 int pagenum
; ///< seek page number
113 int subpagenum
; ///< seek subpage
114 int curr_pagenum
; ///< current page number
115 int pagenumdec
; ///< set page num with dec
117 teletext_format tformat
; ///< see teletext_format enum
118 teletext_zoom zoom
; ///< see teletext_zoom enum
119 mag_t
* mag
; ///< pages magazine (has 8 entities)
120 int primary_language
; ///< primary character set
121 int secondary_language
; ///< secondary character set
122 /// Currently displayed page (with additional info, e.g current time)
123 tt_char display_page
[VBI_ROWS
*VBI_COLUMNS
];
124 /// number of raw bytes between two subsequent encoded bits
126 /// clock run-in sequence will be searched in buffer in [soc:eoc] bytes range
129 /// minimum number of raw vbi bytes wich can be decoded into 8 data bits
131 /// maximum number of raw vbi bytes wich can be decoded into 8 data bits
140 /// vbi stream properties (buffer size,bytes per line, etc)
141 tt_stream_props
* ptsp
;
142 pthread_mutex_t buffer_mutex
;
145 unsigned char* ptt_cache_first_subpage
;
147 unsigned char initialpage
;
148 unsigned int initialsubpage
;
149 unsigned int networkid
;
150 int timeoffset
; // timeoffset=realoffset*2
151 unsigned int juliandate
;
152 unsigned int universaltime
;
153 unsigned char networkname
[21];
155 /// "page changed" flag: 0-unchanged, 1-entire page, 3-only header
160 static unsigned char fixParity
[256];
162 static const tt_char tt_space
={0x20,7,0,0,0,0,0,0,0x20};
163 static const tt_char tt_error
={'?',1,0,0,0,0,0,0,'?'}; // Red '?' on black background
164 static double si
[12];
165 static double co
[12];
167 #define VBI_FORMAT(priv) (*(priv->ptsp))
170 #define ONE_FIXP (1<<FIXP_SH)
171 #define FIXP2INT(a) ((a)>>FIXP_SH)
172 #define ANY2FIXP(a) ((int)((a)*ONE_FIXP))
174 static const unsigned char corrHamm48
[256]={
175 0x01, 0xff, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff,
176 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07,
177 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00,
178 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff,
179 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07,
180 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x07,
181 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff,
182 0x06, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07,
183 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09,
184 0x02, 0x02, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff,
185 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff,
186 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03,
187 0x04, 0xff, 0xff, 0x05, 0x04, 0x04, 0x04, 0xff,
188 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07,
189 0xff, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, 0x05,
190 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff,
191 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09,
192 0x0a, 0xff, 0xff, 0x0b, 0x0a, 0x0a, 0x0a, 0xff,
193 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff,
194 0xff, 0x0b, 0x0b, 0x0b, 0x0a, 0xff, 0xff, 0x0b,
195 0x0c, 0x0c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff,
196 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07,
197 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x0d, 0x0d,
198 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff,
199 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x09,
200 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09,
201 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09,
202 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff,
203 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09,
204 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0e, 0x0f, 0xff,
205 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff,
206 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x0e, 0xff, 0x0e };
218 // conversion table for chars 0x20-0x7F (UTF8)
219 // TODO: add another languages
220 static const unsigned int lang_chars
[LANGS
][0x60]={
223 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
224 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
225 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
226 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
227 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
228 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
229 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
230 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
231 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
232 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
233 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
234 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
237 //Cyrillic-1 (Serbian/Croatian)
238 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
239 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
240 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
241 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
242 0x0427,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
243 0x0425,0x0418,0x0408,0x041a,0x041b,0x041c,0x041d,0x041e,
244 0x041f,0x040c,0x0420,0x0421,0x0422,0x0423,0x0412,0x0403,
245 0x0409,0x040a,0x0417,0x040b,0x0416,0x0402,0x0428,0x040f,
246 0x0447,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
247 0x0445,0x0438,0x0428,0x043a,0x043b,0x043c,0x043d,0x043e,
248 0x043f,0x042c,0x0440,0x0441,0x0442,0x0443,0x0432,0x0423,
249 0x0429,0x042a,0x0437,0x042b,0x0436,0x0422,0x0448,0x042f
252 //Cyrillic-2 (Russian/Bulgarian)
253 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
254 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
255 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
256 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
257 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
258 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
259 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
260 0x042c,0x042a,0x0417,0x0428,0x042d,0x0429,0x0427,0x042b,
261 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
262 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
263 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
264 0x044c,0x044a,0x0437,0x0448,0x044d,0x0449,0x0447,0x044b
267 //Cyrillic-3 (Ukrainian)
268 0x20,0x21,0x22,0x23,0x24,0x25,0xef,0x27,
269 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
270 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
271 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
272 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
273 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
274 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
275 0x042c,0x49,0x0417,0x0428,0x042d,0x0429,0x0427,0xcf,
276 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
277 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
278 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
279 0x044c,0x69,0x0437,0x0448,0x044d,0x0449,0x0447,0xFF
283 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
284 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
285 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
286 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
287 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
288 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
289 0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
290 0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
291 0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
292 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
293 0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
294 0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,0x03cf
299 * Latin National Option Sub-Sets
300 * see Table 36 of ETS specification for details.
302 * 00: £ $ @ « ½ » ¬ # ¼ ¦ ¾ ÷ English
303 * 01: é ï à ë ê ù î # è â ô û ç French
304 * 02: # ¤ É Ä Ö Å Ü _ é ä ö å ü Swedish/Finnish/Hungarian
305 * 03: # ů č ť ž ý í ř é á ě ú š Czech/Slovak
306 * 04: # $ § Ä Ö Ü ^ _ ° ä ö ü ß German
307 * 05: ç $ ¡ á é í ó ú ¿ ü ñ è à Portuguese/Spanish
308 * 06: £ $ é ° ç » ¬ # ù à ò è ì Italian
311 static const unsigned int latin_subchars
[8][13]={
313 {0xa3,0x24,0x40,0xab,0xbd,0xbb,0xac,0x23,0xad,0xbc,0xa6,0xbe,0xf7},
315 {0xe9,0xef,0xe0,0xeb,0xea,0xf9,0xee,0x23,0xe8,0xe2,0xf4,0xfb,0xe7},
316 // Swedish/Finnish/Hungarian
317 {0x23,0xa4,0xc9,0xc4,0xd6,0xc5,0xdc,0x5f,0xe9,0xe4,0xf6,0xe5,0xfc},
319 {0x23,0x16f,0x10d,0x165,0x17e,0xfd,0xed,0x159,0xe9,0xe1,0x11b,0xfa,0x161},
321 {0x23,0x24,0xa7,0xc4,0xd6,0xdc,0x5e,0x5f,0xb0,0xe4,0xf6,0xfc,0xdf},
322 // Portuguese/Spanish
323 {0xe7,0x24,0xa1,0xe1,0xe9,0xed,0xf3,0xfa,0xbf,0xfc,0xf1,0xe8,0xe0},
325 {0xa3,0x24,0xe9,0xb0,0xe7,0xbb,0xac,0x23,0xf9,0xe0,0xf2,0xe8,0xec},
327 {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e}
331 * List of supported languages.
333 * lang_code bits for primary Language:
334 * bits 7-4 corresponds to bits 14-11 of 28 packet's first triplet
335 * bits 3-1 corresponds to bits C12-C14 of packet 0 (lang)
337 * lang_code bits for secondary Language:
338 * bits 7-5 corresponds to bits 3-1 of 28 packet's second triplet
339 * bits 4,2 corresponds to bits 18,16 of 28 packet's first triplet
340 * bits 3,1 corresponds to bits 15,17 of 28 packet's first triplet
342 * For details see Tables 32 and 33 of specification (subclause 15.2)
345 unsigned char lang_code
;
346 unsigned char charset
;
347 const char* lang_name
;
348 } const tt_languages
[]=
350 { 0x01, LATIN
, "French"},
351 { 0x02, LATIN
, "Swedish/Finnish/Hungarian"},
352 { 0x03, LATIN
, "Czech/Slovak"},
353 { 0x04, LATIN
, "German"},
354 { 0x05, LATIN
, "Portuguese/Spanish"},
355 { 0x06, LATIN
, "Italian"},
357 { 0x08, LATIN
, "Polish"},
358 { 0x09, LATIN
, "French"},
359 { 0x0a, LATIN
, "Swedish/Finnish/Hungarian"},
360 { 0x0b, LATIN
, "Czech/Slovak"},
361 { 0x0c, LATIN
, "German"},
362 { 0x0e, LATIN
, "Italian"},
364 { 0x10, LATIN
, "English"},
365 { 0x11, LATIN
, "French"},
366 { 0x12, LATIN
, "Swedish/Finnish/Hungarian"},
367 { 0x13, LATIN
, "Turkish"},
368 { 0x14, LATIN
, "German"},
369 { 0x15, LATIN
, "Portuguese/Spanish"},
370 { 0x16, LATIN
, "Italian"},
372 { 0x1d, LATIN
, "Serbian/Croatian/Slovenian (Latin)"},
374 { 0x20, CYRILLIC1
, "Serbian/Croatian (Cyrillic)"},
375 { 0x21, CYRILLIC2
, "Russian, Bulgarian"},
376 { 0x22, LATIN
, "Estonian"},
377 { 0x23, LATIN
, "Czech/Slovak"},
378 { 0x24, LATIN
, "German"},
379 { 0x25, CYRILLIC3
, "Ukrainian"},
380 { 0x26, LATIN
, "Lettish/Lithuanian"},
382 { 0x33, LATIN
, "Turkish"},
383 { 0x37, GREEK
, "Greek"},
385 { 0x40, LATIN
, "English"},
386 { 0x41, LATIN
, "French"},
387 // { 0x47, ARABIC, "Arabic"},
389 // { 0x55, HEBREW, "Hebrew"},
390 // { 0x57, ARABIC, "Arabic"},
392 { 0x00, LATIN
, "English"},
396 * \brief 24/18 Hamming code decoding
397 * \param data bytes with hamming code (array must be at least 3 bytes long)
398 * \return -1 if multiple bit error occured, D1-DI data bits - otherwise
400 * \note Bits must be correctly ordered, that is for 24/18 (lowest bit first)
401 * P1 P2 D1 P3 D2 D3 D4 P4 D5 D6 D7 D8 D9 DA DB P5 DC DD DE DF DG DH DI P6
403 static int corrHamm24(unsigned char *data
){
404 unsigned char syndrom
=0;
405 int cw
=data
[0] | (data
[1]<<8) | (data
[2]<<16);
409 syndrom
^=((cw
>>i
)&1)*(i
+33);
411 syndrom
^=(cw
>>11)&32;
414 if(syndrom
< 32 || syndrom
> 55)
416 cw
^= 1<<((syndrom
&31)-1);
426 * \brief converts language bits to charset index
427 * \param lang language bits
428 * \return charset index in lang_chars array
430 static int lang2charset (int lang
){
432 for(i
=0;tt_languages
[i
].lang_code
;i
++)
433 if(tt_languages
[i
].lang_code
==lang
)
436 return tt_languages
[i
].charset
;
440 * \brief convert chars from curent teletext codepage into MPlayer charset
441 * \param p raw teletext char to decode
442 * \param charset index on lang_chars
443 * \param lang index in substitution array (latin charset only)
447 * routine will analyze raw member of given tt_char structure and
448 * fill unicode member of the same struct with appropriate utf8 code.
450 static unsigned int conv2uni(unsigned int p
,int charset
,int lang
)
453 if(p
<0x80 && p
>=0x20){
456 if (p
>=0x23 && p
<=0x24){
457 return latin_subchars
[lang
][p
-0x23];
459 return latin_subchars
[lang
][2];
460 }else if (p
>=0x5b && p
<=0x60){
461 return latin_subchars
[lang
][p
-0x5b+3];
462 }else if (p
>=0x7b && p
<=0x7e){
463 return latin_subchars
[lang
][p
-0x7b+9];
466 return lang_chars
[charset
][p
-0x20];
471 static void init_vbi_consts(priv_vbi_t
* priv
){
474 for(i
=0; i
<256; i
++){
479 fixParity
[i
]= i
^ (j
&0x80) ^ 0x80;
482 for(i
=0,ang
=0; i
<12; i
++,ang
+=M_PI
/priv
->bpb
){
487 priv
->bpb
=(priv
->ptsp
->sampling_rate
/6937500.0)*ONE_FIXP
+0.5;
488 priv
->soc
=FFMAX(9.2e-6*priv
->ptsp
->sampling_rate
-priv
->ptsp
->offset
, 0);
489 priv
->eoc
=FFMIN(12.9e-6*priv
->ptsp
->sampling_rate
-priv
->ptsp
->offset
,
490 priv
->ptsp
->samples_per_line
-43*8*priv
->bpb
/ONE_FIXP
);
491 if (priv
->eoc
- priv
->soc
<16*priv
->bpb
/ONE_FIXP
){ // invalid [soc:eoc]
495 priv
->bp8bl
=0.97*8*priv
->bpb
/ONE_FIXP
; // -3% tolerance
496 priv
->bp8bh
=1.03*8*priv
->bpb
/ONE_FIXP
; // +3% tolerance
499 * \brief calculate increased/decreased by given value page number
500 * \param curr current page number in hexadecimal for
501 * \param direction decimal value (can be negative) to add to value
503 * \return new page number in hexadecimal form
505 * VBI page numbers are represented in special hexadecimal form, e.g.
506 * page with number 123 (as seen by user) internally has number 0x123.
507 * and equation 0x123+8 should be equal to 0x131 instead of regular 0x12b.
510 * Page numbers 0xYYY (where Y is not belongs to (0..9).
511 * Page number belongs to [0x000,0x799] or [0x100:0x899] (first 0 can be
514 static int steppage(int p
, int direction
, int skip_hidden
)
517 p
=(p
&15)+((p
>>4)&15)*10+(p
>>8)*100;
521 p
=(p
%10)+((p
/10)%10)*16+(p
/100)*256;
528 ------------------------------------------------------------------
530 ------------------------------------------------------------------
534 * \brief add/update entry in cache
535 * \param priv private data structure
536 * \param pg page to store in cache
537 * \param line line to update (value below 0 means update entire page)
539 static void put_to_cache(priv_vbi_t
* priv
,tt_page
* pg
,int line
){
540 tt_page
* pgc
; //page in cache
545 count
=VBI_ROWS
*VBI_COLUMNS
;
546 }else if(line
<VBI_ROWS
){
548 count
=(line
+1)*VBI_COLUMNS
;
552 pthread_mutex_lock(&(priv
->buffer_mutex
));
554 if(!priv
->ptt_cache
[pg
->pagenum
]){
555 priv
->ptt_cache
[pg
->pagenum
]=calloc(1,sizeof(tt_page
));
556 pgc
=priv
->ptt_cache
[pg
->pagenum
];
558 pgc
=priv
->ptt_cache
[pg
->pagenum
];
559 while(pgc
->next_subpage
&& pgc
->subpagenum
!=pg
->subpagenum
)
560 pgc
=pgc
->next_subpage
;
562 if(pgc
->subpagenum
!=pg
->subpagenum
){
563 pgc
->next_subpage
=calloc(1,sizeof(tt_page
));
564 pgc
=pgc
->next_subpage
;
567 pgc
->pagenum
=pg
->pagenum
;
568 pgc
->subpagenum
=pg
->subpagenum
;
569 pgc
->primary_lang
=pg
->primary_lang
;
570 pgc
->secondary_lang
=pg
->secondary_lang
;
571 pgc
->flags
=pg
->flags
;
573 pgc
->links
[j
]=pg
->links
[j
];
574 //instead of copying entire page into cache, copy only undamaged
577 if(!(pg
->raw
[i
]&0x80))
578 pgc
->raw
[i
]=pg
->raw
[i
];
580 mp_msg(MSGT_TV
,MSGL_DBG3
,"char error. pg:%x, c[%d]=0x%x\n",
581 pg
->pagenum
,i
,pg
->raw
[i
]);
584 pthread_mutex_unlock(&(priv
->buffer_mutex
));
588 * \brief get any subpage number of given page
589 * \param priv private data structure
590 * \param pagenum page number to search subpages in
592 * \return subpage number of first found subpage which belongs to
595 * \note page itself is subpage too (and usually has subpage number 0)
597 static inline int get_subpagenum_from_cache(priv_vbi_t
* priv
, int pagenum
){
598 if (!priv
->ptt_cache
[pagenum
])
601 return priv
->ptt_cache
[pagenum
]->subpagenum
;
605 * \brief get page from cache by it page and subpage number
606 * \param priv private data structure
607 * \param pagenum page number
608 * \param subpagenum subpage number
610 * \return pointer to tt_page structure if requested page is found
613 static inline tt_page
* get_from_cache(priv_vbi_t
* priv
, int pagenum
,int subpagenum
){
614 tt_page
* tp
=priv
->ptt_cache
[pagenum
];
616 while(tp
&& tp
->subpagenum
!=subpagenum
)
622 * \brief clears cache
623 * \param priv private data structure
625 * Deletes all tt_page structures from cache and frees allocated memory.
626 * Only zero-filled array of pointers remains in memory
628 static void clear_cache(priv_vbi_t
* priv
){
633 Skip next 5 buffers to avoid mixing teletext pages from different
634 channels during channel switch
637 for(i
=0;i
<VBI_MAX_PAGES
;i
++){
638 while(priv
->ptt_cache
[i
]){
639 tp
=priv
->ptt_cache
[i
];
640 priv
->ptt_cache
[i
]=tp
->next_subpage
;
644 priv
->initialsubpage
=priv
->networkid
=0;
646 priv
->juliandate
=priv
->universaltime
=0;
647 memset(priv
->networkname
,0,21);
651 * \brief cache initialization
652 * \param priv private data structure
654 * \note Has to be called before any cache operations!
656 static void init_cache(priv_vbi_t
* priv
){
657 priv
->ptt_cache
=calloc(VBI_MAX_PAGES
,sizeof(tt_page
*));
661 * \brief destroys cache
662 * \param priv private data structure
664 * Frees all memory allocated for cache (including array of pointers).
665 * It is safe to call this routine multiple times
667 static void destroy_cache(priv_vbi_t
* priv
){
670 free(priv
->ptt_cache
);
671 priv
->ptt_cache
=NULL
;
676 ------------------------------------------------------------------
678 ------------------------------------------------------------------
681 * \brief converts raw teletext page into useful format (1st rendering stage)
682 * \param pg page to decode
683 * \param raw raw data to decode page from
684 * \param primary_lang primary language code
685 * \param secondary_lang secondary language code
687 * Routine fills tt_char structure of each teletext_page character with proper
688 * info about foreground and background colors, character
689 * type (graphics/control/text).
691 static void decode_page(tt_char
* p
,unsigned char* raw
,int primary_lang
,int secondary_lang
,int flags
)
694 int prim_charset
=lang2charset(primary_lang
);
695 int sec_charset
=lang2charset(secondary_lang
);
697 for(row
=0;row
<VBI_ROWS
;row
++) {
708 tt_char tt_held
=tt_space
;
709 for(col
=0;col
<VBI_COLUMNS
;col
++){
710 int i
=row
*VBI_COLUMNS
+col
;
713 if(c
&0x80){ //damaged char
717 if((flags
&TT_PGFL_SUBTITLE
) || (flags
&TT_PGFL_NEWFLASH
))
721 p
[i
].gfx
=gfx
?(separated
?2:1):0;
723 p
[i
].ctl
=(c
&0x60)==0?1:0;
728 if ((c
&0x60)==0){ //control chars
729 if(c
>=0x08 && c
<=0x09){//Flash/Steady
736 }else if(c
>=0x0a && c
<=0x0b){
738 }else if(c
>=0x0c && c
<=0x0f){
739 }else if (c
<=0x17){ //colors
746 }else if (c
<=0x1a){ //Contiguous/Separated gfx
749 prim_lang
=!prim_lang
;
751 bg_color
=(c
&1)?fg_color
:0;
753 }else{ //Hold/Release Graphics
762 p
[i
].unicode
=p
[i
].gfx
?0:' ';
771 if (p
[i
].unicode
>0x3f) p
[i
].unicode
-=0x20;
775 p
[i
].unicode
=conv2uni(c
,prim_charset
,primary_lang
&7);
777 p
[i
].unicode
=conv2uni(c
,sec_charset
,secondary_lang
&7);
787 * \brief prepares current page for displaying
788 * \param priv_vbi private data structure
790 * Routine adds some useful info (time and page number of page, grabbed by
791 * background thread to top line of current page). Displays "No teletext"
792 * string if no vbi data available.
794 #define PRINT_HEX(dp,i,h) dp[i].unicode=((h)&0xf)>9?'A'+((h)&0xf)-10:'0'+((h)&0xf)
795 static void prepare_visible_page(priv_vbi_t
* priv
){
796 tt_page
*pg
,*curr_pg
;
800 pthread_mutex_lock(&(priv
->buffer_mutex
));
801 mp_msg(MSGT_TV
,MSGL_DBG3
,"tvi_vbi: prepare_visible_page pg:0x%x, sub:0x%x\n",
802 priv
->pagenum
,priv
->subpagenum
);
803 if(priv
->subpagenum
==0x3f7f) //no page yet
804 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
806 pg
=get_from_cache(priv
,priv
->pagenum
,priv
->subpagenum
);
807 mp_dbg(MSGT_TV
,MSGL_DBG3
,"tvi_vbi: prepare_vibible_page2 pg:0x%x, sub:0x%x\n",
808 priv
->pagenum
,priv
->subpagenum
);
810 curr_pg
=get_from_cache(priv
,priv
->curr_pagenum
,
811 get_subpagenum_from_cache(priv
,priv
->curr_pagenum
));
812 if (!pg
&& !curr_pg
){
813 p
=MSGTR_TV_NoTeletext
;
814 for(i
=0;i
<VBI_COLUMNS
&& *p
;i
++){
815 GET_UTF8(priv
->display_page
[i
].unicode
,*p
++,break;);
817 for(;i
<VBI_ROWS
*VBI_COLUMNS
;i
++)
818 priv
->display_page
[i
]=tt_space
;
819 pthread_mutex_unlock(&(priv
->buffer_mutex
));
823 if (!pg
|| !pg
->active
){
824 for(i
=0;i
<VBI_ROWS
*VBI_COLUMNS
;i
++){
825 priv
->display_page
[i
]=tt_space
;
828 decode_page(priv
->display_page
,pg
->raw
,pg
->primary_lang
,pg
->secondary_lang
,pg
->flags
);
829 mp_msg(MSGT_TV
,MSGL_DBG3
,"page #%x was decoded!\n",pg
->pagenum
);
832 PRINT_HEX(priv
->display_page
,0,(priv
->curr_pagenum
&0x700)?priv
->curr_pagenum
>>8:8);
833 PRINT_HEX(priv
->display_page
,1,priv
->curr_pagenum
>>4);
834 PRINT_HEX(priv
->display_page
,2,priv
->curr_pagenum
);
835 priv
->display_page
[3].unicode
=' ';
836 priv
->display_page
[4].unicode
=' ';
837 switch(priv
->pagenumdec
>>12){
839 priv
->display_page
[5].unicode
='_';
840 priv
->display_page
[6].unicode
='_';
841 PRINT_HEX(priv
->display_page
,7,priv
->pagenumdec
);
844 priv
->display_page
[5].unicode
='_';
845 PRINT_HEX(priv
->display_page
,6,priv
->pagenumdec
>>4);
846 PRINT_HEX(priv
->display_page
,7,priv
->pagenumdec
);
849 PRINT_HEX(priv
->display_page
,5,(priv
->pagenum
&0x700)?priv
->pagenum
>>8:8);
850 PRINT_HEX(priv
->display_page
,6,priv
->pagenum
>>4);
851 PRINT_HEX(priv
->display_page
,7,priv
->pagenum
);
853 if(priv
->subpagenum
!=0x3f7f){
854 priv
->display_page
[8].unicode
='.';
855 PRINT_HEX(priv
->display_page
,9,priv
->subpagenum
>>4);
856 PRINT_HEX(priv
->display_page
,10,priv
->subpagenum
);
858 priv
->display_page
[8].unicode
=' ';
859 priv
->display_page
[9].unicode
=' ';
860 priv
->display_page
[10].unicode
=' ';
862 priv
->display_page
[11].unicode
=' ';
863 for(i
=VBI_COLUMNS
;i
>VBI_TIME_LINEPOS
||
864 ((curr_pg
->raw
[i
]&0x60) && curr_pg
->raw
[i
]!=0x20 && i
>11);
866 if(curr_pg
->raw
[i
]&0x60)
867 priv
->display_page
[i
].unicode
=curr_pg
->raw
[i
];
869 priv
->display_page
[i
].unicode
=' ';
870 pthread_mutex_unlock(&(priv
->buffer_mutex
));
873 ------------------------------------------------------------------
875 ------------------------------------------------------------------
879 * \brief renders teletext page into given file
880 * \param pt page to render
881 * \param f opened file descriptor
882 * \param pagenum which page to render
883 * \param colored use colors not implementede yet)
885 * Text will be UTF8 encoded
887 static void render2text(tt_page
* pt
,FILE* f
,int colored
){
890 unsigned char buf
[8];
893 tt_char dp
[VBI_ROWS
*VBI_COLUMNS
];
899 fprintf(f
,"+========================================+\n");
900 fprintf(f
,"| lang:%d pagenum:0x%x subpagenum:%d flags:0x%x|\n",
905 fprintf(f
,"+----------------------------------------+\n");
907 decode_page(dp
,pt
->raw
,pt
->primary_lang
,pt
->secondary_lang
,pt
->flags
);
908 for(i
=0;i
<VBI_ROWS
;i
++){
910 if(colored
) fprintf(f
,"\033[40m");
911 for(j
=0;j
<VBI_COLUMNS
;j
++)
913 u
=dp
[i
*VBI_COLUMNS
+j
].unicode
;
914 if(dp
[i
*VBI_COLUMNS
+j
].fg
<= 7)
915 c1
=30+dp
[i
*VBI_COLUMNS
+j
].fg
;
918 if(dp
[i
*VBI_COLUMNS
+j
].bg
<= 7)
919 b1
=40+dp
[i
*VBI_COLUMNS
+j
].bg
;
922 if (b1
!=bkg
&& colored
){
923 fprintf(f
,"\033[%dm",b1
);
926 if(c1
!=color
&& colored
){
927 fprintf(f
,"\033[%dm",c1
);
930 if(dp
[i
*VBI_COLUMNS
+j
].gfx
){
934 PUT_UTF8(u
,tmp
,if(pos
<7) buf
[pos
++]=tmp
;);
940 if (colored
) fprintf(f
,"\033[0m");
946 fprintf(f
,"+====================raw=================+\n");
947 for(i
=0;i
<VBI_ROWS
;i
++){
948 for(j
=0;j
<VBI_COLUMNS
;j
++)
949 fprintf(f
,"%02x ",dp
[i
*VBI_COLUMNS
+j
].raw
);
952 fprintf(f
,"+====================lng=================+\n");
953 for(i
=0;i
<VBI_ROWS
;i
++){
954 for(j
=0;j
<VBI_COLUMNS
;j
++)
955 fprintf(f
,"%02x ",dp
[i
*VBI_COLUMNS
+j
].lng
);
959 fprintf(f
,"+========================================+\n");
963 * \brief dump page into pgXXX.txt file in vurrent directory
964 * \param pt page to dump
966 * \note XXX in filename is page number
967 * \note use only for debug purposes
969 static void dump_page(tt_page
* pt
)
973 snprintf(name
,99,"pg%x.txt",pt
->pagenum
);
982 * \brief checks whether page is ready and copies it into cache array if so
983 * \param priv private data structure
984 * \param magAddr page's magazine address (0-7)
986 * Routine also calls decode_page to perform 1st stage of rendering
988 static void store_in_cache(priv_vbi_t
* priv
, int magAddr
, int line
){
989 mp_msg(MSGT_TV
,MSGL_DBG2
,"store_in_cache(%d): pagenum:%x\n",
990 priv
->mag
[magAddr
].order
,
991 priv
->mag
[magAddr
].pt
->pagenum
);
993 put_to_cache(priv
,priv
->mag
[magAddr
].pt
,line
);
994 priv
->curr_pagenum
=priv
->mag
[magAddr
].pt
->pagenum
;
997 dump_page(get_from_cache(priv
,
998 priv
->mag
[magAddr
].pt
->pagenum
,
999 priv
->mag
[magAddr
].pt
->subpagenum
));
1005 ------------------------------------------------------------------
1007 ------------------------------------------------------------------
1009 #define PLL_SAMPLES 4
1011 #define PLL_ADJUST 4
1014 * \brief adjust current phase for better signal decoding
1015 * \param n count of bytes processed (?)
1016 * \param err count of error bytes (?)
1018 * \remarks code was got from MythTV project
1020 static void pll_add(priv_vbi_t
* priv
,int n
,int err
){
1023 if(err
>PLL_ERROR
*2/3)
1027 if(priv
->pll_cnt
<PLL_SAMPLES
)
1029 if(priv
->pll_err
>PLL_ERROR
)
1031 if(priv
->pll_err
>priv
->pll_lerr
)
1032 priv
->pll_dir
= -priv
->pll_dir
;
1033 priv
->pll_lerr
=priv
->pll_err
;
1034 priv
->pll_adj
+=priv
->pll_dir
;
1035 if (priv
->pll_adj
<-PLL_ADJUST
|| priv
->pll_adj
>PLL_ADJUST
)
1041 mp_msg(MSGT_TV
,MSGL_DBG3
,"vbi: pll_adj=%2d\n",priv
->pll_adj
);
1048 * \brief reset error correction
1049 * \param priv private data structure
1050 * \param fine_tune shift value for adjusting
1052 * \remarks code was got from MythTV project
1054 static void pll_reset(priv_vbi_t
* priv
,int fine_tune
){
1055 priv
->pll_fixed
=fine_tune
>= -PLL_ADJUST
&& fine_tune
<= PLL_ADJUST
;
1063 priv
->pll_adj
=fine_tune
;
1065 mp_msg(MSGT_TV
,MSGL_DBG3
,"pll_reset (fixed@%2d)\n",priv
->pll_adj
);
1067 mp_msg(MSGT_TV
,MSGL_DBG3
,"pll_reset (auto)\n");
1071 * \brief decode packet 0 (teletext page header)
1072 * \param priv private data structure
1073 * \param data raw teletext data (with not applied hamm correction yet)
1074 * \param magAddr teletext page's magazine address
1077 * data buffer was shifted by 6 and now contains:
1080 * 6..7 control codes
1081 * 8..39 display data
1083 * only first 8 bytes protected by Hamm 8/4 code
1085 static int decode_pkt0(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
)
1090 if (magAddr
<0 || magAddr
>7)
1093 d
[i
]= corrHamm48
[ data
[i
] ];
1097 if(priv
->mag
[magAddr
].pt
)
1098 free(priv
->mag
[magAddr
].pt
);
1099 priv
->mag
[magAddr
].pt
=NULL
;
1100 priv
->mag
[magAddr
].order
=0;
1104 if (!priv
->mag
[magAddr
].pt
)
1105 priv
->mag
[magAddr
].pt
= malloc(sizeof(tt_page
));
1107 if(priv
->primary_language
)
1108 priv
->mag
[magAddr
].pt
->primary_lang
=priv
->primary_language
;
1110 priv
->mag
[magAddr
].pt
->primary_lang
= (d
[7]&7)>>1;
1111 priv
->mag
[magAddr
].pt
->secondary_lang
=priv
->secondary_language
;
1112 priv
->mag
[magAddr
].pt
->subpagenum
=(d
[2]|(d
[3]<<4)|(d
[4]<<8)|(d
[5]<<12))&0x3f7f;
1113 priv
->mag
[magAddr
].pt
->pagenum
=(magAddr
<<8) | d
[0] | (d
[1]<<4);
1114 priv
->mag
[magAddr
].pt
->flags
=((d
[7]&1)<<7) | ((d
[3]&8)<<3) | ((d
[5]&12)<<2) | d
[6];
1116 memset(priv
->mag
[magAddr
].pt
->raw
, 0x00, VBI_COLUMNS
*VBI_ROWS
);
1117 priv
->mag
[magAddr
].order
=0;
1120 priv
->mag
[magAddr
].pt
->raw
[i
]=0x20;
1123 for(i
=8; i
<VBI_COLUMNS
; i
++){
1124 data
[i
]= fixParity
[data
[i
]];
1125 priv
->mag
[magAddr
].pt
->raw
[i
]=data
[i
];
1126 if(data
[i
]&0x80) //Error
1128 pll_add(priv
,1,err
);
1131 store_in_cache(priv
,magAddr
,0);
1137 * \brief decode teletext 8/30 Format 1 packet
1138 * \param priv private data structure
1139 * \param data raw teletext data (with not applied hamm correction yet)
1140 * \param magAddr teletext page's magazine address
1144 * 0 designation code
1146 * 3..6 initial subpage & magazine address
1149 * 10..12 julian date
1150 * 13..15 universal time
1151 * 20..40 network name
1153 * First 7 bytes are protected by Hamm 8/4 code.
1154 * Bytes 20-40 has odd parity check.
1156 * See subcaluse 9.8.1 of specification for details
1158 static int decode_pkt30(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
)
1164 d
[i
]= corrHamm48
[ data
[i
] ];
1173 for(i
=20; i
<40; i
++){
1174 data
[i
]= fixParity
[data
[i
]];
1175 if(data
[i
]&0x80)//Unrecoverable error
1177 pll_add(priv
,1,err
);
1181 if (d
[0]&0xe) //This is not 8/30 Format 1 packet
1184 priv
->initialpage
=d
[1] | d
[2]<<4 | (d
[6]&0xc)<<7 | (d
[4]&1)<<8;
1185 priv
->initialsubpage
=d
[3] | d
[4]<<4 | d
[5]<<8 | d
[6]<<12;
1186 priv
->networkid
=data
[7]<<8 | data
[8];
1188 priv
->timeoffset
=(data
[9]>>1)&0xf;
1190 priv
->timeoffset
=-priv
->timeoffset
;
1192 priv
->juliandate
=(data
[10]&0xf)<<16 | data
[11]<<8 | data
[12];
1193 priv
->juliandate
-=0x11111;
1195 priv
->universaltime
=data
[13]<<16 | data
[14]<<8 | data
[15];
1196 priv
->universaltime
-=0x111111;
1198 snprintf(priv
->networkname
,21,"%s",data
+20);
1204 * \brief decode packets 1..24 (teletext page header)
1205 * \param priv private data structure
1206 * \param data raw teletext data
1207 * \param magAddr teletext page's magazine address
1208 * \param rowAddr teletext page's row number
1211 * data buffer was shifted by 6 and now contains 40 bytes of display data:
1212 * this type of packet is not proptected by Hamm 8/4 code
1214 static void decode_pkt_page(priv_vbi_t
* priv
,unsigned char*data
,int magAddr
,int rowAddr
){
1216 if (!priv
->mag
[magAddr
].pt
)
1219 priv
->mag
[magAddr
].order
=rowAddr
;
1222 for(i
=0; i
<VBI_COLUMNS
; i
++){
1223 data
[i
]= fixParity
[ data
[i
] ];
1224 priv
->mag
[magAddr
].pt
->raw
[i
+rowAddr
*VBI_COLUMNS
]=data
[i
];
1225 if( data
[i
]&0x80) //HammError
1228 pll_add(priv
,1,err
);
1230 store_in_cache(priv
,magAddr
,rowAddr
);
1234 * \brief decode packets 27 (teletext links)
1235 * \param priv private data structure
1236 * \param data raw teletext data
1237 * \param magAddr teletext page's magazine address
1239 static int decode_pkt27(priv_vbi_t
* priv
,unsigned char* data
,int magAddr
){
1242 if (!priv
->mag
[magAddr
].pt
)
1245 if ((data
[i
] = corrHamm48
[ data
[i
] ]) & 0x80){
1251 Not a X/27/0 Format 1 packet or
1252 flag "show links on row 24" is not set.
1254 if (data
[0] || !(data
[37] & 8))
1257 hpg
= (magAddr
<<8) ^ ((data
[4+i
*6]&0x8)<<5 | (data
[6+i
*6]&0xc)<<7);
1258 if (!hpg
) hpg
=0x800;
1259 priv
->mag
[magAddr
].pt
->links
[i
].pagenum
= (data
[1+i
*6] & 0xf) |
1260 ((data
[2+i
*6] & 0xf) << 4) | hpg
;
1261 priv
->mag
[magAddr
].pt
->links
[i
].subpagenum
= ((data
[3+i
*6] & 0xf) |
1262 (data
[4+i
*6] & 0xf) << 4 | (data
[5+i
*6] & 0xf) << 8 |
1263 (data
[6+i
*6] & 0xf) << 12) & 0x3f7f;
1265 put_to_cache(priv
,priv
->mag
[magAddr
].pt
,-1);
1270 * \brief Decode teletext X/28/0 Format 1 packet
1271 * \param priv private data structure
1272 * \param data raw teletext data
1274 * Primary G0 charset is transmitted in bits 14-8 of Triplet 1
1275 * See Table 32 of specification for details.
1277 * Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and
1278 * bits 18-15 of Triplet 1
1279 * See Table 33 of specification for details.
1282 static void decode_pkt28(priv_vbi_t
* priv
,unsigned char*data
){
1285 d
=corrHamm48
[ data
[0] ];
1286 if(d
) return; //this is not X/28/0 Format 1 packet or error occured
1288 t1
=corrHamm24(data
+1);
1289 t2
=corrHamm24(data
+4);
1295 priv
->primary_language
=(t1
>>7)&0x7f;
1296 priv
->secondary_language
=((t2
<<4) | (t1
>>14))&0x7f;
1297 if (priv
->secondary_language
==0x7f)
1298 //No secondary language required
1299 priv
->secondary_language
=priv
->primary_language
;
1300 else // Swapping bits 1 and 3
1301 priv
->secondary_language
=(priv
->secondary_language
&0x7a) |
1302 (priv
->secondary_language
&4)>>2 |
1303 (priv
->secondary_language
&1)<<2;
1305 mp_msg(MSGT_TV
,MSGL_DBG2
,"pkt28: language: primary=%02x secondary=0x%02x\n",
1306 priv
->primary_language
,priv
->secondary_language
);
1310 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1311 * \param priv private data structure
1312 * \param buf raw vbi data (one line of frame)
1313 * \param data output buffer for decoded bytes (at least 45 bytes long)
1315 * Used XawTV's algorithm. Signal phase is calculated with help of starting clock
1316 * run-in sequence (min/max values and bit distance values are calculated)
1318 static int decode_raw_line_runin(priv_vbi_t
* priv
,unsigned char* buf
,unsigned char* data
){
1319 const int magic
= 0x27; // reversed 1110010
1320 int dt
[256],hi
[6],lo
[6];
1324 unsigned char min
,max
;
1325 int thr
=0; //threshold
1331 for(i
=soc
;i
<eoc
;i
++)
1332 dt
[i
]=buf
[i
+priv
->bpb
/ONE_FIXP
]-buf
[i
]; // amplifies the edges best.
1334 for (i
=eoc
; i
<eoc
+16; i
+=2)
1335 dt
[i
]=100, dt
[i
+1]=-100;
1337 /* find 6 rising and falling edges */
1338 for (i
=soc
, x
=0; x
<6; ++x
)
1349 return 0; // not enough periods found
1351 i
=hi
[5]-hi
[1]; // length of 4 periods (8 bits)
1352 if (i
<priv
->bp8bl
|| i
>priv
->bp8bh
)
1354 mp_msg(MSGT_TV
,MSGL_DBG3
,"vbi: wrong freq %d (%d,%d)\n",
1355 i
,priv
->bp8bl
,priv
->bp8bh
);
1356 return 0; // bad frequency
1358 /* AGC and sync-reference */
1359 min
=255, max
=0, sync
=0;
1360 for (i
=hi
[4]; i
<hi
[5]; ++i
)
1363 for (i
=lo
[4]; i
<lo
[5]; ++i
)
1369 // searching for '11'
1370 for(i
=priv
->pll_adj
*priv
->bpb
/10;i
<16*priv
->bpb
;i
+=priv
->bpb
)
1371 if(buf
[FIXP2INT(i
)]>thr
&& buf
[FIXP2INT(i
+priv
->bpb
)]>thr
)
1374 for(decoded
=1; decoded
<= (VBI_COLUMNS
+3)<<3;decoded
++){
1376 if(buf
[FIXP2INT(i
)]>thr
) r
|=0x80;
1377 if(!(decoded
& 0x07)){
1378 data
[(decoded
>>3) - 1]=r
;
1384 return 0; //magic not found
1390 mp_msg(MSGT_TV
,MSGL_DBG3
,"thr:%d sync:%d ",thr
,sync
);
1396 //See comment in vbi_decode for a reason of commenting out this routine.
1399 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1400 * \param priv private data structure
1401 * \param buf raw vbi data (one line of frame)
1402 * \param data output buffer for decoded bytes (at least 45 bytes long)
1404 * Used Michael Niedermayer's algorithm.
1405 * Signal phase is calculated using correlation between given samples data and
1408 static int decode_raw_line_sine(priv_vbi_t
* priv
,unsigned char* buf
,unsigned char* data
){
1409 int i
,x
,r
,amp
,xFixp
;
1411 double sin_sum
=0, cos_sum
=0;
1413 for(x
=0; x
< FIXP2INT(10*priv
->bpb
); x
++)
1416 avg
/=FIXP2INT(10*priv
->bpb
);
1418 for(x
=0; x
<12; x
++){
1420 sin_sum
+= si
[x
]*(amp
-avg
);
1421 cos_sum
+= co
[x
]*(amp
-avg
);
1423 //this is always zero. Why ?
1424 xFixp
= atan(sin_sum
/cos_sum
)*priv
->bpb
/M_PI
;
1426 //Without this line the result is full of errors
1427 //and routine is unable to find magic sequence
1428 buf
+=FIXP2INT(10*priv
->bpb
);
1431 for(x
=FIXP2INT(xFixp
);x
<70;x
=FIXP2INT(xFixp
)){
1433 if(buf
[x
]>avg
) r
|=1;
1435 if(r
==0xAAE4) break;
1438 //this is not teletext
1439 if (r
!=0xaae4) return 0;
1441 //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes
1442 for(i
=1; i
<=(42<<3); i
++){
1460 * \brief decodes all vbi lines from one video frame
1461 * \param priv private data structure
1462 * \param buf buffer with raw vbi data in it
1464 * \note buffer size have to be at least priv->ptsp->bufsize bytes
1466 static void vbi_decode(priv_vbi_t
* priv
,unsigned char*buf
){
1469 unsigned char data
[64];
1470 unsigned char* linep
;
1473 mp_msg(MSGT_TV
,MSGL_DBG3
,"vbi: vbi_decode\n");
1474 for(linep
=buf
; !priv
->cache_reset
&& linep
<buf
+priv
->ptsp
->bufsize
; linep
+=priv
->ptsp
->samples_per_line
,i
++){
1477 This routine is alternative implementation of raw VBI data decoding.
1478 Unfortunately, it detects only about 20% of incoming data,
1479 but Michael says that this algorithm is better, and he wants to fix it.
1481 if(decode_raw_line_sine(priv
,linep
,data
)<=0){
1483 if(decode_raw_line_runin(priv
,linep
,data
)<=0){
1484 continue; //this is not valid teletext line
1486 d0
= corrHamm48
[ data
[0] ];
1487 d1
= corrHamm48
[ data
[1] ];
1489 if(d0
&0x80 || d1
&0x80){
1491 mp_msg(MSGT_TV
,MSGL_V
,"vbi_decode(%d):HammErr after decode_raw_line\n",i
);
1493 continue; //hamError
1496 pkt
=(d0
>>3)|(d1
<<1);
1497 mp_msg(MSGT_TV
,MSGL_DBG3
,"vbi_decode(%d):%x %x (mag:%x, pkt:%d)\n",
1498 i
,d0
,d1
,magAddr
,pkt
);
1500 decode_pkt0(priv
,data
+2,magAddr
); //skip MRGA
1501 }else if(pkt
>0 && pkt
<VBI_ROWS
){
1502 if(!priv
->mag
[magAddr
].pt
) continue;
1503 decode_pkt_page(priv
,data
+2,magAddr
,pkt
);//skip MRGA
1505 decode_pkt27(priv
,data
+2,magAddr
);
1507 decode_pkt28(priv
,data
+2);
1509 decode_pkt30(priv
,data
+2,magAddr
);
1511 mp_msg(MSGT_TV
,MSGL_DBG3
,"unsupported packet:%d\n",pkt
);
1514 if (priv
->cache_reset
){
1515 pthread_mutex_lock(&(priv
->buffer_mutex
));
1516 priv
->cache_reset
--;
1517 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1523 ---------------------------------------------------------------------------------
1525 ---------------------------------------------------------------------------------
1529 * \brief toggles teletext page displaying format
1530 * \param priv_vbi private data structure
1531 * \param flag new format
1533 * TVI_CONTROL_TRUE is success,
1534 * TVI_CONTROL_FALSE otherwise
1539 * 2 - opaque with black foreground color (only in bw mode)
1540 * 3 - transparent with black foreground color (only in bw mode)
1542 static int teletext_set_format(priv_vbi_t
* priv
, teletext_format flag
)
1546 mp_msg(MSGT_TV
,MSGL_DBG3
,"teletext_set_format_is called. mode:%d\n",flag
);
1547 pthread_mutex_lock(&(priv
->buffer_mutex
));
1553 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1554 return TVI_CONTROL_TRUE
;
1558 * \brief append just entered digit to editing page number
1559 * \param priv_vbi private data structure
1560 * \param dec decimal digit to append
1563 * '0'..'9' append digit
1564 * '-' remove last digit (backspace emulation)
1566 * This routine allows user to jump to arbitrary page.
1567 * It implements simple page number editing algorithm.
1569 * Subsystem can be on one of two modes: normal and page number edit mode.
1570 * Zero value of priv->pagenumdec means normal mode
1571 * Non-zero value means page number edit mode and equals to packed
1572 * decimal number of already entered part of page number.
1575 * Let's assume that current mode is normal (pagenumdec is zero), teletext page
1576 * 100 are displayed as usual. topmost left corner of page contains page number.
1577 * Then vbi_add_dec is sequentially called (through slave
1578 * command of course) with 1,4,-,2,3 * values of dec parameter.
1580 * +-----+------------+------------------+
1581 * | dec | pagenumdec | displayed number |
1582 * +-----+------------+------------------+
1584 * +-----+------------+------------------+
1585 * | 1 | 0x001 | __1 |
1586 * +-----+------------+------------------+
1587 * | 4 | 0x014 | _14 |
1588 * +-----+------------+------------------+
1589 * | - | 0x001 | __1 |
1590 * +-----+------------+------------------+
1591 * | 2 | 0x012 | _12 |
1592 * +-----+------------+------------------+
1593 * | 3 | 0x123 | 123 |
1594 * +-----+------------+------------------+
1596 * +-----+------------+------------------+
1598 * pagenumdec will automatically receive zero value after third digit of page
1599 * number is entered and current page will be switched to another one with
1600 * entered page number.
1602 static void vbi_add_dec(priv_vbi_t
* priv
, char *dec
)
1609 if ((*dec
<'0' || *dec
>'9') && *dec
!='-')
1611 if (!priv
->pagenumdec
) //first digit cannot be '0','9' or '-'
1612 if(*dec
=='-' || *dec
=='0' || *dec
=='9')
1614 pthread_mutex_lock(&(priv
->buffer_mutex
));
1615 count
=(priv
->pagenumdec
>>12)&0xf;
1619 priv
->pagenumdec
=((priv
->pagenumdec
>>4)&0xfff)|(count
<<12);
1626 (((priv
->pagenumdec
)<<4|(*dec
-'0'))&0xfff)|(count
<<12);
1628 priv
->pagenum
=priv
->pagenumdec
&0x7ff;
1629 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1633 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1638 * \brief Teletext control routine
1639 * \param priv_vbi private data structure
1640 * \param cmd command
1641 * \param arg command parameter (has to be not null)
1643 int teletext_control(void* p
, int cmd
, void *arg
)
1646 priv_vbi_t
* priv
=(priv_vbi_t
*)p
;
1649 if (!priv
&& cmd
!=TV_VBI_CONTROL_START
)
1650 return TVI_CONTROL_FALSE
;
1651 if (!arg
&& cmd
!=TV_VBI_CONTROL_STOP
&& cmd
!=TV_VBI_CONTROL_MARK_UNCHANGED
)
1652 return TVI_CONTROL_FALSE
;
1655 case TV_VBI_CONTROL_RESET
:
1658 tv_param_t
* tv_param
=arg
;
1659 pthread_mutex_lock(&(priv
->buffer_mutex
));
1662 priv
->pagenum
=steppage(0,tv_param
->tpage
&0x7ff,1);
1663 priv
->tformat
=tv_param
->tformat
;
1664 priv
->subpagenum
=0x3f7f;
1665 pll_reset(priv
,fine_tune
);
1666 if(tv_param
->tlang
==-1){
1667 mp_msg(MSGT_TV
,MSGL_INFO
,MSGTR_TV_TTSupportedLanguages
);
1668 for(i
=0; tt_languages
[i
].lang_code
; i
++){
1669 mp_msg(MSGT_TV
,MSGL_INFO
," %3d %s\n",
1670 tt_languages
[i
].lang_code
, tt_languages
[i
].lang_name
);
1672 mp_msg(MSGT_TV
,MSGL_INFO
," %3d %s\n",
1673 tt_languages
[i
].lang_code
, tt_languages
[i
].lang_name
);
1675 for(i
=0; tt_languages
[i
].lang_code
; i
++){
1676 if(tt_languages
[i
].lang_code
==tv_param
->tlang
)
1679 if (priv
->primary_language
!=tt_languages
[i
].lang_code
){
1680 mp_msg(MSGT_TV
,MSGL_INFO
,MSGTR_TV_TTSelectedLanguage
,
1681 tt_languages
[i
].lang_name
);
1682 priv
->primary_language
=tt_languages
[i
].lang_code
;
1685 priv
->page_changed
=1;
1686 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1687 return TVI_CONTROL_TRUE
;
1689 case TV_VBI_CONTROL_START
:
1692 tt_stream_props
* ptsp
=*(tt_stream_props
**)arg
;
1695 return TVI_CONTROL_FALSE
;
1697 priv
=calloc(1,sizeof(priv_vbi_t
));
1699 priv
->ptsp
=malloc(sizeof(tt_stream_props
));
1700 memcpy(priv
->ptsp
,ptsp
,sizeof(tt_stream_props
));
1701 *(priv_vbi_t
**)arg
=priv
;
1703 priv
->subpagenum
=0x3f7f;
1704 pthread_mutex_init(&priv
->buffer_mutex
, NULL
);
1706 for(i
=0;i
<VBI_ROWS
*VBI_COLUMNS
;i
++)
1707 priv
->display_page
[i
]=tt_space
;
1709 priv
->mag
=calloc(8,sizeof(mag_t
));
1711 init_vbi_consts(priv
);
1712 pll_reset(priv
,fine_tune
);
1713 priv
->page_changed
=1;
1714 return TVI_CONTROL_TRUE
;
1716 case TV_VBI_CONTROL_STOP
:
1722 destroy_cache(priv
);
1723 priv
->page_changed
=1;
1725 return TVI_CONTROL_TRUE
;
1727 case TV_VBI_CONTROL_SET_MODE
:
1728 priv
->on
=(*(int*)arg
%2);
1729 priv
->page_changed
=1;
1730 return TVI_CONTROL_TRUE
;
1731 case TV_VBI_CONTROL_GET_MODE
:
1732 *(int*)arg
=priv
->on
;
1733 return TVI_CONTROL_TRUE
;
1734 case TV_VBI_CONTROL_SET_FORMAT
:
1735 priv
->page_changed
=1;
1736 return teletext_set_format(priv
, *(int *) arg
);
1737 case TV_VBI_CONTROL_GET_FORMAT
:
1738 pthread_mutex_lock(&(priv
->buffer_mutex
));
1739 *(int*)arg
=priv
->tformat
;
1740 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1741 return TVI_CONTROL_TRUE
;
1742 case TV_VBI_CONTROL_GET_HALF_PAGE
:
1744 return TVI_CONTROL_FALSE
;
1745 *(int *)arg
=priv
->zoom
;
1746 return TVI_CONTROL_TRUE
;
1747 case TV_VBI_CONTROL_SET_HALF_PAGE
:
1753 pthread_mutex_lock(&(priv
->buffer_mutex
));
1755 priv
->page_changed
=1;
1756 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1757 return TVI_CONTROL_TRUE
;
1759 case TV_VBI_CONTROL_GO_LINK
:
1761 int val
=*(int *) arg
;
1763 return TVI_CONTROL_FALSE
;
1764 pthread_mutex_lock(&(priv
->buffer_mutex
));
1765 if (!(pgc
= priv
->ptt_cache
[priv
->pagenum
])) {
1766 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1767 return TVI_CONTROL_FALSE
;
1769 if (!pgc
->links
[val
-1].pagenum
|| pgc
->links
[val
-1].pagenum
>0x7ff) {
1770 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1771 return TVI_CONTROL_FALSE
;
1773 priv
->pagenum
=pgc
->links
[val
-1].pagenum
;
1774 if(pgc
->links
[val
-1].subpagenum
!=0x3f7f)
1775 priv
->subpagenum
=pgc
->links
[val
-1].subpagenum
;
1777 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1778 priv
->page_changed
=1;
1779 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1780 return TVI_CONTROL_TRUE
;
1782 case TV_VBI_CONTROL_SET_PAGE
:
1784 int val
=*(int *) arg
;
1785 if(val
<100 || val
>0x899)
1786 return TVI_CONTROL_FALSE
;
1787 pthread_mutex_lock(&(priv
->buffer_mutex
));
1788 priv
->pagenum
=val
&0x7ff;
1789 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1791 priv
->page_changed
=1;
1792 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1793 return TVI_CONTROL_TRUE
;
1795 case TV_VBI_CONTROL_STEP_PAGE
:
1797 int direction
=*(int *) arg
;
1798 pthread_mutex_lock(&(priv
->buffer_mutex
));
1799 priv
->pagenum
=steppage(priv
->pagenum
, direction
,1);
1800 priv
->subpagenum
=get_subpagenum_from_cache(priv
,priv
->pagenum
);
1802 priv
->page_changed
=1;
1803 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1804 return TVI_CONTROL_TRUE
;
1806 case TV_VBI_CONTROL_GET_PAGE
:
1807 *(int*)arg
=((priv
->pagenum
+0x700)&0x7ff)+0x100;
1808 return TVI_CONTROL_TRUE
;
1809 case TV_VBI_CONTROL_SET_SUBPAGE
:
1810 pthread_mutex_lock(&(priv
->buffer_mutex
));
1812 priv
->subpagenum
=*(int*)arg
;
1813 if(priv
->subpagenum
<0)
1814 priv
->subpagenum
=0x3f7f;
1815 if(priv
->subpagenum
>=VBI_MAX_SUBPAGES
)
1816 priv
->subpagenum
=VBI_MAX_SUBPAGES
-1;
1817 priv
->page_changed
=1;
1818 pthread_mutex_unlock(&(priv
->buffer_mutex
));
1819 return TVI_CONTROL_TRUE
;
1820 case TV_VBI_CONTROL_GET_SUBPAGE
:
1821 *(int*)arg
=priv
->subpagenum
;
1822 return TVI_CONTROL_TRUE
;
1823 case TV_VBI_CONTROL_ADD_DEC
:
1824 vbi_add_dec(priv
, *(char **) arg
);
1825 priv
->page_changed
=1;
1826 return TVI_CONTROL_TRUE
;
1827 case TV_VBI_CONTROL_DECODE_PAGE
:
1828 vbi_decode(priv
,*(unsigned char**)arg
);
1829 return TVI_CONTROL_TRUE
;
1830 case TV_VBI_CONTROL_GET_VBIPAGE
:
1832 return TVI_CONTROL_FALSE
;
1833 prepare_visible_page(priv
);
1834 *(void **)arg
=priv
->display_page
;
1835 return TVI_CONTROL_TRUE
;
1836 case TV_VBI_CONTROL_GET_NETWORKNAME
:
1837 *(void **)arg
=priv
->networkname
;
1838 return TVI_CONTROL_TRUE
;
1839 case TV_VBI_CONTROL_MARK_UNCHANGED
:
1840 priv
->page_changed
=0;
1841 priv
->last_rendered
=GetTimerMS();
1842 return TVI_CONTROL_TRUE
;
1843 case TV_VBI_CONTROL_IS_CHANGED
:
1844 if(GetTimerMS()-priv
->last_rendered
> 250) //forcing page update every 1/4 sec
1845 priv
->page_changed
=3; //mark that header update is enough
1846 *(int*)arg
=priv
->page_changed
;
1847 return TVI_CONTROL_TRUE
;
1849 return TVI_CONTROL_UNKNOWN
;