diff options
author | voroshil <voroshil@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2007-06-10 00:06:12 +0000 |
---|---|---|
committer | voroshil <voroshil@b3059339-0415-0410-9bf9-f77b7e298cf2> | 2007-06-10 00:06:12 +0000 |
commit | 83a2c50ef9ef648b576bf4299765c73212d1f480 (patch) | |
tree | ab09f836c3ca91641c96b0630b2b2f479a3a6c2f | |
parent | 990b33b1c28d6b604a85e588689ad7fb6de59354 (diff) | |
download | mpv-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-- | Changelog | 1 | ||||
-rw-r--r-- | DOCS/man/en/mplayer.1 | 26 | ||||
-rw-r--r-- | DOCS/tech/MAINTAINERS | 1 | ||||
-rw-r--r-- | DOCS/tech/slave.txt | 19 | ||||
-rw-r--r-- | cfg-common.h | 5 | ||||
-rw-r--r-- | command.c | 149 | ||||
-rwxr-xr-x | configure | 30 | ||||
-rw-r--r-- | input/input.c | 10 | ||||
-rw-r--r-- | input/input.h | 2 | ||||
-rw-r--r-- | libvo/sub.c | 130 | ||||
-rw-r--r-- | libvo/sub.h | 10 | ||||
-rw-r--r-- | mpcommon.c | 31 | ||||
-rw-r--r-- | mplayer.c | 13 | ||||
-rw-r--r-- | spudec.c | 115 | ||||
-rw-r--r-- | spudec.h | 3 | ||||
-rw-r--r-- | stream/Makefile | 1 | ||||
-rw-r--r-- | stream/tv.c | 75 | ||||
-rw-r--r-- | stream/tv.h | 59 | ||||
-rw-r--r-- | stream/tvi_vbi.c | 1197 | ||||
-rw-r--r-- | stream/tvi_vbi.h | 75 |
20 files changed, 1950 insertions, 2 deletions
@@ -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} }; @@ -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: @@ -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 +} @@ -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(); } @@ -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 @@ -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)); |