changeset 23903:037737866f6a

Teletext support Part 4/5: teletext page rendering
author voroshil
date Sun, 29 Jul 2007 17:57:39 +0000
parents 29f612207c95
children 545aef4edc84
files libvo/sub.c libvo/sub.h mpcommon.c mplayer.c
diffstat 4 files changed, 299 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/libvo/sub.c	Sun Jul 29 17:57:12 2007 +0000
+++ b/libvo/sub.c	Sun Jul 29 17:57:39 2007 +0000
@@ -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* 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 @@
 }
 #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;i<max_rows;i++){
+        for(j=0;j<VBI_COLUMNS;j++){
+            tc=tdp[i*VBI_COLUMNS+j];
+            if(!tc.ctl && !tc.gfx)
+            {
+                render_one_glyph(vo_font, tc.unicode);
+                if (wm<vo_font->width[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<dxs)
+        x0=(dxs-w)/2;
+    else
+        x0=0;
+    if(h<dys)
+        y0=(dys-h)/2;
+    else
+        y0=0;
+
+    wm12=wm>>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;i<rows;i++){
+        x=x0;
+        for(j=0;j<cols;j++){
+            tc=tdp[(i+start_row)*VBI_COLUMNS+j];
+            if(!tc.gfx){
+                /* Rendering one text character */
+                draw_alpha_buf(obj,x,y,wm,hm,buf[tc.bg],buf[8],wm);
+                if(tc.unicode!=0x20 && tc.unicode!=0x00 && !tc.ctl &&
+                    (font=vo_font->font[tc.unicode])>=0 && y+hm<dys){
+                        tt_draw_alpha_buf(obj,x,y,vo_font->width[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 @@
 	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 @@
 #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
@@ -971,6 +1231,9 @@
 #ifdef USE_DVDNAV
         case OSDTYPE_DVDNAV:
 #endif
+#ifdef HAVE_TV_TELETEXT
+	case OSDTYPE_TELETEXT:
+#endif
 	case OSDTYPE_OSD:
 	case OSDTYPE_SUBTITLE:
 	case OSDTYPE_PROGBAR:
--- a/libvo/sub.h	Sun Jul 29 17:57:12 2007 +0000
+++ b/libvo/sub.h	Sun Jul 29 17:57:39 2007 +0000
@@ -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 @@
 #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 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
 
--- a/mpcommon.c	Sun Jul 29 17:57:12 2007 +0000
+++ b/mpcommon.c	Sun Jul 29 17:57:39 2007 +0000
@@ -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 @@
     }
     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
+}
--- a/mplayer.c	Sun Jul 29 17:57:12 2007 +0000
+++ b/mplayer.c	Sun Jul 29 17:57:39 2007 +0000
@@ -1621,6 +1621,7 @@
 	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 @@
 	    ++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 @@
 	// 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) {