Merge branch 'mplayer1_changes'
[mplayer/greg.git] / libmpcodecs / dec_teletext.c
blobd619ecde80bf1d913be33d13c8623a9656ef8c00
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 free(priv->mag[magAddr].pt);
1104 priv->mag[magAddr].pt=NULL;
1105 priv->mag[magAddr].order=0;
1106 return 0;
1109 if (!priv->mag[magAddr].pt)
1110 priv->mag[magAddr].pt= malloc(sizeof(tt_page));
1112 if(priv->primary_language)
1113 priv->mag[magAddr].pt->primary_lang=priv->primary_language;
1114 else
1115 priv->mag[magAddr].pt->primary_lang= (d[7]>>1)&7;
1116 priv->mag[magAddr].pt->secondary_lang=priv->secondary_language;
1117 priv->mag[magAddr].pt->subpagenum=(d[2]|(d[3]<<4)|(d[4]<<8)|(d[5]<<12))&0x3f7f;
1118 priv->mag[magAddr].pt->pagenum=(magAddr<<8) | d[0] | (d[1]<<4);
1119 priv->mag[magAddr].pt->flags=((d[7]&1)<<7) | ((d[3]&8)<<3) | ((d[5]&12)<<2) | d[6];
1121 memset(priv->mag[magAddr].pt->raw, 0x00, VBI_COLUMNS*VBI_ROWS);
1122 priv->mag[magAddr].order=0;
1124 for(i=0;i<8;i++){
1125 priv->mag[magAddr].pt->raw[i]=0x20;
1127 err=0;
1128 for(i=8; i<VBI_COLUMNS; i++){
1129 data[i]= fixParity[data[i]];
1130 priv->mag[magAddr].pt->raw[i]=data[i];
1131 if(data[i]&0x80) //Error
1132 err++;
1133 pll_add(priv,1,err);
1136 store_in_cache(priv,magAddr,0);
1138 return 1;
1142 * \brief decode teletext 8/30 Format 1 packet
1143 * \param priv private data structure
1144 * \param data raw teletext data (with not applied hamm correction yet)
1145 * \param magAddr teletext page's magazine address
1147 * \remarks
1148 * packet contains:
1149 * 0 designation code
1150 * 1..2 initial page
1151 * 3..6 initial subpage & magazine address
1152 * 7..8 network id
1153 * 9 time offset
1154 * 10..12 julian date
1155 * 13..15 universal time
1156 * 20..40 network name
1158 * First 7 bytes are protected by Hamm 8/4 code.
1159 * Bytes 20-40 has odd parity check.
1161 * See subcaluse 9.8.1 of specification for details
1163 static int decode_pkt30(priv_vbi_t* priv,unsigned char* data,int magAddr)
1165 int d[8];
1166 int i,err;
1168 for(i=0;i<7;i++){
1169 d[i]= corrHamm48[ data[i] ];
1170 if(d[i]&0x80){
1171 pll_add(priv,2,4);
1172 return 0;
1174 d[i]&=0xf;
1177 err=0;
1178 for(i=20; i<40; i++){
1179 data[i]= fixParity[data[i]];
1180 if(data[i]&0x80)//Unrecoverable error
1181 err++;
1182 pll_add(priv,1,err);
1184 if (err) return 0;
1186 if (d[0]&0xe) //This is not 8/30 Format 1 packet
1187 return 1;
1189 priv->initialpage=d[1] | d[2]<<4 | (d[6]&0xc)<<7 | (d[4]&1)<<8;
1190 priv->initialsubpage=d[3] | d[4]<<4 | d[5]<<8 | d[6]<<12;
1191 priv->networkid=data[7]<<8 | data[8];
1193 priv->timeoffset=(data[9]>>1)&0xf;
1194 if(data[9]&0x40)
1195 priv->timeoffset=-priv->timeoffset;
1197 priv->juliandate=(data[10]&0xf)<<16 | data[11]<<8 | data[12];
1198 priv->juliandate-=0x11111;
1200 priv->universaltime=data[13]<<16 | data[14]<<8 | data[15];
1201 priv->universaltime-=0x111111;
1203 snprintf(priv->networkname,21,"%s",data+20);
1205 return 1;
1209 * \brief decode packets 1..24 (teletext page header)
1210 * \param priv private data structure
1211 * \param data raw teletext data
1212 * \param magAddr teletext page's magazine address
1213 * \param rowAddr teletext page's row number
1215 * \remarks
1216 * data buffer was shifted by 6 and now contains 40 bytes of display data:
1217 * this type of packet is not proptected by Hamm 8/4 code
1219 static void decode_pkt_page(priv_vbi_t* priv,unsigned char*data,int magAddr,int rowAddr){
1220 int i,err;
1221 if (!priv->mag[magAddr].pt)
1222 return;
1224 priv->mag[magAddr].order=rowAddr;
1226 err=0;
1227 for(i=0; i<VBI_COLUMNS; i++){
1228 data[i]= fixParity[ data[i] ];
1229 priv->mag[magAddr].pt->raw[i+rowAddr*VBI_COLUMNS]=data[i];
1230 if( data[i]&0x80) //HammError
1231 err++;
1233 pll_add(priv,1,err);
1235 store_in_cache(priv,magAddr,rowAddr);
1239 * \brief decode packets 27 (teletext links)
1240 * \param priv private data structure
1241 * \param data raw teletext data
1242 * \param magAddr teletext page's magazine address
1244 static int decode_pkt27(priv_vbi_t* priv,unsigned char* data,int magAddr){
1245 int i,hpg;
1247 if (!priv->mag[magAddr].pt)
1248 return 0;
1249 for(i=0;i<38;++i)
1250 if ((data[i] = corrHamm48[ data[i] ]) & 0x80){
1251 pll_add(priv,2,4);
1252 return 0;
1256 Not a X/27/0 Format 1 packet or
1257 flag "show links on row 24" is not set.
1259 if (data[0] || !(data[37] & 8))
1260 return 1;
1261 for(i=0;i<6;++i) {
1262 hpg = (magAddr<<8) ^ ((data[4+i*6]&0x8)<<5 | (data[6+i*6]&0xc)<<7);
1263 if (!hpg) hpg=0x800;
1264 priv->mag[magAddr].pt->links[i].pagenum = (data[1+i*6] & 0xf) |
1265 ((data[2+i*6] & 0xf) << 4) | hpg;
1266 priv->mag[magAddr].pt->links[i].subpagenum = ((data[3+i*6] & 0xf) |
1267 (data[4+i*6] & 0xf) << 4 | (data[5+i*6] & 0xf) << 8 |
1268 (data[6+i*6] & 0xf) << 12) & 0x3f7f;
1270 put_to_cache(priv,priv->mag[magAddr].pt,-1);
1271 return 1;
1275 * \brief Decode teletext X/28/0 Format 1 packet
1276 * \param priv private data structure
1277 * \param data raw teletext data
1279 * Primary G0 charset is transmitted in bits 14-8 of Triplet 1
1280 * See Table 32 of specification for details.
1282 * Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and
1283 * bits 18-15 of Triplet 1
1284 * See Table 33 of specification for details.
1287 static void decode_pkt28(priv_vbi_t* priv,unsigned char*data){
1288 int d;
1289 int t1,t2;
1290 d=corrHamm48[ data[0] ];
1291 if(d) return; //this is not X/28/0 Format 1 packet or error occured
1293 t1=corrHamm24(data+1);
1294 t2=corrHamm24(data+4);
1295 if (t1<0 || t2<0){
1296 pll_add(priv,1,4);
1297 return;
1300 priv->primary_language=(t1>>7)&0x7f;
1301 priv->secondary_language=((t2<<4) | (t1>>14))&0x7f;
1302 if (priv->secondary_language==0x7f)
1303 //No secondary language required
1304 priv->secondary_language=priv->primary_language;
1305 else // Swapping bits 1 and 3
1306 priv->secondary_language=(priv->secondary_language&0x7a) |
1307 (priv->secondary_language&4)>>2 |
1308 (priv->secondary_language&1)<<2;
1310 mp_msg(MSGT_TELETEXT,MSGL_DBG2,"pkt28: language: primary=%02x secondary=0x%02x\n",
1311 priv->primary_language,priv->secondary_language);
1315 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1316 * \param priv private data structure
1317 * \param buf raw vbi data (one line of frame)
1318 * \param data output buffer for decoded bytes (at least 45 bytes long)
1320 * Used XawTV's algorithm. Signal phase is calculated with help of starting clock
1321 * run-in sequence (min/max values and bit distance values are calculated)
1323 static int decode_raw_line_runin(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){
1324 const int magic= 0x27; // reversed 1110010
1325 int dt[256],hi[6],lo[6];
1326 int i,x,r;
1327 int decoded;
1328 int sync;
1329 unsigned char min,max;
1330 int thr=0; //threshold
1332 //stubs
1333 int soc=priv->soc;
1334 int eoc=priv->eoc;
1336 for(i=soc;i<eoc;i++)
1337 dt[i]=buf[i+priv->bpb/ONE_FIXP]-buf[i]; // amplifies the edges best.
1338 /* set barrier */
1339 for (i=eoc; i<eoc+16; i+=2)
1340 dt[i]=100, dt[i+1]=-100;
1342 /* find 6 rising and falling edges */
1343 for (i=soc, x=0; x<6; ++x)
1345 while (dt[i]<32)
1346 i++;
1347 hi[x]=i;
1348 while (dt[i]>-32)
1349 i++;
1350 lo[x]=i;
1352 if (i>=eoc)
1354 return 0; // not enough periods found
1356 i=hi[5]-hi[1]; // length of 4 periods (8 bits)
1357 if (i<priv->bp8bl || i>priv->bp8bh)
1359 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: wrong freq %d (%d,%d)\n",
1360 i,priv->bp8bl,priv->bp8bh);
1361 return 0; // bad frequency
1363 /* AGC and sync-reference */
1364 min=255, max=0, sync=0;
1365 for (i=hi[4]; i<hi[5]; ++i)
1366 if (buf[i]>max)
1367 max=buf[i], sync=i;
1368 for (i=lo[4]; i<lo[5]; ++i)
1369 if (buf[i]<min)
1370 min=buf[i];
1371 thr=(min+max)/2;
1373 buf+=sync;
1374 // searching for '11'
1375 for(i=priv->pll_adj*priv->bpb/10;i<16*priv->bpb;i+=priv->bpb)
1376 if(buf[FIXP2INT(i)]>thr && buf[FIXP2INT(i+priv->bpb)]>thr)
1377 break;
1378 r=0;
1379 for(decoded=1; decoded<= (VBI_COLUMNS+3)<<3;decoded++){
1380 r>>=1;
1381 if(buf[FIXP2INT(i)]>thr) r|=0x80;
1382 if(!(decoded & 0x07)){
1383 data[(decoded>>3) - 1]=r;
1384 r=0;
1386 i+=priv->bpb;
1388 if(data[0]!=magic)
1389 return 0; //magic not found
1391 //stub
1392 for(i=0;i<43;i++){
1393 data[i]=data[i+1];
1395 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"thr:%d sync:%d ",thr,sync);
1397 return 1;
1400 #if 0
1401 //See comment in vbi_decode for a reason of commenting out this routine.
1404 * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
1405 * \param priv private data structure
1406 * \param buf raw vbi data (one line of frame)
1407 * \param data output buffer for decoded bytes (at least 45 bytes long)
1409 * Used Michael Niedermayer's algorithm.
1410 * Signal phase is calculated using correlation between given samples data and
1411 * pure sine
1413 static int decode_raw_line_sine(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){
1414 int i,x,r,amp,xFixp;
1415 int avg=0;
1416 double sin_sum=0, cos_sum=0;
1418 for(x=0; x< FIXP2INT(10*priv->bpb); x++)
1419 avg+=buf[x];
1421 avg/=FIXP2INT(10*priv->bpb);
1423 for(x=0; x<12; x++){
1424 amp= buf[x<<1];
1425 sin_sum+= si[x]*(amp-avg);
1426 cos_sum+= co[x]*(amp-avg);
1428 //this is always zero. Why ?
1429 xFixp= atan(sin_sum/cos_sum)*priv->bpb/M_PI;
1431 //Without this line the result is full of errors
1432 //and routine is unable to find magic sequence
1433 buf+=FIXP2INT(10*priv->bpb);
1435 r=0;
1436 for(x=FIXP2INT(xFixp);x<70;x=FIXP2INT(xFixp)){
1437 r=(r<<1) & 0xFFFF;
1438 if(buf[x]>avg) r|=1;
1439 xFixp+=priv->bpb;
1440 if(r==0xAAE4) break;
1443 //this is not teletext
1444 if (r!=0xaae4) return 0;
1446 //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes
1447 for(i=1; i<=(42<<3); i++){
1448 r>>=1;
1449 x=FIXP2INT(xFixp);
1450 if(buf[x]> avg)
1451 r|=0x80;
1453 if(!(i & 0x07)){
1454 data[(i>>3)-1]=r;
1455 r=0;
1457 xFixp+=priv->bpb;
1460 return 1;
1462 #endif
1465 * \brief decodes one vbi line from one video frame
1466 * \param priv private data structure
1467 * \param data buffer with raw vbi data in it
1469 static void vbi_decode_line(priv_vbi_t *priv, unsigned char *data) {
1470 int d0,d1,magAddr,pkt;
1472 d0= corrHamm48[ data[0] ];
1473 d1= corrHamm48[ data[1] ];
1475 if(d0&0x80 || d1&0x80){
1476 pll_add(priv,2,4);
1477 mp_msg(MSGT_TELETEXT,MSGL_V,"vbi_decode_line: HammErr\n");
1479 return; //hamError
1481 magAddr=d0 & 0x7;
1482 pkt=(d0>>3)|(d1<<1);
1483 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi_decode_line:%x %x (mag:%x, pkt:%d)\n",
1484 d0,d1,magAddr,pkt);
1485 if(!pkt){
1486 decode_pkt0(priv,data+2,magAddr); //skip MRGA
1487 }else if(pkt>0 && pkt<VBI_ROWS){
1488 if(!priv->mag[magAddr].pt)
1489 return;
1490 decode_pkt_page(priv,data+2,magAddr,pkt);//skip MRGA
1491 }else if(pkt==27) {
1492 decode_pkt27(priv,data+2,magAddr);
1493 }else if(pkt==28){
1494 decode_pkt28(priv,data+2);
1495 }else if(pkt==30){
1496 decode_pkt30(priv,data+2,magAddr);
1497 } else {
1498 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"unsupported packet:%d\n",pkt);
1503 * \brief decodes all vbi lines from one video frame
1504 * \param priv private data structure
1505 * \param buf buffer with raw vbi data in it
1507 * \note buffer size have to be at least priv->ptsp->bufsize bytes
1509 static void vbi_decode(priv_vbi_t* priv,unsigned char*buf){
1510 unsigned char data[64];
1511 unsigned char* linep;
1512 int i=0;
1513 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"vbi: vbi_decode\n");
1514 for(linep=buf; !priv->cache_reset && linep<buf+priv->ptsp->bufsize; linep+=priv->ptsp->samples_per_line,i++){
1515 #if 0
1517 This routine is alternative implementation of raw VBI data decoding.
1518 Unfortunately, it detects only about 20% of incoming data,
1519 but Michael says that this algorithm is better, and he wants to fix it.
1521 if(decode_raw_line_sine(priv,linep,data)<=0){
1522 #endif
1523 if(decode_raw_line_runin(priv,linep,data)<=0){
1524 continue; //this is not valid teletext line
1526 vbi_decode_line(priv, data);
1528 if (priv->cache_reset){
1529 pthread_mutex_lock(&(priv->buffer_mutex));
1530 priv->cache_reset--;
1531 pthread_mutex_unlock(&(priv->buffer_mutex));
1537 * \brief decodes a vbi line from a DVB teletext stream
1538 * \param priv private data structure
1539 * \param buf buffer with DVB teletext data
1541 * No locking is done since this is only called from a single-threaded context
1543 static void vbi_decode_dvb(priv_vbi_t *priv, const uint8_t buf[44]){
1544 int i;
1545 uint8_t data[42];
1547 mp_msg(MSGT_TELETEXT,MSGL_DBG3, "vbi: vbi_decode_dvb\n");
1549 /* Reverse bit order, skipping the first two bytes (field parity, line
1550 offset and framing code). */
1551 for (i = 0; i < sizeof(data); i++)
1552 data[i] = av_reverse[buf[2 + i]];
1554 vbi_decode_line(priv, data);
1555 if (priv->cache_reset)
1556 priv->cache_reset--;
1560 ---------------------------------------------------------------------------------
1561 Public routines
1562 ---------------------------------------------------------------------------------
1566 * \brief toggles teletext page displaying format
1567 * \param priv_vbi private data structure
1568 * \param flag new format
1569 * \return
1570 * VBI_CONTROL_TRUE is success,
1571 * VBI_CONTROL_FALSE otherwise
1573 * flag:
1574 * 0 - opaque
1575 * 1 - transparent
1576 * 2 - opaque with black foreground color (only in bw mode)
1577 * 3 - transparent with black foreground color (only in bw mode)
1579 static int teletext_set_format(priv_vbi_t * priv, teletext_format flag)
1581 flag&=3;
1583 mp_msg(MSGT_TELETEXT,MSGL_DBG3,"teletext_set_format_is called. mode:%d\n",flag);
1584 pthread_mutex_lock(&(priv->buffer_mutex));
1586 priv->tformat=flag;
1588 priv->pagenumdec=0;
1590 pthread_mutex_unlock(&(priv->buffer_mutex));
1591 return VBI_CONTROL_TRUE;
1595 * \brief append just entered digit to editing page number
1596 * \param priv_vbi private data structure
1597 * \param dec decimal digit to append
1599 * dec:
1600 * '0'..'9' append digit
1601 * '-' remove last digit (backspace emulation)
1603 * This routine allows user to jump to arbitrary page.
1604 * It implements simple page number editing algorithm.
1606 * Subsystem can be on one of two modes: normal and page number edit mode.
1607 * Zero value of priv->pagenumdec means normal mode
1608 * Non-zero value means page number edit mode and equals to packed
1609 * decimal number of already entered part of page number.
1611 * How this works.
1612 * Let's assume that current mode is normal (pagenumdec is zero), teletext page
1613 * 100 are displayed as usual. topmost left corner of page contains page number.
1614 * Then vbi_add_dec is sequentially called (through slave
1615 * command of course) with 1,4,-,2,3 * values of dec parameter.
1617 * +-----+------------+------------------+
1618 * | dec | pagenumdec | displayed number |
1619 * +-----+------------+------------------+
1620 * | | 0x000 | 100 |
1621 * +-----+------------+------------------+
1622 * | 1 | 0x001 | __1 |
1623 * +-----+------------+------------------+
1624 * | 4 | 0x014 | _14 |
1625 * +-----+------------+------------------+
1626 * | - | 0x001 | __1 |
1627 * +-----+------------+------------------+
1628 * | 2 | 0x012 | _12 |
1629 * +-----+------------+------------------+
1630 * | 3 | 0x123 | 123 |
1631 * +-----+------------+------------------+
1632 * | | 0x000 | 123 |
1633 * +-----+------------+------------------+
1635 * pagenumdec will automatically receive zero value after third digit of page
1636 * number is entered and current page will be switched to another one with
1637 * entered page number.
1639 static void vbi_add_dec(priv_vbi_t * priv, char *dec)
1641 int count, shift;
1642 if (!dec)
1643 return;
1644 if (!priv->on)
1645 return;
1646 if ((*dec<'0' || *dec>'9') && *dec!='-')
1647 return;
1648 if (!priv->pagenumdec) //first digit cannot be '0','9' or '-'
1649 if(*dec=='-' || *dec=='0' || *dec=='9')
1650 return;
1651 pthread_mutex_lock(&(priv->buffer_mutex));
1652 count=(priv->pagenumdec>>12)&0xf;
1653 if (*dec=='-') {
1654 count--;
1655 if (count)
1656 priv->pagenumdec=((priv->pagenumdec>>4)&0xfff)|(count<<12);
1657 else
1658 priv->pagenumdec=0;
1659 } else {
1660 shift = count * 4;
1661 count++;
1662 priv->pagenumdec=
1663 (((priv->pagenumdec)<<4|(*dec-'0'))&0xfff)|(count<<12);
1664 if (count==3) {
1665 priv->pagenum=priv->pagenumdec&0x7ff;
1666 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1667 priv->pagenumdec=0;
1670 pthread_mutex_unlock(&(priv->buffer_mutex));
1675 * \brief Teletext control routine
1676 * \param priv_vbi private data structure
1677 * \param cmd command
1678 * \param arg command parameter (has to be not null)
1680 int teletext_control(void* p, int cmd, void *arg)
1682 int fine_tune=99;
1683 priv_vbi_t* priv=(priv_vbi_t*)p;
1684 tt_page* pgc;
1686 if (!priv && cmd!=TV_VBI_CONTROL_START)
1687 return VBI_CONTROL_FALSE;
1688 if (!arg && cmd!=TV_VBI_CONTROL_STOP && cmd!=TV_VBI_CONTROL_MARK_UNCHANGED)
1689 return VBI_CONTROL_FALSE;
1691 switch (cmd) {
1692 case TV_VBI_CONTROL_RESET:
1694 int i;
1695 struct tt_param* tt_param=arg;
1696 pthread_mutex_lock(&(priv->buffer_mutex));
1697 priv->pagenumdec=0;
1698 clear_cache(priv);
1699 priv->pagenum=steppage(0,tt_param->page&0x7ff,1);
1700 priv->tformat=tt_param->format;
1701 priv->subpagenum=0x3f7f;
1702 pll_reset(priv,fine_tune);
1703 if(tt_param->lang==-1){
1704 mp_tmsg(MSGT_TELETEXT,MSGL_INFO,"Supported Teletext languages:\n");
1705 for(i=0; tt_languages[i].lang_code; i++){
1706 mp_msg(MSGT_TELETEXT,MSGL_INFO," %3d %s\n",
1707 tt_languages[i].lang_code, tt_languages[i].lang_name);
1709 mp_msg(MSGT_TELETEXT,MSGL_INFO," %3d %s\n",
1710 tt_languages[i].lang_code, tt_languages[i].lang_name);
1711 }else{
1712 for(i=0; tt_languages[i].lang_code; i++){
1713 if(tt_languages[i].lang_code==tt_param->lang)
1714 break;
1716 if (priv->primary_language!=tt_languages[i].lang_code){
1717 mp_tmsg(MSGT_TELETEXT,MSGL_INFO,"Selected default teletext language: %s\n",
1718 tt_languages[i].lang_name);
1719 priv->primary_language=tt_languages[i].lang_code;
1722 priv->page_changed=1;
1723 pthread_mutex_unlock(&(priv->buffer_mutex));
1724 return VBI_CONTROL_TRUE;
1726 case TV_VBI_CONTROL_START:
1728 int i;
1729 tt_stream_props* ptsp=*(tt_stream_props**)arg;
1731 if(!ptsp)
1732 return VBI_CONTROL_FALSE;
1734 priv=calloc(1,sizeof(priv_vbi_t));
1736 priv->ptsp=malloc(sizeof(tt_stream_props));
1737 memcpy(priv->ptsp,ptsp,sizeof(tt_stream_props));
1738 *(priv_vbi_t**)arg=priv;
1740 priv->subpagenum=0x3f7f;
1741 pthread_mutex_init(&priv->buffer_mutex, NULL);
1742 priv->pagenumdec=0;
1743 for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++)
1744 priv->display_page[i]=tt_space;
1746 priv->mag=calloc(8,sizeof(mag_t));
1747 init_cache(priv);
1748 init_vbi_consts(priv);
1749 pll_reset(priv,fine_tune);
1750 priv->page_changed=1;
1751 return VBI_CONTROL_TRUE;
1753 case TV_VBI_CONTROL_STOP:
1755 free(priv->mag);
1756 free(priv->ptsp);
1757 destroy_cache(priv);
1758 priv->page_changed=1;
1759 pthread_mutex_destroy(&priv->buffer_mutex);
1760 free(priv);
1761 return VBI_CONTROL_TRUE;
1763 case TV_VBI_CONTROL_SET_MODE:
1764 priv->on=(*(int*)arg%2);
1765 priv->page_changed=1;
1766 return VBI_CONTROL_TRUE;
1767 case TV_VBI_CONTROL_GET_MODE:
1768 *(int*)arg=priv->on;
1769 return VBI_CONTROL_TRUE;
1770 case TV_VBI_CONTROL_SET_FORMAT:
1771 priv->page_changed=1;
1772 return teletext_set_format(priv, *(int *) arg);
1773 case TV_VBI_CONTROL_GET_FORMAT:
1774 pthread_mutex_lock(&(priv->buffer_mutex));
1775 *(int*)arg=priv->tformat;
1776 pthread_mutex_unlock(&(priv->buffer_mutex));
1777 return VBI_CONTROL_TRUE;
1778 case TV_VBI_CONTROL_GET_HALF_PAGE:
1779 if(!priv->on)
1780 return VBI_CONTROL_FALSE;
1781 *(int *)arg=priv->zoom;
1782 return VBI_CONTROL_TRUE;
1783 case TV_VBI_CONTROL_SET_HALF_PAGE:
1785 int val=*(int*)arg;
1786 val%=3;
1787 if(val<0)
1788 val+=3;
1789 pthread_mutex_lock(&(priv->buffer_mutex));
1790 priv->zoom=val;
1791 priv->page_changed=1;
1792 pthread_mutex_unlock(&(priv->buffer_mutex));
1793 return VBI_CONTROL_TRUE;
1795 case TV_VBI_CONTROL_GO_LINK:
1797 int val=*(int *) arg;
1798 if(val<1 || val>6)
1799 return VBI_CONTROL_FALSE;
1800 pthread_mutex_lock(&(priv->buffer_mutex));
1801 if (!(pgc = priv->ptt_cache[priv->pagenum])) {
1802 pthread_mutex_unlock(&(priv->buffer_mutex));
1803 return VBI_CONTROL_FALSE;
1805 if (!pgc->links[val-1].pagenum || pgc->links[val-1].pagenum>0x7ff) {
1806 pthread_mutex_unlock(&(priv->buffer_mutex));
1807 return VBI_CONTROL_FALSE;
1809 priv->pagenum=pgc->links[val-1].pagenum;
1810 if(pgc->links[val-1].subpagenum!=0x3f7f)
1811 priv->subpagenum=pgc->links[val-1].subpagenum;
1812 else
1813 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1814 priv->page_changed=1;
1815 pthread_mutex_unlock(&(priv->buffer_mutex));
1816 return VBI_CONTROL_TRUE;
1818 case TV_VBI_CONTROL_SET_PAGE:
1820 int val=*(int *) arg;
1821 if(val<100 || val>0x899)
1822 return VBI_CONTROL_FALSE;
1823 pthread_mutex_lock(&(priv->buffer_mutex));
1824 priv->pagenum=val&0x7ff;
1825 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1826 priv->pagenumdec=0;
1827 priv->page_changed=1;
1828 pthread_mutex_unlock(&(priv->buffer_mutex));
1829 return VBI_CONTROL_TRUE;
1831 case TV_VBI_CONTROL_STEP_PAGE:
1833 int direction=*(int *) arg;
1834 pthread_mutex_lock(&(priv->buffer_mutex));
1835 priv->pagenum=steppage(priv->pagenum, direction,1);
1836 priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum);
1837 priv->pagenumdec=0;
1838 priv->page_changed=1;
1839 pthread_mutex_unlock(&(priv->buffer_mutex));
1840 return VBI_CONTROL_TRUE;
1842 case TV_VBI_CONTROL_GET_PAGE:
1843 *(int*)arg=((priv->pagenum+0x700)&0x7ff)+0x100;
1844 return VBI_CONTROL_TRUE;
1845 case TV_VBI_CONTROL_SET_SUBPAGE:
1846 pthread_mutex_lock(&(priv->buffer_mutex));
1847 priv->pagenumdec=0;
1848 priv->subpagenum=*(int*)arg;
1849 if(priv->subpagenum<0)
1850 priv->subpagenum=0x3f7f;
1851 if(priv->subpagenum>=VBI_MAX_SUBPAGES)
1852 priv->subpagenum=VBI_MAX_SUBPAGES-1;
1853 priv->page_changed=1;
1854 pthread_mutex_unlock(&(priv->buffer_mutex));
1855 return VBI_CONTROL_TRUE;
1856 case TV_VBI_CONTROL_GET_SUBPAGE:
1857 *(int*)arg=priv->subpagenum;
1858 return VBI_CONTROL_TRUE;
1859 case TV_VBI_CONTROL_ADD_DEC:
1860 vbi_add_dec(priv, *(char **) arg);
1861 priv->page_changed=1;
1862 return VBI_CONTROL_TRUE;
1863 case TV_VBI_CONTROL_DECODE_PAGE:
1864 vbi_decode(priv,*(unsigned char**)arg);
1865 return VBI_CONTROL_TRUE;
1866 case TV_VBI_CONTROL_DECODE_DVB:
1867 vbi_decode_dvb(priv, arg);
1868 return VBI_CONTROL_TRUE;
1869 case TV_VBI_CONTROL_GET_VBIPAGE:
1870 if(!priv->on)
1871 return VBI_CONTROL_FALSE;
1872 prepare_visible_page(priv);
1873 *(void **)arg=priv->display_page;
1874 return VBI_CONTROL_TRUE;
1875 case TV_VBI_CONTROL_GET_NETWORKNAME:
1876 *(void **)arg=priv->networkname;
1877 return VBI_CONTROL_TRUE;
1878 case TV_VBI_CONTROL_MARK_UNCHANGED:
1879 priv->page_changed=0;
1880 priv->last_rendered=GetTimerMS();
1881 return VBI_CONTROL_TRUE;
1882 case TV_VBI_CONTROL_IS_CHANGED:
1883 if(GetTimerMS()-priv->last_rendered> 250) //forcing page update every 1/4 sec
1884 priv->page_changed=3; //mark that header update is enough
1885 *(int*)arg=priv->page_changed;
1886 return VBI_CONTROL_TRUE;
1888 return VBI_CONTROL_UNKNOWN;