1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-18 21:06:00 +00:00

Teletext support for tv:// (v4l and v4l2 only)

modified patch from Otvos Attila oattila at chello dot hu

Module uses zvbi library for all low-level  VBI operations (like I/O with vbi
device, converting vbi pages into usefull vbi_page stuctures, rendering them
into RGB32 images).

All teletext related stuff (except properties, slave commands and rendering
osd in text mode or RGB32 rendered teletext pages in spu mode) is implemented
in tvi_vbi.c

New properties:
teletext_page - switching between pages
teletext_mode - switch between on/off/opaque/transparent modes
teletext_format - (currently read-only) allows to get format info
(black/white,gray,text)
teletext_half_page - trivial zooming (displaying top/bottom half of teletext
page)

New slave commands:
teletext_add_dec - user interface for jumping to any page by editing page number
interactively
teletext_go_link - goes though links, specified on current page



git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@23530 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
voroshil 2007-06-10 00:06:12 +00:00
parent 990b33b1c2
commit 83a2c50ef9
20 changed files with 1950 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -459,6 +459,11 @@ m_option_t tvopts_conf[]={
{"alsa", &tv_param_alsa, CONF_TYPE_FLAG, 0, 0, 1, NULL},
#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}

149
command.c
View File

@ -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:

30
configure vendored
View File

@ -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

View File

@ -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" },

View File

@ -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

View File

@ -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
@ -963,6 +1090,9 @@ void vo_draw_text(int dxs,int dys,void (*draw_alpha)(int x0,int y0, int w,int h,
break;
#ifdef USE_DVDNAV
case OSDTYPE_DVDNAV:
#endif
#ifdef HAVE_TV_TELETEXT
case OSDTYPE_TELETEXT:
#endif
case OSDTYPE_OSD:
case OSDTYPE_SUBTITLE:

View File

@ -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

View File

@ -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
}

View File

@ -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();
}

115
spudec.c
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -34,6 +34,10 @@
#include "frequencies.h"
#ifdef HAVE_TV_TELETEXT
#include "tvi_vbi.h"
#endif
/* some default values */
int tv_param_audiorate = 44100;
int tv_param_noaudio = 0;
@ -518,6 +522,9 @@ static demuxer_t* demux_open_tv(demuxer_t *demuxer)
tv_uninit(tvh);
return NULL;
}
#ifdef HAVE_TV_TELETEXT
if(tvh->priv_vbi) teletext_control(tvh->priv_vbi,TVI_CONTROL_VBI_START,1); //arg must be not null
#endif
funcs = tvh->functions;
demuxer->priv=tvh;
@ -657,6 +664,12 @@ no_audio:
static void demux_close_tv(demuxer_t *demuxer)
{
tvi_handle_t *tvh=(tvi_handle_t*)(demuxer->priv);
#ifdef HAVE_TV_TELETEXT
if(tvh->priv_vbi) {
teletext_uninit(tvh->priv_vbi);
tvh->priv_vbi=NULL;
}
#endif
if (!tvh) return;
tvh->functions->uninit(tvh->priv);
demuxer->priv=NULL;
@ -688,6 +701,10 @@ tvi_handle_t *tv_begin(void)
tvi_driver_list[i]->name,
tvi_driver_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, unsigned long freq)
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* norm)
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",

View File

@ -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, float step_interval);
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

1197
stream/tvi_vbi.c Normal file

File diff suppressed because it is too large Load Diff

75
stream/tvi_vbi.h Normal file
View File

@ -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