diff --git a/libvo/sub.c b/libvo/sub.c index 77e3400d78..3deadce98d 100644 --- a/libvo/sub.c +++ b/libvo/sub.c @@ -14,6 +14,10 @@ #define OSD_NAV_BOX_ALPHA 0x7f #endif +#ifdef HAVE_TV_TELETEXT +#include "stream/tv.h" +#endif + #include "mplayer.h" #include "mp_msg.h" #include "help_mp.h" @@ -68,6 +72,13 @@ font_desc_t* vo_font=NULL; font_desc_t* sub_font=NULL; unsigned char* vo_osd_text=NULL; +#ifdef HAVE_TV_TELETEXT +void* vo_osd_teletext_page=NULL; +int vo_osd_teletext_half = 0; +int vo_osd_teletext_mode=0; +int vo_osd_teletext_format=0; +int vo_osd_teletext_scale=0; +#endif int sub_unicode=0; int sub_utf8=0; int sub_pos=100; @@ -230,6 +241,247 @@ inline static void vo_update_nav (mp_osd_obj_t *obj, int dxs, int dys) { } #endif +#ifdef HAVE_TV_TELETEXT +// renders char to a big per-object buffer where alpha and bitmap are separated +static void tt_draw_alpha_buf(mp_osd_obj_t* obj, int x0,int y0, int w,int h, unsigned char* src, int stride,int fg,int bg,int alpha) +{ + int dststride = obj->stride; + int dstskip = obj->stride-w; + int srcskip = stride-w; + int i, j; + unsigned char *b = obj->bitmap_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); + unsigned char *a = obj->alpha_buffer + (y0-obj->bbox.y1)*dststride + (x0-obj->bbox.x1); + unsigned char *bs = src; + if (x0 < obj->bbox.x1 || x0+w > obj->bbox.x2 || y0 < obj->bbox.y1 || y0+h > obj->bbox.y2) { + mp_msg(MSGT_OSD,MSGL_ERR,"tt osd text out of range: bbox [%d %d %d %d], txt [%d %d %d %d]\n", + obj->bbox.x1, obj->bbox.x2, obj->bbox.y1, obj->bbox.y2, + x0, x0+w, y0, y0+h); + return; + } + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++, b++, a++, bs++) { + *b=(fg-bg)*(*bs)/255+bg; + *a=alpha; + } + b+= dstskip; + a+= dstskip; + bs+= srcskip; + } +} +inline static void vo_update_text_teletext(mp_osd_obj_t *obj, int dxs, int dys) +{ + int h=0,w=0,i,j,font; + int wm,hm; + int color; + int x,y,x0,y0; + int cols,rows; + int wm12; + int hm13; + int hm23; + int start_row,max_rows; + int b,ax[6],ay[6],aw[6],ah[6]; + tt_char tc; + tt_char* tdp=vo_osd_teletext_page; + unsigned char colors[8]={1,85,150,226,70,105,179,254}; + unsigned char* buf[9]; + + obj->flags|=OSDFLAG_CHANGED|OSDFLAG_VISIBLE; + if (!tdp || !vo_osd_teletext_mode) { + obj->flags&=~OSDFLAG_VISIBLE; + return; + } + switch(vo_osd_teletext_half){ + case TT_ZOOM_TOP_HALF: + start_row=0; + max_rows=VBI_ROWS/2; + break; + case TT_ZOOM_BOTTOM_HALF: + start_row=VBI_ROWS/2; + max_rows=VBI_ROWS/2; + break; + default: + start_row=0; + max_rows=VBI_ROWS; + break; + } + wm=0; + for(i=start_row;iwidth[tc.unicode]) + wm=vo_font->width[tc.unicode]; + } + } + } + + hm=vo_font->height+1; + wm=dxs*hm*max_rows/(dys*VBI_COLUMNS); + + //very simple teletext font auto scaling + if(!vo_osd_teletext_scale && hm*(max_rows+1)>dys){ + text_font_scale_factor*=1.0*(dys)/((max_rows+1)*hm); + force_load_font=1; + vo_osd_teletext_scale=text_font_scale_factor; + obj->flags&=~OSDFLAG_VISIBLE; + return; + } + + cols=dxs/wm; + rows=dys/hm; + + if(cols>VBI_COLUMNS) + cols=VBI_COLUMNS; + if(rows>max_rows) + rows=max_rows; + w=cols*wm-vo_font->charspace; + h=rows*hm-vo_font->charspace; + + if(w>1; + hm13=(hm+1)/3; + hm23=hm13<<1; + + for(i=0;i<6;i+=2){ + ax[i+0]=0; + aw[i+0]=wm12; + + ax[i+1]=wm12; + aw[i+1]=wm-wm12; + } + + for(i=0;i<2;i++){ + ay[i+0]=0; + ah[i+0]=hm13; + + ay[i+2]=hm13; + ah[i+2]=hm-hm23; + + ay[i+4]=hm-hm13; + ah[i+4]=hm13; + } + + obj->x = 0; + obj->y = 0; + obj->bbox.x1 = x0; + obj->bbox.y1 = y0; + obj->bbox.x2 = x0+w; + obj->bbox.y2 = y0+h; + obj->flags |= OSDFLAG_BBOX; + alloc_buf(obj); + + for(i=0;i<9;i++) + buf[i]=malloc(wm*hm); + + //alpha + if(vo_osd_teletext_format==TT_FORMAT_OPAQUE ||vo_osd_teletext_format==TT_FORMAT_OPAQUE_INV) + color=1; + else + color=200; + memset(buf[8],color,wm*hm); + //colors + if(vo_osd_teletext_format==TT_FORMAT_OPAQUE ||vo_osd_teletext_format==TT_FORMAT_TRANSPARENT){ + for(i=0;i<8;i++){ + memset(buf[i],(unsigned char)(1.0*(255-color)*colors[i]/255),wm*hm); + } + }else{ + for(i=0;i<8;i++) + memset(buf[i],(unsigned char)(1.0*(255-color)*colors[7-i]/255),wm*hm); + } + + y=y0; + for(i=0;ifont[tc.unicode])>=0 && y+hmwidth[tc.unicode],vo_font->height, + vo_font->pic_b[font]->bmp+vo_font->start[tc.unicode]-vo_font->charspace*vo_font->pic_a[font]->w, + vo_font->pic_b[font]->w, + buf[tc.fg][0],buf[tc.bg][0],buf[8][0]); + } + }else{ +/* +Rendering one graphics character +TODO: support for separated graphics symbols (where six rectangles does not touch each other) + + +--+ +--+ 87654321 + |01| |12| -------- + |10| <= |34| <= 00100110 <= 0x26 + |01| |56| + +--+ +--+ + +(0:wm/2) (wm/2:wm-wm/2) + +********** *********** (0:hm/3) +*** **** **** **** +*** 1 **** **** 2 **** +*** **** **** **** +********** *********** +********** *********** + +********** *********** (hm/3:hm-2*hm/3) +********** *********** +*** **** **** **** +*** 3 **** **** 4 **** +*** **** **** **** +********** *********** +********** *********** +********** *********** + +********** *********** (hm-hm/3:hm/3) +*** **** **** **** +*** 5 **** **** 6 **** +*** **** **** **** +********** *********** +********** *********** + +*/ + if(tc.gfx>1){ //separated gfx + for(b=0;b<6;b++){ + color=(tc.unicode>>b)&1?tc.fg:tc.bg; + draw_alpha_buf(obj,x+ax[b]+1,y+ay[b]+1,aw[b]-2,ah[b]-2,buf[color],buf[8],wm); + } + //separated gfx (background borders) + //vertical + draw_alpha_buf(obj,x ,y,1,hm,buf[tc.bg],buf[8],wm); + draw_alpha_buf(obj,x+ax[1]-1,y,2,hm,buf[tc.bg],buf[8],wm); + draw_alpha_buf(obj,x+ax[1]+aw[1]-1,y,wm-ax[1]-aw[1]+1,hm,buf[tc.bg],buf[8],wm); + //horizontal + draw_alpha_buf(obj,x,y ,wm,1,buf[tc.bg],buf[8],wm); + draw_alpha_buf(obj,x,y+ay[0]+ah[0]-1,wm,2,buf[tc.bg],buf[8],wm); + draw_alpha_buf(obj,x,y+ay[2]+ah[2]-1,wm,2,buf[tc.bg],buf[8],wm); + draw_alpha_buf(obj,x,y+ay[4]+ah[4]-1,wm,hm-ay[4]-ah[4]+1,buf[tc.bg],buf[8],wm); + }else{ + for(b=0;b<6;b++){ + color=(tc.unicode>>b)&1?tc.fg:tc.bg; + draw_alpha_buf(obj,x+ax[b],y+ay[b],aw[b],ah[b],buf[color],buf[8],wm); + } + } + } + x+=wm; + } + y+=hm; + } + for(i=0;i<9;i++) + free(buf[i]); +} +#endif + int vo_osd_progbar_type=-1; int vo_osd_progbar_value=100; // 0..256 @@ -866,6 +1118,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; @@ -933,6 +1190,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 @@ -970,6 +1230,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: diff --git a/libvo/sub.h b/libvo/sub.h index e139607e21..c6223f8043 100644 --- a/libvo/sub.h +++ b/libvo/sub.h @@ -2,6 +2,10 @@ #ifndef MPLAYER_SUB_H #define MPLAYER_SUB_H +#ifdef HAVE_TV_TELETEXT +#include "libmpcodecs/mp_image.h" +#endif + typedef struct mp_osd_bbox_s { int x1,y1,x2,y2; } mp_osd_bbox_t; @@ -11,6 +15,7 @@ typedef struct mp_osd_bbox_s { #define OSDTYPE_PROGBAR 3 #define OSDTYPE_SPU 4 #define OSDTYPE_DVDNAV 5 +#define OSDTYPE_TELETEXT 6 #define OSDFLAG_VISIBLE 1 #define OSDFLAG_CHANGED 2 @@ -64,6 +69,13 @@ extern subtitle* vo_sub; extern unsigned char* vo_osd_text; +#ifdef HAVE_TV_TELETEXT +extern void* vo_osd_teletext_page; +extern int vo_osd_teletext_half; +extern int vo_osd_teletext_mode; +extern int vo_osd_teletext_format; +#endif + extern int vo_osd_progbar_type; extern int vo_osd_progbar_value; // 0..255 diff --git a/mpcommon.c b/mpcommon.c index 9a5c52accc..ce1188680f 100644 --- a/mpcommon.c +++ b/mpcommon.c @@ -7,6 +7,9 @@ #include "libvo/video_out.h" #include "spudec.h" #include "vobsub.h" +#ifdef HAVE_TV_TELETEXT +#include "stream/tv.h" +#endif double sub_last_pts = -303; @@ -138,3 +141,21 @@ 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 + tvi_handle_t* tvh=demuxer->priv; + if (demuxer->type != DEMUXER_TYPE_TV || !tvh) return; + + if(tvh->functions->control(tvh->priv,TV_VBI_CONTROL_GET_VBIPAGE,&vo_osd_teletext_page)!=TVI_CONTROL_TRUE) + vo_osd_teletext_page=NULL; + if(tvh->functions->control(tvh->priv,TV_VBI_CONTROL_GET_HALF_PAGE,&vo_osd_teletext_half)!=TVI_CONTROL_TRUE) + vo_osd_teletext_half=0; + if(tvh->functions->control(tvh->priv,TV_VBI_CONTROL_GET_MODE,&vo_osd_teletext_mode)!=TVI_CONTROL_TRUE) + vo_osd_teletext_mode=0; + if(tvh->functions->control(tvh->priv,TV_VBI_CONTROL_GET_FORMAT,&vo_osd_teletext_format)!=TVI_CONTROL_TRUE) + vo_osd_teletext_format=0; + vo_osd_changed(OSDTYPE_TELETEXT); +#endif +} diff --git a/mplayer.c b/mplayer.c index fbc476c9b3..ef06f68129 100644 --- a/mplayer.c +++ b/mplayer.c @@ -1621,6 +1621,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)) @@ -2035,6 +2036,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, @@ -2248,6 +2250,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) {