diff options
-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)); 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) |