📄 dvbo.cpp
字号:
//===========================================================// DVB object (C++)// Handles all DVB stream analysis, in particular PSI data// Code is independent of encryption scheme used// (c) Aug 2008 by Dirktator//===========================================================#include "dvbo.h"#include "/data/dreambox/tuxbox-bb/build/tmp/staging/powerpc-linux/include/ost/dmx.h" #include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <sys/ioctl.h>#include <sys/poll.h>#include <sys/socket.h>#include <sys/types.h>#include <stropts.h> #include <sys/un.h>#include <unistd.h>#include <errno.h>//Constructor method, initializes the required variablesdvbo_handler::dvbo_handler(int progid, int dmx_fd, int debug){ int i; fd = dmx_fd; //just forward the demux file handle into an object-wide variable, saves a lot of passing of variables via function params! dbg = debug; //idem for debug flag ECMpidcount = 0; lock = 0; //We start with a state where no valid cardserver/EMU was identified for (i=0;i<20;i++) //clean ECMpids array { ECMpids[i].CA_PID = 0; ECMpids[i].CA_System_ID = 0; }}//Filter using the demux device; DVB API 1//return 0 on error, nonzero on okint dvbo_handler::Set_Filter(int pid, char filt, char mask){ struct dmxSctFilterParams sFP; if (dbg) printf("Set filter pid:%d, value:%d...",pid, filt); memset(&sFP,0,sizeof(sFP)); sFP.pid = pid; sFP.timeout = 5000; //wait max 5 seconds for ECM message sFP.flags = DMX_IMMEDIATE_START; sFP.filter.filter[0] = filt; sFP.filter.mask[0] = mask; if (ioctl(fd, DMX_SET_FILTER, &sFP) < 0) { perror(" Status"); return 0; } if (dbg) printf(" success!\n"); return 1;}//Stop filteringint dvbo_handler::Stop_Filter(void){ if (dbg) printf("Stopping filtering..."); if (ioctl(fd,DMX_STOP)<0) { perror(" Stop filter"); return 0; } if (dbg) printf(" success!\n"); return 1;}//Read and analyze the Program Allocation Table (id=0)//input: program number and demux device handler//returns: Program Map Table (PMT) idint dvbo_handler::Parse_PAT(int prognr){ char buffer[4096]; int i, j, n, seclen; char nib1, nib2; //nibble1 and 2 int pnr, pmtnr; //General fields printf("Parsing PAT, searching for PMT of SID %d\n",prognr); n=read(fd,buffer,4096); if (dbg) { printf("\tRead %d bytes\n",n); for (j=0;j<n;j+=16) //dump PAT data { printf("\t%04x: ",j); for (i=0;i<16;i++) printf("%02x ",buffer[j*16+i]); printf("\n"); } printf("\ttable_id:%d\n",buffer[0]); //8bit } nib2=(buffer[1]&0xF)<<4; seclen=nib2; seclen=(seclen<<4)+buffer[2]; //12bit if (dbg) printf("\tsection_length:%d\n",seclen); //PMT entries start as of byte 8 //Each entry consists of: i=8; pnr=0; pmtnr=0; while (i<seclen) //section counter { pnr=buffer[i]<<8; pnr+=buffer[i+1]; if (pnr==prognr) //Found it! Now read 13 PMT id bits { pmtnr=((buffer[i+2]<<8) + buffer[i+3])&0x1fff; //13 bits masking, skip first 3 bits printf("\tPMTid: %04x(%04d)\n",pmtnr,pmtnr); break; } i+=4; //next section } if (pnr!=prognr) { perror("\tPMT id not found!"); return 0; } else return pmtnr;}//Read a CA descriptor section from the stream, buffer is the streambuffer, i is the index to start parsing//input: pointer to data from the PMT containing CA data, length of the buffer//returns: nothingvoid dvbo_handler::Parse_CA_Descriptor_Section(char *buf, int cplen){ char cabuf[4096]; int x, j, capid, ptr=0; cabuf[0]=0; for (x=0;x<cplen+2;x++) cabuf[x]=buf[x]; //just bluntly copy all data in buf to the local buffer.... if (dbg) { printf("\t\tCA Descr Section: "); for (j=0;j<cplen;j++) printf("%02x ",cabuf[j]); } int casys=(cabuf[2]<<8)+cabuf[3]; char caSys[255]; if (dbg) switch (casys&0xff00) { case 0x600: sprintf(caSys,"Irdeto"); break; case 0x100: sprintf(caSys,"Seca"); break; case 0x1700: sprintf(caSys,"Betacrypt"); break; case 0x1800: sprintf(caSys,"Nagra (Kudelski)"); break; case 0x0900: sprintf(caSys,"News Datacom - VideoGuard"); break; case 0x0b00: sprintf(caSys,"Conax"); break; case 0x0d00: sprintf(caSys,"Philips Cryptoworks"); break; default: sprintf(caSys,"Unknown (%04x)", casys); } capid=((cabuf[4]<<8) + cabuf[5])&0x1fff; //13 bits masking, skip first 4 bits //now update global ECMpids array ECMpids[ECMpidcount].CA_PID=capid; //add the PID ECMpids[ECMpidcount].CA_System_ID=casys; //add the system id ECMpidcount++; if (dbg) printf("\n\t\t\t=> CA PID[%d]: %04x (%d), type: %04x (%s)\n",ECMpidcount, capid, capid, casys,caSys); }//Read the PMT and get the CA pid// CA sections are indicated by a value of 0x09 in the program_info field or 0x09 in the ES_info field// returns the amount of CA descriptors read;int dvbo_handler::Parse_PMT(int prognr){ char buffer[4096]; int i,j,n; int capid, eslen, seclen, stype; //Object property variable maintenance ECMpidcount=0; //when Parse_PMT is called we need to fill the ECMpids table from scratch! printf("Parsing PMT to find CA pid\n"); n=read(fd,buffer,4096); //read the data from the stream if (dbg) { printf("\tRead %d bytes\n",n); //dump hex table for (j=0;j<n;j+=16) { printf("\t%04x: ",j); for (i=0;i<16;i++) printf("%02x ",buffer[j+i]); printf("\n"); } } //section length seclen=((buffer[1]<<8) + buffer[2])&0x0fff; //12 bits masking if (dbg) printf("\tSection length: %d\n", seclen); //Program_Info_Length int pil=0; pil= ( (buffer[10]<<8) + buffer[11])&0x0fff; //12 bits masking, skip first 4 bits if (dbg) printf("\tProgram Info Section (length: %d)\n",pil); //program_info section int cnt=12; //start of pil subsections while(cnt<pil+17) { int dtag=buffer[cnt]; //printf("\t\tDtag: %02x ",dtag); int delen=buffer[cnt+1]; //printf("Des length: %d\n",delen); if (delen==0) { printf("Error\n"); break; } if (dtag==0x09) Parse_CA_Descriptor_Section(&buffer[cnt],delen); cnt+=(delen+2); } //Video stream descriptor sections if (dbg) printf("\tES Info Section\n"); int sec_start=12+pil; //first section while (sec_start<(seclen-4)) //note 4 last bytes are CRC, so do not try to read these! { //streamtype stype=buffer[sec_start]; //if (stype==0x02) printf("\tStreamtype: video (0x02)\n"); //if (stype==0x04) printf("\tStreamtype: audio (0x04)\n"); eslen=((buffer[sec_start+3]<<8)+buffer[sec_start+4])&0x0fff; //12 bits //printf("\tStreamtype: %02x; ES length: %d\n",stype, eslen); //anaylyse ES info length section, can contain multiple subsections int cnt=sec_start+5; while(cnt<(eslen+sec_start+5)) { int dtag=buffer[cnt]; //printf("\t\tDtag: %02x ",dtag); int delen=buffer[cnt+1]; //printf("Des length: %d\n",delen); if (delen==0) { printf("Error\n"); break; } //dtag=0x09 is CA information, streamtype=0x02 is video if ((stype==0x02)&&(dtag==0x09)) Parse_CA_Descriptor_Section(&buffer[cnt],delen); //for now only consider VIDEO ECM messages!!! cnt+=(delen+2); } sec_start+=(eslen+5); } return(ECMpidcount);}//Parse the CA section, goal: to retrieve the buffer that contains the control words//Inputs: demux file handler; the capid is just passed for debug reasons//Output: sets the object property ECMbuffer which contains the encrypted ECM packet and returns the providerid found in the ECMint dvbo_handler::Parse_ECM(int capid){ char ch; int n,j,i, calen, ecmlen, provid; if (dbg) printf("Parsing CA pid %04x (%04d)\n",capid,capid); for (i=0;i<4096;i++) ECMbuffer[i]=0; ECMbufsize = read(fd,ECMbuffer,184); //read the data from the stream, set the object property ECMbufsize if (dbg) { printf("\tRead %d bytes\n",ECMbufsize); printf("\tTable-id: %02x\n",ECMbuffer[0]); } calen=((ECMbuffer[1]<<8)+ECMbuffer[2])&0x0fff; //12 bits, useless data at the moment, maybe when we start building EMU's.... if (dbg) printf("\tCA section length: %d\n",calen); //Now parse the SECA specific data provid=(ECMbuffer[3]<<8)+ECMbuffer[4]; if (dbg) printf("\t\tProvider ID:%04x\n",provid); return(provid);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -