📄 tvi_vbi.c
字号:
fprintf(f,"\033[%dm",c1); color=c1; } if(dp[i*VBI_COLUMNS+j].gfx){ fprintf(f,"*"); }else{ pos=0; PUT_UTF8(u,tmp,if(pos<7) buf[pos++]=tmp;); buf[pos]='\0'; fprintf(f,"%s",buf); } } if (colored) fprintf(f,"\033[0m"); color=-1;bkg=-1; fprintf(f,"|\n"); }#if 1 //for debug fprintf(f,"+====================raw=================+\n"); for(i=0;i<VBI_ROWS;i++){ for(j=0;j<VBI_COLUMNS;j++) fprintf(f,"%02x ",dp[i*VBI_COLUMNS+j].raw); fprintf(f,"\n"); } fprintf(f,"+====================lng=================+\n"); for(i=0;i<VBI_ROWS;i++){ for(j=0;j<VBI_COLUMNS;j++) fprintf(f,"%02x ",dp[i*VBI_COLUMNS+j].lng); fprintf(f,"\n"); }#endif fprintf(f,"+========================================+\n");}/** * \brief dump page into pgXXX.txt file in vurrent directory * \param pt page to dump * * \note XXX in filename is page number * \note use only for debug purposes */static void dump_page(tt_page* pt){ FILE*f; char name[100]; snprintf(name,99,"pg%x.txt",pt->pagenum); f=fopen(name,"wb"); render2text(pt,f,1); fclose(f);}#endif //DEBUG_DUMP/** * \brief checks whether page is ready and copies it into cache array if so * \param priv private data structure * \param magAddr page's magazine address (0-7) * * Routine also calls decode_page to perform 1st stage of rendering */static void store_in_cache(priv_vbi_t* priv, int magAddr, int line){ mp_msg(MSGT_TV,MSGL_DBG2,"store_in_cache(%d): pagenum:%x\n", priv->mag[magAddr].order, priv->mag[magAddr].pt->pagenum); put_to_cache(priv,priv->mag[magAddr].pt,line); priv->curr_pagenum=priv->mag[magAddr].pt->pagenum;#ifdef DEBUG_DUMP dump_page(get_from_cache(priv, priv->mag[magAddr].pt->pagenum, priv->mag[magAddr].pt->subpagenum));#endif}/*------------------------------------------------------------------ Grabber stuff------------------------------------------------------------------*/#define PLL_SAMPLES 4#define PLL_ERROR 4#define PLL_ADJUST 4/** * \brief adjust current phase for better signal decoding * \param n count of bytes processed (?) * \param err count of error bytes (?) * * \remarks code was got from MythTV project */static void pll_add(priv_vbi_t* priv,int n,int err){ if(priv->pll_fixed) return; if(err>PLL_ERROR*2/3) err=PLL_ERROR*2/3; priv->pll_err+=err; priv->pll_cnt+=n; if(priv->pll_cnt<PLL_SAMPLES) return; if(priv->pll_err>PLL_ERROR) { if(priv->pll_err>priv->pll_lerr) priv->pll_dir= -priv->pll_dir; priv->pll_lerr=priv->pll_err; priv->pll_adj+=priv->pll_dir; if (priv->pll_adj<-PLL_ADJUST || priv->pll_adj>PLL_ADJUST) { priv->pll_adj=0; priv->pll_dir=-1; priv->pll_lerr=0; } mp_msg(MSGT_TV,MSGL_DBG3,"vbi: pll_adj=%2d\n",priv->pll_adj); } priv->pll_cnt=0; priv->pll_err=0;}/** * \brief reset error correction * \param priv private data structure * \param fine_tune shift value for adjusting * * \remarks code was got from MythTV project */static void pll_reset(priv_vbi_t* priv,int fine_tune){ priv->pll_fixed=fine_tune >= -PLL_ADJUST && fine_tune <= PLL_ADJUST; priv->pll_err=0; priv->pll_lerr=0; priv->pll_cnt=0; priv->pll_dir=-1; priv->pll_adj=0; if(priv->pll_fixed) priv->pll_adj=fine_tune; if(priv->pll_fixed) mp_msg(MSGT_TV,MSGL_DBG3,"pll_reset (fixed@%2d)\n",priv->pll_adj); else mp_msg(MSGT_TV,MSGL_DBG3,"pll_reset (auto)\n");}/** * \brief decode packet 0 (teletext page header) * \param priv private data structure * \param data raw teletext data (with not applied hamm correction yet) * \param magAddr teletext page's magazine address * * \remarks * data buffer was shifted by 6 and now contains: * 0..1 page number * 2..5 sub-code * 6..7 control codes * 8..39 display data * * only first 8 bytes protected by Hamm 8/4 code */static int decode_pkt0(priv_vbi_t* priv,unsigned char* data,int magAddr){ int d[8]; int i,err; if (magAddr<0 || magAddr>7) return 0; for(i=0;i<8;i++){ d[i]= corrHamm48[ data[i] ]; if(d[i]&0x80){ pll_add(priv,2,4); if(priv->mag[magAddr].pt) free(priv->mag[magAddr].pt); priv->mag[magAddr].pt=NULL; priv->mag[magAddr].order=0; return 0; } } if (!priv->mag[magAddr].pt) priv->mag[magAddr].pt= malloc(sizeof(tt_page)); if(priv->primary_language) priv->mag[magAddr].pt->primary_lang=priv->primary_language; else priv->mag[magAddr].pt->primary_lang= (d[7]&7)>>1; priv->mag[magAddr].pt->secondary_lang=priv->secondary_language; priv->mag[magAddr].pt->subpagenum=(d[2]|(d[3]<<4)|(d[4]<<8)|(d[5]<<12))&0x3f7f; priv->mag[magAddr].pt->pagenum=(magAddr<<8) | d[0] | (d[1]<<4); priv->mag[magAddr].pt->flags=((d[7]&1)<<7) | ((d[3]&8)<<3) | ((d[5]&12)<<2) | d[6]; memset(priv->mag[magAddr].pt->raw, 0x00, VBI_COLUMNS*VBI_ROWS); priv->mag[magAddr].order=0; for(i=0;i<8;i++){ priv->mag[magAddr].pt->raw[i]=0x20; } err=0; for(i=8; i<VBI_COLUMNS; i++){ data[i]= fixParity[data[i]]; priv->mag[magAddr].pt->raw[i]=data[i]; if(data[i]&0x80) //Error err++; pll_add(priv,1,err); } store_in_cache(priv,magAddr,0); return 1;}/** * \brief decode teletext 8/30 Format 1 packet * \param priv private data structure * \param data raw teletext data (with not applied hamm correction yet) * \param magAddr teletext page's magazine address * * \remarks * packet contains: * 0 designation code * 1..2 initial page * 3..6 initial subpage & magazine address * 7..8 network id * 9 time offset * 10..12 julian date * 13..15 universal time * 20..40 network name * * First 7 bytes are protected by Hamm 8/4 code. * Bytes 20-40 has odd parity check. * * See subcaluse 9.8.1 of specification for details */static int decode_pkt30(priv_vbi_t* priv,unsigned char* data,int magAddr){ int d[8]; int i,err; for(i=0;i<7;i++){ d[i]= corrHamm48[ data[i] ]; if(d[i]&0x80){ pll_add(priv,2,4); return 0; } d[i]&=0xf; } err=0; for(i=20; i<40; i++){ data[i]= fixParity[data[i]]; if(data[i]&0x80)//Unrecoverable error err++; pll_add(priv,1,err); } if (err) return 0; if (d[0]&0xe) //This is not 8/30 Format 1 packet return 1; priv->initialpage=d[1] | d[2]<<4 | (d[6]&0xc)<<7 | (d[4]&1)<<8; priv->initialsubpage=d[3] | d[4]<<4 | d[5]<<8 | d[6]<<12; priv->networkid=data[7]<<8 | data[8]; priv->timeoffset=(data[9]>>1)&0xf; if(data[9]&0x40) priv->timeoffset=-priv->timeoffset; priv->juliandate=(data[10]&0xf)<<16 | data[11]<<8 | data[12]; priv->juliandate-=0x11111; priv->universaltime=data[13]<<16 | data[14]<<8 | data[15]; priv->universaltime-=0x111111; snprintf(priv->networkname,21,"%s",data+20); return 1;}/** * \brief decode packets 1..24 (teletext page header) * \param priv private data structure * \param data raw teletext data * \param magAddr teletext page's magazine address * \param rowAddr teletext page's row number * * \remarks * data buffer was shifted by 6 and now contains 40 bytes of display data: * this type of packet is not proptected by Hamm 8/4 code */static void decode_pkt_page(priv_vbi_t* priv,unsigned char*data,int magAddr,int rowAddr){ int i,err; if (!priv->mag[magAddr].pt) return; priv->mag[magAddr].order=rowAddr; err=0; for(i=0; i<VBI_COLUMNS; i++){ data[i]= fixParity[ data[i] ]; priv->mag[magAddr].pt->raw[i+rowAddr*VBI_COLUMNS]=data[i]; if( data[i]&0x80) //HammError err++; } pll_add(priv,1,err); store_in_cache(priv,magAddr,rowAddr);}/** * \brief decode packets 27 (teletext links) * \param priv private data structure * \param data raw teletext data * \param magAddr teletext page's magazine address */static int decode_pkt27(priv_vbi_t* priv,unsigned char* data,int magAddr){ int i,hpg; if (!priv->mag[magAddr].pt) return 0; for(i=0;i<38;++i) if ((data[i] = corrHamm48[ data[i] ]) & 0x80){ pll_add(priv,2,4); return 0; } /* Not a X/27/0 Format 1 packet or flag "show links on row 24" is not set. */ if (data[0] || !(data[37] & 8)) return 1; for(i=0;i<6;++i) { hpg = (magAddr<<8) ^ ((data[4+i*6]&0x8)<<5 | (data[6+i*6]&0xc)<<7); if (!hpg) hpg=0x800; priv->mag[magAddr].pt->links[i].pagenum = (data[1+i*6] & 0xf) | ((data[2+i*6] & 0xf) << 4) | hpg; priv->mag[magAddr].pt->links[i].subpagenum = ((data[3+i*6] & 0xf) | (data[4+i*6] & 0xf) << 4 | (data[5+i*6] & 0xf) << 8 | (data[6+i*6] & 0xf) << 12) & 0x3f7f; } put_to_cache(priv,priv->mag[magAddr].pt,-1); return 1;}/** * \brief Decode teletext X/28/0 Format 1 packet * \param priv private data structure * \param data raw teletext data * * Primary G0 charset is transmitted in bits 14-8 of Triplet 1 * See Table 32 of specification for details. * * Secondary G0 charset is transmitted in bits 3-1 of Triplet 2 and * bits 18-15 of Triplet 1 * See Table 33 of specification for details. * */static void decode_pkt28(priv_vbi_t* priv,unsigned char*data){ int d; int t1,t2; d=corrHamm48[ data[0] ]; if(d) return; //this is not X/28/0 Format 1 packet or error occured t1=corrHamm24(data+1); t2=corrHamm24(data+4); if (t1<0 || t2<0){ pll_add(priv,1,4); return; } priv->primary_language=(t1>>7)&0x7f; priv->secondary_language=((t2<<4) | (t1>>14))&0x7f; if (priv->secondary_language==0x7f) //No secondary language required priv->secondary_language=priv->primary_language; else // Swapping bits 1 and 3 priv->secondary_language=(priv->secondary_language&0x7a) | (priv->secondary_language&4)>>2 | (priv->secondary_language&1)<<2; mp_msg(MSGT_TV,MSGL_DBG2,"pkt28: language: primary=%02x secondary=0x%02x\n", priv->primary_language,priv->secondary_language);}/** * \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 XawTV's algorithm. Signal phase is calculated with help of starting clock * run-in sequence (min/max values and bit distance values are calculated) */static int decode_raw_line_runin(priv_vbi_t* priv,unsigned char* buf,unsigned char* data){ const int magic= 0x27; // reversed 1110010 int dt[256],hi[6],lo[6]; int i,x,r; int decoded; int sync; unsigned char min,max; int thr=0; //threshold //stubs int soc=priv->soc; int eoc=priv->eoc; for(i=soc;i<eoc;i++) dt[i]=buf[i+priv->bpb/ONE_FIXP]-buf[i]; // amplifies the edges best. /* set barrier */ for (i=eoc; i<eoc+16; i+=2) dt[i]=100, dt[i+1]=-100; /* find 6 rising and falling edges */ for (i=soc, x=0; x<6; ++x) { while (dt[i]<32) i++; hi[x]=i; while (dt[i]>-32) i++; lo[x]=i; } if (i>=eoc) { return 0; // not enough periods found } i=hi[5]-hi[1]; // length of 4 periods (8 bits) if (i<priv->bp8bl || i>priv->bp8bh) { mp_msg(MSGT_TV,MSGL_DBG3,"vbi: wrong freq %d (%d,%d)\n", i,priv->bp8bl,priv->bp8bh); return 0; // bad frequency } /* AGC and sync-reference */ min=255, max=0, sync=0; for (i=hi[4]; i<hi[5]; ++i) if (buf[i]>max) max=buf[i], sync=i; for (i=lo[4]; i<lo[5]; ++i) if (buf[i]<min) min=buf[i]; thr=(min+max)/2; buf+=sync; // searching for '11' for(i=priv->pll_adj*priv->bpb/10;i<16*priv->bpb;i+=priv->bpb) if(buf[FIXP2INT(i)]>thr && buf[FIXP2INT(i+priv->bpb)]>thr) break; r=0; for(decoded=1; decoded<= (VBI_COLUMNS+3)<<3;decoded++){ r>>=1; if(buf[FIXP2INT(i)]>thr) r|=0x80; if(!(decoded & 0x07)){ data[(decoded>>3) - 1]=r; r=0; } i+=priv->bpb; } if(data[0]!=magic) return 0; //magic not found //stub for(i=0;i<43;i++){ data[i]=data[i+1]; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -