comparison libmpcodecs/dec_teletext.c @ 29759:d287e2785570

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