summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvoroshil <voroshil@b3059339-0415-0410-9bf9-f77b7e298cf2>2007-08-31 16:53:27 +0000
committervoroshil <voroshil@b3059339-0415-0410-9bf9-f77b7e298cf2>2007-08-31 16:53:27 +0000
commit374e9dd5bacb689b4ba4f3b85af5f21612604f01 (patch)
treec553335a2cf8da968cbf2ec5d5186c842d62c15d
parent503a85926f925b84a4274328b39304cea4361ca8 (diff)
downloadmpv-374e9dd5bacb689b4ba4f3b85af5f21612604f01.tar.bz2
mpv-374e9dd5bacb689b4ba4f3b85af5f21612604f01.tar.xz
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
-rw-r--r--DOCS/man/en/mplayer.16
-rw-r--r--cfg-common.h1
-rw-r--r--help/help_mp-en.h2
-rw-r--r--stream/stream_tv.c1
-rw-r--r--stream/tv.h6
-rw-r--r--stream/tvi_vbi.c221
6 files changed, 216 insertions, 21 deletions
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index cfc7563bcd..1a2e94bbf4 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -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
diff --git a/cfg-common.h b/cfg-common.h
index 7b5ff29cb8..cfaa4ee66f 100644
--- a/cfg-common.h
+++ b/cfg-common.h
@@ -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}
diff --git a/help/help_mp-en.h b/help/help_mp-en.h
index 5f70a615e4..a764263a83 100644
--- a/help/help_mp-en.h
+++ b/help/help_mp-en.h
@@ -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"
diff --git a/stream/stream_tv.c b/stream/stream_tv.c
index ccad96eb20..6d8967c069 100644
--- a/stream/stream_tv.c
+++ b/stream/stream_tv.c
@@ -75,6 +75,7 @@ tv_param_t stream_tv_defaults = {
NULL, //tdevice
0, //tformat
100, //tpage
+ 0, //tlang
0, //scan_autostart
50, //scan_threshold
diff --git a/stream/tv.h b/stream/tv.h
index 98f9417f2e..d35b78e9bb 100644
--- a/stream/tv.h
+++ b/stream/tv.h
@@ -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
diff --git a/stream/tvi_vbi.c b/stream/tvi_vbi.c
index 50c5943174..f5513528d8 100644
--- a/stream/tvi_vbi.c
+++ b/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));
@@ -1119,6 +1240,46 @@ static int decode_pkt27(priv_vbi_t* priv,unsigned char* data,int magAddr){
}
/**
+ * \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
* \param buf raw vbi data (one line of frame)
@@ -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;
}