summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvoroshil <voroshil@b3059339-0415-0410-9bf9-f77b7e298cf2>2007-06-10 00:06:12 +0000
committervoroshil <voroshil@b3059339-0415-0410-9bf9-f77b7e298cf2>2007-06-10 00:06:12 +0000
commit83a2c50ef9ef648b576bf4299765c73212d1f480 (patch)
treeab09f836c3ca91641c96b0630b2b2f479a3a6c2f
parent990b33b1c28d6b604a85e588689ad7fb6de59354 (diff)
downloadmpv-83a2c50ef9ef648b576bf4299765c73212d1f480.tar.bz2
mpv-83a2c50ef9ef648b576bf4299765c73212d1f480.tar.xz
Teletext support for tv:// (v4l and v4l2 only)
modified patch from Otvos Attila oattila at chello dot hu Module uses zvbi library for all low-level VBI operations (like I/O with vbi device, converting vbi pages into usefull vbi_page stuctures, rendering them into RGB32 images). All teletext related stuff (except properties, slave commands and rendering osd in text mode or RGB32 rendered teletext pages in spu mode) is implemented in tvi_vbi.c New properties: teletext_page - switching between pages teletext_mode - switch between on/off/opaque/transparent modes teletext_format - (currently read-only) allows to get format info (black/white,gray,text) teletext_half_page - trivial zooming (displaying top/bottom half of teletext page) New slave commands: teletext_add_dec - user interface for jumping to any page by editing page number interactively teletext_go_link - goes though links, specified on current page git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@23530 b3059339-0415-0410-9bf9-f77b7e298cf2
-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