Support for selecting language via packet 28.

Also  allows to select default teletext language.
It will be used if language is not specified by network provider
via packet 28.



git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@24310 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
voroshil 2007-08-31 16:53:27 +00:00
parent 503a85926f
commit 374e9dd5ba
6 changed files with 216 additions and 21 deletions

View File

@ -1896,6 +1896,12 @@ Specify TV teletext display format (default: 0):
.REss
.IPs tpage=<100-899>
Specify initial TV teletext page number (default: 100).
.IPs tlang=<\-1\-127>
Specify default teletext language code (default: 0).
Given value will be used as primary language until 28 packet received.
Useful when teletext system uses non-latin charset, but language codes
are not transmitted via 28 teletext packets for some reason.
To see list of supported language codes set this option to \-1.
.RE
.
.TP

View File

@ -464,6 +464,7 @@ m_option_t tvopts_conf[]={
{"tdevice", &stream_tv_defaults.tdevice, CONF_TYPE_STRING, 0, 0, 0, NULL},
{"tpage", &stream_tv_defaults.tpage, CONF_TYPE_INT, CONF_RANGE, 100, 899, NULL},
{"tformat", &stream_tv_defaults.tformat, CONF_TYPE_INT, CONF_RANGE, 0, 3, NULL},
{"tlang", &stream_tv_defaults.tlang, CONF_TYPE_INT, CONF_RANGE, -1, 0x7f, NULL},
#endif
{"audioid", &stream_tv_defaults.audio_id, CONF_TYPE_INT, CONF_RANGE, 0, 9, NULL},
{NULL, NULL, 0, 0, 0, 0, NULL}

View File

@ -2097,3 +2097,5 @@ static char help_text[]=
#define MSGTR_TV_Bt848ErrorSettingWidth "tvi_bsdbt848: Error setting picture width. Error: %s\n"
#define MSGTR_TV_Bt848ErrorSettingHeight "tvi_bsdbt848: Error setting picture height. Error: %s\n"
#define MSGTR_TV_Bt848UnableToStopCapture "tvi_bsdbt848: Unable to stop capture. Error: %s\n"
#define MSGTR_TV_TTSupportedLanguages "Supported Teletext languages:\n"
#define MSGTR_TV_TTSelectedLanguage "Selected default teletext language: %s\n"

View File

@ -75,6 +75,7 @@ tv_param_t stream_tv_defaults = {
NULL, //tdevice
0, //tformat
100, //tpage
0, //tlang
0, //scan_autostart
50, //scan_threshold

View File

@ -50,6 +50,7 @@ typedef struct tv_param_s {
char *tdevice; ///< teletext device
int tformat; ///< teletext display format
int tpage; ///< start teletext page
int tlang; ///< primary language code
int scan;
int scan_threshold;
@ -276,7 +277,7 @@ typedef struct tt_char_s{
unsigned char bg; ///< background color
unsigned char gfx; ///< 0-no gfx, 1-solid gfx, 2-separated gfx
unsigned char ctl; ///< control character
unsigned char lng; ///< lang: 0-lating,1-national
unsigned char lng; ///< lang: 0-secondary language,1-primary language
unsigned char raw; ///< raw character (as received from device)
} tt_char;
@ -288,7 +289,8 @@ typedef struct tt_link_s{
typedef struct tt_page_s{
int pagenum; ///< page number
int subpagenum; ///< subpage number
unsigned char lang; ///< language code
unsigned char primary_lang; ///< primary language code
unsigned char secondary_lang; ///< secondary language code
unsigned char active; ///< page is complete and ready for rendering
unsigned char flags; ///< page flags, not used
unsigned char raw[VBI_ROWS*VBI_COLUMNS]; ///< page data

View File

@ -103,7 +103,6 @@
typedef struct mag_s{
tt_page* pt;
int order;
int lang;
} mag_t;
typedef struct {
@ -116,6 +115,8 @@ typedef struct {
teletext_format tformat; ///< see teletext_format enum
teletext_zoom zoom; ///< see teletext_zoom enum
mag_t* mag; ///< pages magazine (has 8 entities)
int primary_language; ///< primary character set
int secondary_language; ///< secondary character set
/// 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
@ -320,25 +321,132 @@ static unsigned int latin_subchars[8][13]={
{0x23,0x24,0x40,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x7b,0x7c,0x7d,0x7e}
};
static int lang2id (int lang){
return LATIN;
/**
* List of supported languages.
*
* lang_code bits for primary Language:
* bits 7-4 corresponds to bits 14-11 of 28 packet's first triplet
* bits 3-1 corresponds to bits C12-C14 of packet 0 (lang)
*
* lang_code bits for secondary Language:
* bits 7-5 corresponds to bits 3-1 of 28 packet's second triplet
* bits 4,2 corresponds to bits 18,16 of 28 packet's first triplet
* bits 3,1 corresponds to bits 15,17 of 28 packet's first triplet
*
* For details see Tables 32 and 33 of specification (subclause 15.2)
*/
struct {
unsigned char lang_code;
unsigned char charset;
char* lang_name;
} tt_languages[]=
{
{ 0x01, LATIN, "French"},
{ 0x02, LATIN, "Swedish/Finnish/Hungarian"},
{ 0x03, LATIN, "Czech/Slovak"},
{ 0x04, LATIN, "German"},
{ 0x05, LATIN, "Portuguese/Spanish"},
{ 0x06, LATIN, "Italian"},
{ 0x08, LATIN, "Polish"},
{ 0x09, LATIN, "French"},
{ 0x0a, LATIN, "Swedish/Finnish/Hungarian"},
{ 0x0b, LATIN, "Czech/Slovak"},
{ 0x0c, LATIN, "German"},
{ 0x0e, LATIN, "Italian"},
{ 0x10, LATIN, "English"},
{ 0x11, LATIN, "French"},
{ 0x12, LATIN, "Swedish/Finnish/Hungarian"},
{ 0x13, LATIN, "Turkish"},
{ 0x14, LATIN, "German"},
{ 0x15, LATIN, "Portuguese/Spanish"},
{ 0x16, LATIN, "Italian"},
{ 0x1d, LATIN, "Serbian/Croatian/Slovenian (Latin)"},
{ 0x20, CYRILLIC1, "Serbian/Croatian (Cyrillic)"},
{ 0x21, CYRILLIC2, "Russian, Bulgarian"},
{ 0x22, LATIN, "Estonian"},
{ 0x23, LATIN, "Czech/Slovak"},
{ 0x24, LATIN, "German"},
{ 0x25, CYRILLIC3, "Ukrainian"},
{ 0x26, LATIN, "Lettish/Lithuanian"},
{ 0x33, LATIN, "Turkish"},
{ 0x37, GREEK, "Greek"},
{ 0x40, LATIN, "English"},
{ 0x41, LATIN, "French"},
// { 0x47, ARABIC, "Arabic"},
// { 0x55, HEBREW, "Hebrew"},
// { 0x57, ARABIC, "Arabic"},
{ 0x00, LATIN, "English"},
};
/**
* \brief 24/18 Hamming code decoding
* \param data bytes with hamming code (array must be at least 3 bytes long)
* \return -1 if multiple bit error occured, D1-DI data bits - otherwise
*
* \note Bits must be correctly ordered, that is for 24/18 (lowest bit first)
* P1 P2 D1 P3 D2 D3 D4 P4 D5 D6 D7 D8 D9 DA DB P5 DC DD DE DF DG DH DI P6
*/
int corrHamm24(unsigned char *data){
unsigned char syndrom=0;
int cw=data[0] | (data[1]<<8) | (data[2]<<16);
int i;
for(i=0;i<23;i++)
syndrom^=((cw>>i)&1)*(i+33);
syndrom^=(cw>>11)&32;
if(syndrom&31){
if(syndrom < 32 || syndrom > 55)
return -1;
cw ^= 1<<((syndrom&31)-1);
}
return (cw&4)>>2 |
(cw&0x70)>>3 |
(cw&0x3f00)>>4 |
(cw&0x3f0000)>>5;
}
/**
* \brief converts language bits to charset index
* \param lang language bits
* \return charset index in lang_chars array
*/
static int lang2charset (int lang){
int i;
for(i=0;tt_languages[i].lang_code;i++)
if(tt_languages[i].lang_code==lang)
break;
return tt_languages[i].charset;
}
/**
* \brief convert chars from curent teletext codepage into MPlayer charset
* \param p raw teletext char to decode
* \param lang teletext internal language code (see lang2id)
* \param charset index on lang_chars
* \param lang index in substitution array (latin charset only)
* \return UTF8 char
*
* \remarks
* routine will analyze raw member of given tt_char structure and
* fill unicode member of the same struct with appropriate utf8 code.
*/
static unsigned int conv2uni(unsigned int p,int lang)
static unsigned int conv2uni(unsigned int p,int charset,int lang)
{
int charset=lang2id(lang);
if(p<0x80 && p>=0x20){
if(charset==LATIN){
lang&=7;
if (p>=0x23 && p<=0x24){
return latin_subchars[lang][p-0x23];
}else if (p==0x40){
@ -452,7 +560,8 @@ static void put_to_cache(priv_vbi_t* priv,tt_page* pg,int line){
}
pgc->pagenum=pg->pagenum;
pgc->subpagenum=pg->subpagenum;
pgc->lang=pg->lang;
pgc->primary_lang=pg->primary_lang;
pgc->secondary_lang=pg->secondary_lang;
pgc->flags=pg->flags;
for(j=0;j<6;++j)
pgc->links[j]=pg->links[j];
@ -559,17 +668,22 @@ static void destroy_cache(priv_vbi_t* priv){
/**
* \brief converts raw teletext page into useful format (1st rendering stage)
* \param pg page to decode
*
* \param raw raw data to decode page from
* \param primary_lang primary language code
* \param secondary_lang secondary language code
*
* Routine fills tt_char structure of each teletext_page character with proper
* info about foreground and background colors, character
* type (graphics/control/text).
*/
static void decode_page(tt_char* p,int lang,unsigned char* raw)
static void decode_page(tt_char* p,unsigned char* raw,int primary_lang,int secondary_lang)
{
int row,col;
int prim_charset=lang2charset(primary_lang);
int sec_charset=lang2charset(secondary_lang);
for(row=0;row<VBI_ROWS;row++) {
int lat=(lang==0);
int prim_lang=1;
int gfx=0;
int fg_color=7;
int bg_color=0;
@ -586,7 +700,7 @@ static void decode_page(tt_char* p,int lang,unsigned char* raw)
continue;
}
p[i].gfx=gfx?(separated?2:1):0;
p[i].lng=lat?0:lang;
p[i].lng=prim_lang;
p[i].ctl=(c&0x60)==0?1:0;
p[i].fg=fg_color;
p[i].bg=bg_color;
@ -609,7 +723,7 @@ static void decode_page(tt_char* p,int lang,unsigned char* raw)
}else if (c<=0x1a){ //Contiguous/Separated gfx
separated=!(c&1);
}else if (c<=0x1b){
lat=!lat;
prim_lang=!prim_lang;
}else if (c<=0x1d){
bg_color=(c&1)?fg_color:0;
p[i].bg=bg_color;
@ -633,9 +747,13 @@ static void decode_page(tt_char* p,int lang,unsigned char* raw)
p[i].unicode=c-0x20;
if (p[i].unicode>0x3f) p[i].unicode-=0x20;
tt_held=p[i];
}else
p[i].unicode=conv2uni(c,p[i].lng);
}else{
if(p[i].lng){
p[i].unicode=conv2uni(c,prim_charset,primary_lang&7);
}else{
p[i].unicode=conv2uni(c,sec_charset,secondary_lang&7);
}
}
p[i].fg=fg_color;
p[i].bg=bg_color;
}
@ -684,7 +802,7 @@ static void prepare_visible_page(priv_vbi_t* priv){
priv->display_page[i]=tt_space;
}
}else{
decode_page(priv->display_page,pg->lang,pg->raw);
decode_page(priv->display_page,pg->raw,pg->primary_lang,pg->secondary_lang);
mp_msg(MSGT_TV,MSGL_DBG3,"page #%x was decoded!\n",pg->pagenum);
}
@ -759,7 +877,7 @@ static void render2text(tt_page* pt,FILE* f,int colored){
0);
fprintf(f,"+----------------------------------------+\n");
decode_page(dp,pt->lang,pt->raw);
decode_page(dp,pt->raw,pt->primary_lang,pt->secondary_lang);
for(i=0;i<VBI_ROWS;i++){
fprintf(f,"|");
if(colored) fprintf(f,"\033[40m");
@ -959,8 +1077,11 @@ static int decode_pkt0(priv_vbi_t* priv,unsigned char* data,int magAddr)
if (!priv->mag[magAddr].pt)
priv->mag[magAddr].pt= malloc(sizeof(tt_page));
priv->mag[magAddr].lang=(d[7]>>1)&0x7;
priv->mag[magAddr].pt->lang=priv->mag[magAddr].lang;
if(priv->primary_language)
priv->mag[magAddr].pt->primary_lang=priv->primary_language;
else
priv->mag[magAddr].pt->primary_lang= (d[7]&7)>>1;
priv->mag[magAddr].pt->secondary_lang=priv->secondary_language;
priv->mag[magAddr].pt->subpagenum=(d[2]|(d[3]<<4)|(d[4]<<8)|(d[5]<<12))&0x3f7f;
priv->mag[magAddr].pt->pagenum=(magAddr<<8) | d[0] | (d[1]<<4);
priv->mag[magAddr].pt->flags=( d[6] | (d[7]<<4));
@ -1118,6 +1239,46 @@ static int decode_pkt27(priv_vbi_t* priv,unsigned char* data,int magAddr){
return 1;
}
/**
* \brief Decode teletext X/28/0 Format 1 packet
* \param priv private data structure
* \param data raw teletext data
*
* Primary G0 charset is transmitted in bits 14-8 of Triplet 1
* See Table 32 of specification for details.
*
* Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and
* bits 18-15 of Triplet 1
* See Table 33 of specification for details.
*
*/
static void decode_pkt28(priv_vbi_t* priv,unsigned char*data){
int d;
int t1,t2;
d=corrHamm48[ data[0] ];
if(d) return; //this is not X/28/0 Format 1 packet or error occured
t1=corrHamm24(data+1);
t2=corrHamm24(data+4);
if (t1<0 || t2<0){
pll_add(priv,1,4);
return;
}
priv->primary_language=(t1>>7)&0x7f;
priv->secondary_language=((t2<<4) | (t1>>14))&0x7f;
if (priv->secondary_language==0x7f)
//No secondary language required
priv->secondary_language=priv->primary_language;
else // Swapping bits 1 and 3
priv->secondary_language=(priv->secondary_language&0x7a) |
(priv->secondary_language&4)>>2 |
(priv->secondary_language&1)<<2;
mp_msg(MSGT_TV,MSGL_DBG2,"pkt28: language: primary=%02x secondary=0x%02x\n",
priv->primary_language,priv->secondary_language);
}
/**
* \brief decodes raw vbi data (signal amplitudes) into sequence of bytes
* \param priv private data structure
@ -1311,6 +1472,8 @@ static void vbi_decode(priv_vbi_t* priv,unsigned char*buf){
decode_pkt_page(priv,data+2,magAddr,pkt);//skip MRGA
}else if(pkt==27) {
decode_pkt27(priv,data+2,magAddr);
}else if(pkt==28){
decode_pkt28(priv,data+2);
}else if(pkt==30){
decode_pkt30(priv,data+2,magAddr);
} else {
@ -1455,6 +1618,7 @@ int teletext_control(void* p, int cmd, void *arg)
switch (cmd) {
case TV_VBI_CONTROL_RESET:
{
int i;
tv_param_t* tv_param=arg;
pthread_mutex_lock(&(priv->buffer_mutex));
priv->pagenumdec=0;
@ -1463,6 +1627,25 @@ int teletext_control(void* p, int cmd, void *arg)
priv->tformat=tv_param->tformat;
priv->subpagenum=0;
pll_reset(priv,fine_tune);
if(tv_param->tlang==-1){
mp_msg(MSGT_TV,MSGL_INFO,MSGTR_TV_TTSupportedLanguages);
for(i=0; tt_languages[i].lang_code; i++){
mp_msg(MSGT_TV,MSGL_INFO," %3d %s\n",
tt_languages[i].lang_code, tt_languages[i].lang_name);
}
mp_msg(MSGT_TV,MSGL_INFO," %3d %s\n",
tt_languages[i].lang_code, tt_languages[i].lang_name);
}else{
for(i=0; tt_languages[i].lang_code; i++){
if(tt_languages[i].lang_code==tv_param->tlang)
break;
}
if (priv->primary_language!=tt_languages[i].lang_code){
mp_msg(MSGT_TV,MSGL_INFO,MSGTR_TV_TTSelectedLanguage,
tt_languages[i].lang_name);
priv->primary_language=tt_languages[i].lang_code;
}
}
pthread_mutex_unlock(&(priv->buffer_mutex));
return TVI_CONTROL_TRUE;
}