m_config.c: cosmetics: Move functions to avoid forward declarations
[mplayer.git] / libmpcodecs / dec_teletext.c
blob215246af89e5fff2113c30df4cf85efd93f86f0f
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 "libmpcodecs/img_format.h"
106 #include "libavutil/common.h"
107 #include "input/input.h"
108 #include "osdep/timer.h"
110 //#define DEBUG_DUMP 1
112 /// page magazine entry structure
113 typedef struct mag_s{
114 tt_page* pt;
115 int order;
116 } mag_t;
118 typedef struct {
119 int on; ///< teletext on/off
120 int pagenum; ///< seek page number
121 int subpagenum; ///< seek subpage
122 int curr_pagenum; ///< current page number
123 int pagenumdec; ///< set page num with dec
125 teletext_format tformat; ///< see teletext_format enum
126 teletext_zoom zoom; ///< see teletext_zoom enum
127 mag_t* mag; ///< pages magazine (has 8 entities)
128 int primary_language; ///< primary character set
129 int secondary_language; ///< secondary character set
130 /// Currently displayed page (with additional info, e.g current time)
131 tt_char display_page[VBI_ROWS*VBI_COLUMNS];
132 /// number of raw bytes between two subsequent encoded bits
133 int bpb;
134 /// clock run-in sequence will be searched in buffer in [soc:eoc] bytes range
135 int soc;
136 int eoc;
137 /// minimum number of raw vbi bytes wich can be decoded into 8 data bits
138 int bp8bl;
139 /// maximum number of raw vbi bytes wich can be decoded into 8 data bits
140 int bp8bh;
142 int pll_adj;
143 int pll_dir;
144 int pll_cnt;
145 int pll_err;
146 int pll_lerr;
147 int pll_fixed;
148 /// vbi stream properties (buffer size,bytes per line, etc)
149 tt_stream_props* ptsp;
150 #ifdef HAVE_PTHREADS
151 pthread_mutex_t buffer_mutex;
152 #endif
154 tt_page** ptt_cache;
155 unsigned char* ptt_cache_first_subpage;
156 /// network info
157 unsigned char initialpage;
158 unsigned int initialsubpage;
159 unsigned int networkid;
160 int timeoffset; // timeoffset=realoffset*2
161 unsigned int juliandate;
162 unsigned int universaltime;
163 unsigned char networkname[21];
164 int cache_reset;
165 /// "page changed" flag: 0-unchanged, 1-entire page, 3-only header
166 int page_changed;
167 int last_rendered;
168 } priv_vbi_t;
170 static unsigned char fixParity[256];
172 static const tt_char tt_space={0x20,7,0,0,0,0,0,0,0x20};
173 static const tt_char tt_error={'?',1,0,0,0,0,0,0,'?'}; // Red '?' on black background
174 static double si[12];
175 static double co[12];
177 #define VBI_FORMAT(priv) (*(priv->ptsp))
179 #define FIXP_SH 16
180 #define ONE_FIXP (1<<FIXP_SH)
181 #define FIXP2INT(a) ((a)>>FIXP_SH)
182 #define ANY2FIXP(a) ((int)((a)*ONE_FIXP))
184 static const unsigned char corrHamm48[256]={
185 0x01, 0xff, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff,
186 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07,
187 0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00,
188 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff,
189 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07,
190 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x07,
191 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff,
192 0x06, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07,
193 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09,
194 0x02, 0x02, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff,
195 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff,
196 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03,
197 0x04, 0xff, 0xff, 0x05, 0x04, 0x04, 0x04, 0xff,
198 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07,
199 0xff, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, 0x05,
200 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff,
201 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09,
202 0x0a, 0xff, 0xff, 0x0b, 0x0a, 0x0a, 0x0a, 0xff,
203 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff,
204 0xff, 0x0b, 0x0b, 0x0b, 0x0a, 0xff, 0xff, 0x0b,
205 0x0c, 0x0c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff,
206 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07,
207 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x0d, 0x0d,
208 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff,
209 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x09,
210 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09,
211 0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09,
212 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff,
213 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09,
214 0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0e, 0x0f, 0xff,
215 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff,
216 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x0e, 0xff, 0x0e };
219 enum {
220 LATIN=0,
221 CYRILLIC1,
222 CYRILLIC2,
223 CYRILLIC3,
224 GREEK,
225 LANGS
228 // conversion table for chars 0x20-0x7F (UTF8)
229 // TODO: add another languages
230 static const unsigned int lang_chars[LANGS][0x60]={
232 //Latin
233 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
234 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
235 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
236 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
237 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
238 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
239 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
240 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
241 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
242 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
243 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
244 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
247 //Cyrillic-1 (Serbian/Croatian)
248 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
249 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
250 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
251 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
252 0x0427,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
253 0x0425,0x0418,0x0408,0x041a,0x041b,0x041c,0x041d,0x041e,
254 0x041f,0x040c,0x0420,0x0421,0x0422,0x0423,0x0412,0x0403,
255 0x0409,0x040a,0x0417,0x040b,0x0416,0x0402,0x0428,0x040f,
256 0x0447,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
257 0x0445,0x0438,0x0428,0x043a,0x043b,0x043c,0x043d,0x043e,
258 0x043f,0x042c,0x0440,0x0441,0x0442,0x0443,0x0432,0x0423,
259 0x0429,0x042a,0x0437,0x042b,0x0436,0x0422,0x0448,0x042f
262 //Cyrillic-2 (Russian/Bulgarian)
263 0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
264 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
265 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
266 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
267 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
268 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
269 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
270 0x042c,0x042a,0x0417,0x0428,0x042d,0x0429,0x0427,0x042b,
271 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
272 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
273 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
274 0x044c,0x044a,0x0437,0x0448,0x044d,0x0449,0x0447,0x044b
277 //Cyrillic-3 (Ukrainian)
278 0x20,0x21,0x22,0x23,0x24,0x25,0xef,0x27,
279 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
280 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
281 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
282 0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
283 0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
284 0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
285 0x042c,0x49,0x0417,0x0428,0x042d,0x0429,0x0427,0xcf,
286 0x044e,0x0430,0x0431,0x0446,0x0434,0x0435,0x0444,0x0433,
287 0x0445,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
288 0x043f,0x044f,0x0440,0x0441,0x0442,0x0443,0x0436,0x0432,
289 0x044c,0x69,0x0437,0x0448,0x044d,0x0449,0x0447,0xFF
292 //Greek
293 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
294 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
295 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
296 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
297 0x0390,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,
298 0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,
299 0x03a0,0x03a1,0x03a2,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,
300 0x03a8,0x03a9,0x03aa,0x03ab,0x03ac,0x03ad,0x03ae,0x03af,
301 0x03b0,0x03b1,0x03b2,0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,
302 0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,0x03bd,0x03be,0x03bf,
303 0x03c0,0x03c1,0x03c2,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
304 0x03c8,0x03c9,0x03ca,0x03cb,0x03cc,0x03cd,0x03ce,0x03cf
309 * Latin National Option Sub-Sets
310 * see Table 36 of ETS specification for details.
312 * 00: £ $ @ « ½ » ¬ # ­ ¼ ¦ ¾ ÷ English
313 * 01: é ï à ë ê ù î # è â ô û ç French
314 * 02: # ¤ É Ä Ö Å Ü _ é ä ö å ü Swedish/Finnish/Hungarian
315 * 03: # ů č ť ž ý í ř é á ě ú š Czech/Slovak
316 * 04: # $ § Ä Ö Ü ^ _ ° ä ö ü ß German
317 * 05: ç $ ¡ á é í ó ú ¿ ü ñ è à Portuguese/Spanish
318 * 06: £ $ é ° ç » ¬ # ù à ò è ì Italian
321 static const unsigned int latin_subchars[8][13]={
322 // English
323 {0xa3,0x24,0x40,0xab,0xbd,0xbb,0xac,0x23,0xad,0xbc,0xa6,0xbe,0xf7},
324 // French
325 {0xe9,0xef,0xe0,0xeb,0xea,0xf9,0xee,0x23,0xe8,0xe2,0xf4,0xfb,0xe7},
326 // Swedish/Finnish/Hungarian
327 {0x23,0xa4,0xc9,0xc4,0xd6,0xc5,0xdc,0x5f,0xe9,0xe4,0xf6,0xe5,0xfc},
328 // Czech/Slovak
329 {0x23,0x16f,0x10d,0x165,0x17e,0xfd,0xed,0x159,0xe9,0xe1,0x11b,0xfa,0x161},
330 // German
331 {0x23,0x24,0xa7,0xc4,0xd6,0xdc,0x5e,0x5f,0xb0,0xe4,0xf6,0xfc,0xdf},
332 // Portuguese/Spanish
333 {0xe7,0x24,0xa1,0xe1,0xe9,0xed,0xf3,0xfa,0xbf,0xfc,0xf1,0xe8,0xe0},
334 // Italian
335 {0xa3,0x24,0xe9,0xb0,0xe7,0xbb,0xac,0x23,0xf9,0xe0,0xf2,0xe8,0xec},
336 // Reserved
337 {0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e}
341 * List of supported languages.
343 * lang_code bits for primary Language:
344 * bits 7-4 corresponds to bits 14-11 of 28 packet's first triplet
345 * bits 3-1 corresponds to bits C12-C14 of packet 0 (lang)
347 * lang_code bits for secondary Language:
348 * bits 7-5 corresponds to bits 3-1 of 28 packet's second triplet
349 * bits 4,2 corresponds to bits 18,16 of 28 packet's first triplet
350 * bits 3,1 corresponds to bits 15,17 of 28 packet's first triplet
352 * For details see Tables 32 and 33 of specification (subclause 15.2)
354 struct {
355 unsigned char lang_code;
356 unsigned char charset;
357 const char* lang_name;
358 } const tt_languages[]=
360 { 0x01, LATIN, "French"},
361 { 0x02, LATIN, "Swedish/Finnish/Hungarian"},
362 { 0x03, LATIN, "Czech/Slovak"},
363 { 0x04, LATIN, "German"},
364 { 0x05, LATIN, "Portuguese/Spanish"},
365 { 0x06, LATIN, "Italian"},
367 { 0x08, LATIN, "Polish"},
368 { 0x09, LATIN, "French"},
369 { 0x0a, LATIN, "Swedish/Finnish/Hungarian"},
370 { 0x0b, LATIN, "Czech/Slovak"},
371 { 0x0c, LATIN, "German"},
372 { 0x0e, LATIN, "Italian"},
374 { 0x10, LATIN, "English"},
375 { 0x11, LATIN, "French"},
376 { 0x12, LATIN, "Swedish/Finnish/Hungarian"},
377 { 0x13, LATIN, "Turkish"},
378 { 0x14, LATIN, "German"},
379 { 0x15, LATIN, "Portuguese/Spanish"},
380 { 0x16, LATIN, "Italian"},
382 { 0x1d, LATIN, "Serbian/Croatian/Slovenian (Latin)"},
384 { 0x20, CYRILLIC1, "Serbian/Croatian (Cyrillic)"},
385 { 0x21, CYRILLIC2, "Russian, Bulgarian"},
386 { 0x22, LATIN, "Estonian"},
387 { 0x23, LATIN, "Czech/Slovak"},
388 { 0x24, LATIN, "German"},
389 { 0x25, CYRILLIC3, "Ukrainian"},
390 { 0x26, LATIN, "Lettish/Lithuanian"},
392 { 0x33, LATIN, "Turkish"},
393 { 0x37, GREEK, "Greek"},
395 { 0x40, LATIN, "English"},
396 { 0x41, LATIN, "French"},
397 // { 0x47, ARABIC, "Arabic"},
399 // { 0x55, HEBREW, "Hebrew"},
400 // { 0x57, ARABIC, "Arabic"},
402 { 0x00, LATIN, "English"},
406 * \brief 24/18 Hamming code decoding
407 * \param data bytes with hamming code (array must be at least 3 bytes long)
408 * \return -1 if multiple bit error occured, D1-DI data bits - otherwise
410 * \note Bits must be correctly ordered, that is for 24/18 (lowest bit first)
411 * P1 P2 D1 P3 D2 D3 D4 P4 D5 D6 D7 D8 D9 DA DB P5 DC DD DE DF DG DH DI P6
413 static int corrHamm24(unsigned char *data){
414 unsigned char syndrom=0;
415 int cw=data[0] | (data[1]<<8) | (data[2]<<16);
416 int i;
418 for(i=0;i<23;i++)
419 syndrom^=((cw>>i)&1)*(i+33);
421 syndrom^=(cw>>11)&32;
423 if(syndrom&31){
424 if(syndrom < 32 || syndrom > 55)
425 return -1;
426 cw ^= 1<<((syndrom&31)-1);
429 return (cw&4)>>2 |
430 (cw&0x70)>>3 |
431 (cw&0x3f00)>>4 |
432 (cw&0x3f0000)>>5;
436 * \brief converts language bits to charset index
437 * \param lang language bits
438 * \return charset index in lang_chars array
440 static int lang2charset (int lang){
441 int i;
442 for(i=0;tt_languages[i].lang_code;i++)
443 if(tt_languages[i].lang_code==lang)
444 break;
446 return tt_languages[i].charset;
450 * \brief convert chars from curent teletext codepage into MPlayer charset
451 * \param p raw teletext char to decode
452 * \param charset index on lang_chars
453 * \param lang index in substitution array (latin charset only)
454 * \return UTF8 char
456 * \remarks
457 * routine will analyze raw member of given tt_char structure and
458 * fill unicode member of the same struct with appropriate utf8 code.
460 static unsigned int conv2uni(unsigned int p,int charset,int lang)
463 if(p<0x80 && p>=0x20){
464 if(charset==LATIN){
465 lang&=7;
466 if (p>=0x23 && p<=0x24){
467 return latin_subchars[lang][p-0x23];
468 }else if (p==0x40){
469 return latin_subchars[lang][2];
470 }else if (p>=0x5b && p<=0x60){
471 return latin_subchars[lang][p-0x5b+3];
472 }else if (p>=0x7b && p<=0x7e){
473 return latin_subchars[lang][p-0x7b+9];
476 return lang_chars[charset][p-0x20];
477 }else
478 return 0x20;
481 static void init_vbi_consts(priv_vbi_t* priv){
482 int i,j;
483 double ang;
484 for(i=0; i<256; i++){
485 j=i&0x7F;
486 j^= j+j;
487 j^= j<<2;
488 j^= j<<4;
489 fixParity[i]= i ^ (j&0x80) ^ 0x80;
492 for(i=0,ang=0; i<12; i++,ang+=M_PI/priv->bpb){
493 si[i]= sin(ang);
494 co[i]= cos(ang);
497 priv->bpb=(priv->ptsp->sampling_rate/6937500.0)*ONE_FIXP+0.5;
498 priv->soc=FFMAX(9.2e-6*priv->ptsp->sampling_rate-priv->ptsp->offset, 0);
499 priv->eoc=FFMIN(12.9e-6*priv->ptsp->sampling_rate-priv->ptsp->offset,
500 priv->ptsp->samples_per_line-43*8*priv->bpb/ONE_FIXP);
501 if (priv->eoc - priv->soc<16*priv->bpb/ONE_FIXP){ // invalid [soc:eoc]
502 priv->soc=0;
503 priv->eoc=92;
505 priv->bp8bl=0.97*8*priv->bpb/ONE_FIXP; // -3% tolerance
506 priv->bp8bh=1.03*8*priv->bpb/ONE_FIXP; // +3% tolerance
509 * \brief calculate increased/decreased by given value page number
510 * \param curr current page number in hexadecimal for
511 * \param direction decimal value (can be negative) to add to value
512 * of curr parameter
513 * \return new page number in hexadecimal form
515 * VBI page numbers are represented in special hexadecimal form, e.g.
516 * page with number 123 (as seen by user) internally has number 0x123.
517 * and equation 0x123+8 should be equal to 0x131 instead of regular 0x12b.
520 * Page numbers 0xYYY (where Y is not belongs to (0..9).
521 * Page number belongs to [0x000,0x799] or [0x100:0x899] (first 0 can be
522 * treated as '8')
524 static int steppage(int p, int direction, int skip_hidden)
526 if(skip_hidden)
527 p=(p&15)+((p>>4)&15)*10+(p>>8)*100;
528 p+=direction;
529 if(skip_hidden){
530 p=(p+800)%800;
531 p=(p%10)+((p/10)%10)*16+(p/100)*256;
534 return p&0x7ff;
538 ------------------------------------------------------------------
539 Cache stuff
540 ------------------------------------------------------------------
544 * \brief add/update entry in cache
545 * \param priv private data structure
546 * \param pg page to store in cache
547 * \param line line to update (value below 0 means update entire page)
549 static void put_to_cache(priv_vbi_t* priv,tt_page* pg,int line){
550 tt_page* pgc; //page in cache
551 int i,j,count;
553 if(line<0){
554 i=0;
555 count=VBI_ROWS*VBI_COLUMNS;
556 }else if(line<VBI_ROWS){
557 i=line*VBI_COLUMNS;
558 count=(line+1)*VBI_COLUMNS;
559 }else
560 return;
562 pthread_mutex_lock(&(priv->buffer_mutex));
564 if(!priv->ptt_cache[pg->pagenum]){
565 priv->ptt_cache[pg->pagenum]=calloc(1,sizeof(tt_page));
566 pgc=priv->ptt_cache[pg->pagenum];
567 }else{
568 pgc=priv->ptt_cache[pg->pagenum];
569 while(pgc->next_subpage && pgc->subpagenum!=pg->subpagenum)
570 pgc=pgc->next_subpage;
572 if(pgc->subpagenum!=pg->subpagenum){
573 pgc->next_subpage=calloc(1,sizeof(tt_page));
574 pgc=pgc->next_subpage;
577 pgc->pagenum=pg->pagenum;
578 pgc->subpagenum=pg->subpagenum;
579 pgc->primary_lang=pg->primary_lang;
580 pgc->secondary_lang=pg->secondary_lang;
581 pgc->flags=pg->flags;
582 for(j=0;j<6;++j)
583 pgc->links[j]=pg->links[j];
584 //instead of copying entire page into cache, copy only undamaged
585 //symbols into cache
586 for(;i<count;i++){
587 if(!(pg->raw[i]&0x80))
588 pgc->raw[i]=pg->raw[i];
589 else
590 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"char error. pg:%x, c[%d]=0x%x\n",
591 pg->pagenum,i,pg->raw[i]);
593 pgc->active=1;
594 pthread_mutex_unlock(&(priv->buffer_mutex));
598 * \brief get any subpage number of given page
599 * \param priv private data structure
600 * \param pagenum page number to search subpages in
602 * \return subpage number of first found subpage which belongs to
603 * given page number
605 * \note page itself is subpage too (and usually has subpage number 0)
607 static inline int get_subpagenum_from_cache(priv_vbi_t* priv, int pagenum){
608 if (!priv->ptt_cache[pagenum])
609 return 0x3f7f;
610 else
611 return priv->ptt_cache[pagenum]->subpagenum;
615 * \brief get page from cache by it page and subpage number
616 * \param priv private data structure
617 * \param pagenum page number
618 * \param subpagenum subpage number
620 * \return pointer to tt_page structure if requested page is found
621 * and NULL otherwise
623 static inline tt_page* get_from_cache(priv_vbi_t* priv, int pagenum,int subpagenum){
624 tt_page* tp=priv->ptt_cache[pagenum];
626 while(tp && tp->subpagenum!=subpagenum)
627 tp=tp->next_subpage;
628 return tp;
632 * \brief clears cache
633 * \param priv private data structure
635 * Deletes all tt_page structures from cache and frees allocated memory.
636 * Only zero-filled array of pointers remains in memory
638 static void clear_cache(priv_vbi_t* priv){
639 int i;
640 tt_page* tp;
643 Skip next 5 buffers to avoid mixing teletext pages from different
644 channels during channel switch
646 priv->cache_reset=5;
647 for(i=0;i<VBI_MAX_PAGES;i++){
648 while(priv->ptt_cache[i]){
649 tp=priv->ptt_cache[i];
650 priv->ptt_cache[i]=tp->next_subpage;
651 free(tp);
654 priv->initialsubpage=priv->networkid=0;
655 priv->timeoffset=0;
656 priv->juliandate=priv->universaltime=0;
657 memset(priv->networkname,0,21);
661 * \brief cache initialization
662 * \param priv private data structure
664 * \note Has to be called before any cache operations!
666 static void init_cache(priv_vbi_t* priv){
667 priv->ptt_cache=calloc(VBI_MAX_PAGES,sizeof(tt_page*));
671 * \brief destroys cache
672 * \param priv private data structure
674 * Frees all memory allocated for cache (including array of pointers).
675 * It is safe to call this routine multiple times
677 static void destroy_cache(priv_vbi_t* priv){
678 if(priv->ptt_cache){
679 clear_cache(priv);
680 free(priv->ptt_cache);
681 priv->ptt_cache=NULL;
686 ------------------------------------------------------------------
687 Decoder stuff
688 ------------------------------------------------------------------
691 * \brief converts raw teletext page into useful format (1st rendering stage)
692 * \param pg page to decode
693 * \param raw raw data to decode page from
694 * \param primary_lang primary language code
695 * \param secondary_lang secondary language code
697 * Routine fills tt_char structure of each teletext_page character with proper
698 * info about foreground and background colors, character
699 * type (graphics/control/text).
701 static void decode_page(tt_char* p,unsigned char* raw,int primary_lang,int secondary_lang,int flags)
703 int row,col;
704 int prim_charset=lang2charset(primary_lang);
705 int sec_charset=lang2charset(secondary_lang);
707 for(row=0;row<VBI_ROWS;row++) {
708 int prim_lang=1;
709 int gfx=0;
710 int fg_color=7;
711 int bg_color=0;
712 int separated=0;
713 int conceal=0;
714 int hold=0;
715 int flash=0;
716 int box=0;
718 tt_char tt_held=tt_space;
719 for(col=0;col<VBI_COLUMNS;col++){
720 int i=row*VBI_COLUMNS+col;
721 int c=raw[i];
722 p[i].raw=c;
723 if(c&0x80){ //damaged char
724 p[i]=tt_error;
725 continue;
727 if((flags&TT_PGFL_SUBTITLE) || (flags&TT_PGFL_NEWFLASH))
728 p[i].hidden=!box;
729 else
730 p[i].hidden=0;
731 p[i].gfx=gfx?(separated?2:1):0;
732 p[i].lng=prim_lang;
733 p[i].ctl=(c&0x60)==0?1:0;
734 p[i].fg=fg_color;
735 p[i].bg=bg_color;
736 p[i].flh=flash;
738 if ((c&0x60)==0){ //control chars
739 if(c>=0x08 && c<=0x09){//Flash/Steady
740 flash=c==0x08;
741 p[i].flh=flash;
742 if(c==0x09){
743 p[i].fg=fg_color;
744 p[i].bg=bg_color;
746 }else if(c>=0x0a && c<=0x0b){
747 box=c&1;
748 }else if(c>=0x0c && c<=0x0f){
749 }else if (c<=0x17){ //colors
750 fg_color=c&0x0f;
751 gfx=c>>4;
752 conceal=0;
753 if(!gfx) hold=0;
754 }else if (c<=0x18){
755 conceal=1;
756 }else if (c<=0x1a){ //Contiguous/Separated gfx
757 separated=!(c&1);
758 }else if (c<=0x1b){
759 prim_lang=!prim_lang;
760 }else if (c<=0x1d){
761 bg_color=(c&1)?fg_color:0;
762 p[i].bg=bg_color;
763 }else{ //Hold/Release Graphics
764 hold=!(c&1);
766 p[i].ctl=1;
767 if(hold || c==0x1f){
768 p[i]=tt_held;
769 p[i].fg=fg_color;
770 p[i].bg=bg_color;
771 }else
772 p[i].unicode=p[i].gfx?0:' ';
773 continue;
776 if(conceal){
777 p[i].gfx=0;
778 p[i].unicode=' ';
779 }else if(gfx){
780 p[i].unicode=c-0x20;
781 if (p[i].unicode>0x3f) p[i].unicode-=0x20;
782 tt_held=p[i];
783 }else{
784 if(p[i].lng){
785 p[i].unicode=conv2uni(c,prim_charset,primary_lang&7);
786 }else{
787 p[i].unicode=conv2uni(c,sec_charset,secondary_lang&7);
790 p[i].fg=fg_color;
791 p[i].bg=bg_color;
797 * \brief prepares current page for displaying
798 * \param priv_vbi private data structure
800 * Routine adds some useful info (time and page number of page, grabbed by
801 * background thread to top line of current page). Displays "No teletext"
802 * string if no vbi data available.
804 #define PRINT_HEX(dp,i,h) dp[i].unicode=((h)&0xf)>9?'A'+((h)&0xf)-10:'0'+((h)&0xf)
805 static void prepare_visible_page(priv_vbi_t* priv){
806 tt_page *pg,*curr_pg;
807 unsigned char *p;
808 int i;
810 pthread_mutex_lock(&(priv->buffer_mutex));
811 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"dec_teletext: prepare_visible_page pg:0x%x, sub:0x%x\n",
812 priv->pagenum,priv->subpagenum);
813 if(priv->subpagenum==0x3f7f) //no page yet
814 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
816 pg=get_from_cache(priv,priv->pagenum,priv->subpagenum);
817 mp_dbg(MSGT_TELETEXT,MSGL_DBG3,"dec_teletext: prepare_vibible_page2 pg:0x%x, sub:0x%x\n",
818 priv->pagenum,priv->subpagenum);
820 curr_pg=get_from_cache(priv,priv->curr_pagenum,
821 get_subpagenum_from_cache(priv,priv->curr_pagenum));
822 if (!pg && !curr_pg){
823 p=_("No teletext");
824 for(i=0;i<VBI_COLUMNS && *p;i++){
825 GET_UTF8(priv->display_page[i].unicode,*p++,break;);
827 for(;i<VBI_ROWS*VBI_COLUMNS;i++)
828 priv->display_page[i]=tt_space;
829 pthread_mutex_unlock(&(priv->buffer_mutex));
830 return;
833 if (!pg || !pg->active){
834 for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++){
835 priv->display_page[i]=tt_space;
837 }else{
838 decode_page(priv->display_page,pg->raw,pg->primary_lang,pg->secondary_lang,pg->flags);
839 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"page #%x was decoded!\n",pg->pagenum);
842 PRINT_HEX(priv->display_page,0,(priv->curr_pagenum&0x700)?priv->curr_pagenum>>8:8);
843 PRINT_HEX(priv->display_page,1,priv->curr_pagenum>>4);
844 PRINT_HEX(priv->display_page,2,priv->curr_pagenum);
845 priv->display_page[3].unicode=' ';
846 priv->display_page[4].unicode=' ';
847 switch(priv->pagenumdec>>12){
848 case 1:
849 priv->display_page[5].unicode='_';
850 priv->display_page[6].unicode='_';
851 PRINT_HEX(priv->display_page,7,priv->pagenumdec);
852 break;
853 case 2:
854 priv->display_page[5].unicode='_';
855 PRINT_HEX(priv->display_page,6,priv->pagenumdec>>4);
856 PRINT_HEX(priv->display_page,7,priv->pagenumdec);
857 break;
858 default:
859 PRINT_HEX(priv->display_page,5,(priv->pagenum&0x700)?priv->pagenum>>8:8);
860 PRINT_HEX(priv->display_page,6,priv->pagenum>>4);
861 PRINT_HEX(priv->display_page,7,priv->pagenum);
863 if(priv->subpagenum!=0x3f7f){
864 priv->display_page[8].unicode='.';
865 PRINT_HEX(priv->display_page,9,priv->subpagenum>>4);
866 PRINT_HEX(priv->display_page,10,priv->subpagenum);
867 }else{
868 priv->display_page[8].unicode=' ';
869 priv->display_page[9].unicode=' ';
870 priv->display_page[10].unicode=' ';
872 priv->display_page[11].unicode=' ';
873 for(i=VBI_COLUMNS;i>VBI_TIME_LINEPOS ||
874 ((curr_pg->raw[i]&0x60) && curr_pg->raw[i]!=0x20 && i>11);
875 --i)
876 if(curr_pg->raw[i]&0x60)
877 priv->display_page[i].unicode=curr_pg->raw[i];
878 else
879 priv->display_page[i].unicode=' ';
880 pthread_mutex_unlock(&(priv->buffer_mutex));
883 ------------------------------------------------------------------
884 Renderer stuff
885 ------------------------------------------------------------------
887 #ifdef DEBUG_DUMP
889 * \brief renders teletext page into given file
890 * \param pt page to render
891 * \param f opened file descriptor
892 * \param pagenum which page to render
893 * \param colored use colors not implemented yet)
895 * Text will be UTF8 encoded
897 static void render2text(tt_page* pt,FILE* f,int colored){
898 int i,j;
899 unsigned int u;
900 unsigned char buf[8];
901 unsigned char tmp;
902 int pos;
903 tt_char dp[VBI_ROWS*VBI_COLUMNS];
904 int color=0;
905 int bkg=0;
906 int c1,b1;
907 if(!pt)
908 return;
909 fprintf(f,"+========================================+\n");
910 fprintf(f,"| lang:%d pagenum:0x%x subpagenum:%d flags:0x%x|\n",
911 pt->lang,
912 pt->pagenum,
913 pt->subpagenum,
915 fprintf(f,"+----------------------------------------+\n");
917 decode_page(dp,pt->raw,pt->primary_lang,pt->secondary_lang,pt->flags);
918 for(i=0;i<VBI_ROWS;i++){
919 fprintf(f,"|");
920 if(colored) fprintf(f,"\033[40m");
921 for(j=0;j<VBI_COLUMNS;j++)
923 u=dp[i*VBI_COLUMNS+j].unicode;
924 if(dp[i*VBI_COLUMNS+j].fg <= 7)
925 c1=30+dp[i*VBI_COLUMNS+j].fg;
926 else
927 c1=38;
928 if(dp[i*VBI_COLUMNS+j].bg <= 7)
929 b1=40+dp[i*VBI_COLUMNS+j].bg;
930 else
931 b1=40;
932 if (b1!=bkg && colored){
933 fprintf(f,"\033[%dm",b1);
934 bkg=b1;
936 if(c1!=color && colored){
937 fprintf(f,"\033[%dm",c1);
938 color=c1;
940 if(dp[i*VBI_COLUMNS+j].gfx){
941 fprintf(f,"*");
942 }else{
943 pos=0;
944 PUT_UTF8(u,tmp,if(pos<7) buf[pos++]=tmp;);
945 buf[pos]='\0';
946 fprintf(f,"%s",buf);
950 if (colored) fprintf(f,"\033[0m");
951 color=-1;bkg=-1;
952 fprintf(f,"|\n");
954 //for debug
955 fprintf(f,"+====================raw=================+\n");
956 for(i=0;i<VBI_ROWS;i++){
957 for(j=0;j<VBI_COLUMNS;j++)
958 fprintf(f,"%02x ",dp[i*VBI_COLUMNS+j].raw);
959 fprintf(f,"\n");
961 fprintf(f,"+====================lng=================+\n");
962 for(i=0;i<VBI_ROWS;i++){
963 for(j=0;j<VBI_COLUMNS;j++)
964 fprintf(f,"%02x ",dp[i*VBI_COLUMNS+j].lng);
965 fprintf(f,"\n");
967 fprintf(f,"+========================================+\n");
971 * \brief dump page into pgXXX.txt file in vurrent directory
972 * \param pt page to dump
974 * \note XXX in filename is page number
975 * \note use only for debug purposes
977 static void dump_page(tt_page* pt)
979 FILE*f;
980 char name[100];
981 snprintf(name,99,"pg%x.txt",pt->pagenum);
982 f=fopen(name,"wb");
983 render2text(pt,f,1);
984 fclose(f);
986 #endif //DEBUG_DUMP
990 * \brief checks whether page is ready and copies it into cache array if so
991 * \param priv private data structure
992 * \param magAddr page's magazine address (0-7)
994 static void store_in_cache(priv_vbi_t* priv, int magAddr, int line){
995 mp_msg(MSGT_TELETEXT,MSGL_DBG2,"store_in_cache(%d): pagenum:%x\n",
996 priv->mag[magAddr].order,
997 priv->mag[magAddr].pt->pagenum);
999 put_to_cache(priv,priv->mag[magAddr].pt,line);
1000 priv->curr_pagenum=priv->mag[magAddr].pt->pagenum;
1002 #ifdef DEBUG_DUMP
1003 dump_page(get_from_cache(priv,
1004 priv->mag[magAddr].pt->pagenum,
1005 priv->mag[magAddr].pt->subpagenum));
1006 #endif
1011 ------------------------------------------------------------------
1012 Grabber stuff
1013 ------------------------------------------------------------------
1015 #define PLL_SAMPLES 4
1016 #define PLL_ERROR 4
1017 #define PLL_ADJUST 4
1020 * \brief adjust current phase for better signal decoding
1021 * \param n count of bytes processed (?)
1022 * \param err count of error bytes (?)
1024 * \remarks code was got from MythTV project
1026 static void pll_add(priv_vbi_t* priv,int n,int err){
1027 if(priv->pll_fixed)
1028 return;
1029 if(err>PLL_ERROR*2/3)
1030 err=PLL_ERROR*2/3;
1031 priv->pll_err+=err;
1032 priv->pll_cnt+=n;
1033 if(priv->pll_cnt<PLL_SAMPLES)
1034 return;
1035 if(priv->pll_err>PLL_ERROR)
1037 if(priv->pll_err>priv->pll_lerr)
1038 priv->pll_dir= -priv->pll_dir;
1039 priv->pll_lerr=priv->pll_err;
1040 priv->pll_adj+=priv->pll_dir;
1041 if (priv->pll_adj<-PLL_ADJUST || priv->pll_adj>PLL_ADJUST)
1043 priv->pll_adj=0;
1044 priv->pll_dir=-1;
1045 priv->pll_lerr=0;
1047 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: pll_adj=%2d\n",priv->pll_adj);
1049 priv->pll_cnt=0;
1050 priv->pll_err=0;
1054 * \brief reset error correction
1055 * \param priv private data structure
1056 * \param fine_tune shift value for adjusting
1058 * \remarks code was got from MythTV project
1060 static void pll_reset(priv_vbi_t* priv,int fine_tune){
1061 priv->pll_fixed=fine_tune >= -PLL_ADJUST && fine_tune <= PLL_ADJUST;
1063 priv->pll_err=0;
1064 priv->pll_lerr=0;
1065 priv->pll_cnt=0;
1066 priv->pll_dir=-1;
1067 priv->pll_adj=0;
1068 if(priv->pll_fixed)
1069 priv->pll_adj=fine_tune;
1070 if(priv->pll_fixed)
1071 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"pll_reset (fixed@%2d)\n",priv->pll_adj);
1072 else
1073 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"pll_reset (auto)\n");
1077 * \brief decode packet 0 (teletext page header)
1078 * \param priv private data structure
1079 * \param data raw teletext data (with not applied hamm correction yet)
1080 * \param magAddr teletext page's magazine address
1082 * \remarks
1083 * data buffer was shifted by 6 and now contains:
1084 * 0..1 page number
1085 * 2..5 sub-code
1086 * 6..7 control codes
1087 * 8..39 display data
1089 * only first 8 bytes protected by Hamm 8/4 code
1091 static int decode_pkt0(priv_vbi_t* priv,unsigned char* data,int magAddr)
1093 int d[8];
1094 int i,err;
1096 if (magAddr<0 || magAddr>7)
1097 return 0;
1098 for(i=0;i<8;i++){
1099 d[i]= corrHamm48[ data[i] ];
1100 if(d[i]&0x80){
1101 pll_add(priv,2,4);
1103 if(priv->mag[magAddr].pt)
1104 free(priv->mag[magAddr].pt);
1105 priv->mag[magAddr].pt=NULL;
1106 priv->mag[magAddr].order=0;
1107 return 0;
1110 if (!priv->mag[magAddr].pt)
1111 priv->mag[magAddr].pt= malloc(sizeof(tt_page));
1113 if(priv->primary_language)
1114 priv->mag[magAddr].pt->primary_lang=priv->primary_language;
1115 else
1116 priv->mag[magAddr].pt->primary_lang= (d[7]>>1)&7;
1117 priv->mag[magAddr].pt->secondary_lang=priv->secondary_language;
1118 priv->mag[magAddr].pt->subpagenum=(d[2]|(d[3]<<4)|(d[4]<<8)|(d[5]<<12))&0x3f7f;
1119 priv->mag[magAddr].pt->pagenum=(magAddr<<8) | d[0] | (d[1]<<4);
1120 priv->mag[magAddr].pt->flags=((d[7]&1)<<7) | ((d[3]&8)<<3) | ((d[5]&12)<<2) | d[6];
1122 memset(priv->mag[magAddr].pt->raw, 0x00, VBI_COLUMNS*VBI_ROWS);
1123 priv->mag[magAddr].order=0;
1125 for(i=0;i<8;i++){
1126 priv->mag[magAddr].pt->raw[i]=0x20;
1128 err=0;
1129 for(i=8; i<VBI_COLUMNS; i++){
1130 data[i]= fixParity[data[i]];
1131 priv->mag[magAddr].pt->raw[i]=data[i];
1132 if(data[i]&0x80) //Error
1133 err++;
1134 pll_add(priv,1,err);
1137 store_in_cache(priv,magAddr,0);
1139 return 1;
1143 * \brief decode teletext 8/30 Format 1 packet
1144 * \param priv private data structure
1145 * \param data raw teletext data (with not applied hamm correction yet)
1146 * \param magAddr teletext page's magazine address
1148 * \remarks
1149 * packet contains:
1150 * 0 designation code
1151 * 1..2 initial page
1152 * 3..6 initial subpage & magazine address
1153 * 7..8 network id
1154 * 9 time offset
1155 * 10..12 julian date
1156 * 13..15 universal time
1157 * 20..40 network name
1159 * First 7 bytes are protected by Hamm 8/4 code.
1160 * Bytes 20-40 has odd parity check.
1162 * See subcaluse 9.8.1 of specification for details
1164 static int decode_pkt30(priv_vbi_t* priv,unsigned char* data,int magAddr)
1166 int d[8];
1167 int i,err;
1169 for(i=0;i<7;i++){
1170 d[i]= corrHamm48[ data[i] ];
1171 if(d[i]&0x80){
1172 pll_add(priv,2,4);
1173 return 0;
1175 d[i]&=0xf;
1178 err=0;
1179 for(i=20; i<40; i++){
1180 data[i]= fixParity[data[i]];
1181 if(data[i]&0x80)//Unrecoverable error
1182 err++;
1183 pll_add(priv,1,err);
1185 if (err) return 0;
1187 if (d[0]&0xe) //This is not 8/30 Format 1 packet
1188 return 1;
1190 priv->initialpage=d[1] | d[2]<<4 | (d[6]&0xc)<<7 | (d[4]&1)<<8;
1191 priv->initialsubpage=d[3] | d[4]<<4 | d[5]<<8 | d[6]<<12;
1192 priv->networkid=data[7]<<8 | data[8];
1194 priv->timeoffset=(data[9]>>1)&0xf;
1195 if(data[9]&0x40)
1196 priv->timeoffset=-priv->timeoffset;
1198 priv->juliandate=(data[10]&0xf)<<16 | data[11]<<8 | data[12];
1199 priv->juliandate-=0x11111;
1201 priv->universaltime=data[13]<<16 | data[14]<<8 | data[15];
1202 priv->universaltime-=0x111111;
1204 snprintf(priv->networkname,21,"%s",data+20);
1206 return 1;
1210 * \brief decode packets 1..24 (teletext page header)
1211 * \param priv private data structure
1212 * \param data raw teletext data
1213 * \param magAddr teletext page's magazine address
1214 * \param rowAddr teletext page's row number
1216 * \remarks
1217 * data buffer was shifted by 6 and now contains 40 bytes of display data:
1218 * this type of packet is not proptected by Hamm 8/4 code
1220 static void decode_pkt_page(priv_vbi_t* priv,unsigned char*data,int magAddr,int rowAddr){
1221 int i,err;
1222 if (!priv->mag[magAddr].pt)
1223 return;
1225 priv->mag[magAddr].order=rowAddr;
1227 err=0;
1228 for(i=0; i<VBI_COLUMNS; i++){
1229 data[i]= fixParity[ data[i] ];
1230 priv->mag[magAddr].pt->raw[i+rowAddr*VBI_COLUMNS]=data[i];
1231 if( data[i]&0x80) //HammError
1232 err++;
1234 pll_add(priv,1,err);
1236 store_in_cache(priv,magAddr,rowAddr);
1240 * \brief decode packets 27 (teletext links)
1241 * \param priv private data structure
1242 * \param data raw teletext data
1243 * \param magAddr teletext page's magazine address
1245 static int decode_pkt27(priv_vbi_t* priv,unsigned char* data,int magAddr){
1246 int i,hpg;
1248 if (!priv->mag[magAddr].pt)
1249 return 0;
1250 for(i=0;i<38;++i)
1251 if ((data[i] = corrHamm48[ data[i] ]) & 0x80){
1252 pll_add(priv,2,4);
1253 return 0;
1257 Not a X/27/0 Format 1 packet or
1258 flag "show links on row 24" is not set.
1260 if (data[0] || !(data[37] & 8))
1261 return 1;
1262 for(i=0;i<6;++i) {
1263 hpg = (magAddr<<8) ^ ((data[4+i*6]&0x8)<<5 | (data[6+i*6]&0xc)<<7);
1264 if (!hpg) hpg=0x800;
1265 priv->mag[magAddr].pt->links[i].pagenum = (data[1+i*6] & 0xf) |
1266 ((data[2+i*6] & 0xf) << 4) | hpg;
1267 priv->mag[magAddr].pt->links[i].subpagenum = ((data[3+i*6] & 0xf) |
1268 (data[4+i*6] & 0xf) << 4 | (data[5+i*6] & 0xf) << 8 |
1269 (data[6+i*6] & 0xf) << 12) & 0x3f7f;
1271 put_to_cache(priv,priv->mag[magAddr].pt,-1);
1272 return 1;
1276 * \brief Decode teletext X/28/0 Format 1 packet
1277 * \param priv private data structure
1278 * \param data raw teletext data
1280 * Primary G0 charset is transmitted in bits 14-8 of Triplet 1
1281 * See Table 32 of specification for details.
1283 * Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and
1284 * bits 18-15 of Triplet 1
1285 * See Table 33 of specification for details.
1288 static void decode_pkt28(priv_vbi_t* priv,unsigned char*data){
1289 int d;
1290 int t1,t2;
1291 d=corrHamm48[ data[0] ];
1292 if(d) return; //this is not X/28/0 Format 1 packet or error occured
1294 t1=corrHamm24(data+1);
1295 t2=corrHamm24(data+4);
1296 if (t1<0 || t2<0){
1297 pll_add(priv,1,4);
1298 return;
1301 priv->primary_language=(t1>>7)&0x7f;
1302 priv->secondary_language=((t2<<4) | (t1>>14))&0x7f;
1303 if (priv->secondary_language==0x7f)
1304 //No secondary language required
1305 priv->secondary_language=priv->primary_language;
1306 else // Swapping bits 1 and 3
1307 priv->secondary_language=(priv->secondary_language&0x7a) |
1308 (priv->secondary_language&4)>>2 |
1309 (priv->secondary_language&1)<<2;
1311 mp_msg(MSGT_TELETEXT,MSGL_DBG2,"pkt28: language: primary=%02x secondary=0x%02x\n",
1312 priv->primary_language,priv->secondary_language);
1316 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1317 * \param priv private data structure
1318 * \param buf raw vbi data (one line of frame)
1319 * \param data output buffer for decoded bytes (at least 45 bytes long)
1321 * Used XawTV's algorithm. Signal phase is calculated with help of starting clock
1322 * run-in sequence (min/max values and bit distance values are calculated)
1324 static int decode_raw_line_runin(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){
1325 const int magic= 0x27; // reversed 1110010
1326 int dt[256],hi[6],lo[6];
1327 int i,x,r;
1328 int decoded;
1329 int sync;
1330 unsigned char min,max;
1331 int thr=0; //threshold
1333 //stubs
1334 int soc=priv->soc;
1335 int eoc=priv->eoc;
1337 for(i=soc;i<eoc;i++)
1338 dt[i]=buf[i+priv->bpb/ONE_FIXP]-buf[i]; // amplifies the edges best.
1339 /* set barrier */
1340 for (i=eoc; i<eoc+16; i+=2)
1341 dt[i]=100, dt[i+1]=-100;
1343 /* find 6 rising and falling edges */
1344 for (i=soc, x=0; x<6; ++x)
1346 while (dt[i]<32)
1347 i++;
1348 hi[x]=i;
1349 while (dt[i]>-32)
1350 i++;
1351 lo[x]=i;
1353 if (i>=eoc)
1355 return 0; // not enough periods found
1357 i=hi[5]-hi[1]; // length of 4 periods (8 bits)
1358 if (i<priv->bp8bl || i>priv->bp8bh)
1360 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: wrong freq %d (%d,%d)\n",
1361 i,priv->bp8bl,priv->bp8bh);
1362 return 0; // bad frequency
1364 /* AGC and sync-reference */
1365 min=255, max=0, sync=0;
1366 for (i=hi[4]; i<hi[5]; ++i)
1367 if (buf[i]>max)
1368 max=buf[i], sync=i;
1369 for (i=lo[4]; i<lo[5]; ++i)
1370 if (buf[i]<min)
1371 min=buf[i];
1372 thr=(min+max)/2;
1374 buf+=sync;
1375 // searching for '11'
1376 for(i=priv->pll_adj*priv->bpb/10;i<16*priv->bpb;i+=priv->bpb)
1377 if(buf[FIXP2INT(i)]>thr && buf[FIXP2INT(i+priv->bpb)]>thr)
1378 break;
1379 r=0;
1380 for(decoded=1; decoded<= (VBI_COLUMNS+3)<<3;decoded++){
1381 r>>=1;
1382 if(buf[FIXP2INT(i)]>thr) r|=0x80;
1383 if(!(decoded & 0x07)){
1384 data[(decoded>>3) - 1]=r;
1385 r=0;
1387 i+=priv->bpb;
1389 if(data[0]!=magic)
1390 return 0; //magic not found
1392 //stub
1393 for(i=0;i<43;i++){
1394 data[i]=data[i+1];
1396 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"thr:%d sync:%d ",thr,sync);
1398 return 1;
1401 #if 0
1402 //See comment in vbi_decode for a reason of commenting out this routine.
1405 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1406 * \param priv private data structure
1407 * \param buf raw vbi data (one line of frame)
1408 * \param data output buffer for decoded bytes (at least 45 bytes long)
1410 * Used Michael Niedermayer's algorithm.
1411 * Signal phase is calculated using correlation between given samples data and
1412 * pure sine
1414 static int decode_raw_line_sine(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){
1415 int i,x,r,amp,xFixp;
1416 int avg=0;
1417 double sin_sum=0, cos_sum=0;
1419 for(x=0; x< FIXP2INT(10*priv->bpb); x++)
1420 avg+=buf[x];
1422 avg/=FIXP2INT(10*priv->bpb);
1424 for(x=0; x<12; x++){
1425 amp= buf[x<<1];
1426 sin_sum+= si[x]*(amp-avg);
1427 cos_sum+= co[x]*(amp-avg);
1429 //this is always zero. Why ?
1430 xFixp= atan(sin_sum/cos_sum)*priv->bpb/M_PI;
1432 //Without this line the result is full of errors
1433 //and routine is unable to find magic sequence
1434 buf+=FIXP2INT(10*priv->bpb);
1436 r=0;
1437 for(x=FIXP2INT(xFixp);x<70;x=FIXP2INT(xFixp)){
1438 r=(r<<1) & 0xFFFF;
1439 if(buf[x]>avg) r|=1;
1440 xFixp+=priv->bpb;
1441 if(r==0xAAE4) break;
1444 //this is not teletext
1445 if (r!=0xaae4) return 0;
1447 //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes
1448 for(i=1; i<=(42<<3); i++){
1449 r>>=1;
1450 x=FIXP2INT(xFixp);
1451 if(buf[x]> avg)
1452 r|=0x80;
1454 if(!(i & 0x07)){
1455 data[(i>>3)-1]=r;
1456 r=0;
1458 xFixp+=priv->bpb;
1461 return 1;
1463 #endif
1466 * \brief decodes one vbi line from one video frame
1467 * \param priv private data structure
1468 * \param data buffer with raw vbi data in it
1470 static void vbi_decode_line(priv_vbi_t *priv, unsigned char *data) {
1471 int d0,d1,magAddr,pkt;
1473 d0= corrHamm48[ data[0] ];
1474 d1= corrHamm48[ data[1] ];
1476 if(d0&0x80 || d1&0x80){
1477 pll_add(priv,2,4);
1478 mp_msg(MSGT_TELETEXT,MSGL_V,"vbi_decode_line: HammErr\n");
1480 return; //hamError
1482 magAddr=d0 & 0x7;
1483 pkt=(d0>>3)|(d1<<1);
1484 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi_decode_line:%x %x (mag:%x, pkt:%d)\n",
1485 d0,d1,magAddr,pkt);
1486 if(!pkt){
1487 decode_pkt0(priv,data+2,magAddr); //skip MRGA
1488 }else if(pkt>0 && pkt<VBI_ROWS){
1489 if(!priv->mag[magAddr].pt)
1490 return;
1491 decode_pkt_page(priv,data+2,magAddr,pkt);//skip MRGA
1492 }else if(pkt==27) {
1493 decode_pkt27(priv,data+2,magAddr);
1494 }else if(pkt==28){
1495 decode_pkt28(priv,data+2);
1496 }else if(pkt==30){
1497 decode_pkt30(priv,data+2,magAddr);
1498 } else {
1499 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"unsupported packet:%d\n",pkt);
1504 * \brief decodes all vbi lines from one video frame
1505 * \param priv private data structure
1506 * \param buf buffer with raw vbi data in it
1508 * \note buffer size have to be at least priv->ptsp->bufsize bytes
1510 static void vbi_decode(priv_vbi_t* priv,unsigned char*buf){
1511 unsigned char data[64];
1512 unsigned char* linep;
1513 int i=0;
1514 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: vbi_decode\n");
1515 for(linep=buf; !priv->cache_reset && linep<buf+priv->ptsp->bufsize; linep+=priv->ptsp->samples_per_line,i++){
1516 #if 0
1518 This routine is alternative implementation of raw VBI data decoding.
1519 Unfortunately, it detects only about 20% of incoming data,
1520 but Michael says that this algorithm is better, and he wants to fix it.
1522 if(decode_raw_line_sine(priv,linep,data)<=0){
1523 #endif
1524 if(decode_raw_line_runin(priv,linep,data)<=0){
1525 continue; //this is not valid teletext line
1527 vbi_decode_line(priv, data);
1529 if (priv->cache_reset){
1530 pthread_mutex_lock(&(priv->buffer_mutex));
1531 priv->cache_reset--;
1532 pthread_mutex_unlock(&(priv->buffer_mutex));
1538 * \brief decodes a vbi line from a DVB teletext stream
1539 * \param priv private data structure
1540 * \param buf buffer with DVB teletext data
1542 * No locking is done since this is only called from a single-threaded context
1544 static void vbi_decode_dvb(priv_vbi_t *priv, const uint8_t buf[44]){
1545 int i;
1546 uint8_t data[42];
1548 mp_msg(MSGT_TELETEXT,MSGL_DBG3, "vbi: vbi_decode_dvb\n");
1550 /* Reverse bit order, skipping the first two bytes (field parity, line
1551 offset and framing code). */
1552 for (i = 0; i < sizeof(data); i++)
1553 data[i] = av_reverse[buf[2 + i]];
1555 vbi_decode_line(priv, data);
1556 if (priv->cache_reset)
1557 priv->cache_reset--;
1561 ---------------------------------------------------------------------------------
1562 Public routines
1563 ---------------------------------------------------------------------------------
1567 * \brief toggles teletext page displaying format
1568 * \param priv_vbi private data structure
1569 * \param flag new format
1570 * \return
1571 * VBI_CONTROL_TRUE is success,
1572 * VBI_CONTROL_FALSE otherwise
1574 * flag:
1575 * 0 - opaque
1576 * 1 - transparent
1577 * 2 - opaque with black foreground color (only in bw mode)
1578 * 3 - transparent with black foreground color (only in bw mode)
1580 static int teletext_set_format(priv_vbi_t * priv, teletext_format flag)
1582 flag&=3;
1584 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"teletext_set_format_is called. mode:%d\n",flag);
1585 pthread_mutex_lock(&(priv->buffer_mutex));
1587 priv->tformat=flag;
1589 priv->pagenumdec=0;
1591 pthread_mutex_unlock(&(priv->buffer_mutex));
1592 return VBI_CONTROL_TRUE;
1596 * \brief append just entered digit to editing page number
1597 * \param priv_vbi private data structure
1598 * \param dec decimal digit to append
1600 * dec:
1601 * '0'..'9' append digit
1602 * '-' remove last digit (backspace emulation)
1604 * This routine allows user to jump to arbitrary page.
1605 * It implements simple page number editing algorithm.
1607 * Subsystem can be on one of two modes: normal and page number edit mode.
1608 * Zero value of priv->pagenumdec means normal mode
1609 * Non-zero value means page number edit mode and equals to packed
1610 * decimal number of already entered part of page number.
1612 * How this works.
1613 * Let's assume that current mode is normal (pagenumdec is zero), teletext page
1614 * 100 are displayed as usual. topmost left corner of page contains page number.
1615 * Then vbi_add_dec is sequentially called (through slave
1616 * command of course) with 1,4,-,2,3 * values of dec parameter.
1618 * +-----+------------+------------------+
1619 * | dec | pagenumdec | displayed number |
1620 * +-----+------------+------------------+
1621 * | | 0x000 | 100 |
1622 * +-----+------------+------------------+
1623 * | 1 | 0x001 | __1 |
1624 * +-----+------------+------------------+
1625 * | 4 | 0x014 | _14 |
1626 * +-----+------------+------------------+
1627 * | - | 0x001 | __1 |
1628 * +-----+------------+------------------+
1629 * | 2 | 0x012 | _12 |
1630 * +-----+------------+------------------+
1631 * | 3 | 0x123 | 123 |
1632 * +-----+------------+------------------+
1633 * | | 0x000 | 123 |
1634 * +-----+------------+------------------+
1636 * pagenumdec will automatically receive zero value after third digit of page
1637 * number is entered and current page will be switched to another one with
1638 * entered page number.
1640 static void vbi_add_dec(priv_vbi_t * priv, char *dec)
1642 int count, shift;
1643 if (!dec)
1644 return;
1645 if (!priv->on)
1646 return;
1647 if ((*dec<'0' || *dec>'9') && *dec!='-')
1648 return;
1649 if (!priv->pagenumdec) //first digit cannot be '0','9' or '-'
1650 if(*dec=='-' || *dec=='0' || *dec=='9')
1651 return;
1652 pthread_mutex_lock(&(priv->buffer_mutex));
1653 count=(priv->pagenumdec>>12)&0xf;
1654 if (*dec=='-') {
1655 count--;
1656 if (count)
1657 priv->pagenumdec=((priv->pagenumdec>>4)&0xfff)|(count<<12);
1658 else
1659 priv->pagenumdec=0;
1660 } else {
1661 shift = count * 4;
1662 count++;
1663 priv->pagenumdec=
1664 (((priv->pagenumdec)<<4|(*dec-'0'))&0xfff)|(count<<12);
1665 if (count==3) {
1666 priv->pagenum=priv->pagenumdec&0x7ff;
1667 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1668 priv->pagenumdec=0;
1671 pthread_mutex_unlock(&(priv->buffer_mutex));
1676 * \brief Teletext control routine
1677 * \param priv_vbi private data structure
1678 * \param cmd command
1679 * \param arg command parameter (has to be not null)
1681 int teletext_control(void* p, int cmd, void *arg)
1683 int fine_tune=99;
1684 priv_vbi_t* priv=(priv_vbi_t*)p;
1685 tt_page* pgc;
1687 if (!priv && cmd!=TV_VBI_CONTROL_START)
1688 return VBI_CONTROL_FALSE;
1689 if (!arg && cmd!=TV_VBI_CONTROL_STOP && cmd!=TV_VBI_CONTROL_MARK_UNCHANGED)
1690 return VBI_CONTROL_FALSE;
1692 switch (cmd) {
1693 case TV_VBI_CONTROL_RESET:
1695 int i;
1696 struct tt_param* tt_param=arg;
1697 pthread_mutex_lock(&(priv->buffer_mutex));
1698 priv->pagenumdec=0;
1699 clear_cache(priv);
1700 priv->pagenum=steppage(0,tt_param->page&0x7ff,1);
1701 priv->tformat=tt_param->format;
1702 priv->subpagenum=0x3f7f;
1703 pll_reset(priv,fine_tune);
1704 if(tt_param->lang==-1){
1705 mp_tmsg(MSGT_TELETEXT,MSGL_INFO,"Supported Teletext languages:\n");
1706 for(i=0; tt_languages[i].lang_code; i++){
1707 mp_msg(MSGT_TELETEXT,MSGL_INFO," %3d %s\n",
1708 tt_languages[i].lang_code, tt_languages[i].lang_name);
1710 mp_msg(MSGT_TELETEXT,MSGL_INFO," %3d %s\n",
1711 tt_languages[i].lang_code, tt_languages[i].lang_name);
1712 }else{
1713 for(i=0; tt_languages[i].lang_code; i++){
1714 if(tt_languages[i].lang_code==tt_param->lang)
1715 break;
1717 if (priv->primary_language!=tt_languages[i].lang_code){
1718 mp_tmsg(MSGT_TELETEXT,MSGL_INFO,"Selected default teletext language: %s\n",
1719 tt_languages[i].lang_name);
1720 priv->primary_language=tt_languages[i].lang_code;
1723 priv->page_changed=1;
1724 pthread_mutex_unlock(&(priv->buffer_mutex));
1725 return VBI_CONTROL_TRUE;
1727 case TV_VBI_CONTROL_START:
1729 int i;
1730 tt_stream_props* ptsp=*(tt_stream_props**)arg;
1732 if(!ptsp)
1733 return VBI_CONTROL_FALSE;
1735 priv=calloc(1,sizeof(priv_vbi_t));
1737 priv->ptsp=malloc(sizeof(tt_stream_props));
1738 memcpy(priv->ptsp,ptsp,sizeof(tt_stream_props));
1739 *(priv_vbi_t**)arg=priv;
1741 priv->subpagenum=0x3f7f;
1742 pthread_mutex_init(&priv->buffer_mutex, NULL);
1743 priv->pagenumdec=0;
1744 for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++)
1745 priv->display_page[i]=tt_space;
1747 priv->mag=calloc(8,sizeof(mag_t));
1748 init_cache(priv);
1749 init_vbi_consts(priv);
1750 pll_reset(priv,fine_tune);
1751 priv->page_changed=1;
1752 return VBI_CONTROL_TRUE;
1754 case TV_VBI_CONTROL_STOP:
1756 if(priv->mag)
1757 free(priv->mag);
1758 if(priv->ptsp)
1759 free(priv->ptsp);
1760 destroy_cache(priv);
1761 priv->page_changed=1;
1762 pthread_mutex_destroy(&priv->buffer_mutex);
1763 free(priv);
1764 return VBI_CONTROL_TRUE;
1766 case TV_VBI_CONTROL_SET_MODE:
1767 priv->on=(*(int*)arg%2);
1768 priv->page_changed=1;
1769 return VBI_CONTROL_TRUE;
1770 case TV_VBI_CONTROL_GET_MODE:
1771 *(int*)arg=priv->on;
1772 return VBI_CONTROL_TRUE;
1773 case TV_VBI_CONTROL_SET_FORMAT:
1774 priv->page_changed=1;
1775 return teletext_set_format(priv, *(int *) arg);
1776 case TV_VBI_CONTROL_GET_FORMAT:
1777 pthread_mutex_lock(&(priv->buffer_mutex));
1778 *(int*)arg=priv->tformat;
1779 pthread_mutex_unlock(&(priv->buffer_mutex));
1780 return VBI_CONTROL_TRUE;
1781 case TV_VBI_CONTROL_GET_HALF_PAGE:
1782 if(!priv->on)
1783 return VBI_CONTROL_FALSE;
1784 *(int *)arg=priv->zoom;
1785 return VBI_CONTROL_TRUE;
1786 case TV_VBI_CONTROL_SET_HALF_PAGE:
1788 int val=*(int*)arg;
1789 val%=3;
1790 if(val<0)
1791 val+=3;
1792 pthread_mutex_lock(&(priv->buffer_mutex));
1793 priv->zoom=val;
1794 priv->page_changed=1;
1795 pthread_mutex_unlock(&(priv->buffer_mutex));
1796 return VBI_CONTROL_TRUE;
1798 case TV_VBI_CONTROL_GO_LINK:
1800 int val=*(int *) arg;
1801 if(val<1 || val>6)
1802 return VBI_CONTROL_FALSE;
1803 pthread_mutex_lock(&(priv->buffer_mutex));
1804 if (!(pgc = priv->ptt_cache[priv->pagenum])) {
1805 pthread_mutex_unlock(&(priv->buffer_mutex));
1806 return VBI_CONTROL_FALSE;
1808 if (!pgc->links[val-1].pagenum || pgc->links[val-1].pagenum>0x7ff) {
1809 pthread_mutex_unlock(&(priv->buffer_mutex));
1810 return VBI_CONTROL_FALSE;
1812 priv->pagenum=pgc->links[val-1].pagenum;
1813 if(pgc->links[val-1].subpagenum!=0x3f7f)
1814 priv->subpagenum=pgc->links[val-1].subpagenum;
1815 else
1816 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1817 priv->page_changed=1;
1818 pthread_mutex_unlock(&(priv->buffer_mutex));
1819 return VBI_CONTROL_TRUE;
1821 case TV_VBI_CONTROL_SET_PAGE:
1823 int val=*(int *) arg;
1824 if(val<100 || val>0x899)
1825 return VBI_CONTROL_FALSE;
1826 pthread_mutex_lock(&(priv->buffer_mutex));
1827 priv->pagenum=val&0x7ff;
1828 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1829 priv->pagenumdec=0;
1830 priv->page_changed=1;
1831 pthread_mutex_unlock(&(priv->buffer_mutex));
1832 return VBI_CONTROL_TRUE;
1834 case TV_VBI_CONTROL_STEP_PAGE:
1836 int direction=*(int *) arg;
1837 pthread_mutex_lock(&(priv->buffer_mutex));
1838 priv->pagenum=steppage(priv->pagenum, direction,1);
1839 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1840 priv->pagenumdec=0;
1841 priv->page_changed=1;
1842 pthread_mutex_unlock(&(priv->buffer_mutex));
1843 return VBI_CONTROL_TRUE;
1845 case TV_VBI_CONTROL_GET_PAGE:
1846 *(int*)arg=((priv->pagenum+0x700)&0x7ff)+0x100;
1847 return VBI_CONTROL_TRUE;
1848 case TV_VBI_CONTROL_SET_SUBPAGE:
1849 pthread_mutex_lock(&(priv->buffer_mutex));
1850 priv->pagenumdec=0;
1851 priv->subpagenum=*(int*)arg;
1852 if(priv->subpagenum<0)
1853 priv->subpagenum=0x3f7f;
1854 if(priv->subpagenum>=VBI_MAX_SUBPAGES)
1855 priv->subpagenum=VBI_MAX_SUBPAGES-1;
1856 priv->page_changed=1;
1857 pthread_mutex_unlock(&(priv->buffer_mutex));
1858 return VBI_CONTROL_TRUE;
1859 case TV_VBI_CONTROL_GET_SUBPAGE:
1860 *(int*)arg=priv->subpagenum;
1861 return VBI_CONTROL_TRUE;
1862 case TV_VBI_CONTROL_ADD_DEC:
1863 vbi_add_dec(priv, *(char **) arg);
1864 priv->page_changed=1;
1865 return VBI_CONTROL_TRUE;
1866 case TV_VBI_CONTROL_DECODE_PAGE:
1867 vbi_decode(priv,*(unsigned char**)arg);
1868 return VBI_CONTROL_TRUE;
1869 case TV_VBI_CONTROL_DECODE_DVB:
1870 vbi_decode_dvb(priv, arg);
1871 return VBI_CONTROL_TRUE;
1872 case TV_VBI_CONTROL_GET_VBIPAGE:
1873 if(!priv->on)
1874 return VBI_CONTROL_FALSE;
1875 prepare_visible_page(priv);
1876 *(void **)arg=priv->display_page;
1877 return VBI_CONTROL_TRUE;
1878 case TV_VBI_CONTROL_GET_NETWORKNAME:
1879 *(void **)arg=priv->networkname;
1880 return VBI_CONTROL_TRUE;
1881 case TV_VBI_CONTROL_MARK_UNCHANGED:
1882 priv->page_changed=0;
1883 priv->last_rendered=GetTimerMS();
1884 return VBI_CONTROL_TRUE;
1885 case TV_VBI_CONTROL_IS_CHANGED:
1886 if(GetTimerMS()-priv->last_rendered> 250) //forcing page update every 1/4 sec
1887 priv->page_changed=3; //mark that header update is enough
1888 *(int*)arg=priv->page_changed;
1889 return VBI_CONTROL_TRUE;
1891 return VBI_CONTROL_UNKNOWN;