Mercurial > mplayer.hg
comparison stream/tvi_vbi.c @ 23510:a6c619ee9d30
Teletext support for tv:// (v4l and v4l2 only)
modified patch from Otvos Attila oattila at chello dot hu
Module uses zvbi library for all low-level VBI operations (like I/O with vbi
device, converting vbi pages into usefull vbi_page stuctures, rendering them
into RGB32 images).
All teletext related stuff (except properties, slave commands and rendering
osd in text mode or RGB32 rendered teletext pages in spu mode) is implemented
in tvi_vbi.c
New properties:
teletext_page - switching between pages
teletext_mode - switch between on/off/opaque/transparent modes
teletext_format - (currently read-only) allows to get format info
(black/white,gray,text)
teletext_half_page - trivial zooming (displaying top/bottom half of teletext
page)
New slave commands:
teletext_add_dec - user interface for jumping to any page by editing page number
interactively
teletext_go_link - goes though links, specified on current page
author | voroshil |
---|---|
date | Sun, 10 Jun 2007 00:06:12 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
23509:53d57a0ebe13 | 23510:a6c619ee9d30 |
---|---|
1 #include "config.h" | |
2 | |
3 #include <stdlib.h> | |
4 #include <string.h> | |
5 #include <unistd.h> | |
6 #include <errno.h> | |
7 | |
8 #include "tv.h" | |
9 #include "tvi_vbi.h" | |
10 #include "mp_msg.h" | |
11 #include "libmpcodecs/img_format.h" | |
12 | |
13 #ifdef USE_ICONV | |
14 #include <iconv.h> | |
15 #endif | |
16 | |
17 #define VBI_TEXT_CHARSET "UTF-8" | |
18 | |
19 char* tv_param_tdevice=NULL; ///< teletext vbi device | |
20 char* tv_param_tformat="gray"; ///< format: text,bw,gray,color | |
21 int tv_param_tpage=100; ///< page number | |
22 | |
23 | |
24 #ifdef USE_ICONV | |
25 /* | |
26 ------------------------------------------------------------------ | |
27 zvbi-0.2.25/src/exp-txt.c skip debug "if(1) fprintf(stderr,) " message | |
28 ------------------------------------------------------------------ | |
29 */ | |
30 | |
31 /** | |
32 * libzvbi - Text export functions | |
33 * | |
34 * Copyright (C) 2001, 2002 Michael H. Schimek | |
35 * | |
36 * Based on code from AleVT 1.5.1 | |
37 * Copyright (C) 1998, 1999 Edgar Toernig <froese@gmx.de> | |
38 * | |
39 * This program is free software; you can redistribute it and/or modify | |
40 * it under the terms of the GNU General Public License as published by | |
41 * the Free Software Foundation; either version 2 of the License, or | |
42 * (at your option) any later version. | |
43 * | |
44 * This program is distributed in the hope that it will be useful, | |
45 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
47 * GNU General Public License for more details. | |
48 * | |
49 * You should have received a copy of the GNU General Public License | |
50 * along with this program; if not, write to the Free Software | |
51 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
52 **/ | |
53 | |
54 /** $Id$ **/ | |
55 | |
56 static vbi_bool | |
57 print_unicode(iconv_t cd, int endian, int unicode, char **p, int n) | |
58 { | |
59 char in[2], *ip, *op; | |
60 size_t li, lo, r; | |
61 | |
62 in[0 + endian] = unicode; | |
63 in[1 - endian] = unicode >> 8; | |
64 ip = in; op = *p; | |
65 li = sizeof(in); lo = n; | |
66 | |
67 r = iconv(cd, &ip, &li, &op, &lo); | |
68 | |
69 if ((size_t) -1 == r | |
70 || (**p == 0x40 && unicode != 0x0040)) { | |
71 in[0 + endian] = 0x20; | |
72 in[1 - endian] = 0; | |
73 ip = in; op = *p; | |
74 li = sizeof(in); lo = n; | |
75 | |
76 r = iconv(cd, &ip, &li, &op, &lo); | |
77 | |
78 if ((size_t) -1 == r | |
79 || (r == 1 && **p == 0x40)) | |
80 goto error; | |
81 } | |
82 | |
83 *p = op; | |
84 | |
85 return TRUE; | |
86 | |
87 error: | |
88 return FALSE; | |
89 } | |
90 | |
91 static int | |
92 vbi_print_page_region_nodebug(vbi_page * pg, char *buf, int size, | |
93 const char *format, vbi_bool table, | |
94 vbi_bool rtl, int column, int row, int width, | |
95 int height) | |
96 { | |
97 int endian = vbi_ucs2be(); | |
98 int column0, column1, row0, row1; | |
99 int x, y, spaces, doubleh, doubleh0; | |
100 iconv_t cd; | |
101 char *p; | |
102 | |
103 rtl = rtl; | |
104 | |
105 #if 0 | |
106 if (1) | |
107 fprintf (stderr, "vbi_print_page_region '%s' " | |
108 "table=%d col=%d row=%d width=%d height=%d\n", | |
109 format, table, column, row, width, height); | |
110 #endif | |
111 | |
112 column0 = column; | |
113 row0 = row; | |
114 column1 = column + width - 1; | |
115 row1 = row + height - 1; | |
116 | |
117 if (!pg || !buf || size < 0 || !format | |
118 || column0 < 0 || column1 >= pg->columns | |
119 || row0 < 0 || row1 >= pg->rows | |
120 || endian < 0) | |
121 return 0; | |
122 | |
123 if ((cd = iconv_open(format, "UCS-2")) == (iconv_t) -1) | |
124 return 0; | |
125 | |
126 p = buf; | |
127 | |
128 doubleh = 0; | |
129 | |
130 for (y = row0; y <= row1; y++) { | |
131 int x0, x1, xl; | |
132 | |
133 x0 = (table || y == row0) ? column0 : 0; | |
134 x1 = (table || y == row1) ? column1 : (pg->columns - 1); | |
135 | |
136 xl = (table || y != row0 || (y + 1) != row1) ? -1 : column1; | |
137 | |
138 doubleh0 = doubleh; | |
139 | |
140 spaces = 0; | |
141 doubleh = 0; | |
142 | |
143 for (x = x0; x <= x1; x++) { | |
144 vbi_char ac = pg->text[y * pg->columns + x]; | |
145 | |
146 if (table) { | |
147 if (ac.size > VBI_DOUBLE_SIZE) | |
148 ac.unicode = 0x0020; | |
149 } else { | |
150 switch (ac.size) { | |
151 case VBI_NORMAL_SIZE: | |
152 case VBI_DOUBLE_WIDTH: | |
153 break; | |
154 | |
155 case VBI_DOUBLE_HEIGHT: | |
156 case VBI_DOUBLE_SIZE: | |
157 doubleh++; | |
158 break; | |
159 | |
160 case VBI_OVER_TOP: | |
161 case VBI_OVER_BOTTOM: | |
162 continue; | |
163 | |
164 case VBI_DOUBLE_HEIGHT2: | |
165 case VBI_DOUBLE_SIZE2: | |
166 if (y > row0) | |
167 ac.unicode = 0x0020; | |
168 break; | |
169 } | |
170 | |
171 /* | |
172 * Special case two lines row0 ... row1, and all chars | |
173 * in row0, column0 ... column1 are double height: Skip | |
174 * row1, don't wrap around. | |
175 */ | |
176 if (x == xl && doubleh >= (x - x0)) { | |
177 x1 = xl; | |
178 y = row1; | |
179 } | |
180 | |
181 if (ac.unicode == 0x20 || !vbi_is_print(ac.unicode)) { | |
182 spaces++; | |
183 continue; | |
184 } else { | |
185 if (spaces < (x - x0) || y == row0) { | |
186 for (; spaces > 0; spaces--) | |
187 if (!print_unicode(cd, endian, 0x0020, | |
188 &p, buf + size - p)) | |
189 goto failure; | |
190 } else /* discard leading spaces */ | |
191 spaces = 0; | |
192 } | |
193 } | |
194 | |
195 if (!print_unicode(cd, endian, ac.unicode, &p, buf + size - p)) | |
196 goto failure; | |
197 } | |
198 | |
199 /* if !table discard trailing spaces and blank lines */ | |
200 | |
201 if (y < row1) { | |
202 int left = buf + size - p; | |
203 | |
204 if (left < 1) | |
205 goto failure; | |
206 | |
207 if (table) { | |
208 *p++ = '\n'; /* XXX convert this (eg utf16) */ | |
209 } else if (spaces >= (x1 - x0)) { | |
210 ; /* suppress blank line */ | |
211 } else { | |
212 /* exactly one space between adjacent rows */ | |
213 if (!print_unicode(cd, endian, 0x0020, &p, left)) | |
214 goto failure; | |
215 } | |
216 } else { | |
217 if (doubleh0 > 0) { | |
218 ; /* prentend this is a blank double height lower row */ | |
219 } else { | |
220 for (; spaces > 0; spaces--) | |
221 if (!print_unicode(cd, endian, 0x0020, &p, buf + size - p)) | |
222 goto failure; | |
223 } | |
224 } | |
225 } | |
226 | |
227 iconv_close(cd); | |
228 return p - buf; | |
229 | |
230 failure: | |
231 iconv_close(cd); | |
232 return 0; | |
233 } | |
234 #endif | |
235 /* | |
236 end of zvbi-0.2.25/src/exp-txt.c part | |
237 */ | |
238 | |
239 | |
240 /* | |
241 ------------------------------------------------------------------ | |
242 Private routines | |
243 ------------------------------------------------------------------ | |
244 */ | |
245 | |
246 /** | |
247 * \brief Decode event handler | |
248 * \param ev VBI event | |
249 * \param data pointer to user defined data | |
250 * | |
251 */ | |
252 static void event_handler(vbi_event * ev, void *data) | |
253 { | |
254 priv_vbi_t *user_vbi = (priv_vbi_t *) data; | |
255 vbi_page pg; | |
256 char *s; | |
257 int i; | |
258 | |
259 switch (ev->type) { | |
260 case VBI_EVENT_CAPTION: | |
261 mp_msg(MSGT_TV,MSGL_DBG3,"caption\n"); | |
262 break; | |
263 case VBI_EVENT_NETWORK: | |
264 s = ev->ev.network.name; | |
265 if (s) { | |
266 pthread_mutex_lock(&(user_vbi->buffer_mutex)); | |
267 if (user_vbi->network_name) | |
268 free(user_vbi->network_name); | |
269 user_vbi->network_name = strdup(s); | |
270 pthread_mutex_unlock(&(user_vbi->buffer_mutex)); | |
271 } | |
272 break; | |
273 case VBI_EVENT_NETWORK_ID: | |
274 s = ev->ev.network.name; | |
275 if (s) { | |
276 pthread_mutex_lock(&(user_vbi->buffer_mutex)); | |
277 if (user_vbi->network_id) | |
278 free(user_vbi->network_id); | |
279 user_vbi->network_id = strdup(s); | |
280 pthread_mutex_unlock(&(user_vbi->buffer_mutex)); | |
281 } | |
282 break; | |
283 case VBI_EVENT_TTX_PAGE: | |
284 pthread_mutex_lock(&(user_vbi->buffer_mutex)); | |
285 user_vbi->curr_pgno = ev->ev.ttx_page.pgno; // page number | |
286 user_vbi->curr_subno = ev->ev.ttx_page.subno; // subpage | |
287 i = vbi_bcd2dec(ev->ev.ttx_page.pgno); | |
288 if (i > 0 && i < 1000) { | |
289 if (!user_vbi->cache[i]) | |
290 user_vbi->cache[i] = (vbi_page *) malloc(sizeof(vbi_page)); | |
291 vbi_fetch_vt_page(user_vbi->decoder, // fetch page | |
292 user_vbi->cache[i], | |
293 ev->ev.ttx_page.pgno, | |
294 ev->ev.ttx_page.subno, | |
295 VBI_WST_LEVEL_3p5, 25, TRUE); | |
296 memcpy(user_vbi->theader, user_vbi->cache[i]->text, | |
297 sizeof(user_vbi->theader)); | |
298 } | |
299 pthread_mutex_unlock(&(user_vbi->buffer_mutex)); | |
300 break; | |
301 } | |
302 } | |
303 | |
304 /** | |
305 * \brief Prepares page to be shown on screen | |
306 * \param priv_vbi private data structure | |
307 * | |
308 * This routine adds page number, current time, etc to page header | |
309 * | |
310 */ | |
311 static void process_page(priv_vbi_t * priv_vbi) | |
312 { | |
313 char *pagesptr; | |
314 int csize, i, j, subtitle = 0, sflg, send; | |
315 void *canvas; | |
316 char cpage[5]; | |
317 vbi_page page; | |
318 | |
319 memcpy(&(page), priv_vbi->page, sizeof(vbi_page)); | |
320 if (priv_vbi->pgno != priv_vbi->page->pgno) { | |
321 //don't clear first line | |
322 for (i = page.columns; i < 1056; i++) { | |
323 page.text[i].unicode = ' '; | |
324 page.text[i].background = VBI_TRANSPARENT_COLOR; | |
325 } | |
326 snprintf(cpage, sizeof(cpage), "%03X", priv_vbi->pgno); | |
327 page.text[1].unicode = cpage[0]; | |
328 page.text[2].unicode = cpage[1]; | |
329 page.text[3].unicode = cpage[2]; | |
330 page.text[4].unicode = ' '; | |
331 page.text[5].unicode = ' '; | |
332 page.text[6].unicode = ' '; | |
333 } | |
334 | |
335 //background page number & title | |
336 j=vbi_bcd2dec(priv_vbi->curr_pgno); | |
337 if (j>0 && j<1000 && priv_vbi->cache[j]){ | |
338 for(i=8;i<priv_vbi->cache[j]->columns;i++){ | |
339 page.text[i].unicode = priv_vbi->cache[j]->text[i].unicode; | |
340 } | |
341 } | |
342 | |
343 if (page.text[1].unicode == ' ' && page.text[2].unicode == ' ' && | |
344 page.text[3].unicode == ' ' && page.text[4].unicode == ' ' && | |
345 page.text[5].unicode == ' ' && page.text[5].unicode == ' ' | |
346 && !priv_vbi->half) | |
347 subtitle = 1; // subtitle page | |
348 if (priv_vbi->pagenumdec) { | |
349 i = (priv_vbi->pagenumdec >> 12) & 0xf; | |
350 switch (i) { | |
351 case 1: | |
352 page.text[1].unicode = '0' + ((priv_vbi->pagenumdec >> 0) & 0xf); | |
353 page.text[2].unicode = '-'; | |
354 page.text[3].unicode = '-'; | |
355 break; | |
356 case 2: | |
357 page.text[1].unicode = '0' + ((priv_vbi->pagenumdec >> 4) & 0xf); | |
358 page.text[2].unicode = '0' + ((priv_vbi->pagenumdec >> 0) & 0xf); | |
359 page.text[3].unicode = '-'; | |
360 break; | |
361 } | |
362 page.text[4].unicode = ' '; | |
363 page.text[5].unicode = ' '; | |
364 page.text[6].unicode = ' '; | |
365 page.text[1].foreground = VBI_WHITE; | |
366 page.text[2].foreground = VBI_WHITE; | |
367 page.text[3].foreground = VBI_WHITE; | |
368 } | |
369 priv_vbi->columns = page.columns; | |
370 priv_vbi->rows = page.rows; | |
371 if (!subtitle) { // update time in header | |
372 memcpy(&(page.text[VBI_TIME_LINEPOS]), | |
373 &(priv_vbi->theader[VBI_TIME_LINEPOS]), | |
374 sizeof(vbi_char) * (priv_vbi->columns - VBI_TIME_LINEPOS)); | |
375 } | |
376 switch (priv_vbi->tformat) { | |
377 case VBI_TFORMAT_TEXT: // mode: text | |
378 if (priv_vbi->txtpage) { | |
379 #ifdef USE_ICONV | |
380 vbi_print_page_region_nodebug(&(page), priv_vbi->txtpage, | |
381 VBI_TXT_PAGE_SIZE, VBI_TEXT_CHARSET, TRUE, | |
382 0, 0, 0, page.columns, page.rows); // vbi_page to text without message | |
383 #else | |
384 vbi_print_page(&(page), priv_vbi->txtpage, | |
385 VBI_TXT_PAGE_SIZE, VBI_TEXT_CHARSET, TRUE, 0); | |
386 #endif | |
387 } | |
388 priv_vbi->valid_page = 1; | |
389 break; | |
390 case VBI_TFORMAT_BW: // mode: black & white | |
391 for (i=0; i < (priv_vbi->pgno!=page.pgno?page.columns:1056); i++) { | |
392 if (priv_vbi->foreground){ | |
393 page.text[i].foreground = VBI_BLACK; | |
394 page.text[i].background = VBI_WHITE; | |
395 }else{ | |
396 page.text[i].foreground = VBI_WHITE; | |
397 page.text[i].background = VBI_BLACK; | |
398 } | |
399 } | |
400 case VBI_TFORMAT_GRAY: // mode: grayscale | |
401 case VBI_TFORMAT_COLOR: // mode: color (request color spu patch!) | |
402 | |
403 | |
404 | |
405 page.color_map[VBI_TRANSPARENT_COLOR] = 0; | |
406 if (priv_vbi->alpha) { | |
407 if (subtitle) { | |
408 for (i = 0; i < page.rows; i++) { | |
409 sflg = 0; | |
410 send = 0; | |
411 for (j = 0; j < page.columns; j++) { | |
412 if (page.text[i * page.columns + j].unicode != ' ') { | |
413 sflg = 1; | |
414 send = j; | |
415 } | |
416 if (sflg == 0) | |
417 page.text[i * page.columns + j].background = | |
418 VBI_TRANSPARENT_COLOR; | |
419 } | |
420 for (j = send + 1; j < page.columns; j++) | |
421 page.text[i * page.columns + j].background = | |
422 VBI_TRANSPARENT_COLOR; | |
423 } | |
424 } else { | |
425 for (i = 0; i < 1056; i++) | |
426 page.text[i].background = VBI_TRANSPARENT_COLOR; | |
427 } | |
428 } | |
429 csize = page.columns * page.rows * 12 * 10 * sizeof(vbi_rgba); | |
430 if (csize == 0) | |
431 break; | |
432 if (csize > priv_vbi->canvas_size) { // test canvas size | |
433 if (priv_vbi->canvas) | |
434 free(priv_vbi->canvas); | |
435 priv_vbi->canvas = malloc(csize); | |
436 priv_vbi->canvas_size = 0; | |
437 if (priv_vbi->canvas) | |
438 priv_vbi->canvas_size = csize; | |
439 } | |
440 if (priv_vbi->canvas) { | |
441 vbi_draw_vt_page(&(page), | |
442 priv_vbi->fmt, | |
443 priv_vbi->canvas, | |
444 priv_vbi->reveal, priv_vbi->flash_on); | |
445 priv_vbi->csize = csize; | |
446 } | |
447 priv_vbi->spudec_proc = 1; | |
448 priv_vbi->valid_page = 1; | |
449 break; | |
450 } | |
451 } | |
452 | |
453 /** | |
454 * \brief Update page in cache | |
455 * \param priv_vbi private data structure | |
456 * | |
457 * Routine also calls process_page to refresh currently visible page (if so) | |
458 * every time it was received from VBI by background thread. | |
459 * | |
460 */ | |
461 static void update_page(priv_vbi_t * priv_vbi) | |
462 { | |
463 int i; | |
464 int index; | |
465 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
466 /* | |
467 priv_vbi->redraw=1 - page redraw requested | |
468 pgno!=page->pgno - page was switched | |
469 curr_pgno==pgno - backgound process just fetched current page, refresh it | |
470 */ | |
471 if (priv_vbi->redraw || | |
472 priv_vbi->pgno != priv_vbi->page->pgno || | |
473 priv_vbi->curr_pgno == priv_vbi->pgno) { | |
474 index = vbi_bcd2dec(priv_vbi->pgno); | |
475 if ( index <= 0 || index > 999 || !priv_vbi->cache[index]) { | |
476 // curr_pgno is last decoded page | |
477 index = vbi_bcd2dec(priv_vbi->curr_pgno); | |
478 } | |
479 | |
480 if (index <=0 || index >999 || !priv_vbi->cache[index]){ | |
481 priv_vbi->valid_page = 0; | |
482 memset(priv_vbi->page, 0, sizeof(vbi_page)); | |
483 }else | |
484 { | |
485 memcpy(priv_vbi->page, priv_vbi->cache[index], sizeof(vbi_page)); | |
486 process_page(priv_vbi);//prepare page to be shown on screen | |
487 } | |
488 } | |
489 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
490 } | |
491 | |
492 /** | |
493 * \brief background grabber routine | |
494 * \param data user-defined data | |
495 * | |
496 */ | |
497 static void *grabber(void *data) | |
498 { | |
499 priv_vbi_t *user_vbi = (priv_vbi_t *) data; | |
500 vbi_capture_buffer *sliced_buffer; | |
501 struct timeval timeout; | |
502 unsigned int n_lines; | |
503 int r, err_count = 0; | |
504 | |
505 while (!user_vbi->eof) { | |
506 timeout.tv_sec = 0; | |
507 timeout.tv_usec = 500; | |
508 r = vbi_capture_pull(user_vbi->capture, NULL, &sliced_buffer, &timeout); // grab slices | |
509 if (user_vbi->eof) | |
510 return NULL; | |
511 switch (r) { | |
512 case -1: // read error | |
513 if (err_count++ > 4) | |
514 user_vbi->eof = 1; | |
515 break; | |
516 case 0: // time out | |
517 break; | |
518 default: | |
519 err_count = 0; | |
520 } | |
521 if (r != 1) | |
522 continue; | |
523 n_lines = sliced_buffer->size / sizeof(vbi_sliced); | |
524 vbi_decode(user_vbi->decoder, (vbi_sliced *) sliced_buffer->data, | |
525 n_lines, sliced_buffer->timestamp); // decode slice | |
526 update_page(user_vbi); | |
527 } | |
528 switch (r) { | |
529 case -1: | |
530 mp_msg(MSGT_TV, MSGL_ERR, "VBI read error %d (%s)\n", | |
531 errno, strerror(errno)); | |
532 return NULL; | |
533 case 0: | |
534 mp_msg(MSGT_TV, MSGL_ERR, "VBI read timeout\n"); | |
535 return NULL; | |
536 } | |
537 return NULL; | |
538 } | |
539 | |
540 /** | |
541 * \brief calculate increased/decreased by given value page number | |
542 * \param curr current page number in hexadecimal for | |
543 * \param direction decimal value (can be negative) to add to value or curr parameter | |
544 * \return new page number in hexadecimal form | |
545 * | |
546 * VBI page numbers are represented in special hexadecimal form, e.g. | |
547 * page with number 123 (as seen by user) internally has number 0x123. | |
548 * and equation 0x123+8 should be equal to 0x131 instead of regular 0x12b. | |
549 * Page numbers 0xYYY (where Y is not belongs to (0..9) and pages below 0x100 and | |
550 * higher 0x999 are reserved for internal use. | |
551 * | |
552 */ | |
553 static int steppage(int curr, int direction) | |
554 { | |
555 int newpage = vbi_dec2bcd(vbi_bcd2dec(curr) + direction); | |
556 if (newpage < 0x100) | |
557 newpage = 0x100; | |
558 if (newpage > 0x999) | |
559 newpage = 0x999; | |
560 return newpage; | |
561 } | |
562 | |
563 /** | |
564 * \brief toggles teletext page displaying mode | |
565 * \param priv_vbi private data structure | |
566 * \param flag new mode | |
567 * \return | |
568 * TVI_CONTROL_TRUE is success, | |
569 * TVI_CONTROL_FALSE otherwise | |
570 * | |
571 * flag: | |
572 * 0 - off | |
573 * 1 - on & opaque | |
574 * 2 - on & transparent | |
575 * 3 - on & transparent with black foreground color (only in bw mode) | |
576 * | |
577 */ | |
578 static int teletext_set_mode(priv_vbi_t * priv_vbi, int flag) | |
579 { | |
580 if (flag<0 || flag>3) | |
581 return TVI_CONTROL_FALSE; | |
582 | |
583 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
584 | |
585 priv_vbi->on = flag; | |
586 | |
587 if (priv_vbi->on > 2 && priv_vbi->tformat != VBI_TFORMAT_BW) | |
588 priv_vbi->on = 0; | |
589 | |
590 priv_vbi->foreground = 0; | |
591 priv_vbi->pagenumdec = 0; | |
592 priv_vbi->spudec_proc = 1; | |
593 priv_vbi->redraw = 1; | |
594 switch (priv_vbi->on) { | |
595 case 0: | |
596 priv_vbi->csize = 0; | |
597 break; | |
598 case 1: | |
599 priv_vbi->alpha = 0; | |
600 break; | |
601 case 2: | |
602 priv_vbi->alpha = 1; | |
603 break; | |
604 case 3: | |
605 priv_vbi->alpha = 1; | |
606 priv_vbi->foreground = 1; | |
607 break; | |
608 } | |
609 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
610 return TVI_CONTROL_TRUE; | |
611 } | |
612 | |
613 /** | |
614 * \brief get half page mode (only in SPU mode) | |
615 * \param priv_vbi private data structure | |
616 * \return current mode | |
617 * 0 : half mode off | |
618 * 1 : top half page | |
619 * 2 : bottom half page | |
620 */ | |
621 static int vbi_get_half(priv_vbi_t * priv_vbi) | |
622 { | |
623 int flag = 0; | |
624 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
625 if (priv_vbi->valid_page) | |
626 flag = priv_vbi->half; | |
627 priv_vbi->pagenumdec = 0; | |
628 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
629 return flag; | |
630 } | |
631 | |
632 /** | |
633 * \brief set half page mode (only in SPU mode) | |
634 * \param priv_vbi private data structure | |
635 * \param flag new half page mode | |
636 * \return | |
637 * TVI_CONTROL_TRUE is success, | |
638 * TVI_CONTROL_FALSE otherwise | |
639 * | |
640 * | |
641 * flag: | |
642 * 0 : half mode off | |
643 * 1 : top half page | |
644 * 2 : bottom half page | |
645 */ | |
646 static int teletext_set_half_page(priv_vbi_t * priv_vbi, int flag) | |
647 { | |
648 if (flag<0 || flag>2) | |
649 return TVI_CONTROL_FALSE; | |
650 | |
651 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
652 priv_vbi->half = flag; | |
653 if (priv_vbi->tformat == VBI_TFORMAT_TEXT && priv_vbi->half > 1) | |
654 priv_vbi->half = 0; | |
655 priv_vbi->redraw = 1; | |
656 priv_vbi->pagenumdec = 0; | |
657 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
658 return TVI_CONTROL_TRUE; | |
659 } | |
660 | |
661 /** | |
662 * \brief displays specified page | |
663 * \param priv_vbi private data structure | |
664 * \param pgno page number to display | |
665 * \param subno subpage number | |
666 * | |
667 */ | |
668 static void vbi_setpage(priv_vbi_t * priv_vbi, int pgno, int subno) | |
669 { | |
670 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
671 priv_vbi->pgno = steppage(0, pgno); | |
672 priv_vbi->subno = subno; | |
673 priv_vbi->redraw = 1; | |
674 priv_vbi->pagenumdec = 0; | |
675 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
676 } | |
677 | |
678 /** | |
679 * \brief steps over pages by a given value | |
680 * \param priv_vbi private data structure | |
681 * \param direction decimal step value (can be negative) | |
682 * | |
683 */ | |
684 static void vbi_steppage(priv_vbi_t * priv_vbi, int direction) | |
685 { | |
686 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
687 priv_vbi->pgno = steppage(priv_vbi->pgno, direction); | |
688 priv_vbi->redraw = 1; | |
689 priv_vbi->pagenumdec = 0; | |
690 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
691 } | |
692 | |
693 /** | |
694 * \brief append just entered digit to editing page number | |
695 * \param priv_vbi private data structure | |
696 * \param dec decimal digit to append | |
697 * | |
698 * dec: | |
699 * '0'..'9' append digit | |
700 * '-' remove last digit (backspace emulation) | |
701 * | |
702 * This routine allows user to jump to arbitrary page. | |
703 * It implements simple page number editing algorithm. | |
704 * | |
705 * Subsystem can be on one of two modes: normal and page number edit mode. | |
706 * Zero value of priv_vbi->pagenumdec means normal mode | |
707 * Non-zero value means page number edit mode and equals to packed | |
708 * decimal number of already entered part of page number. | |
709 * | |
710 * How this works. | |
711 * Let's assume that current mode is normal (pagenumdec is zero), teletext page | |
712 * 100 are displayed as usual. topmost left corner of page contains page number. | |
713 * Then vbi_add_dec is sequentally called (through slave | |
714 * command of course) with 1,4,-,2,3 * values of dec parameter. | |
715 * | |
716 * +-----+------------+------------------+ | |
717 * | dec | pagenumxec | displayed number | | |
718 * +-----+------------+------------------+ | |
719 * | | 0x000 | 100 | | |
720 * +-----+------------+------------------+ | |
721 * | 1 | 0x001 | __1 | | |
722 * +-----+------------+------------------+ | |
723 * | 4 | 0x014 | _14 | | |
724 * +-----+------------+------------------+ | |
725 * | - | 0x001 | __1 | | |
726 * +-----+------------+------------------+ | |
727 * | 2 | 0x012 | _12 | | |
728 * +-----+------------+------------------+ | |
729 * | 3 | 0x123 | 123 | | |
730 * +-----+------------+------------------+ | |
731 * | | 0x000 | 123 | | |
732 * +-----+------------+------------------+ | |
733 * | |
734 * pagenumdec will automatically receive zero value after third digit of page number | |
735 * is entered and current page will be switched to another one with entered page number. | |
736 * | |
737 */ | |
738 static void vbi_add_dec(priv_vbi_t * priv_vbi, char *dec) | |
739 { | |
740 int count, shift; | |
741 if (!dec) | |
742 return; | |
743 if (!priv_vbi->on) | |
744 return; | |
745 if ((*dec < '0' || *dec > '9') && *dec != '-') | |
746 return; | |
747 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
748 count = (priv_vbi->pagenumdec >> 12) & 0xf; | |
749 if (*dec == '-') { | |
750 count--; | |
751 if (count) | |
752 priv_vbi->pagenumdec = ((priv_vbi->pagenumdec >> 4) & 0xfff) | (count << 12); | |
753 else | |
754 priv_vbi->pagenumdec = 0; | |
755 } else { | |
756 shift = count * 4; | |
757 count++; | |
758 priv_vbi->pagenumdec = | |
759 (((priv_vbi->pagenumdec) << 4 | (*dec -'0')) & 0xfff) | (count << 12); | |
760 if (count == 3) { | |
761 priv_vbi->pgno = priv_vbi->pagenumdec & 0xfff; | |
762 priv_vbi->subno = 0; | |
763 priv_vbi->redraw = 1; | |
764 priv_vbi->pagenumdec = 0; | |
765 } | |
766 } | |
767 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
768 } | |
769 | |
770 /** | |
771 * \brief follows link specified on current page | |
772 * \param priv_vbi private data structure | |
773 * \param linkno link number (0..6) | |
774 * \return | |
775 * TVI_CONTROL_FALSE if linkno is outside 0..6 range or if | |
776 * teletext is switched off | |
777 * TVI_CONTROL_TRUE otherwise | |
778 * | |
779 * linkno: | |
780 * 0: tpage in tv parameters (starting page, usually 100) | |
781 * 1..6: follows link on current page with given number | |
782 * | |
783 * FIXME: quick test shows that this is working strange | |
784 * FIXME: routine does not checks whether links exists on page or not | |
785 * TODO: more precise look | |
786 * | |
787 */ | |
788 static int vbi_golink(priv_vbi_t * priv_vbi, int linkno) | |
789 { | |
790 if (linkno < 0 || linkno > 6) | |
791 return TVI_CONTROL_FALSE; | |
792 if (!priv_vbi->on) | |
793 return TVI_CONTROL_FALSE; | |
794 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
795 if (linkno == 0) { | |
796 priv_vbi->pgno = priv_vbi->tpage; | |
797 priv_vbi->subno = priv_vbi->page->nav_link[linkno].subno; | |
798 priv_vbi->redraw = 1; | |
799 priv_vbi->pagenumdec = 0; | |
800 } else { | |
801 linkno--; | |
802 if (priv_vbi->pgno == priv_vbi->page->pgno) { | |
803 priv_vbi->pgno = priv_vbi->page->nav_link[linkno].pgno; | |
804 priv_vbi->subno = priv_vbi->page->nav_link[linkno].subno; | |
805 priv_vbi->redraw = 1; | |
806 priv_vbi->pagenumdec = 0; | |
807 } | |
808 } | |
809 priv_vbi->pagenumdec = 0; | |
810 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
811 return TVI_CONTROL_TRUE; | |
812 } | |
813 | |
814 /** | |
815 * \brief get pointer to current teletext page | |
816 * \param priv_vbi private data structure | |
817 * \return pointer to vbi_page structure if teletext is | |
818 * switched on and current page is valid, NULL - otherwise | |
819 * | |
820 */ | |
821 static vbi_page *vbi_getpage(priv_vbi_t * priv_vbi) | |
822 { | |
823 vbi_page *page = NULL; | |
824 | |
825 if (!priv_vbi->on) | |
826 return NULL; | |
827 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
828 if (priv_vbi->valid_page) | |
829 if (page = malloc(sizeof(vbi_page))) | |
830 memcpy(page, priv_vbi->page, sizeof(vbi_page)); | |
831 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
832 return page; | |
833 } | |
834 | |
835 /** | |
836 * \brief get pointer to current teletext page | |
837 * \param priv_vbi private data structure | |
838 * \return pointer to character string, containing text-only data of | |
839 * teletext page. If teletext is switched off, current page is invalid | |
840 * or page format if not equal to "text" then returning value is NULL. | |
841 * | |
842 */ | |
843 static char *vbi_getpagetext(priv_vbi_t * priv_vbi) | |
844 { | |
845 char *page = NULL; | |
846 | |
847 if (!priv_vbi->on) | |
848 return NULL; | |
849 if (priv_vbi->tformat != VBI_TFORMAT_TEXT && priv_vbi->canvas) | |
850 return NULL; | |
851 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
852 if (priv_vbi->valid_page) | |
853 page = priv_vbi->txtpage; | |
854 if (!page) | |
855 page = priv_vbi->header; | |
856 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
857 return page; | |
858 } | |
859 | |
860 /** | |
861 * \brief get current page RGBA32 image (only in SPU mode) | |
862 * \param priv_vbi private data structure | |
863 * \return pointer to tv_teletext_img_t structure, containing among | |
864 * other things rendered RGBA32 image of current teletext page. | |
865 * return NULL is image is not available for some reason. | |
866 * | |
867 */ | |
868 static tv_teletext_img_t *vbi_getpageimg(priv_vbi_t * priv_vbi) | |
869 { | |
870 tv_teletext_img_t *img = NULL; | |
871 | |
872 if (priv_vbi->tformat == VBI_TFORMAT_TEXT) | |
873 return NULL; | |
874 if (priv_vbi->spudec_proc == 0) | |
875 return NULL; | |
876 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
877 if (NULL != (img = malloc(sizeof(tv_teletext_img_t)))) { | |
878 img->tformat = priv_vbi->tformat; // format: bw|gray|color | |
879 img->tformat = VBI_TFORMAT_GRAY; // format: bw|gray|color | |
880 img->half = priv_vbi->half; // half mode | |
881 img->columns = priv_vbi->columns; // page size | |
882 img->rows = priv_vbi->rows; | |
883 img->width = priv_vbi->columns * 12; | |
884 img->width = priv_vbi->rows * 10; | |
885 img->canvas = NULL; | |
886 // is page ok? | |
887 if (priv_vbi->canvas && priv_vbi->on && priv_vbi->csize && priv_vbi->valid_page) { | |
888 | |
889 if (NULL != (img->canvas = malloc(priv_vbi->csize))) | |
890 memcpy(img->canvas, priv_vbi->canvas, priv_vbi->csize); | |
891 } | |
892 } | |
893 priv_vbi->spudec_proc = 0; | |
894 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
895 return img; | |
896 } | |
897 | |
898 /** | |
899 * \brief start teletext sybsystem | |
900 * \param priv_vbi private data structure | |
901 * | |
902 * initializes cache, vbi decoder and starts background thread | |
903 * | |
904 */ | |
905 static void vbi_start(priv_vbi_t * priv_vbi) | |
906 { | |
907 if (!priv_vbi) | |
908 return; | |
909 if (NULL != (priv_vbi->txtpage = malloc(VBI_TXT_PAGE_SIZE))) // alloc vbi_page | |
910 memset(priv_vbi->txtpage, 0, VBI_TXT_PAGE_SIZE); | |
911 priv_vbi->page = malloc(sizeof(vbi_page)); | |
912 priv_vbi->cache = (vbi_page **) malloc(1000 * sizeof(vbi_page *)); | |
913 memset(priv_vbi->cache, 0, 1000 * sizeof(vbi_page *)); | |
914 priv_vbi->decoder = vbi_decoder_new(); | |
915 priv_vbi->subno = 0; | |
916 priv_vbi->fmt = VBI_PIXFMT_RGBA32_LE; | |
917 memset(priv_vbi->theader, 0, sizeof(priv_vbi->theader)); | |
918 snprintf(priv_vbi->header, sizeof(priv_vbi->header), "%s", VBI_NO_TELETEXT); | |
919 vbi_event_handler_add(priv_vbi->decoder, ~0, event_handler, (void *) priv_vbi); // add event handler | |
920 pthread_create(&priv_vbi->grabber_thread, NULL, grabber, priv_vbi); // add grab function | |
921 pthread_mutex_init(&priv_vbi->buffer_mutex, NULL); | |
922 priv_vbi->valid_page = 0; | |
923 priv_vbi->pagenumdec = 0; | |
924 mp_msg(MSGT_TV, MSGL_INFO, "Teletext device: %s\n", priv_vbi->device); | |
925 } | |
926 | |
927 /** | |
928 * \brief Teletext reset | |
929 * \param priv_vbi private data structure | |
930 * | |
931 * should be called during frequency, norm change, etc | |
932 * | |
933 */ | |
934 static void vbi_reset(priv_vbi_t * priv_vbi) | |
935 { | |
936 int i; | |
937 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
938 if (priv_vbi->canvas) | |
939 free(priv_vbi->canvas); | |
940 priv_vbi->canvas = NULL; | |
941 priv_vbi->canvas_size = 0; | |
942 priv_vbi->redraw = 1; | |
943 priv_vbi->csize = 0; | |
944 priv_vbi->valid_page = 0; | |
945 priv_vbi->spudec_proc = 1; | |
946 priv_vbi->pagenumdec = 0; | |
947 if (priv_vbi->page) | |
948 memset(priv_vbi->page, 0, sizeof(vbi_page)); | |
949 if (priv_vbi->txtpage) | |
950 memset(priv_vbi->txtpage, 0, VBI_TXT_PAGE_SIZE); | |
951 memset(priv_vbi->theader, 0, sizeof(priv_vbi->theader)); | |
952 if (priv_vbi->cache) { | |
953 for (i = 0; i < 1000; i++) { | |
954 if (priv_vbi->cache[i]) | |
955 free(priv_vbi->cache[i]); | |
956 priv_vbi->cache[i] = NULL; | |
957 } | |
958 } | |
959 snprintf(priv_vbi->header, sizeof(priv_vbi->header), "%s", | |
960 VBI_NO_TELETEXT); | |
961 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
962 } | |
963 | |
964 /* | |
965 --------------------------------------------------------------------------------- | |
966 Public routines | |
967 --------------------------------------------------------------------------------- | |
968 */ | |
969 | |
970 /** | |
971 * \brief teletext subsystem init | |
972 * \note Routine uses global variables tv_param_tdevice, tv_param_tpage | |
973 * and tv_param_tformat for initialization. | |
974 * | |
975 */ | |
976 priv_vbi_t *teletext_init(void) | |
977 { | |
978 priv_vbi_t *priv_vbi; | |
979 int formatid, startpage; | |
980 unsigned int services = VBI_SLICED_TELETEXT_B | | |
981 VBI_SLICED_CAPTION_525 | | |
982 VBI_SLICED_CAPTION_625 | | |
983 VBI_SLICED_VBI_525 | | |
984 VBI_SLICED_VBI_625 | | |
985 VBI_SLICED_WSS_625 | | |
986 VBI_SLICED_WSS_CPR1204 | | |
987 VBI_SLICED_VPS; | |
988 | |
989 if (!tv_param_tdevice) | |
990 return NULL; | |
991 | |
992 if (NULL == (priv_vbi = malloc(sizeof(priv_vbi_t)))) | |
993 return NULL; | |
994 memset(priv_vbi, 0, sizeof(priv_vbi_t)); | |
995 formatid = VBI_TFORMAT_TEXT; // default | |
996 if (tv_param_tformat != NULL) { | |
997 if (strcmp(tv_param_tformat, "text") == 0) | |
998 formatid = VBI_TFORMAT_TEXT; | |
999 if (strcmp(tv_param_tformat, "bw") == 0) | |
1000 formatid = VBI_TFORMAT_BW; | |
1001 if (strcmp(tv_param_tformat, "gray") == 0) | |
1002 formatid = VBI_TFORMAT_GRAY; | |
1003 if (strcmp(tv_param_tformat, "color") == 0) | |
1004 formatid = VBI_TFORMAT_COLOR; | |
1005 } | |
1006 startpage = steppage(0, tv_param_tpage); // page number is HEX | |
1007 if (startpage < 0x100 || startpage > 0x999) | |
1008 startpage = 0x100; | |
1009 priv_vbi->device = strdup(tv_param_tdevice); | |
1010 priv_vbi->tformat = formatid; | |
1011 priv_vbi->tpage = startpage; // page number | |
1012 priv_vbi->pgno = startpage; // page number | |
1013 | |
1014 | |
1015 if (!priv_vbi->capture) { | |
1016 priv_vbi->services = services; // probe v4l2 | |
1017 priv_vbi->capture = vbi_capture_v4l2_new(priv_vbi->device, // device | |
1018 20, // buffer numbers | |
1019 &(priv_vbi->services), // services | |
1020 0, // strict | |
1021 &(priv_vbi->errstr), // error string | |
1022 0); // trace | |
1023 } | |
1024 services = priv_vbi->services; | |
1025 if (priv_vbi->capture == NULL) { | |
1026 priv_vbi->services = services; // probe v4l | |
1027 priv_vbi->capture = vbi_capture_v4l_new(priv_vbi->device, | |
1028 20, | |
1029 &(priv_vbi->services), | |
1030 0, &(priv_vbi->errstr), 0); | |
1031 } | |
1032 | |
1033 if (!priv_vbi->capture) { | |
1034 free(priv_vbi->device); | |
1035 free(priv_vbi); | |
1036 mp_msg(MSGT_TV, MSGL_INFO, "No teletext\n"); | |
1037 return NULL; | |
1038 } | |
1039 return priv_vbi; | |
1040 } | |
1041 | |
1042 /** | |
1043 * \brief teletext subsystem uninitialization | |
1044 * \param priv_vbi private data structure | |
1045 * | |
1046 * closes vbi capture, decode and and frees priv_vbi structure | |
1047 * | |
1048 */ | |
1049 void teletext_uninit(priv_vbi_t * priv_vbi) | |
1050 { | |
1051 int i; | |
1052 if (priv_vbi == NULL) | |
1053 return; | |
1054 priv_vbi->eof = 1; | |
1055 if (priv_vbi->capture){ | |
1056 vbi_capture_delete(priv_vbi->capture); | |
1057 priv_vbi->capture = NULL; | |
1058 } | |
1059 if (priv_vbi->decoder){ | |
1060 vbi_event_handler_remove(priv_vbi->decoder, event_handler); | |
1061 vbi_decoder_delete(priv_vbi->decoder); | |
1062 priv_vbi->decoder = NULL; | |
1063 } | |
1064 if (priv_vbi->grabber_thread) | |
1065 pthread_join(priv_vbi->grabber_thread, NULL); | |
1066 pthread_mutex_destroy(&priv_vbi->buffer_mutex); | |
1067 if (priv_vbi->device){ | |
1068 free(priv_vbi->device); | |
1069 priv_vbi->device = NULL; | |
1070 } | |
1071 if (priv_vbi->errstr){ | |
1072 free(priv_vbi->errstr); | |
1073 priv_vbi->errstr = NULL; | |
1074 } | |
1075 if (priv_vbi->canvas){ | |
1076 free(priv_vbi->canvas); | |
1077 priv_vbi->canvas = NULL; | |
1078 } | |
1079 if (priv_vbi->txtpage){ | |
1080 free(priv_vbi->txtpage); | |
1081 priv_vbi->txtpage = NULL; | |
1082 } | |
1083 if (priv_vbi->network_name){ | |
1084 free(priv_vbi->network_name); | |
1085 priv_vbi->network_name = NULL; | |
1086 } | |
1087 if (priv_vbi->network_id){ | |
1088 free(priv_vbi->network_id); | |
1089 priv_vbi->network_id = NULL; | |
1090 } | |
1091 if (priv_vbi->page){ | |
1092 free(priv_vbi->page); | |
1093 priv_vbi->page = NULL; | |
1094 } | |
1095 if (priv_vbi->cache) { | |
1096 for (i = 0; i < 1000; i++) { | |
1097 if (priv_vbi->cache[i]) | |
1098 free(priv_vbi->cache[i]); | |
1099 } | |
1100 free(priv_vbi->cache); | |
1101 priv_vbi->cache = NULL; | |
1102 } | |
1103 free(priv_vbi); | |
1104 } | |
1105 | |
1106 /** | |
1107 * \brief Teletext control routine | |
1108 * \param priv_vbi private data structure | |
1109 * \param cmd command | |
1110 * \param arg command parameter (has to be not null) | |
1111 * | |
1112 */ | |
1113 int teletext_control(priv_vbi_t * priv_vbi, int cmd, void *arg) | |
1114 { | |
1115 vbi_page *page = NULL; | |
1116 char *txtpage = NULL; | |
1117 tv_teletext_img_t *img = NULL; | |
1118 if (!priv_vbi) | |
1119 return TVI_CONTROL_FALSE; | |
1120 if (!arg) | |
1121 return TVI_CONTROL_FALSE; | |
1122 switch (cmd) { | |
1123 case TVI_CONTROL_VBI_RESET: | |
1124 vbi_reset(priv_vbi); | |
1125 return TVI_CONTROL_TRUE; | |
1126 case TVI_CONTROL_VBI_START: | |
1127 vbi_start(priv_vbi); | |
1128 return TVI_CONTROL_TRUE; | |
1129 case TVI_CONTROL_VBI_GET_FORMAT: | |
1130 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
1131 *(int*)arg=priv_vbi->tformat; | |
1132 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
1133 return TVI_CONTROL_TRUE; | |
1134 case TVI_CONTROL_VBI_SET_MODE: | |
1135 return teletext_set_mode(priv_vbi, *(int *) arg); | |
1136 case TVI_CONTROL_VBI_GET_MODE: | |
1137 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
1138 *(int*)arg=priv_vbi->on; | |
1139 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
1140 return TVI_CONTROL_TRUE; | |
1141 case TVI_CONTROL_VBI_STEP_MODE: | |
1142 { | |
1143 int val; | |
1144 pthread_mutex_lock(&(priv_vbi->buffer_mutex)); | |
1145 val=(priv_vbi->on+*(int*)arg)%4; | |
1146 pthread_mutex_unlock(&(priv_vbi->buffer_mutex)); | |
1147 if (val<0) | |
1148 val+=4; | |
1149 return teletext_set_mode(priv_vbi,val); | |
1150 } | |
1151 case TVI_CONTROL_VBI_GET_HALF_PAGE: | |
1152 *(void **) arg = (void *) vbi_get_half(priv_vbi); | |
1153 return TVI_CONTROL_TRUE; | |
1154 case TVI_CONTROL_VBI_SET_HALF_PAGE: | |
1155 return teletext_set_half_page(priv_vbi, *(int *) arg); | |
1156 case TVI_CONTROL_VBI_STEP_HALF_PAGE: | |
1157 { | |
1158 int val; | |
1159 val=(vbi_get_half(priv_vbi)+*(int*)arg)%3; | |
1160 | |
1161 if (val<0) | |
1162 val+=3; | |
1163 return teletext_set_half_page(priv_vbi,val); | |
1164 } | |
1165 | |
1166 case TVI_CONTROL_VBI_SET_PAGE: | |
1167 vbi_setpage(priv_vbi, *(int *) arg, 0); | |
1168 return TVI_CONTROL_TRUE; | |
1169 case TVI_CONTROL_VBI_STEP_PAGE: | |
1170 vbi_steppage(priv_vbi, *(int *) arg); | |
1171 return TVI_CONTROL_TRUE; | |
1172 case TVI_CONTROL_VBI_ADD_DEC: | |
1173 vbi_add_dec(priv_vbi, *(char **) arg); | |
1174 return TVI_CONTROL_TRUE; | |
1175 case TVI_CONTROL_VBI_GO_LINK: | |
1176 return vbi_golink(priv_vbi, *(int *) arg); | |
1177 case TVI_CONTROL_VBI_GET_PAGE: | |
1178 *(int*) arg = priv_vbi->pgno; | |
1179 return TVI_CONTROL_TRUE; | |
1180 case TVI_CONTROL_VBI_GET_VBIPAGE: | |
1181 if (NULL == (page = vbi_getpage(priv_vbi))) | |
1182 return TVI_CONTROL_FALSE; | |
1183 *(void **) arg = (void *) page; | |
1184 return TVI_CONTROL_TRUE; | |
1185 case TVI_CONTROL_VBI_GET_TXTPAGE: | |
1186 if (NULL == (txtpage = vbi_getpagetext(priv_vbi))) | |
1187 return TVI_CONTROL_FALSE; | |
1188 *(void **) arg = (void *) txtpage; | |
1189 return TVI_CONTROL_TRUE; | |
1190 case TVI_CONTROL_VBI_GET_IMGPAGE: | |
1191 if (NULL == (img = vbi_getpageimg(priv_vbi))) | |
1192 return TVI_CONTROL_FALSE; | |
1193 *(void **) arg = (void *) img; | |
1194 return TVI_CONTROL_TRUE; | |
1195 } | |
1196 return TVI_CONTROL_UNKNOWN; | |
1197 } |