# HG changeset patch # User voroshil # Date 1188579207 0 # Node ID ca7ee5c1b88d0b63280aea99bf2d86934c4a8c5b # Parent 53f2436d68d7ec79998437fa101451abf96f16b5 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. diff -r 53f2436d68d7 -r ca7ee5c1b88d DOCS/man/en/mplayer.1 --- a/DOCS/man/en/mplayer.1 Fri Aug 31 14:57:50 2007 +0000 +++ b/DOCS/man/en/mplayer.1 Fri Aug 31 16:53:27 2007 +0000 @@ -1896,6 +1896,12 @@ .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 -r 53f2436d68d7 -r ca7ee5c1b88d cfg-common.h --- a/cfg-common.h Fri Aug 31 14:57:50 2007 +0000 +++ b/cfg-common.h Fri Aug 31 16:53:27 2007 +0000 @@ -464,6 +464,7 @@ {"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 -r 53f2436d68d7 -r ca7ee5c1b88d help/help_mp-en.h --- a/help/help_mp-en.h Fri Aug 31 14:57:50 2007 +0000 +++ b/help/help_mp-en.h Fri Aug 31 16:53:27 2007 +0000 @@ -2097,3 +2097,5 @@ #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 -r 53f2436d68d7 -r ca7ee5c1b88d stream/stream_tv.c --- a/stream/stream_tv.c Fri Aug 31 14:57:50 2007 +0000 +++ b/stream/stream_tv.c Fri Aug 31 16:53:27 2007 +0000 @@ -75,6 +75,7 @@ NULL, //tdevice 0, //tformat 100, //tpage + 0, //tlang 0, //scan_autostart 50, //scan_threshold diff -r 53f2436d68d7 -r ca7ee5c1b88d stream/tv.h --- a/stream/tv.h Fri Aug 31 14:57:50 2007 +0000 +++ b/stream/tv.h Fri Aug 31 16:53:27 2007 +0000 @@ -50,6 +50,7 @@ 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 @@ 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_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 -r 53f2436d68d7 -r ca7ee5c1b88d stream/tvi_vbi.c --- a/stream/tvi_vbi.c Fri Aug 31 14:57:50 2007 +0000 +++ b/stream/tvi_vbi.c Fri Aug 31 16:53:27 2007 +0000 @@ -103,7 +103,6 @@ typedef struct mag_s{ tt_page* pt; int order; - int lang; } mag_t; typedef struct { @@ -116,6 +115,8 @@ 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 @@ {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 @@ } 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 @@ /** * \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;row0x3f) 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 @@ 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 @@ 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;imag[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 @@ } /** + * \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 @@ 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 @@ 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 @@ 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; }