mirror of https://github.com/mpv-player/mpv
1198 lines
37 KiB
C
1198 lines
37 KiB
C
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include "tv.h"
|
|
#include "tvi_vbi.h"
|
|
#include "mp_msg.h"
|
|
#include "libmpcodecs/img_format.h"
|
|
|
|
#ifdef USE_ICONV
|
|
#include <iconv.h>
|
|
#endif
|
|
|
|
#define VBI_TEXT_CHARSET "UTF-8"
|
|
|
|
char* tv_param_tdevice=NULL; ///< teletext vbi device
|
|
char* tv_param_tformat="gray"; ///< format: text,bw,gray,color
|
|
int tv_param_tpage=100; ///< page number
|
|
|
|
|
|
#ifdef USE_ICONV
|
|
/*
|
|
------------------------------------------------------------------
|
|
zvbi-0.2.25/src/exp-txt.c skip debug "if(1) fprintf(stderr,) " message
|
|
------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* libzvbi - Text export functions
|
|
*
|
|
* Copyright (C) 2001, 2002 Michael H. Schimek
|
|
*
|
|
* Based on code from AleVT 1.5.1
|
|
* Copyright (C) 1998, 1999 Edgar Toernig <froese@gmx.de>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
**/
|
|
|
|
/** $Id$ **/
|
|
|
|
static vbi_bool
|
|
print_unicode(iconv_t cd, int endian, int unicode, char **p, int n)
|
|
{
|
|
char in[2], *ip, *op;
|
|
size_t li, lo, r;
|
|
|
|
in[0 + endian] = unicode;
|
|
in[1 - endian] = unicode >> 8;
|
|
ip = in; op = *p;
|
|
li = sizeof(in); lo = n;
|
|
|
|
r = iconv(cd, &ip, &li, &op, &lo);
|
|
|
|
if ((size_t) -1 == r
|
|
|| (**p == 0x40 && unicode != 0x0040)) {
|
|
in[0 + endian] = 0x20;
|
|
in[1 - endian] = 0;
|
|
ip = in; op = *p;
|
|
li = sizeof(in); lo = n;
|
|
|
|
r = iconv(cd, &ip, &li, &op, &lo);
|
|
|
|
if ((size_t) -1 == r
|
|
|| (r == 1 && **p == 0x40))
|
|
goto error;
|
|
}
|
|
|
|
*p = op;
|
|
|
|
return TRUE;
|
|
|
|
error:
|
|
return FALSE;
|
|
}
|
|
|
|
static int
|
|
vbi_print_page_region_nodebug(vbi_page * pg, char *buf, int size,
|
|
const char *format, vbi_bool table,
|
|
vbi_bool rtl, int column, int row, int width,
|
|
int height)
|
|
{
|
|
int endian = vbi_ucs2be();
|
|
int column0, column1, row0, row1;
|
|
int x, y, spaces, doubleh, doubleh0;
|
|
iconv_t cd;
|
|
char *p;
|
|
|
|
rtl = rtl;
|
|
|
|
#if 0
|
|
if (1)
|
|
fprintf (stderr, "vbi_print_page_region '%s' "
|
|
"table=%d col=%d row=%d width=%d height=%d\n",
|
|
format, table, column, row, width, height);
|
|
#endif
|
|
|
|
column0 = column;
|
|
row0 = row;
|
|
column1 = column + width - 1;
|
|
row1 = row + height - 1;
|
|
|
|
if (!pg || !buf || size < 0 || !format
|
|
|| column0 < 0 || column1 >= pg->columns
|
|
|| row0 < 0 || row1 >= pg->rows
|
|
|| endian < 0)
|
|
return 0;
|
|
|
|
if ((cd = iconv_open(format, "UCS-2")) == (iconv_t) -1)
|
|
return 0;
|
|
|
|
p = buf;
|
|
|
|
doubleh = 0;
|
|
|
|
for (y = row0; y <= row1; y++) {
|
|
int x0, x1, xl;
|
|
|
|
x0 = (table || y == row0) ? column0 : 0;
|
|
x1 = (table || y == row1) ? column1 : (pg->columns - 1);
|
|
|
|
xl = (table || y != row0 || (y + 1) != row1) ? -1 : column1;
|
|
|
|
doubleh0 = doubleh;
|
|
|
|
spaces = 0;
|
|
doubleh = 0;
|
|
|
|
for (x = x0; x <= x1; x++) {
|
|
vbi_char ac = pg->text[y * pg->columns + x];
|
|
|
|
if (table) {
|
|
if (ac.size > VBI_DOUBLE_SIZE)
|
|
ac.unicode = 0x0020;
|
|
} else {
|
|
switch (ac.size) {
|
|
case VBI_NORMAL_SIZE:
|
|
case VBI_DOUBLE_WIDTH:
|
|
break;
|
|
|
|
case VBI_DOUBLE_HEIGHT:
|
|
case VBI_DOUBLE_SIZE:
|
|
doubleh++;
|
|
break;
|
|
|
|
case VBI_OVER_TOP:
|
|
case VBI_OVER_BOTTOM:
|
|
continue;
|
|
|
|
case VBI_DOUBLE_HEIGHT2:
|
|
case VBI_DOUBLE_SIZE2:
|
|
if (y > row0)
|
|
ac.unicode = 0x0020;
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Special case two lines row0 ... row1, and all chars
|
|
* in row0, column0 ... column1 are double height: Skip
|
|
* row1, don't wrap around.
|
|
*/
|
|
if (x == xl && doubleh >= (x - x0)) {
|
|
x1 = xl;
|
|
y = row1;
|
|
}
|
|
|
|
if (ac.unicode == 0x20 || !vbi_is_print(ac.unicode)) {
|
|
spaces++;
|
|
continue;
|
|
} else {
|
|
if (spaces < (x - x0) || y == row0) {
|
|
for (; spaces > 0; spaces--)
|
|
if (!print_unicode(cd, endian, 0x0020,
|
|
&p, buf + size - p))
|
|
goto failure;
|
|
} else /* discard leading spaces */
|
|
spaces = 0;
|
|
}
|
|
}
|
|
|
|
if (!print_unicode(cd, endian, ac.unicode, &p, buf + size - p))
|
|
goto failure;
|
|
}
|
|
|
|
/* if !table discard trailing spaces and blank lines */
|
|
|
|
if (y < row1) {
|
|
int left = buf + size - p;
|
|
|
|
if (left < 1)
|
|
goto failure;
|
|
|
|
if (table) {
|
|
*p++ = '\n'; /* XXX convert this (eg utf16) */
|
|
} else if (spaces >= (x1 - x0)) {
|
|
; /* suppress blank line */
|
|
} else {
|
|
/* exactly one space between adjacent rows */
|
|
if (!print_unicode(cd, endian, 0x0020, &p, left))
|
|
goto failure;
|
|
}
|
|
} else {
|
|
if (doubleh0 > 0) {
|
|
; /* prentend this is a blank double height lower row */
|
|
} else {
|
|
for (; spaces > 0; spaces--)
|
|
if (!print_unicode(cd, endian, 0x0020, &p, buf + size - p))
|
|
goto failure;
|
|
}
|
|
}
|
|
}
|
|
|
|
iconv_close(cd);
|
|
return p - buf;
|
|
|
|
failure:
|
|
iconv_close(cd);
|
|
return 0;
|
|
}
|
|
#endif
|
|
/*
|
|
end of zvbi-0.2.25/src/exp-txt.c part
|
|
*/
|
|
|
|
|
|
/*
|
|
------------------------------------------------------------------
|
|
Private routines
|
|
------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* \brief Decode event handler
|
|
* \param ev VBI event
|
|
* \param data pointer to user defined data
|
|
*
|
|
*/
|
|
static void event_handler(vbi_event * ev, void *data)
|
|
{
|
|
priv_vbi_t *user_vbi = (priv_vbi_t *) data;
|
|
vbi_page pg;
|
|
char *s;
|
|
int i;
|
|
|
|
switch (ev->type) {
|
|
case VBI_EVENT_CAPTION:
|
|
mp_msg(MSGT_TV,MSGL_DBG3,"caption\n");
|
|
break;
|
|
case VBI_EVENT_NETWORK:
|
|
s = ev->ev.network.name;
|
|
if (s) {
|
|
pthread_mutex_lock(&(user_vbi->buffer_mutex));
|
|
if (user_vbi->network_name)
|
|
free(user_vbi->network_name);
|
|
user_vbi->network_name = strdup(s);
|
|
pthread_mutex_unlock(&(user_vbi->buffer_mutex));
|
|
}
|
|
break;
|
|
case VBI_EVENT_NETWORK_ID:
|
|
s = ev->ev.network.name;
|
|
if (s) {
|
|
pthread_mutex_lock(&(user_vbi->buffer_mutex));
|
|
if (user_vbi->network_id)
|
|
free(user_vbi->network_id);
|
|
user_vbi->network_id = strdup(s);
|
|
pthread_mutex_unlock(&(user_vbi->buffer_mutex));
|
|
}
|
|
break;
|
|
case VBI_EVENT_TTX_PAGE:
|
|
pthread_mutex_lock(&(user_vbi->buffer_mutex));
|
|
user_vbi->curr_pgno = ev->ev.ttx_page.pgno; // page number
|
|
user_vbi->curr_subno = ev->ev.ttx_page.subno; // subpage
|
|
i = vbi_bcd2dec(ev->ev.ttx_page.pgno);
|
|
if (i > 0 && i < 1000) {
|
|
if (!user_vbi->cache[i])
|
|
user_vbi->cache[i] = (vbi_page *) malloc(sizeof(vbi_page));
|
|
vbi_fetch_vt_page(user_vbi->decoder, // fetch page
|
|
user_vbi->cache[i],
|
|
ev->ev.ttx_page.pgno,
|
|
ev->ev.ttx_page.subno,
|
|
VBI_WST_LEVEL_3p5, 25, TRUE);
|
|
memcpy(user_vbi->theader, user_vbi->cache[i]->text,
|
|
sizeof(user_vbi->theader));
|
|
}
|
|
pthread_mutex_unlock(&(user_vbi->buffer_mutex));
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Prepares page to be shown on screen
|
|
* \param priv_vbi private data structure
|
|
*
|
|
* This routine adds page number, current time, etc to page header
|
|
*
|
|
*/
|
|
static void process_page(priv_vbi_t * priv_vbi)
|
|
{
|
|
char *pagesptr;
|
|
int csize, i, j, subtitle = 0, sflg, send;
|
|
void *canvas;
|
|
char cpage[5];
|
|
vbi_page page;
|
|
|
|
memcpy(&(page), priv_vbi->page, sizeof(vbi_page));
|
|
if (priv_vbi->pgno != priv_vbi->page->pgno) {
|
|
//don't clear first line
|
|
for (i = page.columns; i < 1056; i++) {
|
|
page.text[i].unicode = ' ';
|
|
page.text[i].background = VBI_TRANSPARENT_COLOR;
|
|
}
|
|
snprintf(cpage, sizeof(cpage), "%03X", priv_vbi->pgno);
|
|
page.text[1].unicode = cpage[0];
|
|
page.text[2].unicode = cpage[1];
|
|
page.text[3].unicode = cpage[2];
|
|
page.text[4].unicode = ' ';
|
|
page.text[5].unicode = ' ';
|
|
page.text[6].unicode = ' ';
|
|
}
|
|
|
|
//background page number & title
|
|
j=vbi_bcd2dec(priv_vbi->curr_pgno);
|
|
if (j>0 && j<1000 && priv_vbi->cache[j]){
|
|
for(i=8;i<priv_vbi->cache[j]->columns;i++){
|
|
page.text[i].unicode = priv_vbi->cache[j]->text[i].unicode;
|
|
}
|
|
}
|
|
|
|
if (page.text[1].unicode == ' ' && page.text[2].unicode == ' ' &&
|
|
page.text[3].unicode == ' ' && page.text[4].unicode == ' ' &&
|
|
page.text[5].unicode == ' ' && page.text[5].unicode == ' '
|
|
&& !priv_vbi->half)
|
|
subtitle = 1; // subtitle page
|
|
if (priv_vbi->pagenumdec) {
|
|
i = (priv_vbi->pagenumdec >> 12) & 0xf;
|
|
switch (i) {
|
|
case 1:
|
|
page.text[1].unicode = '0' + ((priv_vbi->pagenumdec >> 0) & 0xf);
|
|
page.text[2].unicode = '-';
|
|
page.text[3].unicode = '-';
|
|
break;
|
|
case 2:
|
|
page.text[1].unicode = '0' + ((priv_vbi->pagenumdec >> 4) & 0xf);
|
|
page.text[2].unicode = '0' + ((priv_vbi->pagenumdec >> 0) & 0xf);
|
|
page.text[3].unicode = '-';
|
|
break;
|
|
}
|
|
page.text[4].unicode = ' ';
|
|
page.text[5].unicode = ' ';
|
|
page.text[6].unicode = ' ';
|
|
page.text[1].foreground = VBI_WHITE;
|
|
page.text[2].foreground = VBI_WHITE;
|
|
page.text[3].foreground = VBI_WHITE;
|
|
}
|
|
priv_vbi->columns = page.columns;
|
|
priv_vbi->rows = page.rows;
|
|
if (!subtitle) { // update time in header
|
|
memcpy(&(page.text[VBI_TIME_LINEPOS]),
|
|
&(priv_vbi->theader[VBI_TIME_LINEPOS]),
|
|
sizeof(vbi_char) * (priv_vbi->columns - VBI_TIME_LINEPOS));
|
|
}
|
|
switch (priv_vbi->tformat) {
|
|
case VBI_TFORMAT_TEXT: // mode: text
|
|
if (priv_vbi->txtpage) {
|
|
#ifdef USE_ICONV
|
|
vbi_print_page_region_nodebug(&(page), priv_vbi->txtpage,
|
|
VBI_TXT_PAGE_SIZE, VBI_TEXT_CHARSET, TRUE,
|
|
0, 0, 0, page.columns, page.rows); // vbi_page to text without message
|
|
#else
|
|
vbi_print_page(&(page), priv_vbi->txtpage,
|
|
VBI_TXT_PAGE_SIZE, VBI_TEXT_CHARSET, TRUE, 0);
|
|
#endif
|
|
}
|
|
priv_vbi->valid_page = 1;
|
|
break;
|
|
case VBI_TFORMAT_BW: // mode: black & white
|
|
for (i=0; i < (priv_vbi->pgno!=page.pgno?page.columns:1056); i++) {
|
|
if (priv_vbi->foreground){
|
|
page.text[i].foreground = VBI_BLACK;
|
|
page.text[i].background = VBI_WHITE;
|
|
}else{
|
|
page.text[i].foreground = VBI_WHITE;
|
|
page.text[i].background = VBI_BLACK;
|
|
}
|
|
}
|
|
case VBI_TFORMAT_GRAY: // mode: grayscale
|
|
case VBI_TFORMAT_COLOR: // mode: color (request color spu patch!)
|
|
|
|
|
|
|
|
page.color_map[VBI_TRANSPARENT_COLOR] = 0;
|
|
if (priv_vbi->alpha) {
|
|
if (subtitle) {
|
|
for (i = 0; i < page.rows; i++) {
|
|
sflg = 0;
|
|
send = 0;
|
|
for (j = 0; j < page.columns; j++) {
|
|
if (page.text[i * page.columns + j].unicode != ' ') {
|
|
sflg = 1;
|
|
send = j;
|
|
}
|
|
if (sflg == 0)
|
|
page.text[i * page.columns + j].background =
|
|
VBI_TRANSPARENT_COLOR;
|
|
}
|
|
for (j = send + 1; j < page.columns; j++)
|
|
page.text[i * page.columns + j].background =
|
|
VBI_TRANSPARENT_COLOR;
|
|
}
|
|
} else {
|
|
for (i = 0; i < 1056; i++)
|
|
page.text[i].background = VBI_TRANSPARENT_COLOR;
|
|
}
|
|
}
|
|
csize = page.columns * page.rows * 12 * 10 * sizeof(vbi_rgba);
|
|
if (csize == 0)
|
|
break;
|
|
if (csize > priv_vbi->canvas_size) { // test canvas size
|
|
if (priv_vbi->canvas)
|
|
free(priv_vbi->canvas);
|
|
priv_vbi->canvas = malloc(csize);
|
|
priv_vbi->canvas_size = 0;
|
|
if (priv_vbi->canvas)
|
|
priv_vbi->canvas_size = csize;
|
|
}
|
|
if (priv_vbi->canvas) {
|
|
vbi_draw_vt_page(&(page),
|
|
priv_vbi->fmt,
|
|
priv_vbi->canvas,
|
|
priv_vbi->reveal, priv_vbi->flash_on);
|
|
priv_vbi->csize = csize;
|
|
}
|
|
priv_vbi->spudec_proc = 1;
|
|
priv_vbi->valid_page = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \brief Update page in cache
|
|
* \param priv_vbi private data structure
|
|
*
|
|
* Routine also calls process_page to refresh currently visible page (if so)
|
|
* every time it was received from VBI by background thread.
|
|
*
|
|
*/
|
|
static void update_page(priv_vbi_t * priv_vbi)
|
|
{
|
|
int i;
|
|
int index;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
/*
|
|
priv_vbi->redraw=1 - page redraw requested
|
|
pgno!=page->pgno - page was switched
|
|
curr_pgno==pgno - backgound process just fetched current page, refresh it
|
|
*/
|
|
if (priv_vbi->redraw ||
|
|
priv_vbi->pgno != priv_vbi->page->pgno ||
|
|
priv_vbi->curr_pgno == priv_vbi->pgno) {
|
|
index = vbi_bcd2dec(priv_vbi->pgno);
|
|
if ( index <= 0 || index > 999 || !priv_vbi->cache[index]) {
|
|
// curr_pgno is last decoded page
|
|
index = vbi_bcd2dec(priv_vbi->curr_pgno);
|
|
}
|
|
|
|
if (index <=0 || index >999 || !priv_vbi->cache[index]){
|
|
priv_vbi->valid_page = 0;
|
|
memset(priv_vbi->page, 0, sizeof(vbi_page));
|
|
}else
|
|
{
|
|
memcpy(priv_vbi->page, priv_vbi->cache[index], sizeof(vbi_page));
|
|
process_page(priv_vbi);//prepare page to be shown on screen
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
}
|
|
|
|
/**
|
|
* \brief background grabber routine
|
|
* \param data user-defined data
|
|
*
|
|
*/
|
|
static void *grabber(void *data)
|
|
{
|
|
priv_vbi_t *user_vbi = (priv_vbi_t *) data;
|
|
vbi_capture_buffer *sliced_buffer;
|
|
struct timeval timeout;
|
|
unsigned int n_lines;
|
|
int r, err_count = 0;
|
|
|
|
while (!user_vbi->eof) {
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 500;
|
|
r = vbi_capture_pull(user_vbi->capture, NULL, &sliced_buffer, &timeout); // grab slices
|
|
if (user_vbi->eof)
|
|
return NULL;
|
|
switch (r) {
|
|
case -1: // read error
|
|
if (err_count++ > 4)
|
|
user_vbi->eof = 1;
|
|
break;
|
|
case 0: // time out
|
|
break;
|
|
default:
|
|
err_count = 0;
|
|
}
|
|
if (r != 1)
|
|
continue;
|
|
n_lines = sliced_buffer->size / sizeof(vbi_sliced);
|
|
vbi_decode(user_vbi->decoder, (vbi_sliced *) sliced_buffer->data,
|
|
n_lines, sliced_buffer->timestamp); // decode slice
|
|
update_page(user_vbi);
|
|
}
|
|
switch (r) {
|
|
case -1:
|
|
mp_msg(MSGT_TV, MSGL_ERR, "VBI read error %d (%s)\n",
|
|
errno, strerror(errno));
|
|
return NULL;
|
|
case 0:
|
|
mp_msg(MSGT_TV, MSGL_ERR, "VBI read timeout\n");
|
|
return NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* \brief calculate increased/decreased by given value page number
|
|
* \param curr current page number in hexadecimal for
|
|
* \param direction decimal value (can be negative) to add to value or curr parameter
|
|
* \return new page number in hexadecimal form
|
|
*
|
|
* VBI page numbers are represented in special hexadecimal form, e.g.
|
|
* page with number 123 (as seen by user) internally has number 0x123.
|
|
* and equation 0x123+8 should be equal to 0x131 instead of regular 0x12b.
|
|
* Page numbers 0xYYY (where Y is not belongs to (0..9) and pages below 0x100 and
|
|
* higher 0x999 are reserved for internal use.
|
|
*
|
|
*/
|
|
static int steppage(int curr, int direction)
|
|
{
|
|
int newpage = vbi_dec2bcd(vbi_bcd2dec(curr) + direction);
|
|
if (newpage < 0x100)
|
|
newpage = 0x100;
|
|
if (newpage > 0x999)
|
|
newpage = 0x999;
|
|
return newpage;
|
|
}
|
|
|
|
/**
|
|
* \brief toggles teletext page displaying mode
|
|
* \param priv_vbi private data structure
|
|
* \param flag new mode
|
|
* \return
|
|
* TVI_CONTROL_TRUE is success,
|
|
* TVI_CONTROL_FALSE otherwise
|
|
*
|
|
* flag:
|
|
* 0 - off
|
|
* 1 - on & opaque
|
|
* 2 - on & transparent
|
|
* 3 - on & transparent with black foreground color (only in bw mode)
|
|
*
|
|
*/
|
|
static int teletext_set_mode(priv_vbi_t * priv_vbi, int flag)
|
|
{
|
|
if (flag<0 || flag>3)
|
|
return TVI_CONTROL_FALSE;
|
|
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
|
|
priv_vbi->on = flag;
|
|
|
|
if (priv_vbi->on > 2 && priv_vbi->tformat != VBI_TFORMAT_BW)
|
|
priv_vbi->on = 0;
|
|
|
|
priv_vbi->foreground = 0;
|
|
priv_vbi->pagenumdec = 0;
|
|
priv_vbi->spudec_proc = 1;
|
|
priv_vbi->redraw = 1;
|
|
switch (priv_vbi->on) {
|
|
case 0:
|
|
priv_vbi->csize = 0;
|
|
break;
|
|
case 1:
|
|
priv_vbi->alpha = 0;
|
|
break;
|
|
case 2:
|
|
priv_vbi->alpha = 1;
|
|
break;
|
|
case 3:
|
|
priv_vbi->alpha = 1;
|
|
priv_vbi->foreground = 1;
|
|
break;
|
|
}
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return TVI_CONTROL_TRUE;
|
|
}
|
|
|
|
/**
|
|
* \brief get half page mode (only in SPU mode)
|
|
* \param priv_vbi private data structure
|
|
* \return current mode
|
|
* 0 : half mode off
|
|
* 1 : top half page
|
|
* 2 : bottom half page
|
|
*/
|
|
static int vbi_get_half(priv_vbi_t * priv_vbi)
|
|
{
|
|
int flag = 0;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
if (priv_vbi->valid_page)
|
|
flag = priv_vbi->half;
|
|
priv_vbi->pagenumdec = 0;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return flag;
|
|
}
|
|
|
|
/**
|
|
* \brief set half page mode (only in SPU mode)
|
|
* \param priv_vbi private data structure
|
|
* \param flag new half page mode
|
|
* \return
|
|
* TVI_CONTROL_TRUE is success,
|
|
* TVI_CONTROL_FALSE otherwise
|
|
*
|
|
*
|
|
* flag:
|
|
* 0 : half mode off
|
|
* 1 : top half page
|
|
* 2 : bottom half page
|
|
*/
|
|
static int teletext_set_half_page(priv_vbi_t * priv_vbi, int flag)
|
|
{
|
|
if (flag<0 || flag>2)
|
|
return TVI_CONTROL_FALSE;
|
|
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
priv_vbi->half = flag;
|
|
if (priv_vbi->tformat == VBI_TFORMAT_TEXT && priv_vbi->half > 1)
|
|
priv_vbi->half = 0;
|
|
priv_vbi->redraw = 1;
|
|
priv_vbi->pagenumdec = 0;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return TVI_CONTROL_TRUE;
|
|
}
|
|
|
|
/**
|
|
* \brief displays specified page
|
|
* \param priv_vbi private data structure
|
|
* \param pgno page number to display
|
|
* \param subno subpage number
|
|
*
|
|
*/
|
|
static void vbi_setpage(priv_vbi_t * priv_vbi, int pgno, int subno)
|
|
{
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
priv_vbi->pgno = steppage(0, pgno);
|
|
priv_vbi->subno = subno;
|
|
priv_vbi->redraw = 1;
|
|
priv_vbi->pagenumdec = 0;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
}
|
|
|
|
/**
|
|
* \brief steps over pages by a given value
|
|
* \param priv_vbi private data structure
|
|
* \param direction decimal step value (can be negative)
|
|
*
|
|
*/
|
|
static void vbi_steppage(priv_vbi_t * priv_vbi, int direction)
|
|
{
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
priv_vbi->pgno = steppage(priv_vbi->pgno, direction);
|
|
priv_vbi->redraw = 1;
|
|
priv_vbi->pagenumdec = 0;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
}
|
|
|
|
/**
|
|
* \brief append just entered digit to editing page number
|
|
* \param priv_vbi private data structure
|
|
* \param dec decimal digit to append
|
|
*
|
|
* dec:
|
|
* '0'..'9' append digit
|
|
* '-' remove last digit (backspace emulation)
|
|
*
|
|
* This routine allows user to jump to arbitrary page.
|
|
* It implements simple page number editing algorithm.
|
|
*
|
|
* Subsystem can be on one of two modes: normal and page number edit mode.
|
|
* Zero value of priv_vbi->pagenumdec means normal mode
|
|
* Non-zero value means page number edit mode and equals to packed
|
|
* decimal number of already entered part of page number.
|
|
*
|
|
* How this works.
|
|
* Let's assume that current mode is normal (pagenumdec is zero), teletext page
|
|
* 100 are displayed as usual. topmost left corner of page contains page number.
|
|
* Then vbi_add_dec is sequentally called (through slave
|
|
* command of course) with 1,4,-,2,3 * values of dec parameter.
|
|
*
|
|
* +-----+------------+------------------+
|
|
* | dec | pagenumxec | displayed number |
|
|
* +-----+------------+------------------+
|
|
* | | 0x000 | 100 |
|
|
* +-----+------------+------------------+
|
|
* | 1 | 0x001 | __1 |
|
|
* +-----+------------+------------------+
|
|
* | 4 | 0x014 | _14 |
|
|
* +-----+------------+------------------+
|
|
* | - | 0x001 | __1 |
|
|
* +-----+------------+------------------+
|
|
* | 2 | 0x012 | _12 |
|
|
* +-----+------------+------------------+
|
|
* | 3 | 0x123 | 123 |
|
|
* +-----+------------+------------------+
|
|
* | | 0x000 | 123 |
|
|
* +-----+------------+------------------+
|
|
*
|
|
* pagenumdec will automatically receive zero value after third digit of page number
|
|
* is entered and current page will be switched to another one with entered page number.
|
|
*
|
|
*/
|
|
static void vbi_add_dec(priv_vbi_t * priv_vbi, char *dec)
|
|
{
|
|
int count, shift;
|
|
if (!dec)
|
|
return;
|
|
if (!priv_vbi->on)
|
|
return;
|
|
if ((*dec < '0' || *dec > '9') && *dec != '-')
|
|
return;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
count = (priv_vbi->pagenumdec >> 12) & 0xf;
|
|
if (*dec == '-') {
|
|
count--;
|
|
if (count)
|
|
priv_vbi->pagenumdec = ((priv_vbi->pagenumdec >> 4) & 0xfff) | (count << 12);
|
|
else
|
|
priv_vbi->pagenumdec = 0;
|
|
} else {
|
|
shift = count * 4;
|
|
count++;
|
|
priv_vbi->pagenumdec =
|
|
(((priv_vbi->pagenumdec) << 4 | (*dec -'0')) & 0xfff) | (count << 12);
|
|
if (count == 3) {
|
|
priv_vbi->pgno = priv_vbi->pagenumdec & 0xfff;
|
|
priv_vbi->subno = 0;
|
|
priv_vbi->redraw = 1;
|
|
priv_vbi->pagenumdec = 0;
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
}
|
|
|
|
/**
|
|
* \brief follows link specified on current page
|
|
* \param priv_vbi private data structure
|
|
* \param linkno link number (0..6)
|
|
* \return
|
|
* TVI_CONTROL_FALSE if linkno is outside 0..6 range or if
|
|
* teletext is switched off
|
|
* TVI_CONTROL_TRUE otherwise
|
|
*
|
|
* linkno:
|
|
* 0: tpage in tv parameters (starting page, usually 100)
|
|
* 1..6: follows link on current page with given number
|
|
*
|
|
* FIXME: quick test shows that this is working strange
|
|
* FIXME: routine does not checks whether links exists on page or not
|
|
* TODO: more precise look
|
|
*
|
|
*/
|
|
static int vbi_golink(priv_vbi_t * priv_vbi, int linkno)
|
|
{
|
|
if (linkno < 0 || linkno > 6)
|
|
return TVI_CONTROL_FALSE;
|
|
if (!priv_vbi->on)
|
|
return TVI_CONTROL_FALSE;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
if (linkno == 0) {
|
|
priv_vbi->pgno = priv_vbi->tpage;
|
|
priv_vbi->subno = priv_vbi->page->nav_link[linkno].subno;
|
|
priv_vbi->redraw = 1;
|
|
priv_vbi->pagenumdec = 0;
|
|
} else {
|
|
linkno--;
|
|
if (priv_vbi->pgno == priv_vbi->page->pgno) {
|
|
priv_vbi->pgno = priv_vbi->page->nav_link[linkno].pgno;
|
|
priv_vbi->subno = priv_vbi->page->nav_link[linkno].subno;
|
|
priv_vbi->redraw = 1;
|
|
priv_vbi->pagenumdec = 0;
|
|
}
|
|
}
|
|
priv_vbi->pagenumdec = 0;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return TVI_CONTROL_TRUE;
|
|
}
|
|
|
|
/**
|
|
* \brief get pointer to current teletext page
|
|
* \param priv_vbi private data structure
|
|
* \return pointer to vbi_page structure if teletext is
|
|
* switched on and current page is valid, NULL - otherwise
|
|
*
|
|
*/
|
|
static vbi_page *vbi_getpage(priv_vbi_t * priv_vbi)
|
|
{
|
|
vbi_page *page = NULL;
|
|
|
|
if (!priv_vbi->on)
|
|
return NULL;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
if (priv_vbi->valid_page)
|
|
if (page = malloc(sizeof(vbi_page)))
|
|
memcpy(page, priv_vbi->page, sizeof(vbi_page));
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return page;
|
|
}
|
|
|
|
/**
|
|
* \brief get pointer to current teletext page
|
|
* \param priv_vbi private data structure
|
|
* \return pointer to character string, containing text-only data of
|
|
* teletext page. If teletext is switched off, current page is invalid
|
|
* or page format if not equal to "text" then returning value is NULL.
|
|
*
|
|
*/
|
|
static char *vbi_getpagetext(priv_vbi_t * priv_vbi)
|
|
{
|
|
char *page = NULL;
|
|
|
|
if (!priv_vbi->on)
|
|
return NULL;
|
|
if (priv_vbi->tformat != VBI_TFORMAT_TEXT && priv_vbi->canvas)
|
|
return NULL;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
if (priv_vbi->valid_page)
|
|
page = priv_vbi->txtpage;
|
|
if (!page)
|
|
page = priv_vbi->header;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return page;
|
|
}
|
|
|
|
/**
|
|
* \brief get current page RGBA32 image (only in SPU mode)
|
|
* \param priv_vbi private data structure
|
|
* \return pointer to tv_teletext_img_t structure, containing among
|
|
* other things rendered RGBA32 image of current teletext page.
|
|
* return NULL is image is not available for some reason.
|
|
*
|
|
*/
|
|
static tv_teletext_img_t *vbi_getpageimg(priv_vbi_t * priv_vbi)
|
|
{
|
|
tv_teletext_img_t *img = NULL;
|
|
|
|
if (priv_vbi->tformat == VBI_TFORMAT_TEXT)
|
|
return NULL;
|
|
if (priv_vbi->spudec_proc == 0)
|
|
return NULL;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
if (NULL != (img = malloc(sizeof(tv_teletext_img_t)))) {
|
|
img->tformat = priv_vbi->tformat; // format: bw|gray|color
|
|
img->tformat = VBI_TFORMAT_GRAY; // format: bw|gray|color
|
|
img->half = priv_vbi->half; // half mode
|
|
img->columns = priv_vbi->columns; // page size
|
|
img->rows = priv_vbi->rows;
|
|
img->width = priv_vbi->columns * 12;
|
|
img->width = priv_vbi->rows * 10;
|
|
img->canvas = NULL;
|
|
// is page ok?
|
|
if (priv_vbi->canvas && priv_vbi->on && priv_vbi->csize && priv_vbi->valid_page) {
|
|
|
|
if (NULL != (img->canvas = malloc(priv_vbi->csize)))
|
|
memcpy(img->canvas, priv_vbi->canvas, priv_vbi->csize);
|
|
}
|
|
}
|
|
priv_vbi->spudec_proc = 0;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return img;
|
|
}
|
|
|
|
/**
|
|
* \brief start teletext sybsystem
|
|
* \param priv_vbi private data structure
|
|
*
|
|
* initializes cache, vbi decoder and starts background thread
|
|
*
|
|
*/
|
|
static void vbi_start(priv_vbi_t * priv_vbi)
|
|
{
|
|
if (!priv_vbi)
|
|
return;
|
|
if (NULL != (priv_vbi->txtpage = malloc(VBI_TXT_PAGE_SIZE))) // alloc vbi_page
|
|
memset(priv_vbi->txtpage, 0, VBI_TXT_PAGE_SIZE);
|
|
priv_vbi->page = malloc(sizeof(vbi_page));
|
|
priv_vbi->cache = (vbi_page **) malloc(1000 * sizeof(vbi_page *));
|
|
memset(priv_vbi->cache, 0, 1000 * sizeof(vbi_page *));
|
|
priv_vbi->decoder = vbi_decoder_new();
|
|
priv_vbi->subno = 0;
|
|
priv_vbi->fmt = VBI_PIXFMT_RGBA32_LE;
|
|
memset(priv_vbi->theader, 0, sizeof(priv_vbi->theader));
|
|
snprintf(priv_vbi->header, sizeof(priv_vbi->header), "%s", VBI_NO_TELETEXT);
|
|
vbi_event_handler_add(priv_vbi->decoder, ~0, event_handler, (void *) priv_vbi); // add event handler
|
|
pthread_create(&priv_vbi->grabber_thread, NULL, grabber, priv_vbi); // add grab function
|
|
pthread_mutex_init(&priv_vbi->buffer_mutex, NULL);
|
|
priv_vbi->valid_page = 0;
|
|
priv_vbi->pagenumdec = 0;
|
|
mp_msg(MSGT_TV, MSGL_INFO, "Teletext device: %s\n", priv_vbi->device);
|
|
}
|
|
|
|
/**
|
|
* \brief Teletext reset
|
|
* \param priv_vbi private data structure
|
|
*
|
|
* should be called during frequency, norm change, etc
|
|
*
|
|
*/
|
|
static void vbi_reset(priv_vbi_t * priv_vbi)
|
|
{
|
|
int i;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
if (priv_vbi->canvas)
|
|
free(priv_vbi->canvas);
|
|
priv_vbi->canvas = NULL;
|
|
priv_vbi->canvas_size = 0;
|
|
priv_vbi->redraw = 1;
|
|
priv_vbi->csize = 0;
|
|
priv_vbi->valid_page = 0;
|
|
priv_vbi->spudec_proc = 1;
|
|
priv_vbi->pagenumdec = 0;
|
|
if (priv_vbi->page)
|
|
memset(priv_vbi->page, 0, sizeof(vbi_page));
|
|
if (priv_vbi->txtpage)
|
|
memset(priv_vbi->txtpage, 0, VBI_TXT_PAGE_SIZE);
|
|
memset(priv_vbi->theader, 0, sizeof(priv_vbi->theader));
|
|
if (priv_vbi->cache) {
|
|
for (i = 0; i < 1000; i++) {
|
|
if (priv_vbi->cache[i])
|
|
free(priv_vbi->cache[i]);
|
|
priv_vbi->cache[i] = NULL;
|
|
}
|
|
}
|
|
snprintf(priv_vbi->header, sizeof(priv_vbi->header), "%s",
|
|
VBI_NO_TELETEXT);
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
}
|
|
|
|
/*
|
|
---------------------------------------------------------------------------------
|
|
Public routines
|
|
---------------------------------------------------------------------------------
|
|
*/
|
|
|
|
/**
|
|
* \brief teletext subsystem init
|
|
* \note Routine uses global variables tv_param_tdevice, tv_param_tpage
|
|
* and tv_param_tformat for initialization.
|
|
*
|
|
*/
|
|
priv_vbi_t *teletext_init(void)
|
|
{
|
|
priv_vbi_t *priv_vbi;
|
|
int formatid, startpage;
|
|
unsigned int services = VBI_SLICED_TELETEXT_B |
|
|
VBI_SLICED_CAPTION_525 |
|
|
VBI_SLICED_CAPTION_625 |
|
|
VBI_SLICED_VBI_525 |
|
|
VBI_SLICED_VBI_625 |
|
|
VBI_SLICED_WSS_625 |
|
|
VBI_SLICED_WSS_CPR1204 |
|
|
VBI_SLICED_VPS;
|
|
|
|
if (!tv_param_tdevice)
|
|
return NULL;
|
|
|
|
if (NULL == (priv_vbi = malloc(sizeof(priv_vbi_t))))
|
|
return NULL;
|
|
memset(priv_vbi, 0, sizeof(priv_vbi_t));
|
|
formatid = VBI_TFORMAT_TEXT; // default
|
|
if (tv_param_tformat != NULL) {
|
|
if (strcmp(tv_param_tformat, "text") == 0)
|
|
formatid = VBI_TFORMAT_TEXT;
|
|
if (strcmp(tv_param_tformat, "bw") == 0)
|
|
formatid = VBI_TFORMAT_BW;
|
|
if (strcmp(tv_param_tformat, "gray") == 0)
|
|
formatid = VBI_TFORMAT_GRAY;
|
|
if (strcmp(tv_param_tformat, "color") == 0)
|
|
formatid = VBI_TFORMAT_COLOR;
|
|
}
|
|
startpage = steppage(0, tv_param_tpage); // page number is HEX
|
|
if (startpage < 0x100 || startpage > 0x999)
|
|
startpage = 0x100;
|
|
priv_vbi->device = strdup(tv_param_tdevice);
|
|
priv_vbi->tformat = formatid;
|
|
priv_vbi->tpage = startpage; // page number
|
|
priv_vbi->pgno = startpage; // page number
|
|
|
|
|
|
if (!priv_vbi->capture) {
|
|
priv_vbi->services = services; // probe v4l2
|
|
priv_vbi->capture = vbi_capture_v4l2_new(priv_vbi->device, // device
|
|
20, // buffer numbers
|
|
&(priv_vbi->services), // services
|
|
0, // strict
|
|
&(priv_vbi->errstr), // error string
|
|
0); // trace
|
|
}
|
|
services = priv_vbi->services;
|
|
if (priv_vbi->capture == NULL) {
|
|
priv_vbi->services = services; // probe v4l
|
|
priv_vbi->capture = vbi_capture_v4l_new(priv_vbi->device,
|
|
20,
|
|
&(priv_vbi->services),
|
|
0, &(priv_vbi->errstr), 0);
|
|
}
|
|
|
|
if (!priv_vbi->capture) {
|
|
free(priv_vbi->device);
|
|
free(priv_vbi);
|
|
mp_msg(MSGT_TV, MSGL_INFO, "No teletext\n");
|
|
return NULL;
|
|
}
|
|
return priv_vbi;
|
|
}
|
|
|
|
/**
|
|
* \brief teletext subsystem uninitialization
|
|
* \param priv_vbi private data structure
|
|
*
|
|
* closes vbi capture, decode and and frees priv_vbi structure
|
|
*
|
|
*/
|
|
void teletext_uninit(priv_vbi_t * priv_vbi)
|
|
{
|
|
int i;
|
|
if (priv_vbi == NULL)
|
|
return;
|
|
priv_vbi->eof = 1;
|
|
if (priv_vbi->capture){
|
|
vbi_capture_delete(priv_vbi->capture);
|
|
priv_vbi->capture = NULL;
|
|
}
|
|
if (priv_vbi->decoder){
|
|
vbi_event_handler_remove(priv_vbi->decoder, event_handler);
|
|
vbi_decoder_delete(priv_vbi->decoder);
|
|
priv_vbi->decoder = NULL;
|
|
}
|
|
if (priv_vbi->grabber_thread)
|
|
pthread_join(priv_vbi->grabber_thread, NULL);
|
|
pthread_mutex_destroy(&priv_vbi->buffer_mutex);
|
|
if (priv_vbi->device){
|
|
free(priv_vbi->device);
|
|
priv_vbi->device = NULL;
|
|
}
|
|
if (priv_vbi->errstr){
|
|
free(priv_vbi->errstr);
|
|
priv_vbi->errstr = NULL;
|
|
}
|
|
if (priv_vbi->canvas){
|
|
free(priv_vbi->canvas);
|
|
priv_vbi->canvas = NULL;
|
|
}
|
|
if (priv_vbi->txtpage){
|
|
free(priv_vbi->txtpage);
|
|
priv_vbi->txtpage = NULL;
|
|
}
|
|
if (priv_vbi->network_name){
|
|
free(priv_vbi->network_name);
|
|
priv_vbi->network_name = NULL;
|
|
}
|
|
if (priv_vbi->network_id){
|
|
free(priv_vbi->network_id);
|
|
priv_vbi->network_id = NULL;
|
|
}
|
|
if (priv_vbi->page){
|
|
free(priv_vbi->page);
|
|
priv_vbi->page = NULL;
|
|
}
|
|
if (priv_vbi->cache) {
|
|
for (i = 0; i < 1000; i++) {
|
|
if (priv_vbi->cache[i])
|
|
free(priv_vbi->cache[i]);
|
|
}
|
|
free(priv_vbi->cache);
|
|
priv_vbi->cache = NULL;
|
|
}
|
|
free(priv_vbi);
|
|
}
|
|
|
|
/**
|
|
* \brief Teletext control routine
|
|
* \param priv_vbi private data structure
|
|
* \param cmd command
|
|
* \param arg command parameter (has to be not null)
|
|
*
|
|
*/
|
|
int teletext_control(priv_vbi_t * priv_vbi, int cmd, void *arg)
|
|
{
|
|
vbi_page *page = NULL;
|
|
char *txtpage = NULL;
|
|
tv_teletext_img_t *img = NULL;
|
|
if (!priv_vbi)
|
|
return TVI_CONTROL_FALSE;
|
|
if (!arg)
|
|
return TVI_CONTROL_FALSE;
|
|
switch (cmd) {
|
|
case TVI_CONTROL_VBI_RESET:
|
|
vbi_reset(priv_vbi);
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_START:
|
|
vbi_start(priv_vbi);
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_GET_FORMAT:
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
*(int*)arg=priv_vbi->tformat;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_SET_MODE:
|
|
return teletext_set_mode(priv_vbi, *(int *) arg);
|
|
case TVI_CONTROL_VBI_GET_MODE:
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
*(int*)arg=priv_vbi->on;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_STEP_MODE:
|
|
{
|
|
int val;
|
|
pthread_mutex_lock(&(priv_vbi->buffer_mutex));
|
|
val=(priv_vbi->on+*(int*)arg)%4;
|
|
pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
|
|
if (val<0)
|
|
val+=4;
|
|
return teletext_set_mode(priv_vbi,val);
|
|
}
|
|
case TVI_CONTROL_VBI_GET_HALF_PAGE:
|
|
*(void **) arg = (void *) vbi_get_half(priv_vbi);
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_SET_HALF_PAGE:
|
|
return teletext_set_half_page(priv_vbi, *(int *) arg);
|
|
case TVI_CONTROL_VBI_STEP_HALF_PAGE:
|
|
{
|
|
int val;
|
|
val=(vbi_get_half(priv_vbi)+*(int*)arg)%3;
|
|
|
|
if (val<0)
|
|
val+=3;
|
|
return teletext_set_half_page(priv_vbi,val);
|
|
}
|
|
|
|
case TVI_CONTROL_VBI_SET_PAGE:
|
|
vbi_setpage(priv_vbi, *(int *) arg, 0);
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_STEP_PAGE:
|
|
vbi_steppage(priv_vbi, *(int *) arg);
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_ADD_DEC:
|
|
vbi_add_dec(priv_vbi, *(char **) arg);
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_GO_LINK:
|
|
return vbi_golink(priv_vbi, *(int *) arg);
|
|
case TVI_CONTROL_VBI_GET_PAGE:
|
|
*(int*) arg = priv_vbi->pgno;
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_GET_VBIPAGE:
|
|
if (NULL == (page = vbi_getpage(priv_vbi)))
|
|
return TVI_CONTROL_FALSE;
|
|
*(void **) arg = (void *) page;
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_GET_TXTPAGE:
|
|
if (NULL == (txtpage = vbi_getpagetext(priv_vbi)))
|
|
return TVI_CONTROL_FALSE;
|
|
*(void **) arg = (void *) txtpage;
|
|
return TVI_CONTROL_TRUE;
|
|
case TVI_CONTROL_VBI_GET_IMGPAGE:
|
|
if (NULL == (img = vbi_getpageimg(priv_vbi)))
|
|
return TVI_CONTROL_FALSE;
|
|
*(void **) arg = (void *) img;
|
|
return TVI_CONTROL_TRUE;
|
|
}
|
|
return TVI_CONTROL_UNKNOWN;
|
|
}
|