📄 tvi_vbi.c
字号:
mp_msg(MSGT_TV,MSGL_DBG3,"thr:%d sync:%d ",thr,sync); return 1;}#if 0//See comment in vbi_decode for a reason of commenting out this routine./** * \brief decodes raw vbi data (signal amplitudes) into sequence of bytes * \param priv private data structure * \param buf raw vbi data (one line of frame) * \param data output buffer for decoded bytes (at least 45 bytes long) * * Used Michael Niedermayer's algorithm. * Signal phase is calculated using correlation between given samples data and * pure sine */static int decode_raw_line_sine(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){ int i,x,r,amp,xFixp; int avg=0; double sin_sum=0, cos_sum=0; for(x=0; x< FIXP2INT(10*priv->bpb); x++) avg+=buf[x]; avg/=FIXP2INT(10*priv->bpb); for(x=0; x<12; x++){ amp= buf[x<<1]; sin_sum+= si[x]*(amp-avg); cos_sum+= co[x]*(amp-avg); } //this is always zero. Why ? xFixp= atan(sin_sum/cos_sum)*priv->bpb/M_PI; //Without this line the result is full of errors //and routine is unable to find magic sequence buf+=FIXP2INT(10*priv->bpb); r=0; for(x=FIXP2INT(xFixp);x<70;x=FIXP2INT(xFixp)){ r=(r<<1) & 0xFFFF; if(buf[x]>avg) r|=1; xFixp+=priv->bpb; if(r==0xAAE4) break; } //this is not teletext if (r!=0xaae4) return 0; //Decode remaining 45-2(clock run-in)-1(framing code)=42 bytes for(i=1; i<=(42<<3); i++){ r>>=1; x=FIXP2INT(xFixp); if(buf[x]> avg) r|=0x80; if(!(i & 0x07)){ data[(i>>3)-1]=r; r=0; } xFixp+=priv->bpb; } return 1;}#endif/** * \brief decodes all vbi lines from one video frame * \param priv private data structure * \param buf buffer with raw vbi data in it * * \note buffer size have to be at least priv->ptsp->bufsize bytes */static void vbi_decode(priv_vbi_t* priv,unsigned char*buf){ int magAddr; int pkt; unsigned char data[64]; unsigned char* linep; int d0,d1; int i=0; mp_msg(MSGT_TV,MSGL_DBG3,"vbi: vbi_decode\n"); for(linep=buf; !priv->cache_reset && linep<buf+priv->ptsp->bufsize; linep+=priv->ptsp->samples_per_line,i++){#if 0 /* This routine is alternative implementation of raw VBI data decoding. Unfortunately, it detects only about 20% of incoming data, but Michael says that this algorithm is better, and he wants to fix it. */ if(decode_raw_line_sine(priv,linep,data)<=0){#endif if(decode_raw_line_runin(priv,linep,data)<=0){ continue; //this is not valid teletext line } d0= corrHamm48[ data[0] ]; d1= corrHamm48[ data[1] ]; if(d0&0x80 || d1&0x80){ pll_add(priv,2,4); mp_msg(MSGT_TV,MSGL_V,"vbi_decode(%d):HammErr after decode_raw_line\n",i); continue; //hamError } magAddr=d0 & 0x7; pkt=(d0>>3)|(d1<<1); mp_msg(MSGT_TV,MSGL_DBG3,"vbi_decode(%d):%x %x (mag:%x, pkt:%d)\n", i,d0,d1,magAddr,pkt); if(!pkt){ decode_pkt0(priv,data+2,magAddr); //skip MRGA }else if(pkt>0 && pkt<VBI_ROWS){ if(!priv->mag[magAddr].pt) continue; decode_pkt_page(priv,data+2,magAddr,pkt);//skip MRGA }else if(pkt==27) { decode_pkt27(priv,data+2,magAddr); }else if(pkt==28){ decode_pkt28(priv,data+2); }else if(pkt==30){ decode_pkt30(priv,data+2,magAddr); } else { mp_msg(MSGT_TV,MSGL_DBG3,"unsupported packet:%d\n",pkt); } } if (priv->cache_reset){ pthread_mutex_lock(&(priv->buffer_mutex)); priv->cache_reset--; pthread_mutex_unlock(&(priv->buffer_mutex)); }}/*--------------------------------------------------------------------------------- Public routines---------------------------------------------------------------------------------*//** * \brief toggles teletext page displaying format * \param priv_vbi private data structure * \param flag new format * \return * TVI_CONTROL_TRUE is success, * TVI_CONTROL_FALSE otherwise * * flag: * 0 - opaque * 1 - transparent * 2 - opaque with black foreground color (only in bw mode) * 3 - transparent with black foreground color (only in bw mode) */static int teletext_set_format(priv_vbi_t * priv, teletext_format flag){ flag&=3; mp_msg(MSGT_TV,MSGL_DBG3,"teletext_set_format_is called. mode:%d\n",flag); pthread_mutex_lock(&(priv->buffer_mutex)); priv->tformat=flag; priv->pagenumdec=0; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE;}/** * \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->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 sequentially called (through slave * command of course) with 1,4,-,2,3 * values of dec parameter. * * +-----+------------+------------------+ * | dec | pagenumdec | 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, char *dec){ int count, shift; if (!dec) return; if (!priv->on) return; if ((*dec<'0' || *dec>'9') && *dec!='-') return; if (!priv->pagenumdec) //first digit cannot be '0','9' or '-' if(*dec=='-' || *dec=='0' || *dec=='9') return; pthread_mutex_lock(&(priv->buffer_mutex)); count=(priv->pagenumdec>>12)&0xf; if (*dec=='-') { count--; if (count) priv->pagenumdec=((priv->pagenumdec>>4)&0xfff)|(count<<12); else priv->pagenumdec=0; } else { shift = count * 4; count++; priv->pagenumdec= (((priv->pagenumdec)<<4|(*dec-'0'))&0xfff)|(count<<12); if (count==3) { priv->pagenum=priv->pagenumdec&0x7ff; priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum); priv->pagenumdec=0; } } pthread_mutex_unlock(&(priv->buffer_mutex));}/** * \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(void* p, int cmd, void *arg){ int fine_tune=99; priv_vbi_t* priv=(priv_vbi_t*)p; tt_page* pgc; if (!priv && cmd!=TV_VBI_CONTROL_START) return TVI_CONTROL_FALSE; if (!arg && cmd!=TV_VBI_CONTROL_STOP && cmd!=TV_VBI_CONTROL_MARK_UNCHANGED) return TVI_CONTROL_FALSE; switch (cmd) { case TV_VBI_CONTROL_RESET: { int i; tv_param_t* tv_param=arg; pthread_mutex_lock(&(priv->buffer_mutex)); priv->pagenumdec=0; clear_cache(priv); priv->pagenum=steppage(0,tv_param->tpage&0x7ff,1); priv->tformat=tv_param->tformat; priv->subpagenum=0x3f7f; pll_reset(priv,fine_tune); if(tv_param->tlang==-1){ mp_msg(MSGT_TV,MSGL_INFO,MSGTR_TV_TTSupportedLanguages); for(i=0; tt_languages[i].lang_code; i++){ mp_msg(MSGT_TV,MSGL_INFO," %3d %s\n", tt_languages[i].lang_code, tt_languages[i].lang_name); } mp_msg(MSGT_TV,MSGL_INFO," %3d %s\n", tt_languages[i].lang_code, tt_languages[i].lang_name); }else{ for(i=0; tt_languages[i].lang_code; i++){ if(tt_languages[i].lang_code==tv_param->tlang) break; } if (priv->primary_language!=tt_languages[i].lang_code){ mp_msg(MSGT_TV,MSGL_INFO,MSGTR_TV_TTSelectedLanguage, tt_languages[i].lang_name); priv->primary_language=tt_languages[i].lang_code; } } priv->page_changed=1; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE; } case TV_VBI_CONTROL_START: { int i; tt_stream_props* ptsp=*(tt_stream_props**)arg; if(!ptsp) return TVI_CONTROL_FALSE; priv=calloc(1,sizeof(priv_vbi_t)); priv->ptsp=malloc(sizeof(tt_stream_props)); memcpy(priv->ptsp,ptsp,sizeof(tt_stream_props)); *(priv_vbi_t**)arg=priv; priv->subpagenum=0x3f7f; pthread_mutex_init(&priv->buffer_mutex, NULL); priv->pagenumdec=0; for(i=0;i<VBI_ROWS*VBI_COLUMNS;i++) priv->display_page[i]=tt_space; priv->mag=calloc(8,sizeof(mag_t)); init_cache(priv); init_vbi_consts(priv); pll_reset(priv,fine_tune); priv->page_changed=1; return TVI_CONTROL_TRUE; } case TV_VBI_CONTROL_STOP: { if(priv->mag) free(priv->mag); if(priv->ptsp) free(priv->ptsp); destroy_cache(priv); priv->page_changed=1; free(priv); return TVI_CONTROL_TRUE; } case TV_VBI_CONTROL_SET_MODE: priv->on=(*(int*)arg%2); priv->page_changed=1; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_GET_MODE: *(int*)arg=priv->on; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_SET_FORMAT: priv->page_changed=1; return teletext_set_format(priv, *(int *) arg); case TV_VBI_CONTROL_GET_FORMAT: pthread_mutex_lock(&(priv->buffer_mutex)); *(int*)arg=priv->tformat; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_GET_HALF_PAGE: if(!priv->on) return TVI_CONTROL_FALSE; *(int *)arg=priv->zoom; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_SET_HALF_PAGE: { int val=*(int*)arg; val%=3; if(val<0) val+=3; pthread_mutex_lock(&(priv->buffer_mutex)); priv->zoom=val; priv->page_changed=1; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE; } case TV_VBI_CONTROL_GO_LINK: { int val=*(int *) arg; if(val<1 || val>6) return TVI_CONTROL_FALSE; pthread_mutex_lock(&(priv->buffer_mutex)); if (!(pgc = priv->ptt_cache[priv->pagenum])) { pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_FALSE; } if (!pgc->links[val-1].pagenum || pgc->links[val-1].pagenum>0x7ff) { pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_FALSE; } priv->pagenum=pgc->links[val-1].pagenum; if(pgc->links[val-1].subpagenum!=0x3f7f) priv->subpagenum=pgc->links[val-1].subpagenum; else priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum); priv->page_changed=1; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE; } case TV_VBI_CONTROL_SET_PAGE: { int val=*(int *) arg; if(val<100 || val>0x899) return TVI_CONTROL_FALSE; pthread_mutex_lock(&(priv->buffer_mutex)); priv->pagenum=val&0x7ff; priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum); priv->pagenumdec=0; priv->page_changed=1; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE; } case TV_VBI_CONTROL_STEP_PAGE: { int direction=*(int *) arg; pthread_mutex_lock(&(priv->buffer_mutex)); priv->pagenum=steppage(priv->pagenum, direction,1); priv->subpagenum=get_subpagenum_from_cache(priv,priv->pagenum); priv->pagenumdec=0; priv->page_changed=1; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE; } case TV_VBI_CONTROL_GET_PAGE: *(int*)arg=((priv->pagenum+0x700)&0x7ff)+0x100; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_SET_SUBPAGE: pthread_mutex_lock(&(priv->buffer_mutex)); priv->pagenumdec=0; priv->subpagenum=*(int*)arg; if(priv->subpagenum<0) priv->subpagenum=0x3f7f; if(priv->subpagenum>=VBI_MAX_SUBPAGES) priv->subpagenum=VBI_MAX_SUBPAGES-1; priv->page_changed=1; pthread_mutex_unlock(&(priv->buffer_mutex)); return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_GET_SUBPAGE: *(int*)arg=priv->subpagenum; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_ADD_DEC: vbi_add_dec(priv, *(char **) arg); priv->page_changed=1; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_DECODE_PAGE: vbi_decode(priv,*(unsigned char**)arg); return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_GET_VBIPAGE: if(!priv->on) return TVI_CONTROL_FALSE; prepare_visible_page(priv); *(void **)arg=priv->display_page; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_GET_NETWORKNAME: *(void **)arg=priv->networkname; return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_MARK_UNCHANGED: priv->page_changed=0; priv->last_rendered=GetTimerMS(); return TVI_CONTROL_TRUE; case TV_VBI_CONTROL_IS_CHANGED: if(GetTimerMS()-priv->last_rendered> 250) //forcing page update every 1/4 sec priv->page_changed=3; //mark that header update is enough *(int*)arg=priv->page_changed; return TVI_CONTROL_TRUE; } return TVI_CONTROL_UNKNOWN;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -