[MPlayer-cvslog] r23530 - in trunk: Changelog DOCS/man/en/mplayer.1 DOCS/tech/MAINTAINERS DOCS/tech/slave.txt cfg-common.h command.c configure input/input.c input/input.h libvo/sub.c libvo/sub.h mpcommon.c mplayer.c spudec.c spudec.h stream/Makefile stream/tv.c stream/tv.h stream/tvi_vbi.c stream/tvi_vbi.h
voroshil
subversion at mplayerhq.hu
Sun Jun 10 02:06:12 CEST 2007
Author: voroshil
Date: Sun Jun 10 02:06:12 2007
New Revision: 23530
Log:
Teletext support for tv:// (v4l and v4l2 only)
modified patch from Otvos Attila oattila at chello dot hu
Added:
trunk/stream/tvi_vbi.c (contents, props changed)
trunk/stream/tvi_vbi.h (contents, props changed)
Modified:
trunk/Changelog
trunk/DOCS/tech/MAINTAINERS
trunk/DOCS/tech/slave.txt
trunk/cfg-common.h
trunk/command.c
trunk/configure
trunk/input/input.c
trunk/input/input.h
trunk/libvo/sub.c
trunk/libvo/sub.h
trunk/mpcommon.c
trunk/mplayer.c
trunk/spudec.c
trunk/spudec.h
trunk/stream/Makefile
trunk/stream/tv.c
trunk/stream/tv.h
Changes in other areas also in this revision:
Modified:
trunk/DOCS/man/en/mplayer.1
Modified: trunk/Changelog
==============================================================================
--- trunk/Changelog (original)
+++ trunk/Changelog Sun Jun 10 02:06:12 2007
@@ -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
Modified: trunk/DOCS/tech/MAINTAINERS
==============================================================================
--- trunk/DOCS/tech/MAINTAINERS (original)
+++ trunk/DOCS/tech/MAINTAINERS Sun Jun 10 02:06:12 2007
@@ -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
Modified: trunk/DOCS/tech/slave.txt
==============================================================================
--- trunk/DOCS/tech/slave.txt (original)
+++ trunk/DOCS/tech/slave.txt Sun Jun 10 02:06:12 2007
@@ -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
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
Modified: trunk/cfg-common.h
==============================================================================
--- trunk/cfg-common.h (original)
+++ trunk/cfg-common.h Sun Jun 10 02:06:12 2007
@@ -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}
};
Modified: trunk/command.c
==============================================================================
--- trunk/command.c (original)
+++ trunk/command.c Sun Jun 10 02:06:12 2007
@@ -1415,6 +1415,134 @@ static int mp_property_tv_color(m_option
#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_cm
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:
Modified: trunk/configure
==============================================================================
--- trunk/configure (original)
+++ trunk/configure Sun Jun 10 02:06:12 2007
@@ -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
Modified: trunk/input/input.c
==============================================================================
--- trunk/input/input.c (original)
+++ trunk/input/input.c Sun Jun 10 02:06:12 2007
@@ -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" },
Modified: trunk/input/input.h
==============================================================================
--- trunk/input/input.h (original)
+++ trunk/input/input.h Sun Jun 10 02:06:12 2007
@@ -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
Modified: trunk/libvo/sub.c
==============================================================================
--- trunk/libvo/sub.c (original)
+++ trunk/libvo/sub.c Sun Jun 10 02:06:12 2007
@@ -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
}
#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 (
#ifdef USE_DVDNAV
case OSDTYPE_DVDNAV:
#endif
+#ifdef HAVE_TV_TELETEXT
+ case OSDTYPE_TELETEXT:
+#endif
case OSDTYPE_OSD:
case OSDTYPE_SUBTITLE:
case OSDTYPE_PROGBAR:
Modified: trunk/libvo/sub.h
==============================================================================
--- trunk/libvo/sub.h (original)
+++ trunk/libvo/sub.h Sun Jun 10 02:06:12 2007
@@ -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
Modified: trunk/mpcommon.c
==============================================================================
--- trunk/mpcommon.c (original)
+++ trunk/mpcommon.c Sun Jun 10 02:06:12 2007
@@ -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_vid
}
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
+}
Modified: trunk/mplayer.c
==============================================================================
--- trunk/mplayer.c (original)
+++ trunk/mplayer.c Sun Jun 10 02:06:12 2007
@@ -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
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_fra
++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
// 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();
}
Modified: trunk/spudec.c
==============================================================================
--- trunk/spudec.c (original)
+++ trunk/spudec.c Sun Jun 10 02:06:12 2007
@@ -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_fu
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
Modified: trunk/spudec.h
==============================================================================
--- trunk/spudec.h (original)
+++ trunk/spudec.h Sun Jun 10 02:06:12 2007
@@ -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
Modified: trunk/stream/Makefile
==============================================================================
--- trunk/stream/Makefile (original)
+++ trunk/stream/Makefile Sun Jun 10 02:06:12 2007
@@ -51,6 +51,7 @@ SRCS_COMMON-$(TV) += stre
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
Modified: trunk/stream/tv.c
==============================================================================
--- trunk/stream/tv.c (original)
+++ trunk/stream/tv.c Sun Jun 10 02:06:12 2007
@@ -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_
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_list[i]->author,
tvi_driver_list[i]->comment?tvi_driver_list[i]->comment:"");
+#ifdef HAVE_TV_TELETEXT
+ h->priv_vbi=teletext_init();
+#endif
+
return h;
}
}
@@ -773,6 +790,9 @@ int tv_set_freq(tvi_handle_t *tvh, unsig
mp_msg(MSGT_TV, MSGL_V, MSGTR_TV_CurrentFrequency,
freq, (float)freq/16);
}
+#ifdef HAVE_TV_TELETEXT
+ if (tvh->priv_vbi) teletext_control(tvh->priv_vbi,TVI_CONTROL_VBI_RESET,1); //arg must be not null
+#endif
return(1);
}
@@ -932,6 +952,9 @@ int tv_step_norm(tvi_handle_t *tvh)
return 0;
}
}
+#ifdef HAVE_TV_TELETEXT
+ if (tvh->priv_vbi) teletext_control(tvh->priv_vbi,TVI_CONTROL_VBI_RESET,1); //arg must be not null
+#endif
return(1);
}
@@ -949,9 +972,61 @@ int tv_set_norm(tvi_handle_t *tvh, char*
mp_msg(MSGT_TV, MSGL_ERR, MSGTR_TV_CannotSetNorm);
return 0;
}
+#ifdef HAVE_TV_TELETEXT
+ if (tvh->priv_vbi) teletext_control(tvh->priv_vbi,TVI_CONTROL_VBI_RESET,1); //arg must be not null
+#endif
return(1);
}
+#ifdef HAVE_TV_TELETEXT
+int tv_teletext_control(tvi_handle_t* tvh, int control, void* arg)
+{
+ if (!tvh || !tvh->priv_vbi)
+ return TVI_CONTROL_FALSE;
+
+ return teletext_control(tvh->priv_vbi,control,arg);
+}
+
+int tv_teletext_add_dec(tvi_handle_t *tvh, char *dec)
+{
+ if(!dec) return 0;
+ if (teletext_control(tvh->priv_vbi, TVI_CONTROL_VBI_ADD_DEC, &dec)!= TVI_CONTROL_TRUE)
+ return 0;
+ return 1;
+}
+
+int tv_teletext_go_link(tvi_handle_t *tvh, int linkno)
+{
+ if (teletext_control(tvh->priv_vbi, TVI_CONTROL_VBI_GO_LINK, &linkno)!= TVI_CONTROL_TRUE)
+ return 0;
+ return 1;
+}
+
+void* tv_get_teletext_vbipage(tvi_handle_t *tvh)
+{
+ void* page = NULL;
+ if (teletext_control(tvh->priv_vbi, TVI_CONTROL_VBI_GET_VBIPAGE, &page)!= TVI_CONTROL_TRUE)
+ return NULL;
+ return page;
+}
+
+char* tv_get_teletext_txtpage(tvi_handle_t *tvh)
+{
+ char* page = NULL;
+ if (teletext_control(tvh->priv_vbi, TVI_CONTROL_VBI_GET_TXTPAGE, &page)!= TVI_CONTROL_TRUE)
+ return NULL;
+ return page;
+}
+
+tv_teletext_img_t* tv_get_teletext_imgpage(tvi_handle_t *tvh)
+{
+ tv_teletext_img_t* tv_teletext_img = NULL;
+ if (teletext_control(tvh->priv_vbi, TVI_CONTROL_VBI_GET_IMGPAGE, &tv_teletext_img)!= TVI_CONTROL_TRUE)
+ return NULL;
+ return tv_teletext_img;
+}
+#endif
+
demuxer_desc_t demuxer_desc_tv = {
"Tv card demuxer",
"tv",
Modified: trunk/stream/tv.h
==============================================================================
--- trunk/stream/tv.h (original)
+++ trunk/stream/tv.h Sun Jun 10 02:06:12 2007
@@ -43,6 +43,11 @@ extern int tv_param_alsa;
#endif
extern char* tv_param_adevice;
#endif
+#ifdef HAVE_TV_TELETEXT
+extern char* tv_param_tdevice; ///< teletext vbi device
+extern char* tv_param_tformat; ///< format: text,bw,gray,color
+extern int tv_param_tpage; ///< page number
+#endif
extern int tv_param_brightness;
extern int tv_param_contrast;
extern int tv_param_hue;
@@ -72,6 +77,9 @@ typedef struct tvi_functions_s
typedef struct tvi_handle_s {
tvi_functions_t *functions;
void *priv;
+#ifdef HAVE_TV_TELETEXT
+ void *priv_vbi;
+#endif
int seq;
/* specific */
@@ -90,6 +98,18 @@ typedef struct tv_channels_s {
struct tv_channels_s *prev;
} tv_channels_t;
+#ifdef HAVE_TV_TELETEXT
+typedef struct tv_teletext_img_s {
+ void* canvas;
+ int tformat;
+ int columns;
+ int rows;
+ int height;
+ int width;
+ int half;
+} tv_teletext_img_t;
+#endif
+
extern tv_channels_t *tv_channel_list;
extern tv_channels_t *tv_channel_current, *tv_channel_last;
extern char *tv_channel_last_real;
@@ -153,6 +173,31 @@ extern char *tv_channel_last_real;
#define TVI_CONTROL_SPC_SET_INPUT 0x402 /* set input channel (tv,s-video,composite..) */
#define TVI_CONTROL_SPC_GET_NORMID 0x403 /* get normid from norm name */
+/* TELETEXT controls */
+#define TVI_CONTROL_VBI_SET_MODE 0x501 ///< on/off grab teletext
+#define TVI_CONTROL_VBI_GET_MODE 0x502 ///< get current mode teletext
+#define TVI_CONTROL_VBI_STEP_MODE 0x503 ///< step teletext mode
+
+#define TVI_CONTROL_VBI_SET_PAGE 0x504 ///< set grab teletext page number
+#define TVI_CONTROL_VBI_STEP_PAGE 0x505 ///< step grab teletext page number
+#define TVI_CONTROL_VBI_GET_PAGE 0x506 ///< get grabbed teletext page
+
+#define TVI_CONTROL_VBI_SET_FORMAT 0x507 ///< set teletext format
+#define TVI_CONTROL_VBI_STEP_FORMAT 0x508 ///< step teletext format
+#define TVI_CONTROL_VBI_GET_FORMAT 0x509 ///< get eletext format
+
+#define TVI_CONTROL_VBI_GET_HALF_PAGE 0x50a ///< get current half page
+#define TVI_CONTROL_VBI_STEP_HALF_PAGE 0x50b ///< switch half page
+#define TVI_CONTROL_VBI_SET_HALF_PAGE 0x50c ///< switch half page
+
+#define TVI_CONTROL_VBI_ADD_DEC 0x50d ///< add page number with dec
+#define TVI_CONTROL_VBI_GO_LINK 0x50e ///< go link (1..6)
+#define TVI_CONTROL_VBI_GET_TXTPAGE 0x50f ///< get grabbed text teletext page
+#define TVI_CONTROL_VBI_GET_IMGPAGE 0x510 ///< get grabbed image teletext page
+#define TVI_CONTROL_VBI_GET_VBIPAGE 0x511 ///< get vbi_image for grabbed teletext page
+#define TVI_CONTROL_VBI_RESET 0x512 ///< vbi reset
+#define TVI_CONTROL_VBI_START 0x513 ///< vbi start
+
extern tvi_handle_t *tv_begin(void);
extern int tv_init(tvi_handle_t *tvh);
extern int tv_uninit(tvi_handle_t *tvh);
@@ -183,6 +228,20 @@ int tv_step_freq(tvi_handle_t *tvh, floa
int tv_set_norm(tvi_handle_t *tvh, char* norm);
+#ifdef HAVE_TV_TELETEXT
+int tv_teletext_control(tvi_handle_t* tvh, int control,void* arg);
+/// add dec to pageno
+int tv_teletext_add_dec(tvi_handle_t *tvh, char *dec);
+/// go link
+int tv_teletext_go_link(tvi_handle_t *tvh, int linkno);
+/// get current vbi_page
+void* tv_get_teletext_vbipage(tvi_handle_t *tvh);
+/// get current page text
+char* tv_get_teletext_txtpage(tvi_handle_t *tvh);
+/// get current page image (RGB32_LB format)
+tv_teletext_img_t* tv_get_teletext_imgpage(tvi_handle_t *tvh);
+#endif
+
#define TV_NORM_PAL 1
#define TV_NORM_NTSC 2
#define TV_NORM_SECAM 3
Added: trunk/stream/tvi_vbi.c
==============================================================================
--- (empty file)
+++ trunk/stream/tvi_vbi.c Sun Jun 10 02:06:12 2007
@@ -0,0 +1,1197 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "tv.h"
+#include "tvi_vbi.h"
+#include "mp_msg.h"
+#include "libmpcodecs/img_format.h"
+
+#ifdef USE_ICONV
+#include <iconv.h>
+#endif
+
+#define VBI_TEXT_CHARSET "UTF-8"
+
+char* tv_param_tdevice=NULL; ///< teletext vbi device
+char* tv_param_tformat="gray"; ///< format: text,bw,gray,color
+int tv_param_tpage=100; ///< page number
+
+
+#ifdef USE_ICONV
+/*
+------------------------------------------------------------------
+ zvbi-0.2.25/src/exp-txt.c skip debug "if(1) fprintf(stderr,) " message
+------------------------------------------------------------------
+*/
+
+/**
+ * libzvbi - Text export functions
+ *
+ * Copyright (C) 2001, 2002 Michael H. Schimek
+ *
+ * Based on code from AleVT 1.5.1
+ * Copyright (C) 1998, 1999 Edgar Toernig <froese at gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ **/
+
+/** $Id$ **/
+
+static vbi_bool
+print_unicode(iconv_t cd, int endian, int unicode, char **p, int n)
+{
+ char in[2], *ip, *op;
+ size_t li, lo, r;
+
+ in[0 + endian] = unicode;
+ in[1 - endian] = unicode >> 8;
+ ip = in; op = *p;
+ li = sizeof(in); lo = n;
+
+ r = iconv(cd, &ip, &li, &op, &lo);
+
+ if ((size_t) -1 == r
+ || (**p == 0x40 && unicode != 0x0040)) {
+ in[0 + endian] = 0x20;
+ in[1 - endian] = 0;
+ ip = in; op = *p;
+ li = sizeof(in); lo = n;
+
+ r = iconv(cd, &ip, &li, &op, &lo);
+
+ if ((size_t) -1 == r
+ || (r == 1 && **p == 0x40))
+ goto error;
+ }
+
+ *p = op;
+
+ return TRUE;
+
+ error:
+ return FALSE;
+}
+
+static int
+vbi_print_page_region_nodebug(vbi_page * pg, char *buf, int size,
+ const char *format, vbi_bool table,
+ vbi_bool rtl, int column, int row, int width,
+ int height)
+{
+ int endian = vbi_ucs2be();
+ int column0, column1, row0, row1;
+ int x, y, spaces, doubleh, doubleh0;
+ iconv_t cd;
+ char *p;
+
+ rtl = rtl;
+
+#if 0
+ if (1)
+ fprintf (stderr, "vbi_print_page_region '%s' "
+ "table=%d col=%d row=%d width=%d height=%d\n",
+ format, table, column, row, width, height);
+#endif
+
+ column0 = column;
+ row0 = row;
+ column1 = column + width - 1;
+ row1 = row + height - 1;
+
+ if (!pg || !buf || size < 0 || !format
+ || column0 < 0 || column1 >= pg->columns
+ || row0 < 0 || row1 >= pg->rows
+ || endian < 0)
+ return 0;
+
+ if ((cd = iconv_open(format, "UCS-2")) == (iconv_t) -1)
+ return 0;
+
+ p = buf;
+
+ doubleh = 0;
+
+ for (y = row0; y <= row1; y++) {
+ int x0, x1, xl;
+
+ x0 = (table || y == row0) ? column0 : 0;
+ x1 = (table || y == row1) ? column1 : (pg->columns - 1);
+
+ xl = (table || y != row0 || (y + 1) != row1) ? -1 : column1;
+
+ doubleh0 = doubleh;
+
+ spaces = 0;
+ doubleh = 0;
+
+ for (x = x0; x <= x1; x++) {
+ vbi_char ac = pg->text[y * pg->columns + x];
+
+ if (table) {
+ if (ac.size > VBI_DOUBLE_SIZE)
+ ac.unicode = 0x0020;
+ } else {
+ switch (ac.size) {
+ case VBI_NORMAL_SIZE:
+ case VBI_DOUBLE_WIDTH:
+ break;
+
+ case VBI_DOUBLE_HEIGHT:
+ case VBI_DOUBLE_SIZE:
+ doubleh++;
+ break;
+
+ case VBI_OVER_TOP:
+ case VBI_OVER_BOTTOM:
+ continue;
+
+ case VBI_DOUBLE_HEIGHT2:
+ case VBI_DOUBLE_SIZE2:
+ if (y > row0)
+ ac.unicode = 0x0020;
+ break;
+ }
+
+ /*
+ * Special case two lines row0 ... row1, and all chars
+ * in row0, column0 ... column1 are double height: Skip
+ * row1, don't wrap around.
+ */
+ if (x == xl && doubleh >= (x - x0)) {
+ x1 = xl;
+ y = row1;
+ }
+
+ if (ac.unicode == 0x20 || !vbi_is_print(ac.unicode)) {
+ spaces++;
+ continue;
+ } else {
+ if (spaces < (x - x0) || y == row0) {
+ for (; spaces > 0; spaces--)
+ if (!print_unicode(cd, endian, 0x0020,
+ &p, buf + size - p))
+ goto failure;
+ } else /* discard leading spaces */
+ spaces = 0;
+ }
+ }
+
+ if (!print_unicode(cd, endian, ac.unicode, &p, buf + size - p))
+ goto failure;
+ }
+
+ /* if !table discard trailing spaces and blank lines */
+
+ if (y < row1) {
+ int left = buf + size - p;
+
+ if (left < 1)
+ goto failure;
+
+ if (table) {
+ *p++ = '\n'; /* XXX convert this (eg utf16) */
+ } else if (spaces >= (x1 - x0)) {
+ ; /* suppress blank line */
+ } else {
+ /* exactly one space between adjacent rows */
+ if (!print_unicode(cd, endian, 0x0020, &p, left))
+ goto failure;
+ }
+ } else {
+ if (doubleh0 > 0) {
+ ; /* prentend this is a blank double height lower row */
+ } else {
+ for (; spaces > 0; spaces--)
+ if (!print_unicode(cd, endian, 0x0020, &p, buf + size - p))
+ goto failure;
+ }
+ }
+ }
+
+ iconv_close(cd);
+ return p - buf;
+
+ failure:
+ iconv_close(cd);
+ return 0;
+}
+#endif
+/*
+ end of zvbi-0.2.25/src/exp-txt.c part
+*/
+
+
+/*
+------------------------------------------------------------------
+ Private routines
+------------------------------------------------------------------
+*/
+
+/**
+ * \brief Decode event handler
+ * \param ev VBI event
+ * \param data pointer to user defined data
+ *
+ */
+static void event_handler(vbi_event * ev, void *data)
+{
+ priv_vbi_t *user_vbi = (priv_vbi_t *) data;
+ vbi_page pg;
+ char *s;
+ int i;
+
+ switch (ev->type) {
+ case VBI_EVENT_CAPTION:
+ mp_msg(MSGT_TV,MSGL_DBG3,"caption\n");
+ break;
+ case VBI_EVENT_NETWORK:
+ s = ev->ev.network.name;
+ if (s) {
+ pthread_mutex_lock(&(user_vbi->buffer_mutex));
+ if (user_vbi->network_name)
+ free(user_vbi->network_name);
+ user_vbi->network_name = strdup(s);
+ pthread_mutex_unlock(&(user_vbi->buffer_mutex));
+ }
+ break;
+ case VBI_EVENT_NETWORK_ID:
+ s = ev->ev.network.name;
+ if (s) {
+ pthread_mutex_lock(&(user_vbi->buffer_mutex));
+ if (user_vbi->network_id)
+ free(user_vbi->network_id);
+ user_vbi->network_id = strdup(s);
+ pthread_mutex_unlock(&(user_vbi->buffer_mutex));
+ }
+ break;
+ case VBI_EVENT_TTX_PAGE:
+ pthread_mutex_lock(&(user_vbi->buffer_mutex));
+ user_vbi->curr_pgno = ev->ev.ttx_page.pgno; // page number
+ user_vbi->curr_subno = ev->ev.ttx_page.subno; // subpage
+ i = vbi_bcd2dec(ev->ev.ttx_page.pgno);
+ if (i > 0 && i < 1000) {
+ if (!user_vbi->cache[i])
+ user_vbi->cache[i] = (vbi_page *) malloc(sizeof(vbi_page));
+ vbi_fetch_vt_page(user_vbi->decoder, // fetch page
+ user_vbi->cache[i],
+ ev->ev.ttx_page.pgno,
+ ev->ev.ttx_page.subno,
+ VBI_WST_LEVEL_3p5, 25, TRUE);
+ memcpy(user_vbi->theader, user_vbi->cache[i]->text,
+ sizeof(user_vbi->theader));
+ }
+ pthread_mutex_unlock(&(user_vbi->buffer_mutex));
+ break;
+ }
+}
+
+/**
+ * \brief Prepares page to be shown on screen
+ * \param priv_vbi private data structure
+ *
+ * This routine adds page number, current time, etc to page header
+ *
+ */
+static void process_page(priv_vbi_t * priv_vbi)
+{
+ char *pagesptr;
+ int csize, i, j, subtitle = 0, sflg, send;
+ void *canvas;
+ char cpage[5];
+ vbi_page page;
+
+ memcpy(&(page), priv_vbi->page, sizeof(vbi_page));
+ if (priv_vbi->pgno != priv_vbi->page->pgno) {
+ //don't clear first line
+ for (i = page.columns; i < 1056; i++) {
+ page.text[i].unicode = ' ';
+ page.text[i].background = VBI_TRANSPARENT_COLOR;
+ }
+ snprintf(cpage, sizeof(cpage), "%03X", priv_vbi->pgno);
+ page.text[1].unicode = cpage[0];
+ page.text[2].unicode = cpage[1];
+ page.text[3].unicode = cpage[2];
+ page.text[4].unicode = ' ';
+ page.text[5].unicode = ' ';
+ page.text[6].unicode = ' ';
+ }
+
+ //background page number & title
+ j=vbi_bcd2dec(priv_vbi->curr_pgno);
+ if (j>0 && j<1000 && priv_vbi->cache[j]){
+ for(i=8;i<priv_vbi->cache[j]->columns;i++){
+ page.text[i].unicode = priv_vbi->cache[j]->text[i].unicode;
+ }
+ }
+
+ if (page.text[1].unicode == ' ' && page.text[2].unicode == ' ' &&
+ page.text[3].unicode == ' ' && page.text[4].unicode == ' ' &&
+ page.text[5].unicode == ' ' && page.text[5].unicode == ' '
+ && !priv_vbi->half)
+ subtitle = 1; // subtitle page
+ if (priv_vbi->pagenumdec) {
+ i = (priv_vbi->pagenumdec >> 12) & 0xf;
+ switch (i) {
+ case 1:
+ page.text[1].unicode = '0' + ((priv_vbi->pagenumdec >> 0) & 0xf);
+ page.text[2].unicode = '-';
+ page.text[3].unicode = '-';
+ break;
+ case 2:
+ page.text[1].unicode = '0' + ((priv_vbi->pagenumdec >> 4) & 0xf);
+ page.text[2].unicode = '0' + ((priv_vbi->pagenumdec >> 0) & 0xf);
+ page.text[3].unicode = '-';
+ break;
+ }
+ page.text[4].unicode = ' ';
+ page.text[5].unicode = ' ';
+ page.text[6].unicode = ' ';
+ page.text[1].foreground = VBI_WHITE;
+ page.text[2].foreground = VBI_WHITE;
+ page.text[3].foreground = VBI_WHITE;
+ }
+ priv_vbi->columns = page.columns;
+ priv_vbi->rows = page.rows;
+ if (!subtitle) { // update time in header
+ memcpy(&(page.text[VBI_TIME_LINEPOS]),
+ &(priv_vbi->theader[VBI_TIME_LINEPOS]),
+ sizeof(vbi_char) * (priv_vbi->columns - VBI_TIME_LINEPOS));
+ }
+ switch (priv_vbi->tformat) {
+ case VBI_TFORMAT_TEXT: // mode: text
+ if (priv_vbi->txtpage) {
+#ifdef USE_ICONV
+ vbi_print_page_region_nodebug(&(page), priv_vbi->txtpage,
+ VBI_TXT_PAGE_SIZE, VBI_TEXT_CHARSET, TRUE,
+ 0, 0, 0, page.columns, page.rows); // vbi_page to text without message
+#else
+ vbi_print_page(&(page), priv_vbi->txtpage,
+ VBI_TXT_PAGE_SIZE, VBI_TEXT_CHARSET, TRUE, 0);
+#endif
+ }
+ priv_vbi->valid_page = 1;
+ break;
+ case VBI_TFORMAT_BW: // mode: black & white
+ for (i=0; i < (priv_vbi->pgno!=page.pgno?page.columns:1056); i++) {
+ if (priv_vbi->foreground){
+ page.text[i].foreground = VBI_BLACK;
+ page.text[i].background = VBI_WHITE;
+ }else{
+ page.text[i].foreground = VBI_WHITE;
+ page.text[i].background = VBI_BLACK;
+ }
+ }
+ case VBI_TFORMAT_GRAY: // mode: grayscale
+ case VBI_TFORMAT_COLOR: // mode: color (request color spu patch!)
+
+
+
+ page.color_map[VBI_TRANSPARENT_COLOR] = 0;
+ if (priv_vbi->alpha) {
+ if (subtitle) {
+ for (i = 0; i < page.rows; i++) {
+ sflg = 0;
+ send = 0;
+ for (j = 0; j < page.columns; j++) {
+ if (page.text[i * page.columns + j].unicode != ' ') {
+ sflg = 1;
+ send = j;
+ }
+ if (sflg == 0)
+ page.text[i * page.columns + j].background =
+ VBI_TRANSPARENT_COLOR;
+ }
+ for (j = send + 1; j < page.columns; j++)
+ page.text[i * page.columns + j].background =
+ VBI_TRANSPARENT_COLOR;
+ }
+ } else {
+ for (i = 0; i < 1056; i++)
+ page.text[i].background = VBI_TRANSPARENT_COLOR;
+ }
+ }
+ csize = page.columns * page.rows * 12 * 10 * sizeof(vbi_rgba);
+ if (csize == 0)
+ break;
+ if (csize > priv_vbi->canvas_size) { // test canvas size
+ if (priv_vbi->canvas)
+ free(priv_vbi->canvas);
+ priv_vbi->canvas = malloc(csize);
+ priv_vbi->canvas_size = 0;
+ if (priv_vbi->canvas)
+ priv_vbi->canvas_size = csize;
+ }
+ if (priv_vbi->canvas) {
+ vbi_draw_vt_page(&(page),
+ priv_vbi->fmt,
+ priv_vbi->canvas,
+ priv_vbi->reveal, priv_vbi->flash_on);
+ priv_vbi->csize = csize;
+ }
+ priv_vbi->spudec_proc = 1;
+ priv_vbi->valid_page = 1;
+ break;
+ }
+}
+
+/**
+ * \brief Update page in cache
+ * \param priv_vbi private data structure
+ *
+ * Routine also calls process_page to refresh currently visible page (if so)
+ * every time it was received from VBI by background thread.
+ *
+ */
+static void update_page(priv_vbi_t * priv_vbi)
+{
+ int i;
+ int index;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ /*
+ priv_vbi->redraw=1 - page redraw requested
+ pgno!=page->pgno - page was switched
+ curr_pgno==pgno - backgound process just fetched current page, refresh it
+ */
+ if (priv_vbi->redraw ||
+ priv_vbi->pgno != priv_vbi->page->pgno ||
+ priv_vbi->curr_pgno == priv_vbi->pgno) {
+ index = vbi_bcd2dec(priv_vbi->pgno);
+ if ( index <= 0 || index > 999 || !priv_vbi->cache[index]) {
+ // curr_pgno is last decoded page
+ index = vbi_bcd2dec(priv_vbi->curr_pgno);
+ }
+
+ if (index <=0 || index >999 || !priv_vbi->cache[index]){
+ priv_vbi->valid_page = 0;
+ memset(priv_vbi->page, 0, sizeof(vbi_page));
+ }else
+ {
+ memcpy(priv_vbi->page, priv_vbi->cache[index], sizeof(vbi_page));
+ process_page(priv_vbi);//prepare page to be shown on screen
+ }
+ }
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+}
+
+/**
+ * \brief background grabber routine
+ * \param data user-defined data
+ *
+ */
+static void *grabber(void *data)
+{
+ priv_vbi_t *user_vbi = (priv_vbi_t *) data;
+ vbi_capture_buffer *sliced_buffer;
+ struct timeval timeout;
+ unsigned int n_lines;
+ int r, err_count = 0;
+
+ while (!user_vbi->eof) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 500;
+ r = vbi_capture_pull(user_vbi->capture, NULL, &sliced_buffer, &timeout); // grab slices
+ if (user_vbi->eof)
+ return NULL;
+ switch (r) {
+ case -1: // read error
+ if (err_count++ > 4)
+ user_vbi->eof = 1;
+ break;
+ case 0: // time out
+ break;
+ default:
+ err_count = 0;
+ }
+ if (r != 1)
+ continue;
+ n_lines = sliced_buffer->size / sizeof(vbi_sliced);
+ vbi_decode(user_vbi->decoder, (vbi_sliced *) sliced_buffer->data,
+ n_lines, sliced_buffer->timestamp); // decode slice
+ update_page(user_vbi);
+ }
+ switch (r) {
+ case -1:
+ mp_msg(MSGT_TV, MSGL_ERR, "VBI read error %d (%s)\n",
+ errno, strerror(errno));
+ return NULL;
+ case 0:
+ mp_msg(MSGT_TV, MSGL_ERR, "VBI read timeout\n");
+ return NULL;
+ }
+ return NULL;
+}
+
+/**
+ * \brief calculate increased/decreased by given value page number
+ * \param curr current page number in hexadecimal for
+ * \param direction decimal value (can be negative) to add to value or curr parameter
+ * \return new page number in hexadecimal form
+ *
+ * VBI page numbers are represented in special hexadecimal form, e.g.
+ * page with number 123 (as seen by user) internally has number 0x123.
+ * and equation 0x123+8 should be equal to 0x131 instead of regular 0x12b.
+ * Page numbers 0xYYY (where Y is not belongs to (0..9) and pages below 0x100 and
+ * higher 0x999 are reserved for internal use.
+ *
+ */
+static int steppage(int curr, int direction)
+{
+ int newpage = vbi_dec2bcd(vbi_bcd2dec(curr) + direction);
+ if (newpage < 0x100)
+ newpage = 0x100;
+ if (newpage > 0x999)
+ newpage = 0x999;
+ return newpage;
+}
+
+/**
+ * \brief toggles teletext page displaying mode
+ * \param priv_vbi private data structure
+ * \param flag new mode
+ * \return
+ * TVI_CONTROL_TRUE is success,
+ * TVI_CONTROL_FALSE otherwise
+ *
+ * flag:
+ * 0 - off
+ * 1 - on & opaque
+ * 2 - on & transparent
+ * 3 - on & transparent with black foreground color (only in bw mode)
+ *
+ */
+static int teletext_set_mode(priv_vbi_t * priv_vbi, int flag)
+{
+ if (flag<0 || flag>3)
+ return TVI_CONTROL_FALSE;
+
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+
+ priv_vbi->on = flag;
+
+ if (priv_vbi->on > 2 && priv_vbi->tformat != VBI_TFORMAT_BW)
+ priv_vbi->on = 0;
+
+ priv_vbi->foreground = 0;
+ priv_vbi->pagenumdec = 0;
+ priv_vbi->spudec_proc = 1;
+ priv_vbi->redraw = 1;
+ switch (priv_vbi->on) {
+ case 0:
+ priv_vbi->csize = 0;
+ break;
+ case 1:
+ priv_vbi->alpha = 0;
+ break;
+ case 2:
+ priv_vbi->alpha = 1;
+ break;
+ case 3:
+ priv_vbi->alpha = 1;
+ priv_vbi->foreground = 1;
+ break;
+ }
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief get half page mode (only in SPU mode)
+ * \param priv_vbi private data structure
+ * \return current mode
+ * 0 : half mode off
+ * 1 : top half page
+ * 2 : bottom half page
+ */
+static int vbi_get_half(priv_vbi_t * priv_vbi)
+{
+ int flag = 0;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ if (priv_vbi->valid_page)
+ flag = priv_vbi->half;
+ priv_vbi->pagenumdec = 0;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return flag;
+}
+
+/**
+ * \brief set half page mode (only in SPU mode)
+ * \param priv_vbi private data structure
+ * \param flag new half page mode
+ * \return
+ * TVI_CONTROL_TRUE is success,
+ * TVI_CONTROL_FALSE otherwise
+ *
+ *
+ * flag:
+ * 0 : half mode off
+ * 1 : top half page
+ * 2 : bottom half page
+ */
+static int teletext_set_half_page(priv_vbi_t * priv_vbi, int flag)
+{
+ if (flag<0 || flag>2)
+ return TVI_CONTROL_FALSE;
+
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ priv_vbi->half = flag;
+ if (priv_vbi->tformat == VBI_TFORMAT_TEXT && priv_vbi->half > 1)
+ priv_vbi->half = 0;
+ priv_vbi->redraw = 1;
+ priv_vbi->pagenumdec = 0;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief displays specified page
+ * \param priv_vbi private data structure
+ * \param pgno page number to display
+ * \param subno subpage number
+ *
+ */
+static void vbi_setpage(priv_vbi_t * priv_vbi, int pgno, int subno)
+{
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ priv_vbi->pgno = steppage(0, pgno);
+ priv_vbi->subno = subno;
+ priv_vbi->redraw = 1;
+ priv_vbi->pagenumdec = 0;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+}
+
+/**
+ * \brief steps over pages by a given value
+ * \param priv_vbi private data structure
+ * \param direction decimal step value (can be negative)
+ *
+ */
+static void vbi_steppage(priv_vbi_t * priv_vbi, int direction)
+{
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ priv_vbi->pgno = steppage(priv_vbi->pgno, direction);
+ priv_vbi->redraw = 1;
+ priv_vbi->pagenumdec = 0;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+}
+
+/**
+ * \brief append just entered digit to editing page number
+ * \param priv_vbi private data structure
+ * \param dec decimal digit to append
+ *
+ * dec:
+ * '0'..'9' append digit
+ * '-' remove last digit (backspace emulation)
+ *
+ * This routine allows user to jump to arbitrary page.
+ * It implements simple page number editing algorithm.
+ *
+ * Subsystem can be on one of two modes: normal and page number edit mode.
+ * Zero value of priv_vbi->pagenumdec means normal mode
+ * Non-zero value means page number edit mode and equals to packed
+ * decimal number of already entered part of page number.
+ *
+ * How this works.
+ * Let's assume that current mode is normal (pagenumdec is zero), teletext page
+ * 100 are displayed as usual. topmost left corner of page contains page number.
+ * Then vbi_add_dec is sequentally called (through slave
+ * command of course) with 1,4,-,2,3 * values of dec parameter.
+ *
+ * +-----+------------+------------------+
+ * | dec | pagenumxec | displayed number |
+ * +-----+------------+------------------+
+ * | | 0x000 | 100 |
+ * +-----+------------+------------------+
+ * | 1 | 0x001 | __1 |
+ * +-----+------------+------------------+
+ * | 4 | 0x014 | _14 |
+ * +-----+------------+------------------+
+ * | - | 0x001 | __1 |
+ * +-----+------------+------------------+
+ * | 2 | 0x012 | _12 |
+ * +-----+------------+------------------+
+ * | 3 | 0x123 | 123 |
+ * +-----+------------+------------------+
+ * | | 0x000 | 123 |
+ * +-----+------------+------------------+
+ *
+ * pagenumdec will automatically receive zero value after third digit of page number
+ * is entered and current page will be switched to another one with entered page number.
+ *
+ */
+static void vbi_add_dec(priv_vbi_t * priv_vbi, char *dec)
+{
+ int count, shift;
+ if (!dec)
+ return;
+ if (!priv_vbi->on)
+ return;
+ if ((*dec < '0' || *dec > '9') && *dec != '-')
+ return;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ count = (priv_vbi->pagenumdec >> 12) & 0xf;
+ if (*dec == '-') {
+ count--;
+ if (count)
+ priv_vbi->pagenumdec = ((priv_vbi->pagenumdec >> 4) & 0xfff) | (count << 12);
+ else
+ priv_vbi->pagenumdec = 0;
+ } else {
+ shift = count * 4;
+ count++;
+ priv_vbi->pagenumdec =
+ (((priv_vbi->pagenumdec) << 4 | (*dec -'0')) & 0xfff) | (count << 12);
+ if (count == 3) {
+ priv_vbi->pgno = priv_vbi->pagenumdec & 0xfff;
+ priv_vbi->subno = 0;
+ priv_vbi->redraw = 1;
+ priv_vbi->pagenumdec = 0;
+ }
+ }
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+}
+
+/**
+ * \brief follows link specified on current page
+ * \param priv_vbi private data structure
+ * \param linkno link number (0..6)
+ * \return
+ * TVI_CONTROL_FALSE if linkno is outside 0..6 range or if
+ * teletext is switched off
+ * TVI_CONTROL_TRUE otherwise
+ *
+ * linkno:
+ * 0: tpage in tv parameters (starting page, usually 100)
+ * 1..6: follows link on current page with given number
+ *
+ * FIXME: quick test shows that this is working strange
+ * FIXME: routine does not checks whether links exists on page or not
+ * TODO: more precise look
+ *
+ */
+static int vbi_golink(priv_vbi_t * priv_vbi, int linkno)
+{
+ if (linkno < 0 || linkno > 6)
+ return TVI_CONTROL_FALSE;
+ if (!priv_vbi->on)
+ return TVI_CONTROL_FALSE;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ if (linkno == 0) {
+ priv_vbi->pgno = priv_vbi->tpage;
+ priv_vbi->subno = priv_vbi->page->nav_link[linkno].subno;
+ priv_vbi->redraw = 1;
+ priv_vbi->pagenumdec = 0;
+ } else {
+ linkno--;
+ if (priv_vbi->pgno == priv_vbi->page->pgno) {
+ priv_vbi->pgno = priv_vbi->page->nav_link[linkno].pgno;
+ priv_vbi->subno = priv_vbi->page->nav_link[linkno].subno;
+ priv_vbi->redraw = 1;
+ priv_vbi->pagenumdec = 0;
+ }
+ }
+ priv_vbi->pagenumdec = 0;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return TVI_CONTROL_TRUE;
+}
+
+/**
+ * \brief get pointer to current teletext page
+ * \param priv_vbi private data structure
+ * \return pointer to vbi_page structure if teletext is
+ * switched on and current page is valid, NULL - otherwise
+ *
+ */
+static vbi_page *vbi_getpage(priv_vbi_t * priv_vbi)
+{
+ vbi_page *page = NULL;
+
+ if (!priv_vbi->on)
+ return NULL;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ if (priv_vbi->valid_page)
+ if (page = malloc(sizeof(vbi_page)))
+ memcpy(page, priv_vbi->page, sizeof(vbi_page));
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return page;
+}
+
+/**
+ * \brief get pointer to current teletext page
+ * \param priv_vbi private data structure
+ * \return pointer to character string, containing text-only data of
+ * teletext page. If teletext is switched off, current page is invalid
+ * or page format if not equal to "text" then returning value is NULL.
+ *
+ */
+static char *vbi_getpagetext(priv_vbi_t * priv_vbi)
+{
+ char *page = NULL;
+
+ if (!priv_vbi->on)
+ return NULL;
+ if (priv_vbi->tformat != VBI_TFORMAT_TEXT && priv_vbi->canvas)
+ return NULL;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ if (priv_vbi->valid_page)
+ page = priv_vbi->txtpage;
+ if (!page)
+ page = priv_vbi->header;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return page;
+}
+
+/**
+ * \brief get current page RGBA32 image (only in SPU mode)
+ * \param priv_vbi private data structure
+ * \return pointer to tv_teletext_img_t structure, containing among
+ * other things rendered RGBA32 image of current teletext page.
+ * return NULL is image is not available for some reason.
+ *
+ */
+static tv_teletext_img_t *vbi_getpageimg(priv_vbi_t * priv_vbi)
+{
+ tv_teletext_img_t *img = NULL;
+
+ if (priv_vbi->tformat == VBI_TFORMAT_TEXT)
+ return NULL;
+ if (priv_vbi->spudec_proc == 0)
+ return NULL;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ if (NULL != (img = malloc(sizeof(tv_teletext_img_t)))) {
+ img->tformat = priv_vbi->tformat; // format: bw|gray|color
+ img->tformat = VBI_TFORMAT_GRAY; // format: bw|gray|color
+ img->half = priv_vbi->half; // half mode
+ img->columns = priv_vbi->columns; // page size
+ img->rows = priv_vbi->rows;
+ img->width = priv_vbi->columns * 12;
+ img->width = priv_vbi->rows * 10;
+ img->canvas = NULL;
+ // is page ok?
+ if (priv_vbi->canvas && priv_vbi->on && priv_vbi->csize && priv_vbi->valid_page) {
+
+ if (NULL != (img->canvas = malloc(priv_vbi->csize)))
+ memcpy(img->canvas, priv_vbi->canvas, priv_vbi->csize);
+ }
+ }
+ priv_vbi->spudec_proc = 0;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return img;
+}
+
+/**
+ * \brief start teletext sybsystem
+ * \param priv_vbi private data structure
+ *
+ * initializes cache, vbi decoder and starts background thread
+ *
+ */
+static void vbi_start(priv_vbi_t * priv_vbi)
+{
+ if (!priv_vbi)
+ return;
+ if (NULL != (priv_vbi->txtpage = malloc(VBI_TXT_PAGE_SIZE))) // alloc vbi_page
+ memset(priv_vbi->txtpage, 0, VBI_TXT_PAGE_SIZE);
+ priv_vbi->page = malloc(sizeof(vbi_page));
+ priv_vbi->cache = (vbi_page **) malloc(1000 * sizeof(vbi_page *));
+ memset(priv_vbi->cache, 0, 1000 * sizeof(vbi_page *));
+ priv_vbi->decoder = vbi_decoder_new();
+ priv_vbi->subno = 0;
+ priv_vbi->fmt = VBI_PIXFMT_RGBA32_LE;
+ memset(priv_vbi->theader, 0, sizeof(priv_vbi->theader));
+ snprintf(priv_vbi->header, sizeof(priv_vbi->header), "%s", VBI_NO_TELETEXT);
+ vbi_event_handler_add(priv_vbi->decoder, ~0, event_handler, (void *) priv_vbi); // add event handler
+ pthread_create(&priv_vbi->grabber_thread, NULL, grabber, priv_vbi); // add grab function
+ pthread_mutex_init(&priv_vbi->buffer_mutex, NULL);
+ priv_vbi->valid_page = 0;
+ priv_vbi->pagenumdec = 0;
+ mp_msg(MSGT_TV, MSGL_INFO, "Teletext device: %s\n", priv_vbi->device);
+}
+
+/**
+ * \brief Teletext reset
+ * \param priv_vbi private data structure
+ *
+ * should be called during frequency, norm change, etc
+ *
+ */
+static void vbi_reset(priv_vbi_t * priv_vbi)
+{
+ int i;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ if (priv_vbi->canvas)
+ free(priv_vbi->canvas);
+ priv_vbi->canvas = NULL;
+ priv_vbi->canvas_size = 0;
+ priv_vbi->redraw = 1;
+ priv_vbi->csize = 0;
+ priv_vbi->valid_page = 0;
+ priv_vbi->spudec_proc = 1;
+ priv_vbi->pagenumdec = 0;
+ if (priv_vbi->page)
+ memset(priv_vbi->page, 0, sizeof(vbi_page));
+ if (priv_vbi->txtpage)
+ memset(priv_vbi->txtpage, 0, VBI_TXT_PAGE_SIZE);
+ memset(priv_vbi->theader, 0, sizeof(priv_vbi->theader));
+ if (priv_vbi->cache) {
+ for (i = 0; i < 1000; i++) {
+ if (priv_vbi->cache[i])
+ free(priv_vbi->cache[i]);
+ priv_vbi->cache[i] = NULL;
+ }
+ }
+ snprintf(priv_vbi->header, sizeof(priv_vbi->header), "%s",
+ VBI_NO_TELETEXT);
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+}
+
+/*
+---------------------------------------------------------------------------------
+ Public routines
+---------------------------------------------------------------------------------
+*/
+
+/**
+ * \brief teletext subsystem init
+ * \note Routine uses global variables tv_param_tdevice, tv_param_tpage
+ * and tv_param_tformat for initialization.
+ *
+ */
+priv_vbi_t *teletext_init(void)
+{
+ priv_vbi_t *priv_vbi;
+ int formatid, startpage;
+ unsigned int services = VBI_SLICED_TELETEXT_B |
+ VBI_SLICED_CAPTION_525 |
+ VBI_SLICED_CAPTION_625 |
+ VBI_SLICED_VBI_525 |
+ VBI_SLICED_VBI_625 |
+ VBI_SLICED_WSS_625 |
+ VBI_SLICED_WSS_CPR1204 |
+ VBI_SLICED_VPS;
+
+ if (!tv_param_tdevice)
+ return NULL;
+
+ if (NULL == (priv_vbi = malloc(sizeof(priv_vbi_t))))
+ return NULL;
+ memset(priv_vbi, 0, sizeof(priv_vbi_t));
+ formatid = VBI_TFORMAT_TEXT; // default
+ if (tv_param_tformat != NULL) {
+ if (strcmp(tv_param_tformat, "text") == 0)
+ formatid = VBI_TFORMAT_TEXT;
+ if (strcmp(tv_param_tformat, "bw") == 0)
+ formatid = VBI_TFORMAT_BW;
+ if (strcmp(tv_param_tformat, "gray") == 0)
+ formatid = VBI_TFORMAT_GRAY;
+ if (strcmp(tv_param_tformat, "color") == 0)
+ formatid = VBI_TFORMAT_COLOR;
+ }
+ startpage = steppage(0, tv_param_tpage); // page number is HEX
+ if (startpage < 0x100 || startpage > 0x999)
+ startpage = 0x100;
+ priv_vbi->device = strdup(tv_param_tdevice);
+ priv_vbi->tformat = formatid;
+ priv_vbi->tpage = startpage; // page number
+ priv_vbi->pgno = startpage; // page number
+
+
+ if (!priv_vbi->capture) {
+ priv_vbi->services = services; // probe v4l2
+ priv_vbi->capture = vbi_capture_v4l2_new(priv_vbi->device, // device
+ 20, // buffer numbers
+ &(priv_vbi->services), // services
+ 0, // strict
+ &(priv_vbi->errstr), // error string
+ 0); // trace
+ }
+ services = priv_vbi->services;
+ if (priv_vbi->capture == NULL) {
+ priv_vbi->services = services; // probe v4l
+ priv_vbi->capture = vbi_capture_v4l_new(priv_vbi->device,
+ 20,
+ &(priv_vbi->services),
+ 0, &(priv_vbi->errstr), 0);
+ }
+
+ if (!priv_vbi->capture) {
+ free(priv_vbi->device);
+ free(priv_vbi);
+ mp_msg(MSGT_TV, MSGL_INFO, "No teletext\n");
+ return NULL;
+ }
+ return priv_vbi;
+}
+
+/**
+ * \brief teletext subsystem uninitialization
+ * \param priv_vbi private data structure
+ *
+ * closes vbi capture, decode and and frees priv_vbi structure
+ *
+ */
+void teletext_uninit(priv_vbi_t * priv_vbi)
+{
+ int i;
+ if (priv_vbi == NULL)
+ return;
+ priv_vbi->eof = 1;
+ if (priv_vbi->capture){
+ vbi_capture_delete(priv_vbi->capture);
+ priv_vbi->capture = NULL;
+ }
+ if (priv_vbi->decoder){
+ vbi_event_handler_remove(priv_vbi->decoder, event_handler);
+ vbi_decoder_delete(priv_vbi->decoder);
+ priv_vbi->decoder = NULL;
+ }
+ if (priv_vbi->grabber_thread)
+ pthread_join(priv_vbi->grabber_thread, NULL);
+ pthread_mutex_destroy(&priv_vbi->buffer_mutex);
+ if (priv_vbi->device){
+ free(priv_vbi->device);
+ priv_vbi->device = NULL;
+ }
+ if (priv_vbi->errstr){
+ free(priv_vbi->errstr);
+ priv_vbi->errstr = NULL;
+ }
+ if (priv_vbi->canvas){
+ free(priv_vbi->canvas);
+ priv_vbi->canvas = NULL;
+ }
+ if (priv_vbi->txtpage){
+ free(priv_vbi->txtpage);
+ priv_vbi->txtpage = NULL;
+ }
+ if (priv_vbi->network_name){
+ free(priv_vbi->network_name);
+ priv_vbi->network_name = NULL;
+ }
+ if (priv_vbi->network_id){
+ free(priv_vbi->network_id);
+ priv_vbi->network_id = NULL;
+ }
+ if (priv_vbi->page){
+ free(priv_vbi->page);
+ priv_vbi->page = NULL;
+ }
+ if (priv_vbi->cache) {
+ for (i = 0; i < 1000; i++) {
+ if (priv_vbi->cache[i])
+ free(priv_vbi->cache[i]);
+ }
+ free(priv_vbi->cache);
+ priv_vbi->cache = NULL;
+ }
+ free(priv_vbi);
+}
+
+/**
+ * \brief Teletext control routine
+ * \param priv_vbi private data structure
+ * \param cmd command
+ * \param arg command parameter (has to be not null)
+ *
+ */
+int teletext_control(priv_vbi_t * priv_vbi, int cmd, void *arg)
+{
+ vbi_page *page = NULL;
+ char *txtpage = NULL;
+ tv_teletext_img_t *img = NULL;
+ if (!priv_vbi)
+ return TVI_CONTROL_FALSE;
+ if (!arg)
+ return TVI_CONTROL_FALSE;
+ switch (cmd) {
+ case TVI_CONTROL_VBI_RESET:
+ vbi_reset(priv_vbi);
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_START:
+ vbi_start(priv_vbi);
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_GET_FORMAT:
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ *(int*)arg=priv_vbi->tformat;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_SET_MODE:
+ return teletext_set_mode(priv_vbi, *(int *) arg);
+ case TVI_CONTROL_VBI_GET_MODE:
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ *(int*)arg=priv_vbi->on;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_STEP_MODE:
+ {
+ int val;
+ pthread_mutex_lock(&(priv_vbi->buffer_mutex));
+ val=(priv_vbi->on+*(int*)arg)%4;
+ pthread_mutex_unlock(&(priv_vbi->buffer_mutex));
+ if (val<0)
+ val+=4;
+ return teletext_set_mode(priv_vbi,val);
+ }
+ case TVI_CONTROL_VBI_GET_HALF_PAGE:
+ *(void **) arg = (void *) vbi_get_half(priv_vbi);
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_SET_HALF_PAGE:
+ return teletext_set_half_page(priv_vbi, *(int *) arg);
+ case TVI_CONTROL_VBI_STEP_HALF_PAGE:
+ {
+ int val;
+ val=(vbi_get_half(priv_vbi)+*(int*)arg)%3;
+
+ if (val<0)
+ val+=3;
+ return teletext_set_half_page(priv_vbi,val);
+ }
+
+ case TVI_CONTROL_VBI_SET_PAGE:
+ vbi_setpage(priv_vbi, *(int *) arg, 0);
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_STEP_PAGE:
+ vbi_steppage(priv_vbi, *(int *) arg);
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_ADD_DEC:
+ vbi_add_dec(priv_vbi, *(char **) arg);
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_GO_LINK:
+ return vbi_golink(priv_vbi, *(int *) arg);
+ case TVI_CONTROL_VBI_GET_PAGE:
+ *(int*) arg = priv_vbi->pgno;
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_GET_VBIPAGE:
+ if (NULL == (page = vbi_getpage(priv_vbi)))
+ return TVI_CONTROL_FALSE;
+ *(void **) arg = (void *) page;
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_GET_TXTPAGE:
+ if (NULL == (txtpage = vbi_getpagetext(priv_vbi)))
+ return TVI_CONTROL_FALSE;
+ *(void **) arg = (void *) txtpage;
+ return TVI_CONTROL_TRUE;
+ case TVI_CONTROL_VBI_GET_IMGPAGE:
+ if (NULL == (img = vbi_getpageimg(priv_vbi)))
+ return TVI_CONTROL_FALSE;
+ *(void **) arg = (void *) img;
+ return TVI_CONTROL_TRUE;
+ }
+ return TVI_CONTROL_UNKNOWN;
+}
Added: trunk/stream/tvi_vbi.h
==============================================================================
--- (empty file)
+++ trunk/stream/tvi_vbi.h Sun Jun 10 02:06:12 2007
@@ -0,0 +1,75 @@
+#ifndef __TVI_VBI_H_
+#define __TVI_VBI_H_
+
+#include "libzvbi.h"
+#include "libmpcodecs/img_format.h"
+#include "libmpcodecs/mp_image.h"
+#include "tv.h"
+
+#define VBI_MAX_SUBPAGES 64 ///< max sub pages number
+#define VBI_TXT_PAGE_SIZE 42*25*2 ///< max text page size
+#define VBI_MAX_LINE_SIZE 42 ///< max line size in text page
+
+#define VBI_TFORMAT_TEXT 0 ///< text mode
+#define VBI_TFORMAT_BW 1 ///< back&white mode
+#define VBI_TFORMAT_GRAY 2 ///< grayscale mode
+#define VBI_TFORMAT_COLOR 3 ///< color mode (require color_spu patch!)
+
+#define VBI_NO_TELETEXT "No teletext"
+
+#define VBI_TRANSPARENT_COLOR 40 ///< transparent color id
+#define VBI_TIME_LINEPOS 13 ///< time line pos in page header
+
+typedef struct {
+ int on; ///< teletext on/off
+
+ char* device; ///< capture device
+ unsigned int services; ///< services
+ vbi_capture* capture; ///< vbi_capture
+ int capture_fd; ///< capture fd (now not used)
+ vbi_decoder* decoder; ///< vbi_decoder
+ char* errstr; ///< error string
+ pthread_t grabber_thread; ///< grab thread
+ pthread_mutex_t buffer_mutex;
+ pthread_mutex_t update_mutex;
+ int eof; ///< end grab
+ int tpage; ///< tpage
+ int pgno; ///< seek page number
+ int subno; ///< seek subpage
+ int curr_pgno; ///< current page number
+ int curr_subno; ///< current subpage
+ uint32_t pagenumdec; ///< set page num with dec
+
+ vbi_page** cache;
+ vbi_page *page; ///< vbi_page
+ int valid_page; ///< valid page flag
+ char* txtpage; ///< decoded vbi_page to text
+ vbi_char theader[VBI_MAX_LINE_SIZE]; ///< vbi header
+ char header[VBI_MAX_LINE_SIZE]; ///< text header
+
+ int tformat; ///< 0:text, 1:bw, 2:gray, 3:color
+ vbi_pixfmt fmt; ///< image format (only VBI_PIXFMT_RGBA32_LE supported)
+ void* canvas; ///< stored image data
+ int csize; ///< stored image size
+ int canvas_size; ///< image buffer size
+ int reveal; ///< reveal (now not used)
+ int flash_on; ///< flash_on (now not used)
+ int alpha; ///< opacity mode
+ int foreground; ///< foreground black in bw mode
+ int half; ///< 0:half mode off, 1:top half page, 2:bottom half page
+ int redraw; ///< is redraw last image
+ int columns; ///< page size: coloumns
+ int rows; ///< page size: rows
+ int spudec_proc; ///< render image request
+
+ char* network_name; ///< network name
+ char* network_id; ///< network id
+ } priv_vbi_t;
+
+/// teletext subsystem initialization
+priv_vbi_t* teletext_init(void);
+/// teletext subsystem uninitialization
+void teletext_uninit(priv_vbi_t* priv_vbi);
+/// ioctl for
+int teletext_control(priv_vbi_t* priv_vbi, int cmd, void *args);
+#endif
More information about the MPlayer-cvslog
mailing list