summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog1
-rw-r--r--DOCS/man/en/mplayer.126
-rw-r--r--DOCS/tech/MAINTAINERS1
-rw-r--r--DOCS/tech/slave.txt19
-rw-r--r--cfg-common.h5
-rw-r--r--command.c149
-rwxr-xr-xconfigure30
-rw-r--r--input/input.c10
-rw-r--r--input/input.h2
-rw-r--r--libvo/sub.c130
-rw-r--r--libvo/sub.h10
-rw-r--r--mpcommon.c31
-rw-r--r--mplayer.c13
-rw-r--r--spudec.c115
-rw-r--r--spudec.h3
-rw-r--r--stream/Makefile1
-rw-r--r--stream/tv.c75
-rw-r--r--stream/tv.h59
-rw-r--r--stream/tvi_vbi.c1197
-rw-r--r--stream/tvi_vbi.h75
20 files changed, 1950 insertions, 2 deletions
diff --git a/Changelog b/Changelog
index be796a0245..db40f27ac4 100644
--- a/Changelog
+++ b/Changelog
@@ -51,6 +51,7 @@ MPlayer (1.0)
* support H.264 over RTSP
* "device" and "adevice" suboptions now works for *BSD BT848 tv driver too
* dvdnav:// now depends on mplayer's fork of libdvdnav
+ * Teletext support for tv:// (v4l and v4l2 only)
FFmpeg/libavcodec:
* Intel Music coder audio decoder
diff --git a/DOCS/man/en/mplayer.1 b/DOCS/man/en/mplayer.1
index 2fb65fedc8..d60c50837a 100644
--- a/DOCS/man/en/mplayer.1
+++ b/DOCS/man/en/mplayer.1
@@ -421,6 +421,26 @@ Confirm choice.
.PP
.RS
.
+(The following keys are only valid if teletext support is enabled during
+compilation: they are used for controlling TV teletext)
+.RE
+.PP
+.PD 0
+.RS
+.IPs "X"
+Switch teletext between on, off and transparent mode.
+.IPs "Q"
+Next teletext page.
+.IPs "W"
+Previous teletext page.
+.IPs "E"
+In text mode flips top or bottom piece of page otherwise
+zooms teletext page: top or bottom or normal.
+.RE
+.PD 1
+.PP
+.RS
+.
.TP
.B mouse control
.PD 0
@@ -1851,6 +1871,12 @@ MJPEG compression:
.IPs quality=<0\-100>
Choose the quality of the JPEG compression
(< 60 recommended for full size).
+.IPs tdevice=<value> (default: none)
+Specify TV teletext device (example: /dev/\:vbi0).
+.IPs tformat=<text|bw|gray|color> (default: gray)
+Specify TV teletext display mode. (Note: color mode requires color SPU support.)
+.IPs tpage=<100-999> (default: 100)
+Specify starting TV teletext page number .
.RE
.
.TP
diff --git a/DOCS/tech/MAINTAINERS b/DOCS/tech/MAINTAINERS
index bddb74f2e8..a0b3c4832a 100644
--- a/DOCS/tech/MAINTAINERS
+++ b/DOCS/tech/MAINTAINERS
@@ -77,6 +77,7 @@ MPlayer code:
* libmpdemux: Roberto Togni, Nico Sabbi
* libmpcodecs: Roberto Togni
* TV input/capture: Vladimir Voroshilov
+ * TV teletext: Vladimir Voroshilov
* network streaming: Roberto Togni, Nico Sabbi, Benjamin Zores
* DVD/VOB subtitles: None
* config files & commandline parser: Alban Bedel
diff --git a/DOCS/tech/slave.txt b/DOCS/tech/slave.txt
index 09e1ef31ea..b1d1158ebb 100644
--- a/DOCS/tech/slave.txt
+++ b/DOCS/tech/slave.txt
@@ -314,6 +314,19 @@ switch_vsync [value]
Toggle vsync (1 == on, 0 == off). If [value] is not provided,
vsync status is inverted.
+teletext_add_dec <value>
+ On/off teletext page number editing mode and append given digit to
+ previously entered one
+ 0..9 - append apropriate digit (enables editing mode if called from normal mode, and
+ switches to normal mode when third digit is entered.
+ - - delete last digit from page number (backspace amulation, works only in page number
+ editing mode)
+
+teletext_go_link <value>
+ Follow given links on current teletext page
+ 0 - go to initial page (specified by -tv tpage= parameter)
+ 1..6 - follow given link
+
tv_step_channel <channel>
Select next/previous TV channel.
@@ -446,4 +459,8 @@ tv_brightness int -100 100 X X X
tv_contrast int -100 100 X X X
tv_saturation int -100 100 X X X
tv_hue int -100 100 X X X
-
+teletext_page int 100 999 X X X
+teletext_mode int 0 3 X X X 0 - off, 1 - opaque, 2 - transparent,
+ 3 - transparent inverted (bw format)
+teletext_format int 0 3 X 0 - text, 1 - b/w, 2 - gray, 3 - color
+teletext_half_page int 0 2 X X X 0 - off, 1 - top half, 2- bottom half
diff --git a/cfg-common.h b/cfg-common.h
index 234b6ab9e2..2f32235b49 100644
--- a/cfg-common.h
+++ b/cfg-common.h
@@ -460,6 +460,11 @@ m_option_t tvopts_conf[]={
#endif
{"adevice", &tv_param_adevice, CONF_TYPE_STRING, 0, 0, 0, NULL},
#endif
+#ifdef HAVE_TV_TELETEXT
+ {"tdevice", &tv_param_tdevice, CONF_TYPE_STRING, 0, 0, 0, NULL},
+ {"tformat", &tv_param_tformat, CONF_TYPE_STRING, 0, 0, 0, NULL},
+ {"tpage", &tv_param_tpage, CONF_TYPE_INT, CONF_RANGE, 100, 999, NULL},
+#endif
{"audioid", &tv_param_audio_id, CONF_TYPE_INT, CONF_RANGE, 0, 9, NULL},
{NULL, NULL, 0, 0, 0, 0, NULL}
};
diff --git a/command.c b/command.c
index ca7338004d..5466176741 100644
--- a/command.c
+++ b/command.c
@@ -1415,6 +1415,134 @@ static int mp_property_tv_color(m_option_t * prop, int action, void *arg,
#endif
+#ifdef HAVE_TV_TELETEXT
+/// teletext page (RW)
+static int mp_property_teletext_page(m_option_t * prop, int action, void *arg,
+ MPContext * mpctx)
+{
+ int val,result;
+ tvi_handle_t *tvh = mpctx->demuxer->priv;
+ if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh || !tvh->priv_vbi)
+ return M_PROPERTY_UNAVAILABLE;
+
+ switch (action) {
+ case M_PROPERTY_SET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ M_PROPERTY_CLAMP(prop, *(int *) arg);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_SET_PAGE, arg);
+ break;
+ case M_PROPERTY_GET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_GET_PAGE, arg);
+ break;
+ case M_PROPERTY_STEP_UP:
+ case M_PROPERTY_STEP_DOWN:
+ val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_STEP_PAGE, &val);
+ break;
+ default:
+ return M_PROPERTY_NOT_IMPLEMENTED;
+ }
+ return (result==TVI_CONTROL_TRUE?M_PROPERTY_OK:M_PROPERTY_ERROR);
+}
+/// VBI teletext mode (RW)
+static int mp_property_teletext_mode(m_option_t * prop, int action, void *arg,
+ MPContext * mpctx)
+{
+ int val,result;
+ tvi_handle_t *tvh = mpctx->demuxer->priv;
+ if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh || !tvh->priv_vbi)
+ return M_PROPERTY_UNAVAILABLE;
+
+ switch (action) {
+ case M_PROPERTY_SET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ M_PROPERTY_CLAMP(prop, *(int *) arg);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_SET_MODE, arg);
+ break;
+ case M_PROPERTY_GET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_GET_MODE, arg);
+ break;
+ case M_PROPERTY_STEP_UP:
+ case M_PROPERTY_STEP_DOWN:
+ val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_STEP_MODE, &val);
+ break;
+ default:
+ return M_PROPERTY_NOT_IMPLEMENTED;
+ }
+ return (result==TVI_CONTROL_TRUE?M_PROPERTY_OK:M_PROPERTY_ERROR);
+}
+/// VBI teletext format (R)
+static int mp_property_teletext_format(m_option_t * prop, int action, void *arg,
+ MPContext * mpctx)
+{
+ int val,result;
+ tvi_handle_t *tvh = mpctx->demuxer->priv;
+ if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh || !tvh->priv_vbi)
+ return M_PROPERTY_UNAVAILABLE;
+
+ switch (action) {
+ case M_PROPERTY_GET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_GET_FORMAT, arg);
+ break;
+ case M_PROPERTY_SET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ M_PROPERTY_CLAMP(prop, *(int *) arg);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_SET_FORMAT, arg);
+ break;
+ case M_PROPERTY_STEP_UP:
+ case M_PROPERTY_STEP_DOWN:
+ val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_STEP_FORMAT, &val);
+ break;
+ default:
+ return M_PROPERTY_NOT_IMPLEMENTED;
+ }
+ return (result==TVI_CONTROL_TRUE?M_PROPERTY_OK:M_PROPERTY_ERROR);
+}
+
+/// VBI teletext half-page mode (RW)
+static int mp_property_teletext_half_page(m_option_t * prop, int action, void *arg,
+ MPContext * mpctx)
+{
+ int val,result;
+ tvi_handle_t *tvh = mpctx->demuxer->priv;
+ if (mpctx->demuxer->type != DEMUXER_TYPE_TV || !tvh || !tvh->priv_vbi)
+ return M_PROPERTY_UNAVAILABLE;
+
+ switch (action) {
+ case M_PROPERTY_GET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_GET_HALF_PAGE, arg);
+ break;
+ case M_PROPERTY_SET:
+ if (!arg)
+ return M_PROPERTY_ERROR;
+ M_PROPERTY_CLAMP(prop, *(int *) arg);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_SET_HALF_PAGE, arg);
+ break;
+ case M_PROPERTY_STEP_UP:
+ case M_PROPERTY_STEP_DOWN:
+ val = (arg ? *(int *) arg : 1) * (action == M_PROPERTY_STEP_DOWN ? -1 : 1);
+ result=tv_teletext_control(tvh, TVI_CONTROL_VBI_STEP_HALF_PAGE, &val);
+ break;
+ default:
+ return M_PROPERTY_NOT_IMPLEMENTED;
+ }
+ return (result==TVI_CONTROL_TRUE?M_PROPERTY_OK:M_PROPERTY_ERROR);
+}
+#endif /* HAVE_TV_TELETEXT */
+
///@}
/// All properties available in MPlayer.
@@ -1540,6 +1668,17 @@ static m_option_t mp_properties[] = {
M_OPT_RANGE, -100, 100, (void *) TV_COLOR_HUE },
#endif
+#ifdef HAVE_TV_TELETEXT
+ { "teletext_page", mp_property_teletext_page, CONF_TYPE_INT,
+ M_OPT_RANGE, -999, 999, NULL },
+ { "teletext_mode", mp_property_teletext_mode, CONF_TYPE_INT,
+ M_OPT_RANGE, 0, 3, NULL },
+ { "teletext_format", mp_property_teletext_format, CONF_TYPE_INT,
+ M_OPT_RANGE, 0, 3, NULL },
+ { "teletext_half_page", mp_property_teletext_half_page, CONF_TYPE_INT,
+ M_OPT_RANGE, 0, 2, NULL },
+#endif
+
{ NULL, NULL, NULL, 0, 0, 0, NULL }
};
@@ -2233,6 +2372,16 @@ int run_command(MPContext * mpctx, mp_cmd_t * cmd)
if (mpctx->file_format == DEMUXER_TYPE_TV)
tv_step_chanlist((tvi_handle_t *) (mpctx->demuxer->priv));
break;
+#ifdef HAVE_TV_TELETEXT
+ case MP_CMD_TV_TELETEXT_ADD_DEC:
+ if (mpctx->file_format == DEMUXER_TYPE_TV)
+ tv_teletext_add_dec((tvi_handle_t *) (mpctx->demuxer->priv),cmd->args[0].v.s);
+ break;
+ case MP_CMD_TV_TELETEXT_GO_LINK:
+ if (mpctx->file_format == DEMUXER_TYPE_TV)
+ tv_teletext_go_link((tvi_handle_t *) (mpctx->demuxer->priv),cmd->args[0].v.i);
+ break;
+#endif /* HAVE_TV_TELETEXT */
#endif /* USE_TV */
case MP_CMD_SUB_LOAD:
diff --git a/configure b/configure
index 00bc302f08..5b54801889 100755
--- a/configure
+++ b/configure
@@ -240,6 +240,7 @@ Optional features:
--disable-tv-v4l1 disable Video4Linux TV interface [autodetect]
--disable-tv-v4l2 disable Video4Linux2 TV interface [autodetect]
--disable-tv-bsdbt848 disable BSD BT848 interface [autodetect]
+ --disable-tv-teletex disable TV teletext interface [autodetect]
--disable-pvr disable Video4Linux2 MPEG PVR [autodetect]
--disable-rtc disable RTC (/dev/rtc) on Linux [autodetect]
--disable-network disable networking [enable]
@@ -588,6 +589,7 @@ _tv=yes
_tv_v4l1=auto
_tv_v4l2=auto
_tv_bsdbt848=auto
+_tv_teletext=auto
_pvr=auto
_network=yes
_winsock2=auto
@@ -935,6 +937,8 @@ for ac_option do
--disable-tv-v4l1) _tv_v4l1=no ;;
--enable-tv-v4l2) _tv_v4l2=yes ;;
--disable-tv-v4l2) _tv_v4l2=no ;;
+ --enable-tv-teletext) _tv_teletext=yes ;;
+ --disable-tv-teletext) _tv_teletext=no ;;
--enable-radio) _radio=yes ;;
--enable-radio-capture) _radio_capture=yes ;;
--disable-radio-capture) _radio_capture=no ;;
@@ -6685,6 +6689,28 @@ else
fi
echores "$_tv_v4l2"
+echocheck "TV teletext interface"
+if test "$_tv_teletext" = auto ; then
+ _tv_teletext=no
+ if test linux ; then
+ cat > $TMPC <<EOF
+#include <stdlib.h>
+#include <libzvbi.h>
+int main(void) { return 0; }
+EOF
+ cc_check && _tv_teletext=yes
+ fi
+fi
+if test "$_tv_teletext" = yes ; then
+ _def_tv_teletext='#define HAVE_TV_TELETEXT 1'
+ _ld_extra="$_ld_extra -lzvbi"
+ _inputmodules="tv-teletext $_inputmodules"
+else
+ _noinputmodules="tv-teletext $_noinputmodules"
+ _def_tv_teletext='#undef HAVE_TV_TELETEXT'
+fi
+echores "$_tv_teletext"
+
echocheck "Radio interface"
if test "$_radio" = yes ; then
@@ -7546,6 +7572,7 @@ TV_V4L = $_tv_v4l
TV_V4L1 = $_tv_v4l1
TV_V4L2 = $_tv_v4l2
TV_BSDBT848 = $_tv_bsdbt848
+TV_TELETEXT = $_tv_teletext
AUDIO_INPUT = $_audio_input
PVR = $_pvr
VCD = $_vcd
@@ -8098,6 +8125,9 @@ $_def_ioctl_bt848_h_name
/* Enable *BSD BrookTree TV interface support */
$_def_tv_bsdbt848
+/* Enable TV Teletext Interface support */
+$_def_tv_teletext
+
/* Enable Radio Interface support */
$_def_radio
diff --git a/input/input.c b/input/input.c
index 0697ec8719..7086782198 100644
--- a/input/input.c
+++ b/input/input.c
@@ -136,6 +136,10 @@ static mp_cmd_t mp_cmds[] = {
{ MP_CMD_LOADLIST, "loadlist", 1, { {MP_CMD_ARG_STRING, {0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}} } },
{ MP_CMD_RUN, "run", 1, { {MP_CMD_ARG_STRING,{0}}, {-1,{0}} } },
{ MP_CMD_VF_CHANGE_RECTANGLE, "change_rectangle", 2, { {MP_CMD_ARG_INT,{0}}, {MP_CMD_ARG_INT,{0}}, {-1,{0}}}},
+#ifdef HAVE_TV_TELETEXT
+ { MP_CMD_TV_TELETEXT_ADD_DEC, "teletext_add_dec", 1, { {MP_CMD_ARG_STRING,{0}}, {-1,{0}} } },
+ { MP_CMD_TV_TELETEXT_GO_LINK, "teletext_go_link",1, { { MP_CMD_ARG_INT ,{0}}, { MP_CMD_ARG_INT ,{0}}, {-1,{0}} } },
+#endif
#ifdef HAVE_NEW_GUI
{ MP_CMD_GUI_LOADFILE, "gui_loadfile", 0, { {-1,{0}} } },
@@ -386,6 +390,12 @@ static mp_cmd_bind_t def_cmd_binds[] = {
{ { 'n', 0 }, "tv_step_norm" },
{ { 'u', 0 }, "tv_step_chanlist" },
#endif
+#ifdef HAVE_TV_TELETEXT
+ { { 'X', 0 }, "step_property teletext_mode 1" },
+ { { 'E', 0 }, "step_property teletext_half_page 1" },
+ { { 'W', 0 }, "step_property teletext_page 1" },
+ { { 'Q', 0 }, "step_property teletext_page -1" },
+#endif
#ifdef HAVE_JOYSTICK
{ { JOY_AXIS0_PLUS, 0 }, "seek 10" },
{ { JOY_AXIS0_MINUS, 0 }, "seek -10" },
diff --git a/input/input.h b/input/input.h
index 8017221d7d..4fb51422b1 100644
--- a/input/input.h
+++ b/input/input.h
@@ -93,6 +93,8 @@
#define MP_CMD_STEP_PROPERTY 91
#define MP_CMD_RADIO_STEP_FREQ 92
#define MP_CMD_TV_STEP_FREQ 93
+#define MP_CMD_TV_TELETEXT_ADD_DEC 94
+#define MP_CMD_TV_TELETEXT_GO_LINK 95
#define MP_CMD_GUI_EVENTS 5000
#define MP_CMD_GUI_LOADFILE 5001
diff --git a/libvo/sub.c b/libvo/sub.c
index 7a7069d12d..c901e28fe5 100644
--- a/libvo/sub.c
+++ b/libvo/sub.c
@@ -67,6 +67,10 @@ font_desc_t* vo_font=NULL;
font_desc_t* sub_font=NULL;
unsigned char* vo_osd_text=NULL;
+#ifdef HAVE_TV_TELETEXT
+unsigned char* vo_osd_teletex_text=NULL;
+int vo_osd_teletext_flip = 0;
+#endif
int sub_unicode=0;
int sub_utf8=0;
int sub_pos=100;
@@ -229,6 +233,121 @@ inline static void vo_update_nav (mp_osd_obj_t *obj, int dxs, int dys) {
}
#endif
+#ifdef HAVE_TV_TELETEXT
+inline static void vo_update_text_teletext(mp_osd_obj_t *obj, int dxs, int dys)
+{
+ char *p,*pe;
+ char line[256];
+ int h=0,w=0,i,c,w1,font,lines,endline;
+ int x1,y1,x2,y2;
+ unsigned char *t;
+
+ obj->flags|=OSDFLAG_CHANGED|OSDFLAG_VISIBLE;
+
+ if (vo_osd_teletex_text==NULL) {
+ obj->flags&=~OSDFLAG_VISIBLE;
+ return;
+ }
+ p=vo_osd_teletex_text;
+ lines=0;
+ endline=0;
+ do { // calculate teletext size
+ memset(line,0,sizeof(line));
+ if(pe=strchr(p,'\n')) {
+ if(pe-p>sizeof(line))
+ strncpy(line,p,sizeof(line));
+ else
+ strncpy(line,p,pe-p);
+ }
+ else
+ strncpy(line,p,sizeof(line));
+
+ t=line;
+ w1=0;
+ while (*t) {
+ c = utf8_get_char(&t);
+ if (!c) c++; // avoid UCS 0
+ render_one_glyph(vo_font, c);
+ w1+=vo_font->width[c]+vo_font->charspace;
+ }
+ h+=vo_font->height;
+ if(w1>w) w=w1;
+ if(pe) pe++;
+ p=pe;
+ lines++;
+ if(h+vo_font->height*2>dys && endline==0) endline=lines;
+ } while (pe!=NULL);
+ h=h+vo_font->height;
+ w=w-vo_font->charspace;
+ if (w>dxs){
+ // calculate bbox size
+ x1=0;
+ x2=dxs;
+ }
+ else
+ {
+ x1=(dxs-w)/2;
+ x2=x1+w+1;
+ }
+ if (h>dys){
+ y1=0;
+ y2=dys;
+ }
+ else {
+ y1=0;
+ y2=y1+h+1;
+ }
+ obj->bbox.x1 = obj->x = x1;
+ obj->bbox.y1 = obj->y = y1;
+ obj->bbox.x2 = x2;
+ obj->bbox.y2 = y2;
+ obj->flags |= OSDFLAG_BBOX;
+ alloc_buf(obj);
+ p=vo_osd_teletex_text;
+ h=y1;
+ if (vo_osd_teletext_flip)
+ endline=lines-endline; // bottom page
+ else
+ endline=0; // top page
+ lines=0;
+ do { // show teletext page
+ memset(line,0,sizeof(line));
+ if(pe=strchr(p,'\n')) {
+ if(pe-p>sizeof(line))
+ strncpy(line,p,sizeof(line));
+ else
+ strncpy(line,p,pe-p);}
+ else
+ strncpy(line,p,sizeof(line));
+
+ t=line;
+
+ w1=x1;
+ if(lines==0 || endline==0 || lines>endline) {
+ while (*t) {
+ c = utf8_get_char(&t);
+ if (!c) c++; // avoid UCS 0
+ render_one_glyph(vo_font, c);
+ if(w1+vo_font->width[c]>=x2) break;
+ if ((font=vo_font->font[c])>=0)
+ draw_alpha_buf(obj,w1,h,
+ vo_font->width[c],
+ vo_font->pic_a[font]->h,
+ vo_font->pic_b[font]->bmp+vo_font->start[c],
+ vo_font->pic_a[font]->bmp+vo_font->start[c],
+ vo_font->pic_a[font]->w);
+ w1+=vo_font->width[c]+vo_font->charspace;
+ }
+ h+=vo_font->height;
+ }
+ if(pe) pe++;
+ p=pe;
+ if(h+vo_font->height*2>dys) pe=NULL;
+ lines++;
+ } while (pe!=NULL);
+}
+#endif
+
int vo_osd_progbar_type=-1;
int vo_osd_progbar_value=100; // 0..256
@@ -859,6 +978,11 @@ int vo_update_osd(int dxs,int dys){
case OSDTYPE_SUBTITLE:
vo_update_text_sub(obj,dxs,dys);
break;
+#ifdef HAVE_TV_TELETEXT
+ case OSDTYPE_TELETEXT:
+ vo_update_text_teletext(obj,dxs,dys);
+ break;
+#endif
case OSDTYPE_PROGBAR:
vo_update_text_progbar(obj,dxs,dys);
break;
@@ -926,6 +1050,9 @@ void vo_init_osd(void){
#ifdef USE_DVDNAV
new_osd_obj(OSDTYPE_DVDNAV);
#endif
+#if HAVE_TV_TELETEXT
+ new_osd_obj(OSDTYPE_TELETEXT);
+#endif
#ifdef HAVE_FREETYPE
force_load_font = 1;
#endif
@@ -964,6 +1091,9 @@ void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h,
#ifdef USE_DVDNAV
case OSDTYPE_DVDNAV:
#endif
+#ifdef HAVE_TV_TELETEXT
+ case OSDTYPE_TELETEXT:
+#endif
case OSDTYPE_OSD:
case OSDTYPE_SUBTITLE:
case OSDTYPE_PROGBAR:
diff --git a/libvo/sub.h b/libvo/sub.h
index 45d39bbd6b..efc0277ba4 100644
--- a/libvo/sub.h
+++ b/libvo/sub.h
@@ -2,6 +2,10 @@
#ifndef __MPLAYER_SUB_H
#define __MPLAYER_SUB_H
+#ifdef HAVE_TV_TELETEXT
+#include "libmpcodecs/mp_image.h"
+#endif
+
typedef struct mp_osd_bbox_s {
int x1,y1,x2,y2;
} mp_osd_bbox_t;
@@ -11,6 +15,7 @@ typedef struct mp_osd_bbox_s {
#define OSDTYPE_PROGBAR 3
#define OSDTYPE_SPU 4
#define OSDTYPE_DVDNAV 5
+#define OSDTYPE_TELETEXT 6
#define OSDFLAG_VISIBLE 1
#define OSDFLAG_CHANGED 2
@@ -64,6 +69,11 @@ extern subtitle* vo_sub;
extern unsigned char* vo_osd_text;
+#ifdef HAVE_TV_TELETEXT
+extern unsigned char* vo_osd_teletex_text;
+extern int vo_osd_teletext_flip;
+#endif
+
extern int vo_osd_progbar_type;
extern int vo_osd_progbar_value; // 0..255
diff --git a/mpcommon.c b/mpcommon.c
index 9a5c52accc..7734c443d0 100644
--- a/mpcommon.c
+++ b/mpcommon.c
@@ -7,6 +7,9 @@
#include "libvo/video_out.h"
#include "spudec.h"
#include "vobsub.h"
+#ifdef HAVE_TV_TELETEXT
+#include "stream/tv.h"
+#endif
double sub_last_pts = -303;
@@ -138,3 +141,31 @@ void update_subtitles(sh_video_t *sh_video, demux_stream_t *d_dvdsub, int reset)
}
current_module=NULL;
}
+
+void update_teletext(sh_video_t *sh_video, demuxer_t *demuxer, int reset)
+{
+#ifdef HAVE_TV_TELETEXT
+ int half_page;
+ tvi_handle_t *tvh = demuxer->priv;
+ if (demuxer->type != DEMUXER_TYPE_TV) return;
+ if(!tvh) return;
+ if(vo_spudec) {
+ tv_teletext_img_t* img=tv_get_teletext_imgpage(tvh);
+ if(img!=NULL) {
+ spudec_heartbeat_teletext(vo_spudec, img);
+ if(img->canvas)
+ free(img->canvas);
+ free(img);
+ vo_osd_changed(OSDTYPE_SPU);
+ vo_osd_teletex_text=NULL;
+ vo_osd_changed(OSDTYPE_TELETEXT);
+ return;
+ }
+ vo_osd_changed(OSDTYPE_SPU);
+ }
+ vo_osd_teletex_text=tv_get_teletext_txtpage(tvh);
+ tv_teletext_control(tvh,TVI_CONTROL_VBI_GET_HALF_PAGE,&half_page);
+ vo_osd_teletext_flip=half_page;
+ vo_osd_changed(OSDTYPE_TELETEXT);
+#endif
+}
diff --git a/mplayer.c b/mplayer.c
index e79f2586aa..693b7ed353 100644
--- a/mplayer.c
+++ b/mplayer.c
@@ -1040,6 +1040,10 @@ void init_vo_spudec(void) {
spudec_set_font_factor(vo_spudec,font_factor);
}
+#ifdef HAVE_TV_TELETEXT
+ if (vo_spudec==NULL && mpctx->demuxer->type==DEMUXER_TYPE_TV)
+ vo_spudec=spudec_new_scaled(NULL, mpctx->sh_video->disp_w, mpctx->sh_video->disp_h);
+#endif
if (vo_spudec!=NULL)
inited_flags|=INITED_SPUDEC;
}
@@ -1622,6 +1626,7 @@ static int generate_video_frame(sh_video_t *sh_video, demux_stream_t *d_video)
decoded_frame = decode_video(sh_video, start, in_size, 0, pts);
if (decoded_frame) {
update_subtitles(sh_video, mpctx->d_sub, 0);
+ update_teletext(sh_video, mpctx->demuxer, 0);
update_osd_msg();
current_module = "filter video";
if (filter_video(sh_video, decoded_frame, sh_video->pts))
@@ -2036,6 +2041,7 @@ static double update_video(int *blit_frame)
++total_frame_cnt;
}
update_subtitles(sh_video, mpctx->d_sub, 0);
+ update_teletext(sh_video, mpctx->demuxer, 0);
update_osd_msg();
current_module = "decode_video";
decoded_frame = decode_video(sh_video, start, in_size, drop_frame,
@@ -2249,6 +2255,7 @@ static int seek(MPContext *mpctx, double amount, int style)
// be completely wrong (probably 0).
mpctx->sh_video->pts = mpctx->d_video->pts;
update_subtitles(mpctx->sh_video, mpctx->d_sub, 1);
+ update_teletext(mpctx->sh_video, mpctx->demuxer, 1);
}
if (mpctx->sh_audio) {
@@ -3123,7 +3130,11 @@ demux_info_print(mpctx->demuxer);
//================== Read SUBTITLES (DVD & TEXT) ==========================
if(vo_spudec==NULL && mpctx->sh_video &&
- (mpctx->stream->type==STREAMTYPE_DVD || mpctx->stream->type == STREAMTYPE_DVDNAV || mpctx->d_sub->id >= 0)){
+ (mpctx->stream->type==STREAMTYPE_DVD || mpctx->stream->type == STREAMTYPE_DVDNAV ||
+#ifdef HAVE_TV_TELETEXT
+ mpctx->demuxer->type==DEMUXER_TYPE_TV ||
+#endif
+ mpctx->d_sub->id >= 0)){
init_vo_spudec();
}
diff --git a/spudec.c b/spudec.c
index 451269a2e3..aaa9128eb3 100644
--- a/spudec.c
+++ b/spudec.c
@@ -29,6 +29,9 @@
#include "avutil.h"
#endif
#include "libswscale/swscale.h"
+#ifdef HAVE_TV_TELETEXT
+#include "stream/tv.h"
+#endif
/* Valid values for spu_aamode:
0: none (fastest, most ugly)
@@ -1185,3 +1188,115 @@ void spudec_set_hw_spu(void *this, vo_functions_t *hw_spu)
spu->hw_spu = hw_spu;
hw_spu->control(VOCTRL_SET_SPU_PALETTE,spu->global_palette);
}
+
+#ifdef HAVE_TV_TELETEXT
+#define VBI_R(rgba) (((rgba) >> 0) & 0xFF)
+#define VBI_G(rgba) (((rgba) >> 8) & 0xFF)
+#define VBI_B(rgba) (((rgba) >> 16) & 0xFF)
+#define VBI_A(rgba) (((rgba) >> 24) & 0xFF)
+
+
+static unsigned char rgbtoy(int r, int g, int b) {
+ int ret=(257*r+504*g+98*b+16000)/1000;
+ return ret & 0xff;
+}
+
+/// correction u and v planes half size
+#define SPU_DOUBLE_SIZE 1
+
+void alloc_images(spudec_handle_t* spu, int cmode) {
+
+ if (spu->image_size < spu->stride * spu->height) {
+ if (spu->image != NULL) {
+ free(spu->image);
+ spu->image_size = 0;
+ }
+ spu->image = malloc(2 * spu->stride * spu->height);
+ if (spu->image) {
+ spu->image_size = spu->stride * spu->height;
+ spu->aimage = spu->image + spu->image_size;
+ }
+ }
+}
+
+/**
+ Render from VBI_PIXFMT_RGBA32_LE to spu
+**/
+void spudec_heartbeat_teletext(void *this, void *imgptr)
+{
+ int px,py;
+ int grey,alpha,cy,cu,cv,alphauv;
+ uint32_t *canvas;
+ uint32_t *pin;
+ spudec_handle_t *spu = (spudec_handle_t*)this;
+ tv_teletext_img_t *img = (tv_teletext_img_t*)imgptr;
+ unsigned char *iptr;
+ unsigned char *aptr;
+ int h1 = 10;
+ int hs = 0;
+
+ if(!spu || !img)
+ return;
+ if(img->canvas==NULL) {
+ spudec_reset(spu);
+ if (spu->image)
+ free(spu->image);
+ spu->image=NULL;
+ spu->image_size = 0;
+ return;
+ }
+
+ if(img->half) h1=5; // top half page
+ if(img->half==2) hs=5; // bottom half page
+
+ spu->start_pts=0;
+ spu->end_pts=0;
+ spu->now_pts=1;
+ spu->orig_frame_width = img->columns*12; // 1 char width 12 pixel
+ spu->orig_frame_height = img->rows*h1; // 1 char height 10 pixel
+ spu->scaled_frame_width = 0;
+ spu->scaled_frame_height = 0;
+ spu->start_col = 0;
+ spu->end_col = img->columns*12;
+ spu->start_row = 0;
+ spu->end_row = img->rows*h1;
+ spu->height = img->rows*h1;
+ spu->width = img->columns*12;
+ spu->height = (spu->height+3)&(~3); // round to 4
+ spu->stride = (spu->width+7)&(~7); // round to 8
+
+ alloc_images(spu,img->tformat); // alloc images buffer
+ if (spu->image == NULL) {
+ spudec_reset(spu);
+ return;
+ }
+ canvas=img->canvas; // RGBA32_LE image
+ pin=canvas+(hs*img->columns*12*img->rows);
+ memset(spu->image,0,spu->image_size*2);
+
+ for(py=0;py<img->rows*h1;py++) {
+ iptr=spu->image+(py-hs)*spu->stride; // image ptr
+ aptr=spu->aimage+(py-hs)*spu->stride; // alpha ptr
+ for(px=0;px<img->columns*12;px++) {
+ grey=rgbtoy(VBI_R(*pin),VBI_G(*pin),VBI_B(*pin)); // RGB to Y
+ if(grey<=0x10) grey=0;
+ alpha=VBI_A(*pin);
+ switch (img->tformat) {
+ case 0x01: // BW
+ case 0x02: // Gray
+ case 0x03: // Color (not supported)
+ alpha=0x100-alpha;
+ if (grey + alpha > 255) grey = 256 - alpha;
+ break;
+ }
+ *iptr=grey; // store Y plane
+ *aptr=alpha; // store alpha
+ iptr++;
+ aptr++;
+ pin++;
+ }
+ }
+ spu->start_pts=0;
+ spu->end_pts=UINT_MAX;
+}
+#endif
diff --git a/spudec.h b/spudec.h
index 2e73ef5df8..d315be3d1b 100644
--- a/spudec.h
+++ b/spudec.h
@@ -20,5 +20,8 @@ int spudec_changed(void *this);
void spudec_calc_bbox(void *me, unsigned int dxs, unsigned int dys, unsigned int* bbox);
void spudec_draw_scaled(void *me, unsigned int dxs, unsigned int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride));
void spudec_set_forced_subs_only(void * const this, const unsigned int flag);
+#ifdef HAVE_TV_TELETEXT
+void spudec_heartbeat_teletext(void *this, void *imgptr);
+#endif
#endif
diff --git a/stream/Makefile b/stream/Makefile
index a5d7edcf37..1ea38018fa 100644
--- a/stream/Makefile
+++ b/stream/Makefile
@@ -51,6 +51,7 @@ SRCS_COMMON-$(TV) += stream_tv.c tv.c frequencies.c tvi_dummy.c
SRCS_COMMON-$(TV_BSDBT848) += tvi_bsdbt848.c
SRCS_COMMON-$(TV_V4L1) += tvi_v4l.c audio_in.c
SRCS_COMMON-$(TV_V4L2) += tvi_v4l2.c audio_in.c
+SRCS_COMMON-$(TV_TELETEXT) += tvi_vbi.c
SRCS_COMMON-$(VCD) += stream_vcd.c
SRCS_COMMON-$(VSTREAM) += stream_vstream.c
diff --git a/stream/tv.c b/stream/tv.c
index dcb96f1126..4133d04939 100644
--- a/stream/tv.c
+++ b/stream/tv.c
@@ -34,6 +34,10 @@
#include "frequencies.h"
+#ifdef HAVE_TV_TELETEXT
+#include "tvi_vbi.h"
+#endif
+
/* some default values */
int tv_param_audiorate = 44100;
int tv_param_noaudio = 0;
@@ -518,6 +522,9 @@ static demuxer_t* demux_open_tv(demuxer_t *demuxer)
tv_uninit(tvh);
return NULL;
}
+#ifdef HAVE_TV_TELETEXT
+ if(tvh->priv_vbi) teletext_control(tvh->priv_vbi,TVI_CONTROL_VBI_START,1); //arg must be not null
+#endif
funcs = tvh->functions;
demuxer->priv=tvh;
@@ -657,6 +664,12 @@ no_audio:
static void demux_close_tv(demuxer_t *demuxer)
{
tvi_handle_t *tvh=(tvi_handle_t*)(demuxer->priv);
+#ifdef HAVE_TV_TELETEXT
+ if(tvh->priv_vbi) {
+ teletext_uninit(tvh->priv_vbi);
+ tvh->priv_vbi=NULL;
+ }
+#endif
if (!tvh) return;
tvh->functions->uninit(tvh->priv);
demuxer->priv=NULL;
@@ -688,6 +701,10 @@ tvi_handle_t *tv_begin(void)
tvi_driver_list[i]->name,
tvi_driver_lis