/*
* Teletext support
* Copyright (C) 2007 Vladimir Voroshilov <voroshil@gmail.com>
*
* This file is part of MPlayer.
*
* MPlayer 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.
*
* MPlayer 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 MPlayer; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*
* Based on Attila Otvos' teletext patch, Michael Niedermayer's
* proof-of-concept teletext capture utility and some parts
* (decode_raw_line_runin,pll_add,pll_reset) of MythTV project.
* Code for calculating [soc:eoc] is based on aletv of Edgar Toernig.
*
* Teletext system is described in
* ETS 300 706 "Enhanced Teletext specification" : May 1997
* http://www.themm.net/~mihu/linux/saa7146/specs/ets_300706e01p.pdf
*
* Some implementation details:
* How to port teletext to another tvi_* driver (see tvi_v4l2.c for example):
*
* 1. Implement TVI_CONTROL_VBI_INIT (initialize driver-related vbi subsystem,
* start grabbing thread)
* input data: vbi device name.
* (driver should also call TV_VBI_CONTROL_START for common vbi subsystem initialization
* with pointer to initialized tt_stream_properties structure.
* After ioctl call variable will contain pointer to initialized priv_vbi_t structure.
*
* 2. After receiving next chunk of raw vbi data call TV_VBI_CONTROL_DECODE_PAGE
* ioctl with pointer to data buffer
* 3. pass all other VBI related ioctl cmds to teletext_control routine
*
* Page displaying process consist of following stages:
*
* ---grabbing stage---
* 0. stream/tvi_*.c: vbi_grabber(...)
* getting vbi data from video device
* ---decoding stage---
* 1. stream/tvi_vbi.c: decode_raw_line_runin(...) or decode_raw_line_sine(...)
* decode raw vbi data into sliced 45(?) bytes long packets
* 2. stream/tvi_vbi.c: decode_pkt0(...), decode_pkt_page(...)
* packets processing (header analyzing, storing complete page in cache,
* only raw member of tt_char is filled at this stage)
* 3. stream/tvi_vbi.c: decode_page(...)
* page decoding. filling unicode,gfx,ctl,etc members of tt_char structure
* with appropriate values according to teletext control chars, converting
* text to utf8.
* ---rendering stage---
* 4. stream/tvi_vbi.c: prepare_visible_page(...)
* processing page. adding number of just received by background process
* teletext page, adding current time,etc.
* 5. libvo/sub.c: vo_update_text_teletext(...)
* rendering displayable osd with text and graphics
*
* TODO:
* v4lv1,bktr support
* spu rendering
* is better quality on poor signal possible ?
* link support
* font autoscale
* greyscale osd
* slave command for dumping pages
* fix bcd<->dec as suggested my Michael
*
* BUGS:
* wrong colors in debug dump
* blinking when visible page was just updated
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <pthread.h>
#include "tv.h"
#include "mp_msg.h"
#include "help_mp.h"
#include "libmpcodecs/img_format.h"
#include "libavutil/common.h"
#include "input/input.h"
//#define DEBUG_DUMP 1
/// page magazine entry structure
typedef struct mag_s{
tt_page* pt;
int order;
int lang;
} mag_t;
typedef struct {
int on; ///< teletext on/off
int pagenum; ///< seek page number
int subpagenum; ///< seek subpage
int curr_pagenum; ///< current page number
int pagenumdec; ///< set page num with dec
teletext_format tformat; ///< see teletext_format enum
teletext_zoom zoom; ///< see teletext_zoom enum
mag_t* mag; ///< pages magazine (has 8 entities)
/// Currently displayed page (with additional info, e.g current time)
tt_char display_page[VBI_ROWS*VBI_COLUMNS];
/// number of raw bytes between two subsequent encoded bits
int bpb;
/// clock run-in sequence will be searched in buffer in [soc:eoc] bytes range
int soc;
int eoc;
/// minimum number of raw vbi bytes wich can be decoded into 8 data bits
int bp8bl;
/// maximum number of raw vbi bytes wich can be decoded into 8 data bits
int bp8bh;
int pll_adj;
int pll_dir;
int pll_cnt;
int pll_err;
int pll_lerr;
int pll_fixed;
/// vbi stream properties (buffer size,bytes per line, etc)
tt_stream_props* ptsp;
pthread_mutex_t buffer_mutex;
tt_page** ptt_cache;
unsigned char* ptt_cache_first_subpage;
/// network info
unsigned char initialpage;
unsigned int initialsubpage;
unsigned int networkid;
int timeoffset; // timeoffset=realoffset*2
unsigned int juliandate;
unsigned int universaltime;
unsigned char networkname[21];
} priv_vbi_t;
static unsigned char fixParity[256];
static tt_char tt_space={0x20,7,0,0,0,0,0x20};
static tt_char tt_error={'?',1,0,0,0,0,'?'}; // Red '?' on black background
static double si[12];
static double co[12];
#define VBI_FORMAT(priv) (*(priv->ptsp))
#define FIXP_SH 16
#define ONE_FIXP (1<<FIXP_SH)
#define FIXP2INT(a) ((a)>>FIXP_SH)
#define ANY2FIXP(a) ((int)((a)*ONE_FIXP))
static const unsigned char corrHamm48[256]={
0x01, 0xff, 0x01, 0x01, 0xff, 0x00, 0x01, 0xff,
0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07,
0xff, 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00,
0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff,
0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07,
0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x07,
0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff,
0x06, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07,
0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09,
0x02, 0x02, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff,
0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff,
0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x03, 0x03,
0x04, 0xff, 0xff, 0x05, 0x04, 0x04, 0x04, 0xff,
0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07,
0xff, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, 0x05,
0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff,
0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09,
0x0a, 0xff, 0xff, 0x0b, 0x0a, 0x0a, 0x0a, 0xff,
0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff,
0xff, 0x0b, 0x0b, 0x0b, 0x0a, 0xff, 0xff, 0x0b,
0x0c, 0x0c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff,
0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07,
0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x0d, 0x0d,
0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff,
0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x09,
0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09,
0x08, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09,
0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff,
0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09,
0x0f, 0xff, 0x0f, 0x0f, 0xff, 0x0e, 0x0f, 0xff,
0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff,
0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x0e, 0xff, 0x0e };
enum {
LAT_UNI=0,
RUS_UNI,
LANGS
};
// conversion table for chars 0x20-0x7F (UTF8)
// TODO: add another languages
static unsigned int lang_chars[LANGS][0x60]={
{
//Latin
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
},
{
//Russian
0x20,0x21,0x22,0x23,0x24,0x25,0x044b,0x27,
0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x042e,0x0410,0x0411,0x0426,0x0414,0x0415,0x0424,0x0413,
0x0425,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,
0x041f,0x042f,0x0420,0x0421,0x0422,0x0423,0x0416,0x0412,
0x042c,0x042a,0x0417,0x0428,0x042d,0x0429,0x0427,0x042b,
0x044e,0x0430,0x0431,0x0446
|