Update to MPlayer SVN rev 29473 and FFmpeg SVN rev 19572.
[vaapi:athaifas-mplayer.git] / stream / tvi_vbi.c
1 /*
2  * Teletext support
3  *
4  * Copyright (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>
5  *
6  * This file is part of MPlayer.
7  *
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.
12  *
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.
17  *
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.
21  *
22  *
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.
27  *
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
31  *
32  * Some implementation details:
33  * How to port teletext to another tvi_* driver (see tvi_v4l2.c for example):
34  *
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.
41  *
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
45  *
46  * Page displaying process consist of following stages:
47  *
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
60  *      text to utf8.
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
67  *
68  * TODO:
69  *  v4lv1,bktr support
70  *  spu rendering
71  *  is better quality on poor signal possible ?
72  *  link support
73  *  font autoscale
74  *  greyscale osd
75  *  slave command for dumping pages
76  *  fix bcd<->dec as suggested my Michael
77  *
78  *  BUGS:
79  *  wrong colors in debug dump
80  *  blinking when visible page was just updated
81  */
82
83 #include "config.h"
84
85 #include <stdlib.h>
86 #include <string.h>
87 #include <unistd.h>
88 #include <errno.h>
89 #include <math.h>
90 #include <stdio.h>
91
92 #include <pthread.h>
93
94 #include "tv.h"
95 #include "mp_msg.h"
96 #include "help_mp.h"
97 #include "libmpcodecs/img_format.h"
98 #include "libavutil/common.h"
99 #include "input/input.h"
100 #include "osdep/timer.h"
101
102 //#define DEBUG_DUMP 1
103
104 /// page magazine entry structure
105 typedef struct mag_s{
106     tt_page* pt;
107     int      order;
108 } mag_t;
109
110 typedef struct {
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
116
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
125     int bpb;
126     /// clock run-in sequence will be searched in buffer in [soc:eoc] bytes range
127     int soc;
128     int eoc;
129     /// minimum number of raw vbi bytes wich can be decoded into 8 data bits
130     int bp8bl;
131     /// maximum number of raw vbi bytes wich can be decoded into 8 data bits
132     int bp8bh;
133
134     int pll_adj;
135     int pll_dir;
136     int pll_cnt;
137     int pll_err;
138     int pll_lerr;
139     int pll_fixed;
140     /// vbi stream properties (buffer size,bytes per line, etc)
141     tt_stream_props* ptsp;
142     pthread_mutex_t buffer_mutex;
143
144     tt_page** ptt_cache;
145     unsigned char* ptt_cache_first_subpage;
146     /// network info
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];
154     int           cache_reset;
155     /// "page changed" flag: 0-unchanged, 1-entire page, 3-only header
156     int           page_changed;
157     int           last_rendered;
158 } priv_vbi_t;
159
160 static unsigned char fixParity[256];
161
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];
166
167 #define VBI_FORMAT(priv) (*(priv->ptsp))
168
169 #define FIXP_SH 16
170 #define ONE_FIXP (1<<FIXP_SH)
171 #define FIXP2INT(a) ((a)>>FIXP_SH)
172 #define ANY2FIXP(a) ((int)((a)*ONE_FIXP))
173
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 };
207
208
209 enum {
210   LATIN=0,
211   CYRILLIC1,
212   CYRILLIC2,
213   CYRILLIC3,
214   GREEK,
215   LANGS
216 };
217
218 // conversion table for chars 0x20-0x7F (UTF8)
219 // TODO: add another languages
220 static const unsigned int lang_chars[LANGS][0x60]={
221  {
222   //Latin
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
235  },
236  {
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
250  },
251  {
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
265  },
266  {
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
280  },
281  {
282   //Greek
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
295  }
296 };
297
298 /**
299  * Latin National Option Sub-Sets
300  * see Table 36 of ETS specification for details.
301  *
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
309  *
310  */
311 static const unsigned int latin_subchars[8][13]={
312   // English
313   {0xa3,0x24,0x40,0xab,0xbd,0xbb,0xac,0x23,0xad,0xbc,0xa6,0xbe,0xf7},
314   // French
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},
318   // Czech/Slovak
319   {0x23,0x16f,0x10d,0x165,0x17e,0xfd,0xed,0x159,0xe9,0xe1,0x11b,0xfa,0x161},
320   // German
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},
324   // Italian
325   {0xa3,0x24,0xe9,0xb0,0xe7,0xbb,0xac,0x23,0xf9,0xe0,0xf2,0xe8,0xec},
326   // Reserved
327   {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e}
328 };
329
330 /**
331  * List of supported languages.
332  *
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)
336  *
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
341  *
342  * For details see Tables 32 and 33 of specification (subclause 15.2)
343  */
344 struct {
345     unsigned char lang_code;
346     unsigned char charset;
347     const char* lang_name;
348 } const tt_languages[]=
349 {
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"},
356
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"},
363
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"},
371
372   { 0x1d, LATIN,     "Serbian/Croatian/Slovenian (Latin)"},
373
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"},
381
382   { 0x33, LATIN,     "Turkish"},
383   { 0x37, GREEK,     "Greek"},
384
385   { 0x40, LATIN,     "English"},
386   { 0x41, LATIN,     "French"},
387 //  { 0x47, ARABIC,    "Arabic"},
388
389 //  { 0x55, HEBREW,    "Hebrew"},
390 //  { 0x57, ARABIC,    "Arabic"},
391
392   { 0x00, LATIN,     "English"},
393 };
394
395 /**
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
399  *
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
402  */
403 static int corrHamm24(unsigned char *data){
404     unsigned char syndrom=0;
405     int cw=data[0] | (data[1]<<8) | (data[2]<<16);
406     int i;
407
408     for(i=0;i<23;i++)
409         syndrom^=((cw>>i)&1)*(i+33);
410
411     syndrom^=(cw>>11)&32;
412
413     if(syndrom&31){
414         if(syndrom < 32 || syndrom > 55)
415             return -1;
416         cw ^= 1<<((syndrom&31)-1);
417    }
418
419    return (cw&4)>>2 |
420           (cw&0x70)>>3 |
421           (cw&0x3f00)>>4 |
422           (cw&0x3f0000)>>5;
423 }
424
425 /**
426  * \brief converts language bits to charset index
427  * \param lang language bits
428  * \return charset index in lang_chars array
429  */
430 static int lang2charset (int lang){
431     int i;
432     for(i=0;tt_languages[i].lang_code;i++)
433         if(tt_languages[i].lang_code==lang)
434             break;
435
436     return tt_languages[i].charset;
437 }
438
439 /**
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)
444  * \return UTF8 char
445  *
446  * \remarks
447  * routine will analyze raw member of given tt_char structure and
448  * fill unicode member of the same struct with appropriate utf8 code.
449  */
450 static unsigned int conv2uni(unsigned int p,int charset,int lang)
451 {
452
453     if(p<0x80 && p>=0x20){
454         if(charset==LATIN){
455             lang&=7;
456             if (p>=0x23 && p<=0x24){
457                 return latin_subchars[lang][p-0x23];
458             }else if (p==0x40){
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];
464             }
465         }
466         return lang_chars[charset][p-0x20];
467     }else
468         return 0x20;
469 }
470
471 static void init_vbi_consts(priv_vbi_t* priv){
472     int i,j;
473     double ang;
474     for(i=0; i<256; i++){
475         j=i&0x7F;
476         j^= j+j;
477         j^= j<<2;
478         j^= j<<4;
479         fixParity[i]= i ^ (j&0x80) ^ 0x80;
480     }
481
482     for(i=0,ang=0; i<12; i++,ang+=M_PI/priv->bpb){
483         si[i]= sin(ang);
484         co[i]= cos(ang);
485     }
486
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]
492         priv->soc=0;
493         priv->eoc=92;
494     }
495     priv->bp8bl=0.97*8*priv->bpb/ONE_FIXP; // -3% tolerance
496     priv->bp8bh=1.03*8*priv->bpb/ONE_FIXP; // +3% tolerance
497 }
498 /**
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
502  *        of curr parameter
503  * \return new page number in hexadecimal form
504  *
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.
508  *
509  *
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
512  * treated as '8')
513  */
514 static int steppage(int p, int direction, int skip_hidden)
515 {
516     if(skip_hidden)
517         p=(p&15)+((p>>4)&15)*10+(p>>8)*100;
518     p+=direction;
519     if(skip_hidden){
520         p=(p+800)%800;
521         p=(p%10)+((p/10)%10)*16+(p/100)*256;
522     }
523
524     return p&0x7ff;
525 }
526
527 /*
528 ------------------------------------------------------------------
529    Cache stuff
530 ------------------------------------------------------------------
531 */
532
533 /**
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)
538  */
539 static void put_to_cache(priv_vbi_t* priv,tt_page* pg,int line){
540     tt_page* pgc; //page in cache
541     int i,j,count;
542
543     if(line<0){
544         i=0;
545         count=VBI_ROWS*VBI_COLUMNS;
546     }else if(line<VBI_ROWS){
547         i=line*VBI_COLUMNS;
548         count=(line+1)*VBI_COLUMNS;
549     }else
550         return;
551
552     pthread_mutex_lock(&(priv->buffer_mutex));
553
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];
557     }else{
558         pgc=priv->ptt_cache[pg->pagenum];
559         while(pgc->next_subpage && pgc->subpagenum!=pg->subpagenum)
560             pgc=pgc->next_subpage;
561
562         if(pgc->subpagenum!=pg->subpagenum){
563             pgc->next_subpage=calloc(1,sizeof(tt_page));
564             pgc=pgc->next_subpage;
565         }
566     }
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;
572     for(j=0;j<6;++j)
573         pgc->links[j]=pg->links[j];
574     //instead of copying entire page into cache, copy only undamaged
575     //symbols into cache
576     for(;i<count;i++){
577         if(!(pg->raw[i]&0x80))
578             pgc->raw[i]=pg->raw[i];
579         else
580             mp_msg(MSGT_TV,MSGL_DBG3,"char error. pg:%x, c[%d]=0x%x\n",
581                 pg->pagenum,i,pg->raw[i]);
582     }
583     pgc->active=1;
584     pthread_mutex_unlock(&(priv->buffer_mutex));
585 }
586
587 /**
588  * \brief get any subpage number of given page
589  * \param priv private data structure
590  * \param pagenum page number to search subpages in
591  *
592  * \return subpage number of first found subpage which belongs to
593  * given page number
594  *
595  * \note page itself is subpage too (and usually has subpage number 0)
596  */
597 static inline int get_subpagenum_from_cache(priv_vbi_t* priv, int pagenum){
598     if (!priv->ptt_cache[pagenum])
599         return 0x3f7f;
600     else
601         return priv->ptt_cache[pagenum]->subpagenum;
602 }
603
604 /**
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
609  *
610  * \return pointer to tt_page structure if requested page is found
611  * and NULL otherwise
612  */
613 static inline tt_page* get_from_cache(priv_vbi_t* priv, int pagenum,int subpagenum){
614     tt_page* tp=priv->ptt_cache[pagenum];
615
616     while(tp && tp->subpagenum!=subpagenum)
617         tp=tp->next_subpage;
618     return tp;
619 }
620
621 /**
622  * \brief clears cache
623  * \param priv private data structure
624  *
625  * Deletes all tt_page structures from cache and frees allocated memory.
626  * Only zero-filled array of pointers remains in memory
627  */
628 static void clear_cache(priv_vbi_t* priv){
629     int i;
630     tt_page* tp;
631
632     /*
633       Skip next 5 buffers to avoid mixing teletext pages from different
634       channels during channel switch
635     */
636     priv->cache_reset=5;
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;
641             free(tp);
642         }
643     }
644     priv->initialsubpage=priv->networkid=0;
645     priv->timeoffset=0;
646     priv->juliandate=priv->universaltime=0;
647     memset(priv->networkname,0,21);
648 }
649
650 /**
651  * \brief cache initialization
652  * \param priv private data structure
653  *
654  * \note Has to be called before any cache operations!
655  */
656 static void init_cache(priv_vbi_t* priv){
657     priv->ptt_cache=calloc(VBI_MAX_PAGES,sizeof(tt_page*));
658 }
659
660 /**
661  * \brief destroys cache
662  * \param priv private data structure
663  *
664  * Frees all memory allocated for cache (including array of pointers).
665  * It is safe to call this routine multiple times
666  */
667 static void destroy_cache(priv_vbi_t* priv){
668     if(priv->ptt_cache){
669         clear_cache(priv);
670         free(priv->ptt_cache);
671         priv->ptt_cache=NULL;
672     }
673 }
674
675 /*
676 ------------------------------------------------------------------
677    Decoder stuff
678 ------------------------------------------------------------------
679 */
680 /**
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
686 *
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).
690  */
691 static void decode_page(tt_char* p,unsigned char* raw,int primary_lang,int secondary_lang,int flags)
692 {
693     int row,col;
694     int prim_charset=lang2charset(primary_lang);
695     int sec_charset=lang2charset(secondary_lang);
696
697     for(row=0;row<VBI_ROWS;row++)   {
698         int prim_lang=1;
699         int gfx=0;
700         int fg_color=7;
701         int bg_color=0;
702         int separated=0;
703         int conceal=0;
704         int hold=0;
705         int flash=0;
706         int box=0;
707
708         tt_char tt_held=tt_space;
709         for(col=0;col<VBI_COLUMNS;col++){
710             int i=row*VBI_COLUMNS+col;
711             int c=raw[i];
712             p[i].raw=c;
713             if(c&0x80){ //damaged char
714                 p[i]=tt_error;
715                 continue;
716             }
717             if((flags&TT_PGFL_SUBTITLE) || (flags&TT_PGFL_NEWFLASH))
718                 p[i].hidden=!box;
719             else
720                 p[i].hidden=0;
721             p[i].gfx=gfx?(separated?2:1):0;
722             p[i].lng=prim_lang;
723             p[i].ctl=(c&0x60)==0?1:0;
724             p[i].fg=fg_color;
725             p[i].bg=bg_color;
726             p[i].flh=flash;
727
728             if ((c&0x60)==0){ //control chars
729                 if(c>=0x08 && c<=0x09){//Flash/Steady
730                     flash=c==0x08;
731                     p[i].flh=flash;
732                     if(c==0x09){
733                         p[i].fg=fg_color;
734                         p[i].bg=bg_color;
735                     }
736                 }else if(c>=0x0a && c<=0x0b){
737                     box=c&1;
738                 }else if(c>=0x0c && c<=0x0f){
739                 }else if (c<=0x17){ //colors
740                     fg_color=c&0x0f;
741                     gfx=c>>4;
742                     conceal=0;
743                     if(!gfx) hold=0;
744                 }else if (c<=0x18){
745                     conceal=1;
746                 }else if (c<=0x1a){ //Contiguous/Separated gfx
747                     separated=!(c&1);
748                 }else if (c<=0x1b){
749                     prim_lang=!prim_lang;
750                 }else if (c<=0x1d){
751                     bg_color=(c&1)?fg_color:0;
752                     p[i].bg=bg_color;
753                 }else{ //Hold/Release Graphics
754                     hold=!(c&1);
755                 }
756                 p[i].ctl=1;
757                 if(hold || c==0x1f){
758                     p[i]=tt_held;
759                     p[i].fg=fg_color;
760                     p[i].bg=bg_color;
761                 }else
762                     p[i].unicode=p[i].gfx?0:' ';
763                 continue;
764             }
765
766             if(conceal){
767                 p[i].gfx=0;
768                 p[i].unicode=' ';
769             }else if(gfx){
770                 p[i].unicode=c-0x20;
771                 if (p[i].unicode>0x3f) p[i].unicode-=0x20;
772                 tt_held=p[i];
773             }else{
774                 if(p[i].lng){
775                     p[i].unicode=conv2uni(c,prim_charset,primary_lang&7);
776                 }else{
777                     p[i].unicode=conv2uni(c,sec_charset,secondary_lang&7);
778                 }
779             }
780             p[i].fg=fg_color;
781             p[i].bg=bg_color;
782         }
783     }
784 }
785
786 /**
787  * \brief prepares current page for displaying
788  * \param priv_vbi private data structure
789  *
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.
793  */
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;
797     unsigned char *p;
798     int i;
799
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);
805
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);
809
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;);
816         }
817         for(;i<VBI_ROWS*VBI_COLUMNS;i++)
818             priv->display_page[i]=tt_space;
819         pthread_mutex_unlock(&(priv->buffer_mutex));
820         return;
821     }
822
823     if (!pg || !pg->active){
824         for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++){
825             priv->display_page[i]=tt_space;
826         }
827     }else{
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);
830     }
831
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){
838     case 1:
839         priv->display_page[5].unicode='_';
840         priv->display_page[6].unicode='_';
841         PRINT_HEX(priv->display_page,7,priv->pagenumdec);
842         break;
843     case 2:
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);
847     break;
848     default:
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);
852     }
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);
857     }else{
858         priv->display_page[8].unicode=' ';
859         priv->display_page[9].unicode=' ';
860         priv->display_page[10].unicode=' ';
861     }
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);
865             --i)
866         if(curr_pg->raw[i]&0x60)
867             priv->display_page[i].unicode=curr_pg->raw[i];
868         else
869             priv->display_page[i].unicode=' ';
870     pthread_mutex_unlock(&(priv->buffer_mutex));
871 }
872 /*
873 ------------------------------------------------------------------
874    Renderer stuff
875 ------------------------------------------------------------------
876 */
877 #ifdef DEBUG_DUMP
878 /**
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 implemented yet)
884  *
885  * Text will be UTF8 encoded
886  */
887 static void render2text(tt_page* pt,FILE* f,int colored){
888     int i,j;
889     unsigned int u;
890     unsigned char buf[8];
891     unsigned char tmp;
892     int pos;
893     tt_char dp[VBI_ROWS*VBI_COLUMNS];
894     int color=0;
895     int bkg=0;
896     int c1,b1;
897     if(!pt)
898         return;
899     fprintf(f,"+========================================+\n");
900     fprintf(f,"| lang:%d pagenum:0x%x subpagenum:%d flags:0x%x|\n",
901     pt->lang,
902     pt->pagenum,
903     pt->subpagenum,
904     0);
905     fprintf(f,"+----------------------------------------+\n");
906
907     decode_page(dp,pt->raw,pt->primary_lang,pt->secondary_lang,pt->flags);
908     for(i=0;i<VBI_ROWS;i++){
909         fprintf(f,"|");
910         if(colored) fprintf(f,"\033[40m");
911         for(j=0;j<VBI_COLUMNS;j++)
912         {
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;
916               else
917                 c1=38;
918               if(dp[i*VBI_COLUMNS+j].bg <= 7)
919                   b1=40+dp[i*VBI_COLUMNS+j].bg;
920               else
921                 b1=40;
922             if (b1!=bkg  && colored){
923                 fprintf(f,"\033[%dm",b1);
924                 bkg=b1;
925             }
926             if(c1!=color && colored){
927                 fprintf(f,"\033[%dm",c1);
928                 color=c1;
929             }
930             if(dp[i*VBI_COLUMNS+j].gfx){
931                 fprintf(f,"*");
932             }else{
933                 pos=0;
934                 PUT_UTF8(u,tmp,if(pos<7) buf[pos++]=tmp;);
935                 buf[pos]='\0';
936                 fprintf(f,"%s",buf);
937             }
938         }
939
940         if (colored) fprintf(f,"\033[0m");
941         color=-1;bkg=-1;
942         fprintf(f,"|\n");
943     }
944 #if 1
945     //for debug
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);
950         fprintf(f,"\n");
951     }
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);
956         fprintf(f,"\n");
957     }
958 #endif
959     fprintf(f,"+========================================+\n");
960 }
961
962 /**
963  * \brief dump page into pgXXX.txt file in vurrent directory
964  * \param pt page to dump
965  *
966  * \note XXX in filename is page number
967  * \note use only for debug purposes
968  */
969 static void dump_page(tt_page* pt)
970 {
971     FILE*f;
972     char name[100];
973     snprintf(name,99,"pg%x.txt",pt->pagenum);
974     f=fopen(name,"wb");
975     render2text(pt,f,1);
976     fclose(f);
977 }
978 #endif //DEBUG_DUMP
979
980
981 /**
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)
985  *
986  * Routine also calls decode_page to perform 1st stage of rendering
987  */
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);
992
993     put_to_cache(priv,priv->mag[magAddr].pt,line);
994     priv->curr_pagenum=priv->mag[magAddr].pt->pagenum;
995
996 #ifdef DEBUG_DUMP
997     dump_page(get_from_cache(priv,
998         priv->mag[magAddr].pt->pagenum,
999         priv->mag[magAddr].pt->subpagenum));
1000 #endif
1001 }
1002
1003
1004 /*
1005 ------------------------------------------------------------------
1006   Grabber stuff
1007 ------------------------------------------------------------------
1008 */
1009 #define PLL_SAMPLES 4
1010 #define PLL_ERROR   4
1011 #define PLL_ADJUST  4
1012
1013 /**
1014  * \brief adjust current phase for better signal decoding
1015  * \param n count of bytes processed (?)
1016  * \param err count of error bytes (?)
1017  *
1018  * \remarks code was got from MythTV project
1019  */
1020 static void pll_add(priv_vbi_t* priv,int n,int err){
1021     if(priv->pll_fixed)
1022         return;
1023     if(err>PLL_ERROR*2/3)
1024         err=PLL_ERROR*2/3;
1025     priv->pll_err+=err;
1026     priv->pll_cnt+=n;
1027     if(priv->pll_cnt<PLL_SAMPLES)
1028         return;
1029     if(priv->pll_err>PLL_ERROR)
1030     {
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)
1036         {
1037             priv->pll_adj=0;
1038             priv->pll_dir=-1;
1039             priv->pll_lerr=0;
1040         }
1041         mp_msg(MSGT_TV,MSGL_DBG3,"vbi: pll_adj=%2d\n",priv->pll_adj);
1042     }
1043     priv->pll_cnt=0;
1044     priv->pll_err=0;
1045 }
1046
1047 /**
1048  * \brief reset error correction
1049  * \param priv private data structure
1050  * \param fine_tune shift value for adjusting
1051  *
1052  * \remarks code was got from MythTV project
1053  */
1054 static void pll_reset(priv_vbi_t* priv,int fine_tune){
1055     priv->pll_fixed=fine_tune >= -PLL_ADJUST && fine_tune <= PLL_ADJUST;
1056
1057     priv->pll_err=0;
1058     priv->pll_lerr=0;
1059     priv->pll_cnt=0;
1060     priv->pll_dir=-1;
1061     priv->pll_adj=0;
1062     if(priv->pll_fixed)
1063         priv->pll_adj=fine_tune;
1064     if(priv->pll_fixed)
1065         mp_msg(MSGT_TV,MSGL_DBG3,"pll_reset (fixed@%2d)\n",priv->pll_adj);
1066     else
1067         mp_msg(MSGT_TV,MSGL_DBG3,"pll_reset (auto)\n");
1068
1069 }
1070 /**
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
1075  *
1076  * \remarks
1077  * data buffer was shifted by 6 and now contains:
1078  *  0..1 page number
1079  *  2..5 sub-code
1080  *  6..7 control codes
1081  *  8..39 display data
1082  *
1083  *  only first 8 bytes protected by Hamm 8/4 code
1084  */
1085 static int decode_pkt0(priv_vbi_t* priv,unsigned char* data,int magAddr)
1086 {
1087     int d[8];
1088     int i,err;
1089
1090     if (magAddr<0 || magAddr>7)
1091         return 0;
1092     for(i=0;i<8;i++){
1093         d[i]= corrHamm48[ data[i] ];
1094         if(d[i]&0x80){
1095             pll_add(priv,2,4);
1096
1097             if(priv->mag[magAddr].pt)
1098                   free(priv->mag[magAddr].pt);
1099             priv->mag[magAddr].pt=NULL;
1100             priv->mag[magAddr].order=0;
1101             return 0;
1102         }
1103     }
1104     if (!priv->mag[magAddr].pt)
1105         priv->mag[magAddr].pt= malloc(sizeof(tt_page));
1106
1107     if(priv->primary_language)
1108         priv->mag[magAddr].pt->primary_lang=priv->primary_language;
1109     else
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];
1115
1116     memset(priv->mag[magAddr].pt->raw, 0x00, VBI_COLUMNS*VBI_ROWS);
1117     priv->mag[magAddr].order=0;
1118
1119     for(i=0;i<8;i++){
1120         priv->mag[magAddr].pt->raw[i]=0x20;
1121     }
1122     err=0;
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
1127             err++;
1128         pll_add(priv,1,err);
1129     }
1130
1131     store_in_cache(priv,magAddr,0);
1132
1133     return 1;
1134 }
1135
1136 /**
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
1141  *
1142  * \remarks
1143  * packet contains:
1144  * 0      designation code
1145  * 1..2   initial page
1146  * 3..6   initial subpage & magazine address
1147  * 7..8   network id
1148  * 9      time offset
1149  * 10..12 julian date
1150  * 13..15 universal time
1151  * 20..40 network name
1152  *
1153  * First 7 bytes are protected by Hamm 8/4 code.
1154  * Bytes 20-40 has odd parity check.
1155  *
1156  * See subcaluse 9.8.1 of specification for details
1157  */
1158 static int decode_pkt30(priv_vbi_t* priv,unsigned char* data,int magAddr)
1159 {
1160     int d[8];
1161     int i,err;
1162
1163     for(i=0;i<7;i++){
1164         d[i]= corrHamm48[ data[i] ];
1165         if(d[i]&0x80){
1166             pll_add(priv,2,4);
1167             return 0;
1168         }
1169         d[i]&=0xf;
1170     }
1171
1172     err=0;
1173     for(i=20; i<40; i++){
1174         data[i]= fixParity[data[i]];
1175         if(data[i]&0x80)//Unrecoverable error
1176             err++;
1177         pll_add(priv,1,err);
1178     }
1179     if (err) return 0;
1180
1181     if (d[0]&0xe) //This is not 8/30 Format 1 packet
1182         return 1;
1183
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];
1187
1188     priv->timeoffset=(data[9]>>1)&0xf;
1189     if(data[9]&0x40)
1190         priv->timeoffset=-priv->timeoffset;
1191
1192     priv->juliandate=(data[10]&0xf)<<16 | data[11]<<8 | data[12];
1193     priv->juliandate-=0x11111;
1194
1195     priv->universaltime=data[13]<<16 | data[14]<<8 | data[15];
1196     priv->universaltime-=0x111111;
1197
1198     snprintf(priv->networkname,21,"%s",data+20);
1199
1200     return 1;
1201 }
1202
1203 /**
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
1209  *
1210  * \remarks
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
1213  */
1214 static void decode_pkt_page(priv_vbi_t* priv,unsigned char*data,int magAddr,int rowAddr){
1215     int i,err;
1216     if (!priv->mag[magAddr].pt)
1217         return;
1218
1219     priv->mag[magAddr].order=rowAddr;
1220
1221     err=0;
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
1226             err++;
1227     }
1228     pll_add(priv,1,err);
1229
1230     store_in_cache(priv,magAddr,rowAddr);
1231 }
1232
1233 /**
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
1238  */
1239 static int decode_pkt27(priv_vbi_t* priv,unsigned char* data,int magAddr){
1240     int i,hpg;
1241
1242     if (!priv->mag[magAddr].pt)
1243         return 0;
1244     for(i=0;i<38;++i)
1245         if ((data[i] = corrHamm48[ data[i] ]) & 0x80){
1246             pll_add(priv,2,4);
1247             return 0;
1248         }
1249
1250     /*
1251       Not a X/27/0 Format 1 packet or
1252       flag "show links on row 24" is not set.
1253     */
1254     if (data[0] || !(data[37] & 8))
1255         return 1;
1256     for(i=0;i<6;++i) {
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;
1264     }
1265     put_to_cache(priv,priv->mag[magAddr].pt,-1);
1266     return 1;
1267 }
1268
1269 /**
1270  * \brief Decode teletext X/28/0 Format 1 packet
1271  * \param priv private data structure
1272  * \param data raw teletext data
1273  *
1274  * Primary G0 charset is transmitted in bits 14-8 of Triplet 1
1275  * See Table 32 of specification for details.
1276  *
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.
1280  *
1281  */
1282 static void decode_pkt28(priv_vbi_t* priv,unsigned char*data){
1283     int d;
1284     int t1,t2;
1285     d=corrHamm48[ data[0] ];
1286     if(d) return; //this is not X/28/0 Format 1 packet or error occured
1287
1288     t1=corrHamm24(data+1);
1289     t2=corrHamm24(data+4);
1290     if (t1<0 || t2<0){
1291         pll_add(priv,1,4);
1292         return;
1293     }
1294
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;
1304
1305     mp_msg(MSGT_TV,MSGL_DBG2,"pkt28: language: primary=%02x secondary=0x%02x\n",
1306         priv->primary_language,priv->secondary_language);
1307 }
1308
1309 /**
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)
1314  *
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)
1317  */
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];
1321     int i,x,r;
1322     int decoded;
1323     int sync;
1324     unsigned char min,max;
1325     int thr=0; //threshold
1326
1327     //stubs
1328     int soc=priv->soc;
1329     int eoc=priv->eoc;
1330
1331     for(i=soc;i<eoc;i++)
1332         dt[i]=buf[i+priv->bpb/ONE_FIXP]-buf[i];    // amplifies the edges best.
1333     /* set barrier */
1334     for (i=eoc; i<eoc+16; i+=2)
1335         dt[i]=100, dt[i+1]=-100;
1336
1337     /* find 6 rising and falling edges */
1338     for (i=soc, x=0; x<6; ++x)
1339     {
1340         while (dt[i]<32)
1341             i++;
1342         hi[x]=i;
1343         while (dt[i]>-32)
1344             i++;
1345         lo[x]=i;
1346     }
1347     if (i>=eoc)
1348     {
1349         return 0;      // not enough periods found
1350     }
1351     i=hi[5]-hi[1]; // length of 4 periods (8 bits)
1352     if (i<priv->bp8bl || i>priv->bp8bh)
1353     {
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
1357     }
1358     /* AGC and sync-reference */
1359     min=255, max=0, sync=0;
1360     for (i=hi[4]; i<hi[5]; ++i)
1361         if (buf[i]>max)
1362             max=buf[i], sync=i;
1363     for (i=lo[4]; i<lo[5]; ++i)
1364         if (buf[i]<min)
1365             min=buf[i];
1366     thr=(min+max)/2;
1367
1368     buf+=sync;
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)
1372             break;
1373     r=0;
1374     for(decoded=1; decoded<= (VBI_COLUMNS+3)<<3;decoded++){
1375         r>>=1;
1376         if(buf[FIXP2INT(i)]>thr) r|=0x80;
1377         if(!(decoded & 0x07)){
1378             data[(decoded>>3) - 1]=r;
1379             r=0;
1380         }
1381         i+=priv->bpb;
1382     }
1383     if(data[0]!=magic)
1384         return 0; //magic not found
1385
1386     //stub
1387     for(i=0;i<43;i++){
1388         data[i]=data[i+1];
1389     }
1390     mp_msg(MSGT_TV,MSGL_DBG3,"thr:%d sync:%d ",thr,sync);
1391
1392     return 1;
1393 }
1394
1395 #if 0
1396 //See comment in vbi_decode for a reason of commenting out this routine.
1397
1398 /**
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)
1403  *
1404  * Used Michael Niedermayer's algorithm.
1405  * Signal phase is calculated using correlation between given samples data and
1406  * pure sine
1407  */
1408 static int decode_raw_line_sine(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){
1409     int i,x,r,amp,xFixp;
1410     int avg=0;
1411     double sin_sum=0, cos_sum=0;
1412
1413     for(x=0; x< FIXP2INT(10*priv->bpb); x++)
1414       avg+=buf[x];
1415
1416     avg/=FIXP2INT(10*priv->bpb);
1417
1418     for(x=0; x<12; x++){
1419       amp= buf[x<<1];
1420       sin_sum+= si[x]*(amp-avg);
1421       cos_sum+= co[x]*(amp-avg);
1422     }
1423     //this is always zero. Why ?
1424     xFixp= atan(sin_sum/cos_sum)*priv->bpb/M_PI;
1425
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);
1429
1430     r=0;
1431     for(x=FIXP2INT(xFixp);x<70;x=FIXP2INT(xFixp)){
1432       r=(r<<1) & 0xFFFF;
1433       if(buf[x]>avg) r|=1;
1434       xFixp+=priv->bpb;
1435       if(r==0xAAE4) break;
1436     }
1437
1438     //this is not teletext
1439     if (r!=0xaae4) return 0;
1440
1441     //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes
1442     for(i=1; i<=(42<<3); i++){
1443       r>>=1;
1444       x=FIXP2INT(xFixp);
1445       if(buf[x]> avg)
1446           r|=0x80;
1447
1448       if(!(i & 0x07)){
1449           data[(i>>3)-1]=r;
1450           r=0;
1451       }
1452       xFixp+=priv->bpb;
1453     }
1454
1455     return 1;
1456 }
1457 #endif
1458
1459 /**
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
1463  *
1464  * \note buffer size have to be at least priv->ptsp->bufsize bytes
1465  */
1466 static void vbi_decode(priv_vbi_t* priv,unsigned char*buf){
1467     int magAddr;
1468     int pkt;
1469     unsigned char data[64];
1470     unsigned char* linep;
1471     int d0,d1;
1472     int i=0;
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++){
1475 #if 0
1476         /*
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.
1480         */
1481         if(decode_raw_line_sine(priv,linep,data)<=0){
1482 #endif
1483         if(decode_raw_line_runin(priv,linep,data)<=0){
1484              continue; //this is not valid teletext line
1485         }
1486         d0= corrHamm48[ data[0] ];
1487         d1= corrHamm48[ data[1] ];
1488
1489         if(d0&0x80 || d1&0x80){
1490            pll_add(priv,2,4);
1491            mp_msg(MSGT_TV,MSGL_V,"vbi_decode(%d):HammErr after decode_raw_line\n",i);
1492
1493            continue; //hamError
1494         }
1495         magAddr=d0 & 0x7;
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);
1499         if(!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
1504         }else if(pkt==27) {
1505             decode_pkt27(priv,data+2,magAddr);
1506         }else if(pkt==28){
1507             decode_pkt28(priv,data+2);
1508         }else if(pkt==30){
1509             decode_pkt30(priv,data+2,magAddr);
1510         } else {
1511             mp_msg(MSGT_TV,MSGL_DBG3,"unsupported packet:%d\n",pkt);
1512         }
1513     }
1514     if (priv->cache_reset){
1515         pthread_mutex_lock(&(priv->buffer_mutex));
1516         priv->cache_reset--;
1517         pthread_mutex_unlock(&(priv->buffer_mutex));
1518     }
1519
1520 }
1521
1522 /*
1523 ---------------------------------------------------------------------------------
1524     Public routines
1525 ---------------------------------------------------------------------------------
1526 */
1527
1528 /**
1529  * \brief toggles teletext page displaying format
1530  * \param priv_vbi private data structure
1531  * \param flag new format
1532  * \return
1533  *   TVI_CONTROL_TRUE is success,
1534  *   TVI_CONTROL_FALSE otherwise
1535  *
1536  * flag:
1537  * 0 - opaque
1538  * 1 - transparent
1539  * 2 - opaque  with black foreground color (only in bw mode)
1540  * 3 - transparent  with black foreground color (only in bw mode)
1541  */
1542 static int teletext_set_format(priv_vbi_t * priv, teletext_format flag)
1543 {
1544     flag&=3;
1545
1546     mp_msg(MSGT_TV,MSGL_DBG3,"teletext_set_format_is called. mode:%d\n",flag);
1547     pthread_mutex_lock(&(priv->buffer_mutex));
1548
1549     priv->tformat=flag;
1550
1551     priv->pagenumdec=0;
1552
1553     pthread_mutex_unlock(&(priv->buffer_mutex));
1554     return TVI_CONTROL_TRUE;
1555 }
1556
1557 /**
1558  * \brief append just entered digit to editing page number
1559  * \param priv_vbi private data structure
1560  * \param dec decimal digit to append
1561  *
1562  *  dec:
1563  *   '0'..'9' append digit
1564  *    '-' remove last digit (backspace emulation)
1565  *
1566  * This routine allows user to jump to arbitrary page.
1567  * It implements simple page number editing algorithm.
1568  *
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.
1573  *
1574  * How this works.
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.
1579  *
1580  * +-----+------------+------------------+
1581  * | dec | pagenumdec | displayed number |
1582  * +-----+------------+------------------+
1583  * |     | 0x000      | 100              |
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  * +-----+------------+------------------+
1595  * |     | 0x000      | 123              |
1596  * +-----+------------+------------------+
1597  *
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.
1601  */
1602 static void vbi_add_dec(priv_vbi_t * priv, char *dec)
1603 {
1604     int count, shift;
1605     if (!dec)
1606         return;
1607     if (!priv->on)
1608         return;
1609     if ((*dec<'0' || *dec>'9') && *dec!='-')
1610         return;
1611     if (!priv->pagenumdec) //first digit cannot be '0','9' or '-'
1612         if(*dec=='-' || *dec=='0' || *dec=='9')
1613             return;
1614     pthread_mutex_lock(&(priv->buffer_mutex));
1615     count=(priv->pagenumdec>>12)&0xf;
1616     if (*dec=='-') {
1617         count--;
1618         if (count)
1619             priv->pagenumdec=((priv->pagenumdec>>4)&0xfff)|(count<<12);
1620         else
1621             priv->pagenumdec=0;
1622     } else {
1623         shift = count * 4;
1624         count++;
1625         priv->pagenumdec=
1626             (((priv->pagenumdec)<<4|(*dec-'0'))&0xfff)|(count<<12);
1627         if (count==3) {
1628             priv->pagenum=priv->pagenumdec&0x7ff;
1629             priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1630             priv->pagenumdec=0;
1631         }
1632     }
1633     pthread_mutex_unlock(&(priv->buffer_mutex));
1634 }
1635
1636
1637 /**
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)
1642  */
1643 int teletext_control(void* p, int cmd, void *arg)
1644 {
1645     int fine_tune=99;
1646     priv_vbi_t* priv=(priv_vbi_t*)p;
1647     tt_page* pgc;
1648
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;
1653
1654     switch (cmd) {
1655     case TV_VBI_CONTROL_RESET:
1656     {
1657         int i;
1658         tv_param_t* tv_param=arg;
1659         pthread_mutex_lock(&(priv->buffer_mutex));
1660         priv->pagenumdec=0;
1661         clear_cache(priv);
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);
1671             }
1672             mp_msg(MSGT_TV,MSGL_INFO,"  %3d  %s\n",
1673                 tt_languages[i].lang_code, tt_languages[i].lang_name);
1674         }else{
1675             for(i=0; tt_languages[i].lang_code; i++){
1676                 if(tt_languages[i].lang_code==tv_param->tlang)
1677                     break;
1678             }
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;
1683             }
1684         }
1685         priv->page_changed=1;
1686         pthread_mutex_unlock(&(priv->buffer_mutex));
1687         return TVI_CONTROL_TRUE;
1688     }
1689     case TV_VBI_CONTROL_START:
1690     {
1691         int i;
1692         tt_stream_props* ptsp=*(tt_stream_props**)arg;
1693
1694         if(!ptsp)
1695             return TVI_CONTROL_FALSE;
1696
1697         priv=calloc(1,sizeof(priv_vbi_t));
1698
1699         priv->ptsp=malloc(sizeof(tt_stream_props));
1700         memcpy(priv->ptsp,ptsp,sizeof(tt_stream_props));
1701         *(priv_vbi_t**)arg=priv;
1702
1703         priv->subpagenum=0x3f7f;
1704         pthread_mutex_init(&priv->buffer_mutex, NULL);
1705         priv->pagenumdec=0;
1706         for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++)
1707             priv->display_page[i]=tt_space;
1708
1709         priv->mag=calloc(8,sizeof(mag_t));
1710         init_cache(priv);
1711         init_vbi_consts(priv);
1712         pll_reset(priv,fine_tune);
1713         priv->page_changed=1;
1714         return TVI_CONTROL_TRUE;
1715     }
1716     case TV_VBI_CONTROL_STOP:
1717     {
1718         if(priv->mag)
1719             free(priv->mag);
1720         if(priv->ptsp)
1721             free(priv->ptsp);
1722         destroy_cache(priv);
1723         priv->page_changed=1;
1724         free(priv);
1725         return TVI_CONTROL_TRUE;
1726     }
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:
1743         if(!priv->on)
1744             return TVI_CONTROL_FALSE;
1745         *(int *)arg=priv->zoom;
1746         return TVI_CONTROL_TRUE;
1747     case TV_VBI_CONTROL_SET_HALF_PAGE:
1748     {
1749         int val=*(int*)arg;
1750         val%=3;
1751         if(val<0)
1752             val+=3;
1753         pthread_mutex_lock(&(priv->buffer_mutex));
1754         priv->zoom=val;
1755         priv->page_changed=1;
1756         pthread_mutex_unlock(&(priv->buffer_mutex));
1757         return TVI_CONTROL_TRUE;
1758     }
1759     case TV_VBI_CONTROL_GO_LINK:
1760     {
1761         int val=*(int *) arg;
1762         if(val<1 || val>6)
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;
1768         }
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;
1772         }
1773         priv->pagenum=pgc->links[val-1].pagenum;
1774         if(pgc->links[val-1].subpagenum!=0x3f7f)
1775             priv->subpagenum=pgc->links[val-1].subpagenum;
1776         else
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;
1781     }
1782     case TV_VBI_CONTROL_SET_PAGE:
1783     {
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);
1790         priv->pagenumdec=0;
1791         priv->page_changed=1;
1792         pthread_mutex_unlock(&(priv->buffer_mutex));
1793         return TVI_CONTROL_TRUE;
1794     }
1795     case TV_VBI_CONTROL_STEP_PAGE:
1796     {
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);
1801         priv->pagenumdec=0;
1802         priv->page_changed=1;
1803         pthread_mutex_unlock(&(priv->buffer_mutex));
1804         return TVI_CONTROL_TRUE;
1805     }
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));
1811         priv->pagenumdec=0;
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:
1831         if(!priv->on)
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;
1848     }
1849     return TVI_CONTROL_UNKNOWN;
1850 }