mirror of
https://github.com/mpv-player/mpv
synced 2025-01-01 04:36:24 +01:00
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:
parent
503a85926f
commit
374e9dd5ba
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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"
|
||||
|
@ -75,6 +75,7 @@ tv_param_t stream_tv_defaults = {
|
||||
NULL, //tdevice
|
||||
0, //tformat
|
||||
100, //tpage
|
||||
0, //tlang
|
||||
|
||||
0, //scan_autostart
|
||||
50, //scan_threshold
|
||||
|
@ -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
|
||||
|
221
stream/tvi_vbi.c
221
stream/tvi_vbi.c
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user