Ignore svn changes up to r30324
[mplayer/glamo.git] / libmpcodecs / dec_teletext.c
blobac12b9aa4ab1d61097fb9ec7df267ef59b798d15
1 /*
2 * Teletext support
4 * Copyright (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 * Based on Attila Otvos' teletext patch, Michael Niedermayer's
24 * proof-of-concept teletext capture utility and some parts
25 * (decode_raw_line_runin,pll_add,pll_reset) of MythTV project.
26 * Code for calculating [soc:eoc] is based on aletv of Edgar Toernig.
28 * Teletext system is described in
29 * ETS 300 706 "Enhanced Teletext specification" : May 1997
30 * http://www.themm.net/~mihu/linux/saa7146/specs/ets_300706e01p.pdf
32 * Some implementation details:
33 * How to port teletext to another tvi_* driver (see tvi_v4l2.c for example):
35 * 1. Implement TVI_CONTROL_VBI_INIT (initialize driver-related vbi subsystem,
36 * start grabbing thread)
37 * input data: vbi device name.
38 * (driver should also call TV_VBI_CONTROL_START for common vbi subsystem initialization
39 * with pointer to initialized tt_stream_properties structure.
40 * After ioctl call variable will contain pointer to initialized priv_vbi_t structure.
42 * 2. After receiving next chunk of raw vbi data call TV_VBI_CONTROL_DECODE_PAGE
43 * ioctl with pointer to data buffer
44 * 3. pass all other VBI related ioctl cmds to teletext_control routine
46 * Page displaying process consist of following stages:
48 * ---grabbing stage---
49 * 0. stream/tvi_*.c: vbi_grabber(...)
50 * getting vbi data from video device
51 * ---decoding stage---
52 * 1. libmpcodecs/dec_teletext.c: decode_raw_line_runin(...) or decode_raw_line_sine(...)
53 * decode raw vbi data into sliced 45(?) bytes long packets
54 * 2. libmpcodecs/dec_teletext.c: decode_pkt0(...), decode_pkt_page(...)
55 * packets processing (header analyzing, storing complete page in cache,
56 * only raw member of tt_char is filled at this stage)
57 * 3. libmpcodecs/dec_teletext.c: decode_page(...)
58 * page decoding. filling unicode,gfx,ctl,etc members of tt_char structure
59 * with appropriate values according to teletext control chars, converting
60 * text to utf8.
61 * ---rendering stage---
62 * 4. libmpcodecs/dec_teletext.c: prepare_visible_page(...)
63 * processing page. adding number of just received by background process
64 * teletext page, adding current time,etc.
65 * 5. libvo/sub.c: vo_update_text_teletext(...)
66 * rendering displayable osd with text and graphics
68 * TODO:
69 * v4lv1,bktr support
70 * spu rendering
71 * is better quality on poor signal possible ?
72 * link support
73 * greyscale osd
74 * slave command for dumping pages
75 * fix bcd<->dec as suggested my Michael
77 * BUGS:
78 * wrong colors in debug dump
79 * blinking when visible page was just updated
82 #include "config.h"
84 #include <stdlib.h>
85 #include <string.h>
86 #include <unistd.h>
87 #include <errno.h>
88 #include <math.h>
89 #include <stdio.h>
91 #ifdef HAVE_PTHREADS
92 // pthreads are needed for async updates from v4l(2)
93 // FIXME: try to avoid using pthread calls when running only a single
94 // thread as e.g. with DVB teletext
95 #include <pthread.h>
96 #else
97 #define pthread_mutex_init(m, p)
98 #define pthread_mutex_destroy(m)
99 #define pthread_mutex_lock(m)
100 #define pthread_mutex_unlock(m)
101 #endif
103 #include "dec_teletext.h"
104 #include "mp_msg.h"
105 #include "help_mp.h"
106 #include "libmpcodecs/img_format.h"
107 #include "libavutil/common.h"
108 #include "input/input.h"
109 #include "osdep/timer.h"
111 //#define DEBUG_DUMP 1
113 /// page magazine entry structure
114 typedef struct mag_s{
115 tt_page* pt;
116 int order;
117 } mag_t;
119 typedef struct {
120 int on; ///< teletext on/off
121 int pagenum; ///< seek page number
122 int subpagenum; ///< seek subpage
123 int curr_pagenum; ///< current page number
124 int pagenumdec; ///< set page num with dec
126 teletext_format tformat; ///< see teletext_format enum
127 teletext_zoom zoom; ///< see teletext_zoom enum
128 mag_t* mag; ///< pages magazine (has 8 entities)
129 int primary_language; ///< primary character set
130 int secondary_language; ///< secondary character set
131 /// Currently displayed page (with additional info, e.g current time)
132 tt_char display_page[VBI_ROWS*VBI_COLUMNS];
133 /// number of raw bytes between two subsequent encoded bits
134 int bpb;
135 /// clock run-in sequence will be searched in buffer in [soc:eoc] bytes range
136 int soc;
137 int eoc;
138 /// minimum number of raw vbi bytes wich can be decoded into 8 data bits
139 int bp8bl;
140 /// maximum number of raw vbi bytes wich can be decoded into 8 data bits
141 int bp8bh;
143 int pll_adj;
144 int pll_dir;
145 int pll_cnt;
146 int pll_err;
147 int pll_lerr;
148 int pll_fixed;
149 /// vbi stream properties (buffer size,bytes per line, etc)
150 tt_stream_props* ptsp;
151 #ifdef HAVE_PTHREADS
152 pthread_mutex_t buffer_mutex;
153 #endif
155 tt_page** ptt_cache;
156 unsigned char* ptt_cache_first_subpage;
157 /// network info
158 unsigned char initialpage;
159 unsigned int initialsubpage;
160 unsigned int networkid;
161 int timeoffset; // timeoffset=realoffset*2
162 unsigned int juliandate;
163 unsigned int universaltime;
164 unsigned char networkname[21];
165 int cache_reset;
166 /// "page changed" flag: 0-unchanged, 1-entire page, 3-only header
167 int page_changed;
168 int last_rendered;
169 } priv_vbi_t;
171 static unsigned char fixParity[256];
173 static const tt_char tt_space={0x20,7,0,0,0,0,0,0,0x20};
174 static const tt_char tt_error={'?',1,0,0,0,0,0,0,'?'}; // Red '?' on black background
175 static double si[12];
176 static double co[12];
178 #define VBI_FORMAT(priv) (*(priv->ptsp))
180 #define FIXP_SH 16
181 #define ONE_FIXP (1<<FIXP_SH)
182 #define FIXP2INT(a) ((a)>>FIXP_SH)
183 #define ANY2FIXP(a) ((int)((a)*ONE_FIXP))
185 static const unsigned char corrHamm48[256]={
186 0x01, 0xff, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff,
187 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07,
188 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00,
189 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff,
190 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07,
191 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x07,
192 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff,
193 0x06, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07,
194 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09,
195 0x02, 0x02, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff,
196 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff,
197 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03,
198 0x04, 0xff, 0xff, 0x05, 0x04, 0x04, 0x04, 0xff,
199 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07,
200 0xff, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, 0x05,
201 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff,
202 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09,
203 0x0a, 0xff, 0xff, 0x0b, 0x0a, 0x0a, 0x0a, 0xff,
204 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff,
205 0xff, 0x0b, 0x0b, 0x0b, 0x0a, 0xff, 0xff, 0x0b,
206 0x0c, 0x0c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff,
207 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07,
208 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x0d, 0x0d,
209 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff,
210 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x09,
211 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09,
212 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09,
213 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff,
214 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09,
215 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0e, 0x0f, 0xff,
216 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff,
217 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x0e, 0xff, 0x0e };
220 enum {
221 LATIN=0,
222 CYRILLIC1,
223 CYRILLIC2,
224 CYRILLIC3,
225 GREEK,
226 LANGS
229 // conversion table for chars 0x20-0x7F (UTF8)
230 // TODO: add another languages
231 static const unsigned int lang_chars[LANGS][0x60]={
233 //Latin
234 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
235 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
236 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
237 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
238 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
239 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
240 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
241 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
242 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
243 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
244 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
245 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
248 //Cyrillic-1 (Serbian/Croatian)
249 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
250 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
251 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
252 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
253 0x0427,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
254 0x0425,0x0418,0x0408,0x041a,0x041b,0x041c,0x041d,0x041e,
255 0x041f,0x040c,0x0420,0x0421,0x0422,0x0423,0x0412,0x0403,
256 0x0409,0x040a,0x0417,0x040b,0x0416,0x0402,0x0428,0x040f,
257 0x0447,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
258 0x0445,0x0438,0x0428,0x043a,0x043b,0x043c,0x043d,0x043e,
259 0x043f,0x042c,0x0440,0x0441,0x0442,0x0443,0x0432,0x0423,
260 0x0429,0x042a,0x0437,0x042b,0x0436,0x0422,0x0448,0x042f
263 //Cyrillic-2 (Russian/Bulgarian)
264 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
265 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
266 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
267 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
268 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
269 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
270 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
271 0x042c,0x042a,0x0417,0x0428,0x042d,0x0429,0x0427,0x042b,
272 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
273 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
274 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
275 0x044c,0x044a,0x0437,0x0448,0x044d,0x0449,0x0447,0x044b
278 //Cyrillic-3 (Ukrainian)
279 0x20,0x21,0x22,0x23,0x24,0x25,0xef,0x27,
280 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
281 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
282 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
283 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
284 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
285 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
286 0x042c,0x49,0x0417,0x0428,0x042d,0x0429,0x0427,0xcf,
287 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
288 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
289 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
290 0x044c,0x69,0x0437,0x0448,0x044d,0x0449,0x0447,0xFF
293 //Greek
294 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
295 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
296 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
297 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
298 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
299 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
300 0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
301 0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
302 0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
303 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
304 0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
305 0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,0x03cf
310 * Latin National Option Sub-Sets
311 * see Table 36 of ETS specification for details.
313 * 00: £ $ @ « ½ » ¬ # ­ ¼ ¦ ¾ ÷ English
314 * 01: é ï à ë ê ù î # è â ô û ç French
315 * 02: # ¤ É Ä Ö Å Ü _ é ä ö å ü Swedish/Finnish/Hungarian
316 * 03: # ů č ť ž ý í ř é á ě ú š Czech/Slovak
317 * 04: # $ § Ä Ö Ü ^ _ ° ä ö ü ß German
318 * 05: ç $ ¡ á é í ó ú ¿ ü ñ è à Portuguese/Spanish
319 * 06: £ $ é ° ç » ¬ # ù à ò è ì Italian
322 static const unsigned int latin_subchars[8][13]={
323 // English
324 {0xa3,0x24,0x40,0xab,0xbd,0xbb,0xac,0x23,0xad,0xbc,0xa6,0xbe,0xf7},
325 // French
326 {0xe9,0xef,0xe0,0xeb,0xea,0xf9,0xee,0x23,0xe8,0xe2,0xf4,0xfb,0xe7},
327 // Swedish/Finnish/Hungarian
328 {0x23,0xa4,0xc9,0xc4,0xd6,0xc5,0xdc,0x5f,0xe9,0xe4,0xf6,0xe5,0xfc},
329 // Czech/Slovak
330 {0x23,0x16f,0x10d,0x165,0x17e,0xfd,0xed,0x159,0xe9,0xe1,0x11b,0xfa,0x161},
331 // German
332 {0x23,0x24,0xa7,0xc4,0xd6,0xdc,0x5e,0x5f,0xb0,0xe4,0xf6,0xfc,0xdf},
333 // Portuguese/Spanish
334 {0xe7,0x24,0xa1,0xe1,0xe9,0xed,0xf3,0xfa,0xbf,0xfc,0xf1,0xe8,0xe0},
335 // Italian
336 {0xa3,0x24,0xe9,0xb0,0xe7,0xbb,0xac,0x23,0xf9,0xe0,0xf2,0xe8,0xec},
337 // Reserved
338 {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e}
342 * List of supported languages.
344 * lang_code bits for primary Language:
345 * bits 7-4 corresponds to bits 14-11 of 28 packet's first triplet
346 * bits 3-1 corresponds to bits C12-C14 of packet 0 (lang)
348 * lang_code bits for secondary Language:
349 * bits 7-5 corresponds to bits 3-1 of 28 packet's second triplet
350 * bits 4,2 corresponds to bits 18,16 of 28 packet's first triplet
351 * bits 3,1 corresponds to bits 15,17 of 28 packet's first triplet
353 * For details see Tables 32 and 33 of specification (subclause 15.2)
355 struct {
356 unsigned char lang_code;
357 unsigned char charset;
358 const char* lang_name;
359 } const tt_languages[]=
361 { 0x01, LATIN, "French"},
362 { 0x02, LATIN, "Swedish/Finnish/Hungarian"},
363 { 0x03, LATIN, "Czech/Slovak"},
364 { 0x04, LATIN, "German"},
365 { 0x05, LATIN, "Portuguese/Spanish"},
366 { 0x06, LATIN, "Italian"},
368 { 0x08, LATIN, "Polish"},
369 { 0x09, LATIN, "French"},
370 { 0x0a, LATIN, "Swedish/Finnish/Hungarian"},
371 { 0x0b, LATIN, "Czech/Slovak"},
372 { 0x0c, LATIN, "German"},
373 { 0x0e, LATIN, "Italian"},
375 { 0x10, LATIN, "English"},
376 { 0x11, LATIN, "French"},
377 { 0x12, LATIN, "Swedish/Finnish/Hungarian"},
378 { 0x13, LATIN, "Turkish"},
379 { 0x14, LATIN, "German"},
380 { 0x15, LATIN, "Portuguese/Spanish"},
381 { 0x16, LATIN, "Italian"},
383 { 0x1d, LATIN, "Serbian/Croatian/Slovenian (Latin)"},
385 { 0x20, CYRILLIC1, "Serbian/Croatian (Cyrillic)"},
386 { 0x21, CYRILLIC2, "Russian, Bulgarian"},
387 { 0x22, LATIN, "Estonian"},
388 { 0x23, LATIN, "Czech/Slovak"},
389 { 0x24, LATIN, "German"},
390 { 0x25, CYRILLIC3, "Ukrainian"},
391 { 0x26, LATIN, "Lettish/Lithuanian"},
393 { 0x33, LATIN, "Turkish"},
394 { 0x37, GREEK, "Greek"},
396 { 0x40, LATIN, "English"},
397 { 0x41, LATIN, "French"},
398 // { 0x47, ARABIC, "Arabic"},
400 // { 0x55, HEBREW, "Hebrew"},
401 // { 0x57, ARABIC, "Arabic"},
403 { 0x00, LATIN, "English"},
407 * \brief 24/18 Hamming code decoding
408 * \param data bytes with hamming code (array must be at least 3 bytes long)
409 * \return -1 if multiple bit error occured, D1-DI data bits - otherwise
411 * \note Bits must be correctly ordered, that is for 24/18 (lowest bit first)
412 * P1 P2 D1 P3 D2 D3 D4 P4 D5 D6 D7 D8 D9 DA DB P5 DC DD DE DF DG DH DI P6
414 static int corrHamm24(unsigned char *data){
415 unsigned char syndrom=0;
416 int cw=data[0] | (data[1]<<8) | (data[2]<<16);
417 int i;
419 for(i=0;i<23;i++)
420 syndrom^=((cw>>i)&1)*(i+33);
422 syndrom^=(cw>>11)&32;
424 if(syndrom&31){
425 if(syndrom < 32 || syndrom > 55)
426 return -1;
427 cw ^= 1<<((syndrom&31)-1);
430 return (cw&4)>>2 |
431 (cw&0x70)>>3 |
432 (cw&0x3f00)>>4 |
433 (cw&0x3f0000)>>5;
437 * \brief converts language bits to charset index
438 * \param lang language bits
439 * \return charset index in lang_chars array
441 static int lang2charset (int lang){
442 int i;
443 for(i=0;tt_languages[i].lang_code;i++)
444 if(tt_languages[i].lang_code==lang)
445 break;
447 return tt_languages[i].charset;
451 * \brief convert chars from curent teletext codepage into MPlayer charset
452 * \param p raw teletext char to decode
453 * \param charset index on lang_chars
454 * \param lang index in substitution array (latin charset only)
455 * \return UTF8 char
457 * \remarks
458 * routine will analyze raw member of given tt_char structure and
459 * fill unicode member of the same struct with appropriate utf8 code.
461 static unsigned int conv2uni(unsigned int p,int charset,int lang)
464 if(p<0x80 && p>=0x20){
465 if(charset==LATIN){
466 lang&=7;
467 if (p>=0x23 && p<=0x24){
468 return latin_subchars[lang][p-0x23];
469 }else if (p==0x40){
470 return latin_subchars[lang][2];
471 }else if (p>=0x5b && p<=0x60){
472 return latin_subchars[lang][p-0x5b+3];
473 }else if (p>=0x7b && p<=0x7e){
474 return latin_subchars[lang][p-0x7b+9];
477 return lang_chars[charset][p-0x20];
478 }else
479 return 0x20;
482 static void init_vbi_consts(priv_vbi_t* priv){
483 int i,j;
484 double ang;
485 for(i=0; i<256; i++){
486 j=i&0x7F;
487 j^= j+j;
488 j^= j<<2;
489 j^= j<<4;
490 fixParity[i]= i ^ (j&0x80) ^ 0x80;
493 for(i=0,ang=0; i<12; i++,ang+=M_PI/priv->bpb){
494 si[i]= sin(ang);
495 co[i]= cos(ang);
498 priv->bpb=(priv->ptsp->sampling_rate/6937500.0)*ONE_FIXP+0.5;
499 priv->soc=FFMAX(9.2e-6*priv->ptsp->sampling_rate-priv->ptsp->offset, 0);
500 priv->eoc=FFMIN(12.9e-6*priv->ptsp->sampling_rate-priv->ptsp->offset,
501 priv->ptsp->samples_per_line-43*8*priv->bpb/ONE_FIXP);
502 if (priv->eoc - priv->soc<16*priv->bpb/ONE_FIXP){ // invalid [soc:eoc]
503 priv->soc=0;
504 priv->eoc=92;
506 priv->bp8bl=0.97*8*priv->bpb/ONE_FIXP; // -3% tolerance
507 priv->bp8bh=1.03*8*priv->bpb/ONE_FIXP; // +3% tolerance
510 * \brief calculate increased/decreased by given value page number
511 * \param curr current page number in hexadecimal for
512 * \param direction decimal value (can be negative) to add to value
513 * of curr parameter
514 * \return new page number in hexadecimal form
516 * VBI page numbers are represented in special hexadecimal form, e.g.
517 * page with number 123 (as seen by user) internally has number 0x123.
518 * and equation 0x123+8 should be equal to 0x131 instead of regular 0x12b.
521 * Page numbers 0xYYY (where Y is not belongs to (0..9).
522 * Page number belongs to [0x000,0x799] or [0x100:0x899] (first 0 can be
523 * treated as '8')
525 static int steppage(int p, int direction, int skip_hidden)
527 if(skip_hidden)
528 p=(p&15)+((p>>4)&15)*10+(p>>8)*100;
529 p+=direction;
530 if(skip_hidden){
531 p=(p+800)%800;
532 p=(p%10)+((p/10)%10)*16+(p/100)*256;
535 return p&0x7ff;
539 ------------------------------------------------------------------
540 Cache stuff
541 ------------------------------------------------------------------
545 * \brief add/update entry in cache
546 * \param priv private data structure
547 * \param pg page to store in cache
548 * \param line line to update (value below 0 means update entire page)
550 static void put_to_cache(priv_vbi_t* priv,tt_page* pg,int line){
551 tt_page* pgc; //page in cache
552 int i,j,count;
554 if(line<0){
555 i=0;
556 count=VBI_ROWS*VBI_COLUMNS;
557 }else if(line<VBI_ROWS){
558 i=line*VBI_COLUMNS;
559 count=(line+1)*VBI_COLUMNS;
560 }else
561 return;
563 pthread_mutex_lock(&(priv->buffer_mutex));
565 if(!priv->ptt_cache[pg->pagenum]){
566 priv->ptt_cache[pg->pagenum]=calloc(1,sizeof(tt_page));
567 pgc=priv->ptt_cache[pg->pagenum];
568 }else{
569 pgc=priv->ptt_cache[pg->pagenum];
570 while(pgc->next_subpage && pgc->subpagenum!=pg->subpagenum)
571 pgc=pgc->next_subpage;
573 if(pgc->subpagenum!=pg->subpagenum){
574 pgc->next_subpage=calloc(1,sizeof(tt_page));
575 pgc=pgc->next_subpage;
578 pgc->pagenum=pg->pagenum;
579 pgc->subpagenum=pg->subpagenum;
580 pgc->primary_lang=pg->primary_lang;
581 pgc->secondary_lang=pg->secondary_lang;
582 pgc->flags=pg->flags;
583 for(j=0;j<6;++j)
584 pgc->links[j]=pg->links[j];
585 //instead of copying entire page into cache, copy only undamaged
586 //symbols into cache
587 for(;i<count;i++){
588 if(!(pg->raw[i]&0x80))
589 pgc->raw[i]=pg->raw[i];
590 else
591 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"char error. pg:%x, c[%d]=0x%x\n",
592 pg->pagenum,i,pg->raw[i]);
594 pgc->active=1;
595 pthread_mutex_unlock(&(priv->buffer_mutex));
599 * \brief get any subpage number of given page
600 * \param priv private data structure
601 * \param pagenum page number to search subpages in
603 * \return subpage number of first found subpage which belongs to
604 * given page number
606 * \note page itself is subpage too (and usually has subpage number 0)
608 static inline int get_subpagenum_from_cache(priv_vbi_t* priv, int pagenum){
609 if (!priv->ptt_cache[pagenum])
610 return 0x3f7f;
611 else
612 return priv->ptt_cache[pagenum]->subpagenum;
616 * \brief get page from cache by it page and subpage number
617 * \param priv private data structure
618 * \param pagenum page number
619 * \param subpagenum subpage number
621 * \return pointer to tt_page structure if requested page is found
622 * and NULL otherwise
624 static inline tt_page* get_from_cache(priv_vbi_t* priv, int pagenum,int subpagenum){
625 tt_page* tp=priv->ptt_cache[pagenum];
627 while(tp && tp->subpagenum!=subpagenum)
628 tp=tp->next_subpage;
629 return tp;
633 * \brief clears cache
634 * \param priv private data structure
636 * Deletes all tt_page structures from cache and frees allocated memory.
637 * Only zero-filled array of pointers remains in memory
639 static void clear_cache(priv_vbi_t* priv){
640 int i;
641 tt_page* tp;
644 Skip next 5 buffers to avoid mixing teletext pages from different
645 channels during channel switch
647 priv->cache_reset=5;
648 for(i=0;i<VBI_MAX_PAGES;i++){
649 while(priv->ptt_cache[i]){
650 tp=priv->ptt_cache[i];
651 priv->ptt_cache[i]=tp->next_subpage;
652 free(tp);
655 priv->initialsubpage=priv->networkid=0;
656 priv->timeoffset=0;
657 priv->juliandate=priv->universaltime=0;
658 memset(priv->networkname,0,21);
662 * \brief cache initialization
663 * \param priv private data structure
665 * \note Has to be called before any cache operations!
667 static void init_cache(priv_vbi_t* priv){
668 priv->ptt_cache=calloc(VBI_MAX_PAGES,sizeof(tt_page*));
672 * \brief destroys cache
673 * \param priv private data structure
675 * Frees all memory allocated for cache (including array of pointers).
676 * It is safe to call this routine multiple times
678 static void destroy_cache(priv_vbi_t* priv){
679 if(priv->ptt_cache){
680 clear_cache(priv);
681 free(priv->ptt_cache);
682 priv->ptt_cache=NULL;
687 ------------------------------------------------------------------
688 Decoder stuff
689 ------------------------------------------------------------------
692 * \brief converts raw teletext page into useful format (1st rendering stage)
693 * \param pg page to decode
694 * \param raw raw data to decode page from
695 * \param primary_lang primary language code
696 * \param secondary_lang secondary language code
698 * Routine fills tt_char structure of each teletext_page character with proper
699 * info about foreground and background colors, character
700 * type (graphics/control/text).
702 static void decode_page(tt_char* p,unsigned char* raw,int primary_lang,int secondary_lang,int flags)
704 int row,col;
705 int prim_charset=lang2charset(primary_lang);
706 int sec_charset=lang2charset(secondary_lang);
708 for(row=0;row<VBI_ROWS;row++) {
709 int prim_lang=1;
710 int gfx=0;
711 int fg_color=7;
712 int bg_color=0;
713 int separated=0;
714 int conceal=0;
715 int hold=0;
716 int flash=0;
717 int box=0;
719 tt_char tt_held=tt_space;
720 for(col=0;col<VBI_COLUMNS;col++){
721 int i=row*VBI_COLUMNS+col;
722 int c=raw[i];
723 p[i].raw=c;
724 if(c&0x80){ //damaged char
725 p[i]=tt_error;
726 continue;
728 if((flags&TT_PGFL_SUBTITLE) || (flags&TT_PGFL_NEWFLASH))
729 p[i].hidden=!box;
730 else
731 p[i].hidden=0;
732 p[i].gfx=gfx?(separated?2:1):0;
733 p[i].lng=prim_lang;
734 p[i].ctl=(c&0x60)==0?1:0;
735 p[i].fg=fg_color;
736 p[i].bg=bg_color;
737 p[i].flh=flash;
739 if ((c&0x60)==0){ //control chars
740 if(c>=0x08 && c<=0x09){//Flash/Steady
741 flash=c==0x08;
742 p[i].flh=flash;
743 if(c==0x09){
744 p[i].fg=fg_color;
745 p[i].bg=bg_color;
747 }else if(c>=0x0a && c<=0x0b){
748 box=c&1;
749 }else if(c>=0x0c && c<=0x0f){
750 }else if (c<=0x17){ //colors
751 fg_color=c&0x0f;
752 gfx=c>>4;
753 conceal=0;
754 if(!gfx) hold=0;
755 }else if (c<=0x18){
756 conceal=1;
757 }else if (c<=0x1a){ //Contiguous/Separated gfx
758 separated=!(c&1);
759 }else if (c<=0x1b){
760 prim_lang=!prim_lang;
761 }else if (c<=0x1d){
762 bg_color=(c&1)?fg_color:0;
763 p[i].bg=bg_color;
764 }else{ //Hold/Release Graphics
765 hold=!(c&1);
767 p[i].ctl=1;
768 if(hold || c==0x1f){
769 p[i]=tt_held;
770 p[i].fg=fg_color;
771 p[i].bg=bg_color;
772 }else
773 p[i].unicode=p[i].gfx?0:' ';
774 continue;
777 if(conceal){
778 p[i].gfx=0;
779 p[i].unicode=' ';
780 }else if(gfx){
781 p[i].unicode=c-0x20;
782 if (p[i].unicode>0x3f) p[i].unicode-=0x20;
783 tt_held=p[i];
784 }else{
785 if(p[i].lng){
786 p[i].unicode=conv2uni(c,prim_charset,primary_lang&7);
787 }else{
788 p[i].unicode=conv2uni(c,sec_charset,secondary_lang&7);
791 p[i].fg=fg_color;
792 p[i].bg=bg_color;
798 * \brief prepares current page for displaying
799 * \param priv_vbi private data structure
801 * Routine adds some useful info (time and page number of page, grabbed by
802 * background thread to top line of current page). Displays "No teletext"
803 * string if no vbi data available.
805 #define PRINT_HEX(dp,i,h) dp[i].unicode=((h)&0xf)>9?'A'+((h)&0xf)-10:'0'+((h)&0xf)
806 static void prepare_visible_page(priv_vbi_t* priv){
807 tt_page *pg,*curr_pg;
808 unsigned char *p;
809 int i;
811 pthread_mutex_lock(&(priv->buffer_mutex));
812 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"dec_teletext: prepare_visible_page pg:0x%x, sub:0x%x\n",
813 priv->pagenum,priv->subpagenum);
814 if(priv->subpagenum==0x3f7f) //no page yet
815 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
817 pg=get_from_cache(priv,priv->pagenum,priv->subpagenum);
818 mp_dbg(MSGT_TELETEXT,MSGL_DBG3,"dec_teletext: prepare_vibible_page2 pg:0x%x, sub:0x%x\n",
819 priv->pagenum,priv->subpagenum);
821 curr_pg=get_from_cache(priv,priv->curr_pagenum,
822 get_subpagenum_from_cache(priv,priv->curr_pagenum));
823 if (!pg && !curr_pg){
824 p=_("No teletext");
825 for(i=0;i<VBI_COLUMNS && *p;i++){
826 GET_UTF8(priv->display_page[i].unicode,*p++,break;);
828 for(;i<VBI_ROWS*VBI_COLUMNS;i++)
829 priv->display_page[i]=tt_space;
830 pthread_mutex_unlock(&(priv->buffer_mutex));
831 return;
834 if (!pg || !pg->active){
835 for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++){
836 priv->display_page[i]=tt_space;
838 }else{
839 decode_page(priv->display_page,pg->raw,pg->primary_lang,pg->secondary_lang,pg->flags);
840 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"page #%x was decoded!\n",pg->pagenum);
843 PRINT_HEX(priv->display_page,0,(priv->curr_pagenum&0x700)?priv->curr_pagenum>>8:8);
844 PRINT_HEX(priv->display_page,1,priv->curr_pagenum>>4);
845 PRINT_HEX(priv->display_page,2,priv->curr_pagenum);
846 priv->display_page[3].unicode=' ';
847 priv->display_page[4].unicode=' ';
848 switch(priv->pagenumdec>>12){
849 case 1:
850 priv->display_page[5].unicode='_';
851 priv->display_page[6].unicode='_';
852 PRINT_HEX(priv->display_page,7,priv->pagenumdec);
853 break;
854 case 2:
855 priv->display_page[5].unicode='_';
856 PRINT_HEX(priv->display_page,6,priv->pagenumdec>>4);
857 PRINT_HEX(priv->display_page,7,priv->pagenumdec);
858 break;
859 default:
860 PRINT_HEX(priv->display_page,5,(priv->pagenum&0x700)?priv->pagenum>>8:8);
861 PRINT_HEX(priv->display_page,6,priv->pagenum>>4);
862 PRINT_HEX(priv->display_page,7,priv->pagenum);
864 if(priv->subpagenum!=0x3f7f){
865 priv->display_page[8].unicode='.';
866 PRINT_HEX(priv->display_page,9,priv->subpagenum>>4);
867 PRINT_HEX(priv->display_page,10,priv->subpagenum);
868 }else{
869 priv->display_page[8].unicode=' ';
870 priv->display_page[9].unicode=' ';
871 priv->display_page[10].unicode=' ';
873 priv->display_page[11].unicode=' ';
874 for(i=VBI_COLUMNS;i>VBI_TIME_LINEPOS ||
875 ((curr_pg->raw[i]&0x60) && curr_pg->raw[i]!=0x20 && i>11);
876 --i)
877 if(curr_pg->raw[i]&0x60)
878 priv->display_page[i].unicode=curr_pg->raw[i];
879 else
880 priv->display_page[i].unicode=' ';
881 pthread_mutex_unlock(&(priv->buffer_mutex));
884 ------------------------------------------------------------------
885 Renderer stuff
886 ------------------------------------------------------------------
888 #ifdef DEBUG_DUMP
890 * \brief renders teletext page into given file
891 * \param pt page to render
892 * \param f opened file descriptor
893 * \param pagenum which page to render
894 * \param colored use colors not implemented yet)
896 * Text will be UTF8 encoded
898 static void render2text(tt_page* pt,FILE* f,int colored){
899 int i,j;
900 unsigned int u;
901 unsigned char buf[8];
902 unsigned char tmp;
903 int pos;
904 tt_char dp[VBI_ROWS*VBI_COLUMNS];
905 int color=0;
906 int bkg=0;
907 int c1,b1;
908 if(!pt)
909 return;
910 fprintf(f,"+========================================+\n");
911 fprintf(f,"| lang:%d pagenum:0x%x subpagenum:%d flags:0x%x|\n",
912 pt->lang,
913 pt->pagenum,
914 pt->subpagenum,
916 fprintf(f,"+----------------------------------------+\n");
918 decode_page(dp,pt->raw,pt->primary_lang,pt->secondary_lang,pt->flags);
919 for(i=0;i<VBI_ROWS;i++){
920 fprintf(f,"|");
921 if(colored) fprintf(f,"\033[40m");
922 for(j=0;j<VBI_COLUMNS;j++)
924 u=dp[i*VBI_COLUMNS+j].unicode;
925 if(dp[i*VBI_COLUMNS+j].fg <= 7)
926 c1=30+dp[i*VBI_COLUMNS+j].fg;
927 else
928 c1=38;
929 if(dp[i*VBI_COLUMNS+j].bg <= 7)
930 b1=40+dp[i*VBI_COLUMNS+j].bg;
931 else
932 b1=40;
933 if (b1!=bkg && colored){
934 fprintf(f,"\033[%dm",b1);
935 bkg=b1;
937 if(c1!=color && colored){
938 fprintf(f,"\033[%dm",c1);
939 color=c1;
941 if(dp[i*VBI_COLUMNS+j].gfx){
942 fprintf(f,"*");
943 }else{
944 pos=0;
945 PUT_UTF8(u,tmp,if(pos<7) buf[pos++]=tmp;);
946 buf[pos]='\0';
947 fprintf(f,"%s",buf);
951 if (colored) fprintf(f,"\033[0m");
952 color=-1;bkg=-1;
953 fprintf(f,"|\n");
955 #if 1
956 //for debug
957 fprintf(f,"+====================raw=================+\n");
958 for(i=0;i<VBI_ROWS;i++){
959 for(j=0;j<VBI_COLUMNS;j++)
960 fprintf(f,"%02x ",dp[i*VBI_COLUMNS+j].raw);
961 fprintf(f,"\n");
963 fprintf(f,"+====================lng=================+\n");
964 for(i=0;i<VBI_ROWS;i++){
965 for(j=0;j<VBI_COLUMNS;j++)
966 fprintf(f,"%02x ",dp[i*VBI_COLUMNS+j].lng);
967 fprintf(f,"\n");
969 #endif
970 fprintf(f,"+========================================+\n");
974 * \brief dump page into pgXXX.txt file in vurrent directory
975 * \param pt page to dump
977 * \note XXX in filename is page number
978 * \note use only for debug purposes
980 static void dump_page(tt_page* pt)
982 FILE*f;
983 char name[100];
984 snprintf(name,99,"pg%x.txt",pt->pagenum);
985 f=fopen(name,"wb");
986 render2text(pt,f,1);
987 fclose(f);
989 #endif //DEBUG_DUMP
993 * \brief checks whether page is ready and copies it into cache array if so
994 * \param priv private data structure
995 * \param magAddr page's magazine address (0-7)
997 static void store_in_cache(priv_vbi_t* priv, int magAddr, int line){
998 mp_msg(MSGT_TELETEXT,MSGL_DBG2,"store_in_cache(%d): pagenum:%x\n",
999 priv->mag[magAddr].order,
1000 priv->mag[magAddr].pt->pagenum);
1002 put_to_cache(priv,priv->mag[magAddr].pt,line);
1003 priv->curr_pagenum=priv->mag[magAddr].pt->pagenum;
1005 #ifdef DEBUG_DUMP
1006 dump_page(get_from_cache(priv,
1007 priv->mag[magAddr].pt->pagenum,
1008 priv->mag[magAddr].pt->subpagenum));
1009 #endif
1014 ------------------------------------------------------------------
1015 Grabber stuff
1016 ------------------------------------------------------------------
1018 #define PLL_SAMPLES 4
1019 #define PLL_ERROR 4
1020 #define PLL_ADJUST 4
1023 * \brief adjust current phase for better signal decoding
1024 * \param n count of bytes processed (?)
1025 * \param err count of error bytes (?)
1027 * \remarks code was got from MythTV project
1029 static void pll_add(priv_vbi_t* priv,int n,int err){
1030 if(priv->pll_fixed)
1031 return;
1032 if(err>PLL_ERROR*2/3)
1033 err=PLL_ERROR*2/3;
1034 priv->pll_err+=err;
1035 priv->pll_cnt+=n;
1036 if(priv->pll_cnt<PLL_SAMPLES)
1037 return;
1038 if(priv->pll_err>PLL_ERROR)
1040 if(priv->pll_err>priv->pll_lerr)
1041 priv->pll_dir= -priv->pll_dir;
1042 priv->pll_lerr=priv->pll_err;
1043 priv->pll_adj+=priv->pll_dir;
1044 if (priv->pll_adj<-PLL_ADJUST || priv->pll_adj>PLL_ADJUST)
1046 priv->pll_adj=0;
1047 priv->pll_dir=-1;
1048 priv->pll_lerr=0;
1050 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: pll_adj=%2d\n",priv->pll_adj);
1052 priv->pll_cnt=0;
1053 priv->pll_err=0;
1057 * \brief reset error correction
1058 * \param priv private data structure
1059 * \param fine_tune shift value for adjusting
1061 * \remarks code was got from MythTV project
1063 static void pll_reset(priv_vbi_t* priv,int fine_tune){
1064 priv->pll_fixed=fine_tune >= -PLL_ADJUST && fine_tune <= PLL_ADJUST;
1066 priv->pll_err=0;
1067 priv->pll_lerr=0;
1068 priv->pll_cnt=0;
1069 priv->pll_dir=-1;
1070 priv->pll_adj=0;
1071 if(priv->pll_fixed)
1072 priv->pll_adj=fine_tune;
1073 if(priv->pll_fixed)
1074 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"pll_reset (fixed@%2d)\n",priv->pll_adj);
1075 else
1076 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"pll_reset (auto)\n");
1080 * \brief decode packet 0 (teletext page header)
1081 * \param priv private data structure
1082 * \param data raw teletext data (with not applied hamm correction yet)
1083 * \param magAddr teletext page's magazine address
1085 * \remarks
1086 * data buffer was shifted by 6 and now contains:
1087 * 0..1 page number
1088 * 2..5 sub-code
1089 * 6..7 control codes
1090 * 8..39 display data
1092 * only first 8 bytes protected by Hamm 8/4 code
1094 static int decode_pkt0(priv_vbi_t* priv,unsigned char* data,int magAddr)
1096 int d[8];
1097 int i,err;
1099 if (magAddr<0 || magAddr>7)
1100 return 0;
1101 for(i=0;i<8;i++){
1102 d[i]= corrHamm48[ data[i] ];
1103 if(d[i]&0x80){
1104 pll_add(priv,2,4);
1106 if(priv->mag[magAddr].pt)
1107 free(priv->mag[magAddr].pt);
1108 priv->mag[magAddr].pt=NULL;
1109 priv->mag[magAddr].order=0;
1110 return 0;
1113 if (!priv->mag[magAddr].pt)
1114 priv->mag[magAddr].pt= malloc(sizeof(tt_page));
1116 if(priv->primary_language)
1117 priv->mag[magAddr].pt->primary_lang=priv->primary_language;
1118 else
1119 priv->mag[magAddr].pt->primary_lang= (d[7]>>1)&7;
1120 priv->mag[magAddr].pt->secondary_lang=priv->secondary_language;
1121 priv->mag[magAddr].pt->subpagenum=(d[2]|(d[3]<<4)|(d[4]<<8)|(d[5]<<12))&0x3f7f;
1122 priv->mag[magAddr].pt->pagenum=(magAddr<<8) | d[0] | (d[1]<<4);
1123 priv->mag[magAddr].pt->flags=((d[7]&1)<<7) | ((d[3]&8)<<3) | ((d[5]&12)<<2) | d[6];
1125 memset(priv->mag[magAddr].pt->raw, 0x00, VBI_COLUMNS*VBI_ROWS);
1126 priv->mag[magAddr].order=0;
1128 for(i=0;i<8;i++){
1129 priv->mag[magAddr].pt->raw[i]=0x20;
1131 err=0;
1132 for(i=8; i<VBI_COLUMNS; i++){
1133 data[i]= fixParity[data[i]];
1134 priv->mag[magAddr].pt->raw[i]=data[i];
1135 if(data[i]&0x80) //Error
1136 err++;
1137 pll_add(priv,1,err);
1140 store_in_cache(priv,magAddr,0);
1142 return 1;
1146 * \brief decode teletext 8/30 Format 1 packet
1147 * \param priv private data structure
1148 * \param data raw teletext data (with not applied hamm correction yet)
1149 * \param magAddr teletext page's magazine address
1151 * \remarks
1152 * packet contains:
1153 * 0 designation code
1154 * 1..2 initial page
1155 * 3..6 initial subpage & magazine address
1156 * 7..8 network id
1157 * 9 time offset
1158 * 10..12 julian date
1159 * 13..15 universal time
1160 * 20..40 network name
1162 * First 7 bytes are protected by Hamm 8/4 code.
1163 * Bytes 20-40 has odd parity check.
1165 * See subcaluse 9.8.1 of specification for details
1167 static int decode_pkt30(priv_vbi_t* priv,unsigned char* data,int magAddr)
1169 int d[8];
1170 int i,err;
1172 for(i=0;i<7;i++){
1173 d[i]= corrHamm48[ data[i] ];
1174 if(d[i]&0x80){
1175 pll_add(priv,2,4);
1176 return 0;
1178 d[i]&=0xf;
1181 err=0;
1182 for(i=20; i<40; i++){
1183 data[i]= fixParity[data[i]];
1184 if(data[i]&0x80)//Unrecoverable error
1185 err++;
1186 pll_add(priv,1,err);
1188 if (err) return 0;
1190 if (d[0]&0xe) //This is not 8/30 Format 1 packet
1191 return 1;
1193 priv->initialpage=d[1] | d[2]<<4 | (d[6]&0xc)<<7 | (d[4]&1)<<8;
1194 priv->initialsubpage=d[3] | d[4]<<4 | d[5]<<8 | d[6]<<12;
1195 priv->networkid=data[7]<<8 | data[8];
1197 priv->timeoffset=(data[9]>>1)&0xf;
1198 if(data[9]&0x40)
1199 priv->timeoffset=-priv->timeoffset;
1201 priv->juliandate=(data[10]&0xf)<<16 | data[11]<<8 | data[12];
1202 priv->juliandate-=0x11111;
1204 priv->universaltime=data[13]<<16 | data[14]<<8 | data[15];
1205 priv->universaltime-=0x111111;
1207 snprintf(priv->networkname,21,"%s",data+20);
1209 return 1;
1213 * \brief decode packets 1..24 (teletext page header)
1214 * \param priv private data structure
1215 * \param data raw teletext data
1216 * \param magAddr teletext page's magazine address
1217 * \param rowAddr teletext page's row number
1219 * \remarks
1220 * data buffer was shifted by 6 and now contains 40 bytes of display data:
1221 * this type of packet is not proptected by Hamm 8/4 code
1223 static void decode_pkt_page(priv_vbi_t* priv,unsigned char*data,int magAddr,int rowAddr){
1224 int i,err;
1225 if (!priv->mag[magAddr].pt)
1226 return;
1228 priv->mag[magAddr].order=rowAddr;
1230 err=0;
1231 for(i=0; i<VBI_COLUMNS; i++){
1232 data[i]= fixParity[ data[i] ];
1233 priv->mag[magAddr].pt->raw[i+rowAddr*VBI_COLUMNS]=data[i];
1234 if( data[i]&0x80) //HammError
1235 err++;
1237 pll_add(priv,1,err);
1239 store_in_cache(priv,magAddr,rowAddr);
1243 * \brief decode packets 27 (teletext links)
1244 * \param priv private data structure
1245 * \param data raw teletext data
1246 * \param magAddr teletext page's magazine address
1248 static int decode_pkt27(priv_vbi_t* priv,unsigned char* data,int magAddr){
1249 int i,hpg;
1251 if (!priv->mag[magAddr].pt)
1252 return 0;
1253 for(i=0;i<38;++i)
1254 if ((data[i] = corrHamm48[ data[i] ]) & 0x80){
1255 pll_add(priv,2,4);
1256 return 0;
1260 Not a X/27/0 Format 1 packet or
1261 flag "show links on row 24" is not set.
1263 if (data[0] || !(data[37] & 8))
1264 return 1;
1265 for(i=0;i<6;++i) {
1266 hpg = (magAddr<<8) ^ ((data[4+i*6]&0x8)<<5 | (data[6+i*6]&0xc)<<7);
1267 if (!hpg) hpg=0x800;
1268 priv->mag[magAddr].pt->links[i].pagenum = (data[1+i*6] & 0xf) |
1269 ((data[2+i*6] & 0xf) << 4) | hpg;
1270 priv->mag[magAddr].pt->links[i].subpagenum = ((data[3+i*6] & 0xf) |
1271 (data[4+i*6] & 0xf) << 4 | (data[5+i*6] & 0xf) << 8 |
1272 (data[6+i*6] & 0xf) << 12) & 0x3f7f;
1274 put_to_cache(priv,priv->mag[magAddr].pt,-1);
1275 return 1;
1279 * \brief Decode teletext X/28/0 Format 1 packet
1280 * \param priv private data structure
1281 * \param data raw teletext data
1283 * Primary G0 charset is transmitted in bits 14-8 of Triplet 1
1284 * See Table 32 of specification for details.
1286 * Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and
1287 * bits 18-15 of Triplet 1
1288 * See Table 33 of specification for details.
1291 static void decode_pkt28(priv_vbi_t* priv,unsigned char*data){
1292 int d;
1293 int t1,t2;
1294 d=corrHamm48[ data[0] ];
1295 if(d) return; //this is not X/28/0 Format 1 packet or error occured
1297 t1=corrHamm24(data+1);
1298 t2=corrHamm24(data+4);
1299 if (t1<0 || t2<0){
1300 pll_add(priv,1,4);
1301 return;
1304 priv->primary_language=(t1>>7)&0x7f;
1305 priv->secondary_language=((t2<<4) | (t1>>14))&0x7f;
1306 if (priv->secondary_language==0x7f)
1307 //No secondary language required
1308 priv->secondary_language=priv->primary_language;
1309 else // Swapping bits 1 and 3
1310 priv->secondary_language=(priv->secondary_language&0x7a) |
1311 (priv->secondary_language&4)>>2 |
1312 (priv->secondary_language&1)<<2;
1314 mp_msg(MSGT_TELETEXT,MSGL_DBG2,"pkt28: language: primary=%02x secondary=0x%02x\n",
1315 priv->primary_language,priv->secondary_language);
1319 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1320 * \param priv private data structure
1321 * \param buf raw vbi data (one line of frame)
1322 * \param data output buffer for decoded bytes (at least 45 bytes long)
1324 * Used XawTV's algorithm. Signal phase is calculated with help of starting clock
1325 * run-in sequence (min/max values and bit distance values are calculated)
1327 static int decode_raw_line_runin(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){
1328 const int magic= 0x27; // reversed 1110010
1329 int dt[256],hi[6],lo[6];
1330 int i,x,r;
1331 int decoded;
1332 int sync;
1333 unsigned char min,max;
1334 int thr=0; //threshold
1336 //stubs
1337 int soc=priv->soc;
1338 int eoc=priv->eoc;
1340 for(i=soc;i<eoc;i++)
1341 dt[i]=buf[i+priv->bpb/ONE_FIXP]-buf[i]; // amplifies the edges best.
1342 /* set barrier */
1343 for (i=eoc; i<eoc+16; i+=2)
1344 dt[i]=100, dt[i+1]=-100;
1346 /* find 6 rising and falling edges */
1347 for (i=soc, x=0; x<6; ++x)
1349 while (dt[i]<32)
1350 i++;
1351 hi[x]=i;
1352 while (dt[i]>-32)
1353 i++;
1354 lo[x]=i;
1356 if (i>=eoc)
1358 return 0; // not enough periods found
1360 i=hi[5]-hi[1]; // length of 4 periods (8 bits)
1361 if (i<priv->bp8bl || i>priv->bp8bh)
1363 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: wrong freq %d (%d,%d)\n",
1364 i,priv->bp8bl,priv->bp8bh);
1365 return 0; // bad frequency
1367 /* AGC and sync-reference */
1368 min=255, max=0, sync=0;
1369 for (i=hi[4]; i<hi[5]; ++i)
1370 if (buf[i]>max)
1371 max=buf[i], sync=i;
1372 for (i=lo[4]; i<lo[5]; ++i)
1373 if (buf[i]<min)
1374 min=buf[i];
1375 thr=(min+max)/2;
1377 buf+=sync;
1378 // searching for '11'
1379 for(i=priv->pll_adj*priv->bpb/10;i<16*priv->bpb;i+=priv->bpb)
1380 if(buf[FIXP2INT(i)]>thr && buf[FIXP2INT(i+priv->bpb)]>thr)
1381 break;
1382 r=0;
1383 for(decoded=1; decoded<= (VBI_COLUMNS+3)<<3;decoded++){
1384 r>>=1;
1385 if(buf[FIXP2INT(i)]>thr) r|=0x80;
1386 if(!(decoded & 0x07)){
1387 data[(decoded>>3) - 1]=r;
1388 r=0;
1390 i+=priv->bpb;
1392 if(data[0]!=magic)
1393 return 0; //magic not found
1395 //stub
1396 for(i=0;i<43;i++){
1397 data[i]=data[i+1];
1399 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"thr:%d sync:%d ",thr,sync);
1401 return 1;
1404 #if 0
1405 //See comment in vbi_decode for a reason of commenting out this routine.
1408 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1409 * \param priv private data structure
1410 * \param buf raw vbi data (one line of frame)
1411 * \param data output buffer for decoded bytes (at least 45 bytes long)
1413 * Used Michael Niedermayer's algorithm.
1414 * Signal phase is calculated using correlation between given samples data and
1415 * pure sine
1417 static int decode_raw_line_sine(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){
1418 int i,x,r,amp,xFixp;
1419 int avg=0;
1420 double sin_sum=0, cos_sum=0;
1422 for(x=0; x< FIXP2INT(10*priv->bpb); x++)
1423 avg+=buf[x];
1425 avg/=FIXP2INT(10*priv->bpb);
1427 for(x=0; x<12; x++){
1428 amp= buf[x<<1];
1429 sin_sum+= si[x]*(amp-avg);
1430 cos_sum+= co[x]*(amp-avg);
1432 //this is always zero. Why ?
1433 xFixp= atan(sin_sum/cos_sum)*priv->bpb/M_PI;
1435 //Without this line the result is full of errors
1436 //and routine is unable to find magic sequence
1437 buf+=FIXP2INT(10*priv->bpb);
1439 r=0;
1440 for(x=FIXP2INT(xFixp);x<70;x=FIXP2INT(xFixp)){
1441 r=(r<<1) & 0xFFFF;
1442 if(buf[x]>avg) r|=1;
1443 xFixp+=priv->bpb;
1444 if(r==0xAAE4) break;
1447 //this is not teletext
1448 if (r!=0xaae4) return 0;
1450 //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes
1451 for(i=1; i<=(42<<3); i++){
1452 r>>=1;
1453 x=FIXP2INT(xFixp);
1454 if(buf[x]> avg)
1455 r|=0x80;
1457 if(!(i & 0x07)){
1458 data[(i>>3)-1]=r;
1459 r=0;
1461 xFixp+=priv->bpb;
1464 return 1;
1466 #endif
1469 * \brief decodes one vbi line from one video frame
1470 * \param priv private data structure
1471 * \param data buffer with raw vbi data in it
1473 static void vbi_decode_line(priv_vbi_t *priv, unsigned char *data) {
1474 int d0,d1,magAddr,pkt;
1476 d0= corrHamm48[ data[0] ];
1477 d1= corrHamm48[ data[1] ];
1479 if(d0&0x80 || d1&0x80){
1480 pll_add(priv,2,4);
1481 mp_msg(MSGT_TELETEXT,MSGL_V,"vbi_decode_line: HammErr\n");
1483 return; //hamError
1485 magAddr=d0 & 0x7;
1486 pkt=(d0>>3)|(d1<<1);
1487 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi_decode_line:%x %x (mag:%x, pkt:%d)\n",
1488 d0,d1,magAddr,pkt);
1489 if(!pkt){
1490 decode_pkt0(priv,data+2,magAddr); //skip MRGA
1491 }else if(pkt>0 && pkt<VBI_ROWS){
1492 if(!priv->mag[magAddr].pt)
1493 return;
1494 decode_pkt_page(priv,data+2,magAddr,pkt);//skip MRGA
1495 }else if(pkt==27) {
1496 decode_pkt27(priv,data+2,magAddr);
1497 }else if(pkt==28){
1498 decode_pkt28(priv,data+2);
1499 }else if(pkt==30){
1500 decode_pkt30(priv,data+2,magAddr);
1501 } else {
1502 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"unsupported packet:%d\n",pkt);
1507 * \brief decodes all vbi lines from one video frame
1508 * \param priv private data structure
1509 * \param buf buffer with raw vbi data in it
1511 * \note buffer size have to be at least priv->ptsp->bufsize bytes
1513 static void vbi_decode(priv_vbi_t* priv,unsigned char*buf){
1514 unsigned char data[64];
1515 unsigned char* linep;
1516 int i=0;
1517 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: vbi_decode\n");
1518 for(linep=buf; !priv->cache_reset && linep<buf+priv->ptsp->bufsize; linep+=priv->ptsp->samples_per_line,i++){
1519 #if 0
1521 This routine is alternative implementation of raw VBI data decoding.
1522 Unfortunately, it detects only about 20% of incoming data,
1523 but Michael says that this algorithm is better, and he wants to fix it.
1525 if(decode_raw_line_sine(priv,linep,data)<=0){
1526 #endif
1527 if(decode_raw_line_runin(priv,linep,data)<=0){
1528 continue; //this is not valid teletext line
1530 vbi_decode_line(priv, data);
1532 if (priv->cache_reset){
1533 pthread_mutex_lock(&(priv->buffer_mutex));
1534 priv->cache_reset--;
1535 pthread_mutex_unlock(&(priv->buffer_mutex));
1541 * \brief decodes a vbi line from a DVB teletext stream
1542 * \param priv private data structure
1543 * \param buf buffer with DVB teletext data
1545 * No locking is done since this is only called from a single-threaded context
1547 static void vbi_decode_dvb(priv_vbi_t *priv, const uint8_t buf[44]){
1548 int i;
1549 uint8_t data[42];
1551 mp_msg(MSGT_TELETEXT,MSGL_DBG3, "vbi: vbi_decode_dvb\n");
1553 /* Reverse bit order, skipping the first two bytes (field parity, line
1554 offset and framing code). */
1555 for (i = 0; i < sizeof(data); i++)
1556 data[i] = av_reverse[buf[2 + i]];
1558 vbi_decode_line(priv, data);
1559 if (priv->cache_reset)
1560 priv->cache_reset--;
1564 ---------------------------------------------------------------------------------
1565 Public routines
1566 ---------------------------------------------------------------------------------
1570 * \brief toggles teletext page displaying format
1571 * \param priv_vbi private data structure
1572 * \param flag new format
1573 * \return
1574 * VBI_CONTROL_TRUE is success,
1575 * VBI_CONTROL_FALSE otherwise
1577 * flag:
1578 * 0 - opaque
1579 * 1 - transparent
1580 * 2 - opaque with black foreground color (only in bw mode)
1581 * 3 - transparent with black foreground color (only in bw mode)
1583 static int teletext_set_format(priv_vbi_t * priv, teletext_format flag)
1585 flag&=3;
1587 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"teletext_set_format_is called. mode:%d\n",flag);
1588 pthread_mutex_lock(&(priv->buffer_mutex));
1590 priv->tformat=flag;
1592 priv->pagenumdec=0;
1594 pthread_mutex_unlock(&(priv->buffer_mutex));
1595 return VBI_CONTROL_TRUE;
1599 * \brief append just entered digit to editing page number
1600 * \param priv_vbi private data structure
1601 * \param dec decimal digit to append
1603 * dec:
1604 * '0'..'9' append digit
1605 * '-' remove last digit (backspace emulation)
1607 * This routine allows user to jump to arbitrary page.
1608 * It implements simple page number editing algorithm.
1610 * Subsystem can be on one of two modes: normal and page number edit mode.
1611 * Zero value of priv->pagenumdec means normal mode
1612 * Non-zero value means page number edit mode and equals to packed
1613 * decimal number of already entered part of page number.
1615 * How this works.
1616 * Let's assume that current mode is normal (pagenumdec is zero), teletext page
1617 * 100 are displayed as usual. topmost left corner of page contains page number.
1618 * Then vbi_add_dec is sequentially called (through slave
1619 * command of course) with 1,4,-,2,3 * values of dec parameter.
1621 * +-----+------------+------------------+
1622 * | dec | pagenumdec | displayed number |
1623 * +-----+------------+------------------+
1624 * | | 0x000 | 100 |
1625 * +-----+------------+------------------+
1626 * | 1 | 0x001 | __1 |
1627 * +-----+------------+------------------+
1628 * | 4 | 0x014 | _14 |
1629 * +-----+------------+------------------+
1630 * | - | 0x001 | __1 |
1631 * +-----+------------+------------------+
1632 * | 2 | 0x012 | _12 |
1633 * +-----+------------+------------------+
1634 * | 3 | 0x123 | 123 |
1635 * +-----+------------+------------------+
1636 * | | 0x000 | 123 |
1637 * +-----+------------+------------------+
1639 * pagenumdec will automatically receive zero value after third digit of page
1640 * number is entered and current page will be switched to another one with
1641 * entered page number.
1643 static void vbi_add_dec(priv_vbi_t * priv, char *dec)
1645 int count, shift;
1646 if (!dec)
1647 return;
1648 if (!priv->on)
1649 return;
1650 if ((*dec<'0' || *dec>'9') && *dec!='-')
1651 return;
1652 if (!priv->pagenumdec) //first digit cannot be '0','9' or '-'
1653 if(*dec=='-' || *dec=='0' || *dec=='9')
1654 return;
1655 pthread_mutex_lock(&(priv->buffer_mutex));
1656 count=(priv->pagenumdec>>12)&0xf;
1657 if (*dec=='-') {
1658 count--;
1659 if (count)
1660 priv->pagenumdec=((priv->pagenumdec>>4)&0xfff)|(count<<12);
1661 else
1662 priv->pagenumdec=0;
1663 } else {
1664 shift = count * 4;
1665 count++;
1666 priv->pagenumdec=
1667 (((priv->pagenumdec)<<4|(*dec-'0'))&0xfff)|(count<<12);
1668 if (count==3) {
1669 priv->pagenum=priv->pagenumdec&0x7ff;
1670 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1671 priv->pagenumdec=0;
1674 pthread_mutex_unlock(&(priv->buffer_mutex));
1679 * \brief Teletext control routine
1680 * \param priv_vbi private data structure
1681 * \param cmd command
1682 * \param arg command parameter (has to be not null)
1684 int teletext_control(void* p, int cmd, void *arg)
1686 int fine_tune=99;
1687 priv_vbi_t* priv=(priv_vbi_t*)p;
1688 tt_page* pgc;
1690 if (!priv && cmd!=TV_VBI_CONTROL_START)
1691 return VBI_CONTROL_FALSE;
1692 if (!arg && cmd!=TV_VBI_CONTROL_STOP && cmd!=TV_VBI_CONTROL_MARK_UNCHANGED)
1693 return VBI_CONTROL_FALSE;
1695 switch (cmd) {
1696 case TV_VBI_CONTROL_RESET:
1698 int i;
1699 struct tt_param* tt_param=arg;
1700 pthread_mutex_lock(&(priv->buffer_mutex));
1701 priv->pagenumdec=0;
1702 clear_cache(priv);
1703 priv->pagenum=steppage(0,tt_param->page&0x7ff,1);
1704 priv->tformat=tt_param->format;
1705 priv->subpagenum=0x3f7f;
1706 pll_reset(priv,fine_tune);
1707 if(tt_param->lang==-1){
1708 mp_tmsg(MSGT_TELETEXT,MSGL_INFO,"Supported Teletext languages:\n");
1709 for(i=0; tt_languages[i].lang_code; i++){
1710 mp_msg(MSGT_TELETEXT,MSGL_INFO," %3d %s\n",
1711 tt_languages[i].lang_code, tt_languages[i].lang_name);
1713 mp_msg(MSGT_TELETEXT,MSGL_INFO," %3d %s\n",
1714 tt_languages[i].lang_code, tt_languages[i].lang_name);
1715 }else{
1716 for(i=0; tt_languages[i].lang_code; i++){
1717 if(tt_languages[i].lang_code==tt_param->lang)
1718 break;
1720 if (priv->primary_language!=tt_languages[i].lang_code){
1721 mp_tmsg(MSGT_TELETEXT,MSGL_INFO,"Selected default teletext language: %s\n",
1722 tt_languages[i].lang_name);
1723 priv->primary_language=tt_languages[i].lang_code;
1726 priv->page_changed=1;
1727 pthread_mutex_unlock(&(priv->buffer_mutex));
1728 return VBI_CONTROL_TRUE;
1730 case TV_VBI_CONTROL_START:
1732 int i;
1733 tt_stream_props* ptsp=*(tt_stream_props**)arg;
1735 if(!ptsp)
1736 return VBI_CONTROL_FALSE;
1738 priv=calloc(1,sizeof(priv_vbi_t));
1740 priv->ptsp=malloc(sizeof(tt_stream_props));
1741 memcpy(priv->ptsp,ptsp,sizeof(tt_stream_props));
1742 *(priv_vbi_t**)arg=priv;
1744 priv->subpagenum=0x3f7f;
1745 pthread_mutex_init(&priv->buffer_mutex, NULL);
1746 priv->pagenumdec=0;
1747 for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++)
1748 priv->display_page[i]=tt_space;
1750 priv->mag=calloc(8,sizeof(mag_t));
1751 init_cache(priv);
1752 init_vbi_consts(priv);
1753 pll_reset(priv,fine_tune);
1754 priv->page_changed=1;
1755 return VBI_CONTROL_TRUE;
1757 case TV_VBI_CONTROL_STOP:
1759 if(priv->mag)
1760 free(priv->mag);
1761 if(priv->ptsp)
1762 free(priv->ptsp);
1763 destroy_cache(priv);
1764 priv->page_changed=1;
1765 pthread_mutex_destroy(&priv->buffer_mutex);
1766 free(priv);
1767 return VBI_CONTROL_TRUE;
1769 case TV_VBI_CONTROL_SET_MODE:
1770 priv->on=(*(int*)arg%2);
1771 priv->page_changed=1;
1772 return VBI_CONTROL_TRUE;
1773 case TV_VBI_CONTROL_GET_MODE:
1774 *(int*)arg=priv->on;
1775 return VBI_CONTROL_TRUE;
1776 case TV_VBI_CONTROL_SET_FORMAT:
1777 priv->page_changed=1;
1778 return teletext_set_format(priv, *(int *) arg);
1779 case TV_VBI_CONTROL_GET_FORMAT:
1780 pthread_mutex_lock(&(priv->buffer_mutex));
1781 *(int*)arg=priv->tformat;
1782 pthread_mutex_unlock(&(priv->buffer_mutex));
1783 return VBI_CONTROL_TRUE;
1784 case TV_VBI_CONTROL_GET_HALF_PAGE:
1785 if(!priv->on)
1786 return VBI_CONTROL_FALSE;
1787 *(int *)arg=priv->zoom;
1788 return VBI_CONTROL_TRUE;
1789 case TV_VBI_CONTROL_SET_HALF_PAGE:
1791 int val=*(int*)arg;
1792 val%=3;
1793 if(val<0)
1794 val+=3;
1795 pthread_mutex_lock(&(priv->buffer_mutex));
1796 priv->zoom=val;
1797 priv->page_changed=1;
1798 pthread_mutex_unlock(&(priv->buffer_mutex));
1799 return VBI_CONTROL_TRUE;
1801 case TV_VBI_CONTROL_GO_LINK:
1803 int val=*(int *) arg;
1804 if(val<1 || val>6)
1805 return VBI_CONTROL_FALSE;
1806 pthread_mutex_lock(&(priv->buffer_mutex));
1807 if (!(pgc = priv->ptt_cache[priv->pagenum])) {
1808 pthread_mutex_unlock(&(priv->buffer_mutex));
1809 return VBI_CONTROL_FALSE;
1811 if (!pgc->links[val-1].pagenum || pgc->links[val-1].pagenum>0x7ff) {
1812 pthread_mutex_unlock(&(priv->buffer_mutex));
1813 return VBI_CONTROL_FALSE;
1815 priv->pagenum=pgc->links[val-1].pagenum;
1816 if(pgc->links[val-1].subpagenum!=0x3f7f)
1817 priv->subpagenum=pgc->links[val-1].subpagenum;
1818 else
1819 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1820 priv->page_changed=1;
1821 pthread_mutex_unlock(&(priv->buffer_mutex));
1822 return VBI_CONTROL_TRUE;
1824 case TV_VBI_CONTROL_SET_PAGE:
1826 int val=*(int *) arg;
1827 if(val<100 || val>0x899)
1828 return VBI_CONTROL_FALSE;
1829 pthread_mutex_lock(&(priv->buffer_mutex));
1830 priv->pagenum=val&0x7ff;
1831 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1832 priv->pagenumdec=0;
1833 priv->page_changed=1;
1834 pthread_mutex_unlock(&(priv->buffer_mutex));
1835 return VBI_CONTROL_TRUE;
1837 case TV_VBI_CONTROL_STEP_PAGE:
1839 int direction=*(int *) arg;
1840 pthread_mutex_lock(&(priv->buffer_mutex));
1841 priv->pagenum=steppage(priv->pagenum, direction,1);
1842 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1843 priv->pagenumdec=0;
1844 priv->page_changed=1;
1845 pthread_mutex_unlock(&(priv->buffer_mutex));
1846 return VBI_CONTROL_TRUE;
1848 case TV_VBI_CONTROL_GET_PAGE:
1849 *(int*)arg=((priv->pagenum+0x700)&0x7ff)+0x100;
1850 return VBI_CONTROL_TRUE;
1851 case TV_VBI_CONTROL_SET_SUBPAGE:
1852 pthread_mutex_lock(&(priv->buffer_mutex));
1853 priv->pagenumdec=0;
1854 priv->subpagenum=*(int*)arg;
1855 if(priv->subpagenum<0)
1856 priv->subpagenum=0x3f7f;
1857 if(priv->subpagenum>=VBI_MAX_SUBPAGES)
1858 priv->subpagenum=VBI_MAX_SUBPAGES-1;
1859 priv->page_changed=1;
1860 pthread_mutex_unlock(&(priv->buffer_mutex));
1861 return VBI_CONTROL_TRUE;
1862 case TV_VBI_CONTROL_GET_SUBPAGE:
1863 *(int*)arg=priv->subpagenum;
1864 return VBI_CONTROL_TRUE;
1865 case TV_VBI_CONTROL_ADD_DEC:
1866 vbi_add_dec(priv, *(char **) arg);
1867 priv->page_changed=1;
1868 return VBI_CONTROL_TRUE;
1869 case TV_VBI_CONTROL_DECODE_PAGE:
1870 vbi_decode(priv,*(unsigned char**)arg);
1871 return VBI_CONTROL_TRUE;
1872 case TV_VBI_CONTROL_DECODE_DVB:
1873 vbi_decode_dvb(priv, arg);
1874 return VBI_CONTROL_TRUE;
1875 case TV_VBI_CONTROL_GET_VBIPAGE:
1876 if(!priv->on)
1877 return VBI_CONTROL_FALSE;
1878 prepare_visible_page(priv);
1879 *(void **)arg=priv->display_page;
1880 return VBI_CONTROL_TRUE;
1881 case TV_VBI_CONTROL_GET_NETWORKNAME:
1882 *(void **)arg=priv->networkname;
1883 return VBI_CONTROL_TRUE;
1884 case TV_VBI_CONTROL_MARK_UNCHANGED:
1885 priv->page_changed=0;
1886 priv->last_rendered=GetTimerMS();
1887 return VBI_CONTROL_TRUE;
1888 case TV_VBI_CONTROL_IS_CHANGED:
1889 if(GetTimerMS()-priv->last_rendered> 250) //forcing page update every 1/4 sec
1890 priv->page_changed=3; //mark that header update is enough
1891 *(int*)arg=priv->page_changed;
1892 return VBI_CONTROL_TRUE;
1894 return VBI_CONTROL_UNKNOWN;