libdvb-0.5.5.1/0000755000175000017500000000000010220016115013016 5ustar mocmmocm00000000000000libdvb-0.5.5.1/include/0000755000175000017500000000000010220016115014441 5ustar mocmmocm00000000000000libdvb-0.5.5.1/include/channel.h0000644000175000017500000000232410220016115016223 0ustar mocmmocm00000000000000#ifndef _CHANNEL_H #define _CHANNEL_H #include struct channel { int id; char name[81]; int type; ushort pnr; ushort vpid; ushort apids[8]; ushort apidnum; ushort ac3pid; ushort pcrpid; uint freq; int pol; int qam; uint srate; int fec; }; #ifdef NEWSTRUCT #include #include #include #include #define DVR_DEV "/dev/dvb/adapter%d/dvr%d" #define VIDEO_DEV "/dev/dvb/adapter%d/video%d" #define AUDIO_DEV "/dev/dvb/adapter%d/audio%d" #define DEMUX_DEV "/dev/dvb/adapter%d/demux%d" #define FRONT_DEV "/dev/dvb/adapter%d/frontend%d" #define OSD_DEV "/dev/dvb/adapter%d/osd%d" #define CA_DEV "/dev/dvb/adapter%d/ca%d" #else #include #include #include #include #include #define DVR_DEV "/dev/ost/dvr%d" #define VIDEO_DEV "/dev/ost/video%d" #define AUDIO_DEV "/dev/ost/audio%d" #define DEMUX_DEV "/dev/ost/demux%d" #define FRONT_DEV "/dev/ost/frontend%d" #define OSD_DEV "/dev/ost/osd%d" #define CA_DEV "/dev/ost/ca%d" #endif #endif libdvb-0.5.5.1/include/DVB.hh0000644000175000017500000002632110220016115015401 0ustar mocmmocm00000000000000#ifndef _DVB_DEV_HH_ #define _DVB_DEV_HH_ extern "C" { #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define NEWSTRUCT #include #include } #include #include #include using namespace std; #include #include #define FRONT_DVBS 1 #define FRONT_DVBC 2 #define FRONT_DVBT 3 #define VTXDIR "/var/vtx" #define MAXSECSIZE 4096 enum {LNB=0,TRANS,CHAN,SAT,PICS,NK}; static const int nums[]={LNB,TRANS,CHAN,SAT,PICS}; static const int maxs[]={ 32, 512,3000,512,100, 50}; #define MAX_TRANS_CHAN 1024 #ifndef DMX_FULL_TS_PID #define DMX_FULL_TS_PID 0x2000 #endif enum{DVB_ORIG=0, DVB_NOKIA, DVB_XML, DVB_SATCO, DVB_ZAPS, DVB_ZAPC, DVB_ZAPT , DVB_VDR}; typedef struct frontend_stat_s{ fe_status_t status; uint16_t snr; uint16_t strength; uint32_t ber; uint32_t u_blocks; } frontend_stat; extern uint8_t hamtab[256]; extern uint8_t invtab[256]; #define MAX_MAG 8 typedef struct mag_struct_ { int valid; int magn; uint8_t flags; uint8_t lang; int pnum,sub; uint8_t pagebuf[25*40]; } magazin_t; #define secflags (DMX_IMMEDIATE_START|DMX_CHECK_CRC) typedef enum {LIBDVB_OUT, ZAP_OUT, VDR_OUT, MYTH_OUT} dvb_outtype; class DVB { public: int no_open; int fd_frontend; int fd_demuxa; int fd_demuxv; int fd_demuxpcr; int fd_demuxtt; int fdvb; dvb_outtype outtype; clock_t lastclock; struct tms ts; int showtime; int minor; int adapter; int max_tpid; int max_satid; int max_chanid; frontend_stat festat; struct dvb_diseqc_master_cmd dcmd; fe_sec_tone_mode_t tone; fe_sec_voltage_t voltage; int burst; struct dmx_pes_filter_params pesFilterParamsV; struct dmx_pes_filter_params pesFilterParamsA; struct dmx_pes_filter_params pesFilterParamsP; struct dmx_pes_filter_params pesFilterParamsTT; struct dvb_frontend_parameters front_param; int front_type; int dvr_enabled; OSD osd; uint32_t transponder_freq; char transponder_pol; uint32_t transponder_srate; fe_status_t status; uint32_t ber, uncorrected_blocks; uint16_t snr, signal; struct Lnb *lnbs; struct Transponder *tps; struct Channel *chans; struct Sat *sats; struct Picture *pics; struct Network *ntws; int num[NK]; int oldsec; int tryit; int oldpol; char *vtxdir; magazin_t magazin[MAX_MAG]; DVB(){ showtime = 0; no_open = 0; max_tpid = 0; max_satid = 0; max_chanid = 0; minor = 0; fd_frontend = -1; fd_demuxa = -1; fd_demuxpcr = -1; fd_demuxv = -1; fd_demuxtt = -1; fdvb = -1; vtxdir = NULL; transponder_freq=0; transponder_pol=0; transponder_srate=0; outtype = LIBDVB_OUT; } DVB(int i){ showtime = 0; if (i >= 0) no_open = 0; else no_open = 1; max_tpid = 0; max_satid = 0; max_chanid = 0; fd_frontend = -1; fd_demuxa = -1; fd_demuxpcr = -1; fd_demuxv = -1; fd_demuxtt = -1; fdvb = -1; vtxdir = NULL; transponder_freq=0; transponder_pol=0; transponder_srate=0; outtype = LIBDVB_OUT; init("","",i); } DVB(char *a, char *b) { showtime = 0; max_tpid = 0; max_satid = 0; max_chanid = 0; fd_frontend = -1; fd_demuxa = -1; fd_demuxpcr = -1; fd_demuxv = -1; fd_demuxtt = -1; fdvb = -1; vtxdir = NULL; init(a,b,0); outtype = LIBDVB_OUT; } ~DVB(); void use_osd(int fd = -1){ char dvn[32]; if (no_open) return; if (fd < 0) fd = 0; sprintf(dvn,OSD_DEV,adapter,fd); fdvb = open(dvn, O_RDWR); if (fdvb >= 0){ cerr << dvn << " for OSD" << endl; osd.init(fdvb); } else perror("osd"); osd.Open(80, 500, 640, 540, 2, 0, 2); osd.SetColor(0, 0, 0, 0, 255); osd.SetColor(1, 240, 240, 240, 255); osd.Show(); } void set_vtxdir(char *newname){ if (!newname) return; if (vtxdir) free(vtxdir); vtxdir = (char *) malloc(sizeof(char)*(strlen(newname)+1)); if (vtxdir) strncpy(vtxdir, newname, strlen(newname)); } void close_osd(){ osd.Close(fdvb); close(fdvb); } void set_showtime(int s){ showtime = s; } int DVR_enabled(){ if (no_open) return -1; return dvr_enabled; } void enable_DVR(){ if (no_open) return; dvr_enabled = 1; } void enable_DVR_other(){ if (no_open) return; dvr_enabled = 2; } void disable_DVR(){ if (no_open) return; dvr_enabled = 0; } void init(char *a="/dev/video0", char *b="/dev/vbi0",int adapt=0, int minor = 0); inline void init(char *a, char *b){ if (no_open) return; init(a,b,0,0); } int check_frontend(); void set_apid(ushort apid); void set_vpid(ushort vpid); void set_pcrpid(ushort vpid); void set_ttpid(ushort ttpid); void stop_apid(); void stop_vpid(); void stop_ttpid(); void stop_pcrpid(); int set_apid_fd(ushort apid, int fd); int set_vpid_fd(ushort vpid, int fd); int set_ttpid_fd(ushort ttpid, int fd); int set_pcrpid_fd(ushort pcrpid, int fd); int set_otherpid_fd(ushort otherpid, int fd); void stop_pid_fd(int fd); int set_lnb(int dis); void set_diseqc_nb(int nr); void set_diseqc(); void toggle_diseqc(); int set_front(void); void get_front(void); void scan_multi_eit(int verbose=0); void scan_pf_eit(int chnr, int (*callback)(uint8_t *data, int l, int pnr, int c_n, uint8_t *t)); void scan_pf_eit(Channel *chan, int (*callback)(uint8_t *data, int l, int pnr, int c_n, uint8_t *t)); void scan_pf_eit(int chnr); int search_in_TP(Transponder &tp, int show=1, int verbose=0); int search_in_TP(uint16_t tpid, uint16_t satid, int show=1, int verbose=0); int scan_tp(uint16_t tpid, uint16_t satid, int timeout=-1, int verbose=0); int scan_TP(uint16_t tpid, uint16_t satid, int timeout=-1, int verbose=0); int scan_current(int timeout=-1, int verbose=0); int GetSection(uint8_t *buf, uint16_t PID, uint8_t TID, uint16_t TIDExt, uint16_t FilterTIDExt, uint8_t secnum, uint8_t &msecnum); int GetSection(uint8_t *buf, uint16_t PID, uint8_t *filter, uint8_t *mask, uint8_t secnum, uint8_t &msecnum); int GetSection(uint8_t *buf, ushort PID, uint8_t sec, uint8_t secnum, uint8_t &msecnum); int SetFilter(uint16_t pid, uint8_t *filter, uint8_t *mask, uint32_t timeout, uint32_t flags); uint16_t SetFilter(uint16_t pid, uint16_t section, uint16_t mode); int CloseFilter(int h); int SetFullFilter(uint16_t pid=NOPID); void bar2(int x, int y, int w, int h, int val, int col1, int col2); int SetTP(unsigned int, unsigned int); int scan(void); int scan_all_tps(void); int scan_lnb(struct Lnb &); int scan_cable(Sat &sat); int scan_sat(struct Sat &); int scan_tp(struct Transponder &); int AddLNB(int id, int t, uint l1, uint l2, uint sl, int dnr, int dis, int sw); int AddSat(Sat &sat); int AddSat(int satid, unsigned int lnbid, char *name, uint fmin, uint fmax); int AddTP(Transponder &tp); int AddChannel(Channel &chan); int parse_descriptor(Channel *chan, uint8_t *data, int length, int verb, Transponder *tp); int parse_pmt(Channel *chan, uint8_t *data); int parse_pat(Channel *chan, uint8_t *data); int check_pids(Channel *chan); void check_all_pids(); void scan_sdt(Channel *chan); int scan_sdts(int *chs, int n); int channel_num(void) { return num[CHAN]; }; int channel_change(int n) { return 0; }; int SetChannel(uint16_t, uint16_t, uint16_t, uint16_t); int SetChannel(Channel *chan, char* apref=NULL, uint16_t *apidp=NULL, uint16_t *vpidp=NULL) ; int SetChannel(int chnr, char *apref=NULL, uint16_t *apidp=NULL, uint16_t *vpidp=NULL, bool tune=true); int GetChannel(int chnr, struct channel *); int NumChannel(void) { return num[CHAN]; } int tune_it(struct dvb_frontend_parameters *qpsk); void find_satid(Channel &chan); Transponder *find_tp(Channel *chan); Transponder *find_tp(unsigned int tpid, unsigned int satid); Sat *find_sat(Transponder *tp); Sat *find_sat(Channel *chan); Lnb *find_lnb(Sat *sat); int check_input_format(istream &ins); void read_original(istream &ins); int get_all_progs(uint16_t *progbuf, uint16_t *pnrbuf, int length); uint16_t find_pnr(uint16_t vpid, uint16_t apid); int get_pids(uint16_t prog_pid, uint16_t *vpid, uint16_t *apids, uint16_t *ttpid, uint8_t *apids_name=NULL); void AddECM(Channel *chan, uint8_t *data, int length); int check_ecm(Channel *chan); void add_vtx_line(magazin_t *mag, int line, uint8_t *data, int pnr); dvb_outtype get_outtype(void); void set_outtype(dvb_outtype type); friend ostream &operator<<(ostream &stream, DVB &x); friend istream &operator>>(istream &stream, DVB &x); }; #define NOKIA_MAX_SAT 4 class nokiaconv{ public: DVB *dvb; struct lnb_sat_l{ int n; int diseqc[NOKIA_MAX_SAT]; char sat_names[NOKIA_MAX_SAT][MAXNAM+1]; int satid[NOKIA_MAX_SAT]; } lnb_sat; nokiaconv(DVB *d){ dvb = d; } friend istream &operator>>(istream &stream, nokiaconv &x); }; #define XML_MAX_SAT 4 class xmlconv{ public: DVB *dvb; struct lnb_sat_l{ int n; int diseqc[XML_MAX_SAT]; char sat_names[XML_MAX_SAT][MAXNAM+1]; int satid[XML_MAX_SAT]; } lnb_sat; xmlconv(DVB *d){ dvb = d; } int read_stream(istream &ins, int nchan); int read_desc(istream &ins, int nchan); int read_serv(istream &ins, int ctp, int csat); int read_trans(istream &ins, int satid); int read_sat(istream &ins, int satid = -1); int skip_tag(istream &ins, char *tag); int read_iso639(istream &ins, int nchan, int apids); friend istream &operator>>(istream &stream, xmlconv &x); }; #define SATCO_MAX_SAT 10 class satcoconv{ public: DVB *dvb; int nlnb; satcoconv(DVB *d){ dvb = d; } friend istream &operator>>(istream &stream, satcoconv &x); }; class vdrconv{ public: DVB *dvb; vdrconv(DVB *d){ dvb = d; } friend istream &operator>>(istream &stream, vdrconv &x); }; class zapconv{ public: DVB *dvb; zapconv(DVB *d){ dvb = d; } friend istream &operator>>(istream &stream, zapconv &x); }; void hdump(uint8_t *buf, int n); int get_dvbrc(char *path, DVB &dv, int dev, int len); int set_dvbrc(char *path, DVB &dv, int dev, int len); void dvb2txt(char *out, char *in, int len); int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum, fe_code_rate_t fec); void set_pes_filt(int fd,uint16_t pes_pid); void set_diseqc(int fdf, int snum, fe_sec_voltage_t v, fe_sec_tone_mode_t t); int tune(int fdf, uint32_t freq, uint32_t sr, fe_code_rate_t fec, fe_spectral_inversion_t inv); int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum, fe_code_rate_t fec); struct in_addr getaddress (const char *name); int tcp_client_connect(const char *hostname, int sckt); int udp_client_connect(const char *filename); void client_send_msg(int fd, uint8_t *msg, int size); int chck_frontend (int fefd, frontend_stat *festat); uint8_t deham(uint8_t x, uint8_t y); #endif libdvb-0.5.5.1/include/OSD.h0000644000175000017500000000216610220016115015244 0ustar mocmmocm00000000000000#ifndef _OSD_H_ #define _OSD_H_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ int OSDClose(int dev); int OSDOpen(int dev, int x0, int y0, int x1, int y1, int BitPerPixel, int mix); int OSDShow(int dev); int OSDHide(int dev); int OSDClear(int dev); int OSDFill(int dev, int color); int OSDSetColor(int dev, int color, int r, int g, int b, int op); int OSDText(int dev, int x, int y, int size, int color, const char *text); int OSDSetPalette(int dev, int first, int last, unsigned char *data); int OSDSetTrans(int dev, int trans); int OSDSetPixel(int dev, int x, int y, unsigned int color); int OSDGetPixel(int dev, int x, int y); int OSDSetRow(int dev, int x, int y, int x1, unsigned char *data); int OSDSetBlock(int dev, int x, int y, int x1, int y1, int inc, unsigned char *data); int OSDFillRow(int dev, int x, int y, int x1, int color); int OSDFillBlock(int dev, int x, int y, int x1, int y1, int color); int OSDLine(int dev, int x, int y, int x1, int y1, int color); int OSDQuery(int dev); int OSDSetWindow(int dev, int win); int OSDMoveWindow(int dev, int x, int y); #ifdef __cplusplus } #endif /* __cplusplus */ #endif libdvb-0.5.5.1/include/cpptools.hh0000644000175000017500000001272510220016115016634 0ustar mocmmocm00000000000000/* * dvb-mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * Copyright (C) 2002 Marcus Metzler * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at mocm@metzlerbros.de, */ #include #include #include #include using namespace std; #ifndef _CPPTOOLS_HH_ #define _CPPTOOLS_HH_ #include "ctools.h" class PES_Packet{ int info; pes_packet p; public: PES_Packet(){ info = 0; init_pes(&p); } ~PES_Packet(){ if (p.pack_header) delete [] p.pack_header; if (p.pes_ext) delete [] p.pes_ext; if (p.pes_pckt_data) delete [] p.pes_pckt_data; if (p.mpeg1_headr) delete [] p.mpeg1_headr; } inline void init(){ if (p.pack_header) delete [] p.pack_header; if (p.pes_ext) delete [] p.pes_ext; if (p.pes_pckt_data) delete [] p.pes_pckt_data; if (p.mpeg1_headr) delete [] p.mpeg1_headr; info = 0; init_pes(&p); } inline pes_packet *P(){ return &p; } inline void setlength(){ setlength_pes(&p); if (p.length) p.pes_pckt_data = new uint8_t[p.length]; } inline void Nlength(){ nlength_pes(&p); p.pes_pckt_data = new uint8_t[p.length]; } inline uint8_t &Stream_ID(){ return p.stream_id; } inline uint8_t &Flags1(){ return p.flags1; } inline uint8_t &Flags2(){ return p.flags2; } inline uint32_t &Length(){ return p.length; } inline uint8_t &HLength(){ return p.pes_hlength; } inline uint8_t &Stuffing(){ return p.stuffing; } inline uint8_t *Data(){ return p.pes_pckt_data; } inline int has_pts(){ return (p.flags2 & PTS_DTS); } inline int &MPEG(){ return p.mpeg; } inline uint8_t *PTS(){ return p.pts; } inline uint8_t *DTS(){ return p.dts; } inline int &Info(){ return info; } inline uint8_t high_pts(){ if (has_pts()) return ((p.pts[0] & 0x08)>>3); else return 0; } inline uint8_t high_dts(){ return ((p.dts[0] & 0x08)>>3); } inline int WDTS(){ int w_dts; w_dts = (int)trans_pts_dts(p.dts); return w_dts; } inline int WPTS(){ int w_dts; w_dts = (int)trans_pts_dts(p.pts); return w_dts; } friend ostream & operator << (ostream & stream, PES_Packet & x); friend istream & operator >> (istream & stream, PES_Packet & x); }; class TS_Packet{ ts_packet p; int info; public: TS_Packet(){ init_ts(&p); info = 0; } ~TS_Packet(){ if (p.priv_dat) delete [] p.priv_dat; } inline void init(){ if (p.priv_dat) delete [] p.priv_dat; init_ts(&p); info = 0; } inline ts_packet *P(){ return &p; } inline int &Rest(){ return p.rest; } inline uint8_t *Data(){ return p.data; } inline short PID(){ return pid_ts(&p); } inline uint8_t FLAG1(){ return (p.pid[0] & ~PID_MASK_HI); } inline int &Info(){ return info; } friend ostream & operator << (ostream & stream, TS_Packet & x); friend istream & operator >> (istream & stream, TS_Packet & x); }; class PS_Packet{ int info; ps_packet p; public: PS_Packet(){ init_ps(&p); info = 0; } ~PS_Packet(){ if (p.data) delete [] p.data; } inline void init(){ if (p.data) delete [] p.data; init_ps(&p); info = 0; } inline ps_packet *P(){ return &p; } inline int MUX(){ return mux_ps(&p); } inline int Rate(){ return rate_ps(&p); } inline void setlength(){ setlength_ps(&p); p.data = new uint8_t[p.sheader_length]; } inline int Stuffing(){ return p.stuff_length & PACK_STUFF_MASK; } inline int NPES(){ return p.npes; } inline int &MPEG(){ return p.mpeg; } inline uint8_t &operator()(int l){ return p.data[l]; } inline char * Data() { return (char *)p.data+p.stuff_length; } inline int &SLENGTH(){ return p.sheader_length; } inline int &Info(){ return info; } uint32_t SCR_base(){ return scr_base_ps(&p); } uint16_t SCR_ext(){ return scr_ext_ps(&p); } friend ostream & operator << (ostream & stream, PS_Packet & x); friend istream & operator >> (istream & stream, PS_Packet & x); }; typedef void (* FILTER)(istream &in, ostream &out); typedef struct thread_args_{ FILTER function; int *fd; int in; int out; } thread_args; void extract_audio_from_PES(istream &in, ostream &out); void extract_video_from_PES(istream &in, ostream &out); void extract_es_audio_from_PES(istream &in, ostream &out); void extract_es_video_from_PES(istream &in, ostream &out); int TS_PIDS(istream &in, ostream &out); int ifilter (istream &in, FILTER function); int ofilter (istream &in, FILTER function); int itfilter (int in, FILTER function); int otfilter (istream &in, FILTER function); int stream_type(int fd); int stream_type(istream &stream); int tv_norm(istream &fin); void analyze(istream &fin); #endif //_CPPTOOLS_HH_ libdvb-0.5.5.1/include/ci.hh0000644000175000017500000001126110220016115015356 0ustar mocmmocm00000000000000/* * ci.hh: Common Interface * * Copyright (C) 2000 Klaus Schmidinger * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at kls@cadsoft.de * * The project's page is at http://www.cadsoft.de/people/kls/vdr * */ #ifndef __CI_H #define __CI_H #include #include #include #include #include #include #include #include #include #define MAXCASYSTEMIDS 16 class cMutex { friend class cCondVar; private: pthread_mutex_t mutex; pid_t lockingPid; int locked; public: cMutex(void); ~cMutex(); void Lock(void); void Unlock(void); }; class cMutexLock { private: cMutex *mutex; bool locked; public: cMutexLock(cMutex *Mutex = NULL); ~cMutexLock(); bool Lock(cMutex *Mutex); }; class cCiMMI; class cCiMenu { friend class cCiMMI; private: enum { MAX_CIMENU_ENTRIES = 64 }; ///< XXX is there a specified maximum? cCiMMI *mmi; bool selectable; char *titleText; char *subTitleText; char *bottomText; char *entries[MAX_CIMENU_ENTRIES]; int numEntries; bool AddEntry(char *s); cCiMenu(cCiMMI *MMI, bool Selectable); public: ~cCiMenu(); const char *TitleText(void) { return titleText; } const char *SubTitleText(void) { return subTitleText; } const char *BottomText(void) { return bottomText; } const char *Entry(int n) { return n < numEntries ? entries[n] : NULL; } int NumEntries(void) { return numEntries; } bool Selectable(void) { return selectable; } bool Select(int Index); bool Cancel(void); }; class cCiEnquiry { friend class cCiMMI; private: cCiMMI *mmi; char *text; bool blind; int expectedLength; cCiEnquiry(cCiMMI *MMI); public: ~cCiEnquiry(); const char *Text(void) { return text; } bool Blind(void) { return blind; } int ExpectedLength(void) { return expectedLength; } bool Reply(const char *s); bool Cancel(void); }; class cCiCaPmt { friend class cCiConditionalAccessSupport; private: int length; int esInfoLengthPos; uint8_t capmt[2048]; ///< XXX is there a specified maximum? public: cCiCaPmt(int ProgramNumber); void AddPid(int Pid); void AddCaDescriptor(int Length, uint8_t *Data); }; #define MAX_CI_SESSION 16 //XXX class cCiSession; class cCiTransportLayer; class cCiTransportConnection; class cCiHandler { private: cMutex mutex; int fd; int numSlots; bool newCaSupport; bool hasUserIO; cCiSession *sessions[MAX_CI_SESSION]; cCiTransportLayer *tpl; cCiTransportConnection *tc; int ResourceIdToInt(const uint8_t *Data); bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1); cCiSession *GetSessionBySessionId(int SessionId); cCiSession *GetSessionByResourceId(int ResourceId, int Slot); cCiSession *CreateSession(int ResourceId); bool OpenSession(int Length, const uint8_t *Data); bool CloseSession(int SessionId); int CloseAllSessions(int Slot); cCiHandler(int Fd, int NumSlots); public: ~cCiHandler(); static cCiHandler *CreateCiHandler(const char *FileName); int NumSlots(void) { return numSlots; } bool Process(void); bool HasUserIO(void) { return hasUserIO; } bool EnterMenu(int Slot); cCiMenu *GetMenu(void); cCiEnquiry *GetEnquiry(void); bool SetCaPmt(cCiCaPmt &CaPmt); const unsigned short *GetCaSystemIds(int Slot); bool SetCaPmt(cCiCaPmt &CaPmt, int Slot); bool Reset(int Slot); bool connected() const; }; int tcp_listen(struct sockaddr_in *name,int sckt,unsigned long address=INADDR_ANY); int accept_tcp(int ip_sock,struct sockaddr_in *ip_name); int udp_listen(struct sockaddr_un *name,char const * const filename); int accept_udp(int ip_sock,struct sockaddr_un *ip_name); extern "C"{ int ci_reset(int fd, int slot); int ci_enable_pnr(int fd, int slot, int ci, uint16_t pnr); int ci_cancel_menu(int fd, int slot); int ci_enter_menu(int fd, int slot); int ci_menu_select(int fd, int slot, uint8_t sl); int ci_getmsg(int fd, int slot, uint8_t *buf); } #endif //__CI_H libdvb-0.5.5.1/include/dvb/0000755000175000017500000000000010220016115015214 5ustar mocmmocm00000000000000libdvb-0.5.5.1/include/dvb/CVS/0000755000175000017500000000000010220016115015647 5ustar mocmmocm00000000000000libdvb-0.5.5.1/include/dvb/CVS/Root0000644000175000017500000000004510220016115016514 0ustar mocmmocm00000000000000:pserver:dmocm@morden:/usr2/home/cvs libdvb-0.5.5.1/include/dvb/CVS/Repository0000644000175000017500000000002710220016115017750 0ustar mocmmocm00000000000000DVB/libdvb/include/dvb libdvb-0.5.5.1/include/dvb/CVS/Entries0000644000175000017500000000000210220016115017173 0ustar mocmmocm00000000000000D libdvb-0.5.5.1/include/ctools.h0000644000175000017500000002315010220016115016116 0ustar mocmmocm00000000000000/* * dvb-mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * Copyright (C) 2002, 2003 Marcus Metzler * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at mocm@metzlerbros.de */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ringbuffy.h" #include "transform.h" #ifndef _CTOOLS_H_ #define _CTOOLS_H_ #define VIDEO_MODE_PAL 0 #define VIDEO_MODE_NTSC 1 #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ enum {PS_STREAM, TS_STREAM, PES_STREAM}; enum {pDUNNO, pPAL, pNTSC}; uint64_t trans_pts_dts(uint8_t *pts); /* PES */ #define PROG_STREAM_MAP 0xBC #ifndef PRIVATE_STREAM1 #define PRIVATE_STREAM1 0xBD #endif #define PADDING_STREAM 0xBE #ifndef PRIVATE_STREAM2 #define PRIVATE_STREAM2 0xBF #endif #define AUDIO_STREAM_S 0xC0 #define AUDIO_STREAM_E 0xDF #define VIDEO_STREAM_S 0xE0 #define VIDEO_STREAM_E 0xEF #define ECM_STREAM 0xF0 #define EMM_STREAM 0xF1 #define DSM_CC_STREAM 0xF2 #define ISO13522_STREAM 0xF3 #define PROG_STREAM_DIR 0xFF #define BUFFYSIZE 10*MAX_PLENGTH #define MAX_PTS 8192 #define MAX_FRAME 8192 #define MAX_PACK_L 4096 #define PS_HEADER_L1 14 #define PS_HEADER_L2 (PS_HEADER_L1+18) #define MAX_H_SIZE (PES_H_MIN + PS_HEADER_L1 + 5) #define PES_MIN 7 #define PES_H_MIN 9 //flags1 #define FLAGS 0x40 #define SCRAMBLE_FLAGS 0x30 #define PRIORITY_FLAG 0x08 #define DATA_ALIGN_FLAG 0x04 #define COPYRIGHT_FLAG 0x02 #define ORIGINAL_FLAG 0x01 //flags2 #define PTS_DTS_FLAGS 0xC0 #define ESCR_FLAG 0x20 #define ES_RATE_FLAG 0x10 #define DSM_TRICK_FLAG 0x08 #define ADD_CPY_FLAG 0x04 #define PES_CRC_FLAG 0x02 #define PES_EXT_FLAG 0x01 //pts_dts flags #define PTS_ONLY 0x80 #define PTS_DTS 0xC0 //private flags #define PRIVATE_DATA 0x80 #define HEADER_FIELD 0x40 #define PACK_SEQ_CTR 0x20 #define P_STD_BUFFER 0x10 #define PES_EXT_FLAG2 0x01 #define MPEG1_2_ID 0x40 #define STFF_LNGTH_MASK 0x3F typedef struct pes_packet_{ uint8_t stream_id; uint8_t llength[2]; uint32_t length; uint8_t flags1; uint8_t flags2; uint8_t pes_hlength; uint8_t pts[5]; uint8_t dts[5]; uint8_t escr[6]; uint8_t es_rate[3]; uint8_t trick; uint8_t add_cpy; uint8_t prev_pes_crc[2]; uint8_t priv_flags; uint8_t pes_priv_data[16]; uint8_t pack_field_length; uint8_t *pack_header; uint8_t pck_sqnc_cntr; uint8_t org_stuff_length; uint8_t p_std[2]; uint8_t pes_ext_lngth; uint8_t *pes_ext; uint8_t *pes_pckt_data; int padding; int mpeg; int mpeg1_pad; uint8_t *mpeg1_headr; uint8_t stuffing; } pes_packet; void init_pes(pes_packet *p); void kill_pes(pes_packet *p); void setlength_pes(pes_packet *p); void nlength_pes(pes_packet *p); int cwrite_pes(uint8_t *buf, pes_packet *p, long length); void write_pes(int fd, pes_packet *p); int read_pes(int f, pes_packet *p); void cread_pes(char *buf, pes_packet *p); /* Transport Stream */ #define TS_SIZE 188 #define TRANS_ERROR 0x80 #define PAY_START 0x40 #define TRANS_PRIO 0x20 #define PID_MASK_HI 0x1F //flags #define TRANS_SCRMBL1 0x80 #define TRANS_SCRMBL2 0x40 #define ADAPT_FIELD 0x20 #define PAYLOAD 0x10 #define COUNT_MASK 0x0F // adaptation flags #define DISCON_IND 0x80 #define RAND_ACC_IND 0x40 #define ES_PRI_IND 0x20 #define PCR_FLAG 0x10 #define OPCR_FLAG 0x08 #define SPLICE_FLAG 0x04 #define TRANS_PRIV 0x02 #define ADAP_EXT_FLAG 0x01 // adaptation extension flags #define LTW_FLAG 0x80 #define PIECE_RATE 0x40 #define SEAM_SPLICE 0x20 typedef struct ts_packet_{ uint8_t pid[2]; uint8_t flags; uint8_t count; uint8_t data[184]; uint8_t adapt_length; uint8_t adapt_flags; uint8_t pcr[6]; uint8_t opcr[6]; uint8_t splice_count; uint8_t priv_dat_len; uint8_t *priv_dat; uint8_t adapt_ext_len; uint8_t adapt_eflags; uint8_t ltw[2]; uint8_t piece_rate[3]; uint8_t dts[5]; int rest; uint8_t stuffing; } ts_packet; void init_ts(ts_packet *p); void kill_ts(ts_packet *p); unsigned short pid_ts(ts_packet *p); int cwrite_ts(uint8_t *buf, ts_packet *p, long length); void write_ts(int fd, ts_packet *p); int read_ts(int f, ts_packet *p); void cread_ts (char *buf, ts_packet *p, long length); /* Program Stream */ #define PACK_STUFF_MASK 0x07 #define FIXED_FLAG 0x02 #define CSPS_FLAG 0x01 #define SAUDIO_LOCK_FLAG 0x80 #define SVIDEO_LOCK_FLAG 0x40 #define PS_MAX 200 typedef struct ps_packet_{ uint8_t scr[6]; uint8_t mux_rate[3]; uint8_t stuff_length; uint8_t *data; uint8_t sheader_llength[2]; int sheader_length; uint8_t rate_bound[3]; uint8_t audio_bound; uint8_t video_bound; uint8_t reserved; int npes; int mpeg; } ps_packet; void init_ps(ps_packet *p); void kill_ps(ps_packet *p); void setlength_ps(ps_packet *p); uint32_t scr_base_ps(ps_packet *p); uint16_t scr_ext_ps(ps_packet *p); int mux_ps(ps_packet *p); int rate_ps(ps_packet *p); int cwrite_ps(uint8_t *buf, ps_packet *p, long length); void write_ps(int fd, ps_packet *p); int read_ps (int f, ps_packet *p); void cread_ps (char *buf, ps_packet *p, long length); #define MAX_PLENGTH 0xFFFF typedef struct sectionstruct { int id; int length; int found; uint8_t payload[4096+3]; } section; typedef uint32_t tflags; #define MAXFILT 32 #define MASKL 16 typedef struct trans_struct { int found; uint8_t packet[188]; uint16_t pid[MAXFILT]; uint8_t mask[MAXFILT*MASKL]; uint8_t filt[MAXFILT*MASKL]; uint8_t transbuf[MAXFILT*188]; int transcount[MAXFILT]; section sec[MAXFILT]; tflags is_full; tflags pes_start; tflags pes_started; tflags pes; tflags set; } trans; void init_trans(trans *p); int set_trans_filt(trans *p, int filtn, uint16_t pid, uint8_t *mask, uint8_t *filt, int pes); void clear_trans_filt(trans *p,int filtn); int filt_is_set(trans *p, int filtn); int pes_is_set(trans *p, int filtn); int pes_is_started(trans *p, int filtn); int pes_is_start(trans *p, int filtn); int filt_is_ready(trans *p,int filtn); void trans_filt(uint8_t *buf, int count, trans *p); void tfilter(trans *p); void pes_filter(trans *p, int filtn, int off); void sec_filter(trans *p, int filtn, int off); int get_filt_buf(trans *p, int filtn,uint8_t **buf); section *get_filt_sec(trans *p, int filtn); typedef struct a2pstruct{ int type; int fd; int found; int length; int headr; int plength; uint8_t cid; uint8_t flags; uint8_t abuf[MAX_PLENGTH]; int alength; uint8_t vbuf[MAX_PLENGTH]; int vlength; uint8_t last_av_pts[4]; uint8_t av_pts[4]; uint8_t scr[4]; uint8_t pid0; uint8_t pid1; uint8_t pidv; uint8_t pida; } a2p; void get_pespts(uint8_t *av_pts,uint8_t *pts); void init_a2p(a2p *p); void av_pes_to_pes(uint8_t *buf,int count, a2p *p); int w_pesh(uint8_t id,int length ,uint8_t *pts, uint8_t *obuf); int w_tsh(uint8_t id,int length ,uint8_t *pts, uint8_t *obuf,a2p *p,int startpes); void pts2pts(uint8_t *av_pts, uint8_t *pts); void write_ps_headr(ps_packet *p,uint8_t *pts,int fd); typedef struct p2t_s{ uint8_t pes[TS_SIZE]; uint8_t counter; long int pos; int frags; void (*t_out)(uint8_t const *buf); } p2t_t; void twrite(uint8_t const *buf); void init_p2t(p2t_t *p, void (*fkt)(uint8_t const *buf)); long int find_pes_header(uint8_t const *buf, long int length, int *frags); void pes_to_ts( uint8_t const *buf, long int length, uint16_t pid, p2t_t *p); void p_to_t( uint8_t const *buf, long int length, uint16_t pid, uint8_t *counter, void (*ts_write)(uint8_t const *)); int write_pes_header(uint8_t id,int length , long PTS, uint8_t *obuf, int stuffing); int write_ps_header(uint8_t *buf, uint32_t SCR, long muxr, uint8_t audio_bound, uint8_t fixed, uint8_t CSPS, uint8_t audio_lock, uint8_t video_lock, uint8_t video_bound, uint8_t stream1, uint8_t buffer1_scale, uint32_t buffer1_size, uint8_t stream2, uint8_t buffer2_scale, uint32_t buffer2_size); int seek_mpg_start(uint8_t *buf, int size); void split_mpg(char *name, uint64_t size); void cut_mpg(char *name, uint64_t size); int http_open (char *url); ssize_t save_read(int fd, void *buf, size_t count); const char * strerrno(void); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /*_CTOOLS_H_*/ libdvb-0.5.5.1/include/devices.hh0000644000175000017500000001454110220016115016411 0ustar mocmmocm00000000000000#ifndef _channel_hh #define _channel_hh using namespace std; #include #include #include #include #include #include #include #include #include #define MAXNAM 25 #define MAXKEY 15 #define DEC(N) dec << setw(N) << setfill('0') #define HEX(N) hex << setw(N) << setfill('0') const int maxname=MAXNAM; const int MAXAPIDS=32; const uint32_t UNSET=0xffffffff; const uint16_t NOID=0xffff; const uint16_t NOPID=0xffff; class Transponder { public: uint16_t id; uint16_t onid; uint16_t satid; uint16_t tsid; int type; char name[maxname+1]; uint32_t freq; int pol; int qam; uint32_t srate; int fec; int band; int hp_rate; int lp_rate; int mod; int transmode; int guard; int hierarchy; fe_spectral_inversion_t inversion; struct Sat *sat; Transponder() { name[0]='\0'; id = NOID; onid = NOID; satid = NOID; tsid = NOID; type = 0; } int orbpos; friend ostream &operator<<(ostream &stream, Transponder &x); friend istream &operator>>(istream &stream, Transponder &x); }; class Sat { public: uint16_t id; char name[maxname+1]; unsigned int lnbid; struct Lnb *lnb; unsigned int rotorid; unsigned int fmin; unsigned int fmax; Sat() { id=NOID; name[0]='\0'; lnb=NULL; rotorid=NOID; lnbid=NOID; fmin=fmax=0; }; int set(int sid, char *sname, int slnbid, int srotorid) { return 0; }; friend ostream &operator<<(ostream &stream, Sat &x); friend istream &operator>>(istream &stream, Sat &x); }; class Lnb { public: Sat *sat; uint16_t id; struct DVB *dvbd; char name[maxname+1]; int type; unsigned int lof1; unsigned int lof2; unsigned int slof; int diseqcnr; uint16_t diseqcid; uint16_t swiid; void cpy (const Lnb &olnb){ this->id=olnb.id; this->type=olnb.type; this->lof1=olnb.lof1; this->lof2=olnb.lof2; this->slof=olnb.slof; this->diseqcnr=olnb.diseqcnr; this->diseqcid=olnb.diseqcid; this->swiid=olnb.swiid; strncpy(this->name,olnb.name,maxname); } void init(int t, uint l1, uint l2, uint sl, int dnr, int disid, int sw) { type=t; lof1=l1; lof2=l2; slof=sl; diseqcnr=dnr; diseqcid=disid; swiid=sw; dvbd=0; name[0]='\0'; } Lnb () { lof1=lof2=slof=0; swiid=NOID; diseqcid=NOID; diseqcnr=-1; name[0]='\0'; } Lnb (const Lnb &olnb){ cpy(olnb); } friend ostream &operator<<(ostream &stream, Lnb &x); friend istream &operator>>(istream &stream, Lnb &x); }; struct diseqcmsg { int burst; int len; unsigned char msg[8]; }; class DiSEqC { public: uint16_t id; char name[maxname+1]; diseqcmsg msgs[4]; friend ostream &operator<<(ostream &stream, DiSEqC &x); friend istream &operator>>(istream &stream, DiSEqC &x); }; class Rotor { public: uint16_t id; char name[maxname+1]; diseqcmsg msgs[4]; friend ostream &operator<<(ostream &stream, Rotor &x); friend istream &operator>>(istream &stream, Rotor &x); }; class Switch { public: uint16_t id; int switchid; char name[maxname+1]; diseqcmsg msg; friend ostream &operator<<(ostream &stream, Switch &x); friend istream &operator>>(istream &stream, Switch &x); }; class Network { public: uint16_t id; char name[maxname+1]; friend ostream &operator<<(ostream &stream, Network &x); friend istream &operator>>(istream &stream, Network &x); }; class Bouquet { public: uint16_t id; char name[maxname+1]; friend ostream &operator<<(ostream &stream, Bouquet &x); friend istream &operator>>(istream &stream, Bouquet &x); }; #define MAX_ECM 16 #define MAX_ECM_DESC 256 typedef struct ecm_struct { int num; uint16_t sysid[MAX_ECM]; uint16_t pid[MAX_ECM]; uint16_t length[MAX_ECM]; uint8_t data[MAX_ECM*MAX_ECM_DESC]; } ecm_t; class Channel{ public: Channel *next; uint32_t id; char name[maxname+1]; char net_name[maxname+1]; char prov_name[maxname+1]; int32_t type; int checked; uint16_t pnr; uint16_t vpid; uint16_t apids[MAXAPIDS]; char apids_name[MAXAPIDS*4]; int32_t apidnum; int last_apidn; uint16_t tmppid; uint16_t ac3pid; uint16_t subpid; uint16_t ttpid; uint16_t pmtpid; uint16_t pcrpid; uint16_t casystem; uint16_t capid; ecm_t ecm; int (*ecm_callback)(Channel *chan); int has_eit; int pres_follow; uint16_t satid; uint16_t tpid; uint16_t onid; uint16_t bid; int8_t eit_ver_n; int8_t eit_ver_c; void clearall(void) { id=UNSET; memset(name,0,MAXNAM+1); memset(prov_name,0,MAXNAM+1); memset(net_name,0,MAXNAM+1); type=0; checked = 0; has_eit = -1; pres_follow = -1; eit_ver_c = -1; eit_ver_n = -1; pnr=NOPID; vpid=NOPID; memset(apids, 0, sizeof(uint16_t)*MAXAPIDS); memset(apids_name, 0, sizeof(char)*MAXAPIDS*4); apidnum=0; last_apidn=-1; tmppid=NOPID; subpid=NOPID; ac3pid=NOPID; ttpid=NOPID; pmtpid=NOPID; pcrpid=NOPID; capid=NOPID; satid=NOID; tpid=NOID; onid=NOID; bid=NOID; ecm_callback = NULL; memset(&ecm,0, sizeof(ecm_t)); }; Channel() { clearall(); } Channel(int cid, char *nam, int ty, int prognr, int vid, int aid, int tid) { int l=strlen(nam); clearall(); if (l>maxname){ cerr << "" << endl; l=maxname; } strncpy(name, nam, l); name[l]='\0'; type=ty; pnr=prognr; vpid=vid; apids[0]=aid; } #ifdef DEBUG ~Channel(){ cerr <<"Channel " << name << " destroyed" << endl; } #endif friend ostream &operator<<(ostream &stream, Channel &x); friend istream &operator>>(istream &stream, Channel &x); }; int findkey(char *name, char *keys[]); void getname(char *name,istream &ins, char startc = '\"', char stopc = '\"'); #endif /*channel.h*/ libdvb-0.5.5.1/include/osd.hh0000644000175000017500000000446110220016115015554 0ustar mocmmocm00000000000000#ifndef _OSD_HH_ #define _OSD_HH_ extern "C" { #include "OSD.h" } struct OSD { int dev; void init(int d) { dev=d; } int Open(int x0, int y0, int x1, int y1, int BitPerPixel, int mix, int win) { if (OSDSetWindow(dev, win)) return -1; return OSDOpen(dev, x0, y0, x1, y1, BitPerPixel, mix); } int Open(int x0, int y0, int x1, int y1, int BitPerPixel, int mix) { return OSDOpen(dev, x0, y0, x1, y1, BitPerPixel, mix); } int Close(int win) { if (OSDSetWindow(dev, win)) return -1; return OSDClose(dev); } int Close(void) { return OSDClose(dev); } int Show(void) { return OSDShow(dev); } int Hide(void) { return OSDHide(dev); } int Clear(void) { return OSDClear(dev); } int Fill(int color) { return OSDFill(dev, color); } int SetColor(int color, int r, int g, int b, int op) { return OSDSetColor(dev, color, r, g, b, op); } int Text(int x, int y, int size, int color, const char *text) { return OSDText(dev, x, y, size, color, text); } int SetPalette(int first, int last, unsigned char *data) { return OSDSetPalette(dev, first, last, data); } int SetTrans(int trans) { return OSDSetTrans(dev, trans); } int SetPixel(int dev, int x, int y, unsigned int color) { return OSDSetPixel(dev, x, y, color); } int GetPixel(int dev, int x, int y) { return OSDGetPixel(dev, x, y); } int SetRow(int x, int y, int x1, unsigned char *data) { return OSDSetRow(dev, x, y, x1, data); } int SetBlock(int x, int y, int x1, int y1, int inc, unsigned char *data) { return OSDSetBlock(dev, x, y, x1, y1, inc, data); } int FillRow(int x, int y, int x1, int color) { return OSDFillRow(dev, x, y, x1, color); } int FillBlock(int x, int y, int x1, int y1, int color) { return OSDFillBlock(dev, x, y, x1, y1, color); } int Line(int x, int y, int x1, int y1, int color) { return OSDLine(dev, x, y, x1, y1, color); } int Query() { return OSDQuery(dev); } int SetWindow(int win) { return OSDSetWindow(dev, win); } }; #endif libdvb-0.5.5.1/include/ringbuffy.h0000644000175000017500000000305310220016115016606 0ustar mocmmocm00000000000000/* Ringbuffer Implementation for gtvscreen Copyright (C) 2000 Marcus Metzler (mocm@metzlerbros.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef RINGBUFFY_H #define RINGBUFFY_H #include #include #include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #define FULL_BUFFER -1000 typedef struct ringbuffy{ int read_pos; int write_pos; int size; char *buffy; } ringbuffy; int ring_init (ringbuffy *rbuf, int size); void ring_destroy(ringbuffy *rbuf); int ring_write(ringbuffy *rbuf, char *data, int count); int ring_read(ringbuffy *rbuf, char *data, int count); int ring_write_file(ringbuffy *rbuf, int fd, int count); int ring_read_file(ringbuffy *rbuf, int fd, int count); int ring_rest(ringbuffy *rbuf); int ring_peek(ringbuffy *rbuf, char *data, int count, long off); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* RINGBUFFY_H */ libdvb-0.5.5.1/include/transform.h0000644000175000017500000001570310220016115016633 0ustar mocmmocm00000000000000/* * dvb-mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * Copyright (C) 2002 Marcus Metzler * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at mocm@metzlerbros.de, */ #ifndef _TS_TRANSFORM_H_ #define _TS_TRANSFORM_H_ #include #include #include #include #define PROG_STREAM_MAP 0xBC #ifndef PRIVATE_STREAM1 #define PRIVATE_STREAM1 0xBD #endif #define PADDING_STREAM 0xBE #ifndef PRIVATE_STREAM2 #define PRIVATE_STREAM2 0xBF #endif #define AUDIO_STREAM_S 0xC0 #define AUDIO_STREAM_E 0xDF #define VIDEO_STREAM_S 0xE0 #define VIDEO_STREAM_E 0xEF #define ECM_STREAM 0xF0 #define EMM_STREAM 0xF1 #define DSM_CC_STREAM 0xF2 #define ISO13522_STREAM 0xF3 #define PROG_STREAM_DIR 0xFF #define BUFFYSIZE 10*MAX_PLENGTH #define MAX_PTS 8192 #define MAX_FRAME 8192 #define MAX_PACK_L 4096 #define PS_HEADER_L1 14 #define PS_HEADER_L2 (PS_HEADER_L1+18) #define MAX_H_SIZE (PES_H_MIN + PS_HEADER_L1 + 5) #define PES_MIN 7 #define PES_H_MIN 9 //flags2 #define PTS_DTS_FLAGS 0xC0 #define ESCR_FLAG 0x20 #define ES_RATE_FLAG 0x10 #define DSM_TRICK_FLAG 0x08 #define ADD_CPY_FLAG 0x04 #define PES_CRC_FLAG 0x02 #define PES_EXT_FLAG 0x01 //pts_dts flags #define PTS_ONLY 0x80 #define PTS_DTS 0xC0 #define TS_SIZE 188 #define TRANS_ERROR 0x80 #define PAY_START 0x40 #define TRANS_PRIO 0x20 #define PID_MASK_HI 0x1F //flags #define TRANS_SCRMBL1 0x80 #define TRANS_SCRMBL2 0x40 #define ADAPT_FIELD 0x20 #define PAYLOAD 0x10 #define COUNT_MASK 0x0F // adaptation flags #define DISCON_IND 0x80 #define RAND_ACC_IND 0x40 #define ES_PRI_IND 0x20 #define PCR_FLAG 0x10 #define OPCR_FLAG 0x08 #define SPLICE_FLAG 0x04 #define TRANS_PRIV 0x02 #define ADAP_EXT_FLAG 0x01 // adaptation extension flags #define LTW_FLAG 0x80 #define PIECE_RATE 0x40 #define SEAM_SPLICE 0x20 #define MAX_PLENGTH 0xFFFF #define MMAX_PLENGTH (8*MAX_PLENGTH) #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ typedef struct video_i{ uint32_t horizontal_size; uint32_t vertical_size ; uint32_t aspect_ratio ; double framerate ; uint32_t video_format; uint32_t bit_rate ; uint32_t comp_bit_rate ; uint32_t vbv_buffer_size; uint32_t CSPF ; uint32_t off; } VideoInfo; typedef struct audio_i{ int layer; uint32_t bit_rate; uint32_t frequency; uint32_t mode; uint32_t mode_extension; uint32_t emphasis; uint32_t framesize; uint32_t off; } AudioInfo; #define P2P_LENGTH 2048 enum{NOPES, AUDIO, VIDEO, AC3}; typedef struct p2pstruct { int found; uint8_t buf[MMAX_PLENGTH]; uint8_t cid; uint8_t subid; uint32_t plength; uint8_t plen[2]; uint8_t flag1; uint8_t flag2; uint8_t hlength; uint8_t pts[5]; int mpeg; uint8_t check; int fd1; int fd2; int es; int filter; int which; int done; int repack; uint16_t bigend_repack; void (*func)(uint8_t *buf, int count, void *p); int startv; int starta; int64_t apts; int64_t vpts; uint16_t pid; uint16_t pida; uint16_t pidv; uint8_t acounter; uint8_t vcounter; uint8_t count0; uint8_t count1; void *data; } p2p; uint64_t trans_pts_dts(uint8_t *pts); int write_ts_header(uint16_t pid, uint8_t *counter, int pes_start, uint8_t *buf, uint8_t length); uint16_t get_pid(uint8_t *pid); void init_p2p(p2p *p, void (*func)(uint8_t *buf, int count, void *p), int repack); void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)); void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)); void pes_repack(p2p *p); void setup_pes2ts( p2p *p, uint32_t pida, uint32_t pidv, void (*ts_write)(uint8_t *buf, int count, void *p)); void kpes_to_ts( p2p *p,uint8_t *buf ,int count ); void setup_ts2pes( p2p *pa, p2p *pv, uint32_t pida, uint32_t pidv, void (*pes_write)(uint8_t *buf, int count, void *p)); void kts_to_pes( p2p *p, uint8_t *buf); void pes_repack(p2p *p); void extract_from_pes(int fdin, int fdout, uint8_t id, int es); int64_t pes_dmx(int fdin, int fdouta, int fdoutv, int es); void pes_to_ts2( int fdin, int fdout, uint16_t pida, uint16_t pidv); void ts_to_pes( int fdin, uint16_t pida, uint16_t pidv, int pad); int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr); int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr); int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr); void filter_audio_from_pes(int fdin, int fdout, uint8_t id, uint8_t subid); //instant repack typedef struct ipack_s { int size; int size_orig; int found; int ps; int has_ai; int has_vi; AudioInfo ai; VideoInfo vi; uint8_t *buf; uint8_t cid; uint32_t plength; uint8_t plen[2]; uint8_t flag1; uint8_t flag2; uint8_t hlength; uint8_t pts[5]; uint8_t last_pts[5]; int mpeg; uint8_t check; int which; int done; void *data; void *data2; void (*func)(uint8_t *buf, int size, void *priv); int count; int start; int fd; int fd1; int fd2; int ffd; int playing; } ipack; void instant_repack (uint8_t *buf, int count, ipack *p); void init_ipack(ipack *p, int size, void (*func)(uint8_t *buf, int size, void *priv), int pad); void free_ipack(ipack * p); void send_ipack(ipack *p); void reset_ipack(ipack *p); void ps_pes(ipack *p); // use with ipack structure, repack size and callback func int64_t ts_demux(int fd_in, int fdv_out,int fda_out,uint16_t pida, uint16_t pidv, int es); void ts2es(int fdin, uint16_t pidv); void ts2es_opt(int fdin, uint16_t pidv, ipack *p, int verb); void insert_pat_pmt( int fdin, int fdout); void change_aspect(int fdin, int fdout, int aspect); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _TS_TRANSFORM_H_*/ libdvb-0.5.5.1/libdvb/0000755000175000017500000000000010220016115014260 5ustar mocmmocm00000000000000libdvb-0.5.5.1/libdvb/Makefile0000644000175000017500000000065410220016115015725 0ustar mocmmocm00000000000000 include ../config.mk OBJS=devices.o DVB.o OSD.o LIBS=-L./ -lpthread DVB_LIBS=libdvb.a main: $(DVB_LIBS) libdvb.a: $(OBJS) ar -rcs libdvb.a $(OBJS) DVB.o: DVB.cc ../include/DVB.hh $(CXX) $(INCLUDES) $(CFLAGS) -c $< devices.o: devices.cc ../include/devices.hh $(CXX) $(INCLUDES) $(CFLAGS) -c $< .c.o: $(CC) $(INCLUDES) $(CFLAGS) -c $< .cc.o: $(CXX) $(INCLUDES) $(CFLAGS) -c $< clean: -rm -f *.o $(DVB_LIBS) *~ libdvb-0.5.5.1/libdvb/DVB.cc0000644000175000017500000033532610220016115015216 0ustar mocmmocm00000000000000#include static const char *vdr_inv_name [] = { "0", "1", "999" }; static const char *vdr_fec_name [] = { "0", "12", "23", "34", "45", "56", "67", "78", "89", "999" }; static const char *vdr_qam_name [] = { "0", "16", "32", "64", "128", "256", "999" }; static const char *vdr_bw_name [] = { "8", "7", "6", "999" }; static const char *vdr_mode_name [] = { "2", "8", "999" }; static const char *vdr_guard_name [] = { "32", "16", "8", "4", "999" }; static const char *vdr_hierarchy_name [] = { "0", "1", "2", "4", "999" }; static const char *fec_name [] = { "FEC_NONE", "FEC_1_2", "FEC_2_3", "FEC_3_4", "FEC_4_5", "FEC_5_6", "FEC_6_7", "FEC_7_8", "FEC_8_9", "FEC_AUTO" }; static const char *inv_name [] = { "INVERSION_OFF", "INVERSION_ON", "INVERSION_AUTO" }; static const char *qam_name [] = { "QPSK", "QAM_16", "QAM_32", "QAM_64", "QAM_128", "QAM_256", "QAM_AUTO" }; static const char *bw_name [] = { "BANDWIDTH_8_MHZ", "BANDWIDTH_7_MHZ", "BANDWIDTH_6_MHZ", "BANDWIDTH_AUTO" }; static const char *mode_name [] = { "TRANSMISSION_MODE_2K", "TRANSMISSION_MODE_8K", "TRANSMISSION_MODE_AUTO" }; static const char *guard_name [] = { "GUARD_INTERVAL_1_32", "GUARD_INTERVAL_1_16", "GUARD_INTERVAL_1_8", "GUARD_INTERVAL_1_4", "GUARD_INTERVAL_AUTO" }; static const char *hierarchy_name [] = { "HIERARCHY_NONE", "HIERARCHY_1", "HIERARCHY_2", "HIERARCHY_4", "HIERARCHY_AUTO" }; static const fe_code_rate_t ftab [8] = { FEC_AUTO, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_NONE, FEC_NONE }; static const fe_modulation_t qtab [6] = { QAM_AUTO, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256 }; void dvb2txt(char *out, char *in, int l) { uint8_t len; len = (uint8_t) l; if (len > MAXNAM) len=MAXNAM; if (strlen(in) < (size_t)len) len = (int)strlen(in); uint8_t *txt=(uint8_t *) in; if (!len) return; switch (*txt) { case 0x01 ... 0x0f: txt++; len--; break; case 0x10: txt+=3; len-=3; break; } while (len>0) { switch(*txt) { case '\"': case 0x01 ... 0x1f: case 0x7f ... 0xa0: len--; txt++; break; case 0x00: len=1; default: *(out++)=(char) *(txt++); len--; break; } } } void show_buf(uint8_t *buf, int length) { fprintf(stderr,"\n"); for (int i=0; i 0) close(fd_frontend); if (fd_demuxa > 0) close(fd_demuxa); if (fd_demuxv > 0) close(fd_demuxv); if (fd_demuxpcr > 0) close(fd_demuxpcr); if (fd_demuxtt > 0) close(fd_demuxtt); char devname[80]; set_vtxdir(VTXDIR); dvr_enabled = 0; sprintf(devname,FRONT_DEV,adapter,minor); fd_frontend=open(devname, O_RDWR); if (fd_frontend < 0) { cerr << "Could not open " << devname << endl; front_type=-1; perror(devname); fd_frontend = -1; failed = 1; } ioctl(fd_frontend, FE_GET_INFO, &feinfo); front_type=feinfo.type; sprintf(devname,DEMUX_DEV,adapter,minor); fd_demuxtt=open(devname, O_RDWR); if (fd_demuxtt < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxtt = -1; failed = 1; } fd_demuxa=open(devname, O_RDWR); if (fd_demuxa < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxa = -1; failed = 1; } fd_demuxpcr=open(devname, O_RDWR); if (fd_demuxpcr < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxpcr = -1; failed = 1; } fd_demuxv=open(devname, O_RDWR); if (fd_demuxv < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxv = -1; failed = 1; } } Transponder *DVB::find_tp(unsigned int tpid, unsigned int satid) { Transponder *tp=NULL; int i; for (i=0; itpid) { tp=&tps[i]; break; } return tp; } Sat *DVB::find_sat(Transponder *tp) { Sat *sat=NULL; int i; for (i=0; isatid) { sat=&sats[i]; break; } return sat; } Sat *DVB::find_sat(Channel *chan) { Sat *sat=NULL; int i; for (i=0; isatid) { sat=&sats[i]; break; } return sat; } Lnb *DVB::find_lnb(Sat *sat) { Lnb *lnb=NULL; int i; for (i=0; ilnbid) { lnb=&lnbs[i]; break; } return lnb; } int DVB::SetTP(unsigned int tpid, unsigned int satid) { int i; Transponder *tp=0; Sat *sat=0; Lnb *lnb=0; if (no_open) return -1; tp = find_tp(tpid, satid); if (!tp) { fprintf(stderr,"Transponder not found!\n"); return -1; } for (i=0; isatid) { sat=&sats[i]; break; } } if (!sat){ fprintf(stderr,"Satellite not found!\n"); return -1; } for (i=0; ilnbid) { lnb=&lnbs[i]; break; } if (!lnb){ fprintf(stderr,"LNB not found!\n"); return -1; } switch (front_type) { case FE_QPSK: if (tp->freq < lnb->slof) { front_param.frequency = (tp->freq - lnb->lof1); tone = SEC_TONE_OFF; } else { front_param.frequency = (tp->freq - lnb->lof2); tone = SEC_TONE_ON; } if (tp->pol) voltage = SEC_VOLTAGE_18; else voltage = SEC_VOLTAGE_13; set_diseqc_nb(lnb->diseqcnr); front_param.u.qpsk.symbol_rate = tp->srate; front_param.u.qpsk.fec_inner = (fe_code_rate_t)tp->fec; front_param.inversion = tp->inversion; transponder_srate = tp->srate; transponder_pol = tp->pol ? 'H':'V'; break; case FE_QAM: front_param.frequency = tp->freq; front_param.inversion = tp->inversion; front_param.u.qam.symbol_rate = tp->srate; front_param.u.qam.fec_inner = (fe_code_rate_t)tp->fec; front_param.u.qam.modulation=(fe_modulation_t) (tp->qam+1); transponder_srate = tp->srate; break; case FE_OFDM: front_param.frequency = tp->freq; front_param.inversion = tp->inversion; front_param.u.ofdm.bandwidth = (fe_bandwidth_t)tp->band; front_param.u.ofdm.code_rate_HP = (fe_code_rate_t)tp->hp_rate; front_param.u.ofdm.code_rate_LP = (fe_code_rate_t)tp->lp_rate; front_param.u.ofdm.constellation = (fe_modulation_t)tp->mod; front_param.u.ofdm.transmission_mode = (fe_transmit_mode_t)tp->transmode; front_param.u.ofdm.guard_interval = (fe_guard_interval_t)tp->guard; front_param.u.ofdm.hierarchy_information = (fe_hierarchy_t)tp->hierarchy; break; } transponder_freq = tp->freq; return 0; } static uint16_t get_pid(uint8_t *pid) { uint16_t pp; pp = (pid[0] & 0x1f) << 8; pp |= pid[1] &0xff; return pp; } static uint32_t bcd32_trafo(uint8_t *buf){ return ((buf[0] >> 4) & 0x0f) * 10000000UL + (buf[0] & 0x0f) * 1000000UL + ((buf[1] >> 4) & 0x0f) * 100000UL + (buf[1] & 0x0f) * 10000UL + ((buf[2] >> 4) & 0x0f) * 1000UL + (buf[2] & 0x0f) * 100UL + ((buf[3] >> 4) & 0x0f) * 10UL + (buf[3] & 0x0f); } int DVB::parse_descriptor(Channel *chan, uint8_t *buf, int length, int verb=0, Transponder *tp=NULL) { int dlength; Transponder dtp; if (!length) return 0; dlength = buf[1]; if (verb) cerr << "desc 0x" << int(buf[0]) << endl; switch(buf[0]){ case 0x0a: if (!chan) break; if (dlength==4 && chan->last_apidn>=0 && chan->last_apidn < MAXAPIDS){ memcpy(chan->apids_name+chan->last_apidn*4,buf+2, 3); } break; case 0x09: uint16_t casys; uint16_t capid; if (verb) cerr << "ECM descriptor" << endl; if (!dlength) break; if (!chan) break; casys =(buf[2]<<8)|buf[3]; capid = get_pid(buf+4); /* if ((dlength>17 && casys==0x100) || casys == 0xb00){ capid = get_pid(buf+19); } */ chan->casystem = casys; chan->capid = capid; AddECM(chan, buf, dlength+2); if (chan->ecm_callback) chan->ecm_callback(chan); break; case 0x40: //network name descriptor { uint8_t slen=0; char name[MAXNAM+1]; if (verb) cerr << "network name descriptor" << endl; if (!chan) break; memset (name,0,MAXNAM+1); slen = buf[1]; if (slen > MAXNAM){ memcpy(name,(char*)(buf+2), MAXNAM); memset(chan->net_name, 0, MAXNAM+1); dvb2txt(chan->net_name,name, MAXNAM); } else if (slen) { memcpy(name,(char*)(buf+2), int(slen)); memset(chan->net_name, 0, MAXNAM+1); dvb2txt(chan->net_name,name, int(slen)); } break; } case 0x41:/* service list */ if (verb) cerr << "service list descriptor" << endl; break; case 0x42:/* stuffing */ if (verb) cerr << "stuffing descriptor" << endl; break; case 0x43:/* satellite delivery system */ if (!tp) tp = &dtp; tp->type = FE_QPSK; tp->freq = 10*bcd32_trafo(buf+2); tp->srate = 10*bcd32_trafo(buf+9); tp->fec = ftab[buf[12] & 0x07]; tp->pol = (buf[8] >> 5) & 0x03; tp->orbpos = ((buf[6] >> 4) & 0x0f) * 1000 + (buf[6] & 0x0f) * 100 + ((buf[7] >> 4) & 0x0f) * 10 + (buf[7] & 0x0f); if (buf[8] >> 7) tp->orbpos = -tp->orbpos; if (verb){ cerr << "Satellite delivery system descriptor " << tp->orbpos << endl; cerr << *tp; } break; case 0x44:/* cable delivery system */ if (!tp) tp=&dtp; tp->type = FE_QAM; tp->freq = 100*bcd32_trafo(buf+2); tp->srate = 10*bcd32_trafo(buf+9); tp->fec = ftab[buf[12] & 0x07]; if ((buf[8] & 0x0f)<= 5) tp->qam = qtab[buf[8] & 0x0f]; else tp->qam = QAM_AUTO; if (verb){ cerr << "Cable delivery system descriptor" << endl; cerr << *tp; } break; case 0x45:/* VBI data */ if (verb) cerr << "VBI data descriptor" << endl; break; case 0x46:/* VBI teletext */ if (verb) cerr << "VBI teletext descriptor" << endl; break; case 0x47:/* bouquet name */ if (verb) cerr << "bouquet name descriptor" << endl; break; case 0x48: /* service desc */ { uint8_t slen=0; char name[MAXNAM+1]; uint8_t *mbuf = buf; if (verb) cerr << "service descriptor" << endl; if (!chan) break; memset (name,0,MAXNAM+1); mbuf += 3; slen = *mbuf; /* provider name */ mbuf++; if (slen > MAXNAM){ memcpy(name, mbuf, MAXNAM); memset(chan->prov_name, 0, MAXNAM+1); dvb2txt(chan->prov_name,name, MAXNAM); } else if (slen) { memcpy(name, mbuf, int(slen)); memset(chan->prov_name, 0, MAXNAM+1); dvb2txt(chan->prov_name,name, int(slen)); } mbuf += slen; /* service name */ slen = *mbuf; mbuf++; if (!slen) break; memset (name,0,MAXNAM+1); if (slen > MAXNAM){ memcpy(name,mbuf, MAXNAM); memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, MAXNAM); } else if(slen>0){ memcpy(name, mbuf, int(slen)); memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, int(slen)); } if (verb) cerr << chan->name << endl; } break; case 0x49:/* country availability */ if (verb) cerr << "country availability descriptor" << endl; break; case 0x4a: /*linkage*/ if (verb) cerr << "linkage descriptor "<< int(buf[8]) << endl; switch (buf[8]){ case 0xb0: /* Multifeed */ { uint16_t ts_id, sid; ts_id = (buf[2] << 8)|buf[3]; sid = (buf[6] << 8)|buf[7]; if (verb) cerr << HEX(2)<< ts_id << " " << HEX(2) << sid << endl; chan = NULL; for (int i = 0; i < num[CHAN]; i++){ if (chans[i].pnr == sid){ chan = &chans[i]; break; } } uint8_t slen=0; char name[MAXNAM+1]; uint8_t *mbuf = buf; memset (name,0,MAXNAM+1); mbuf += 9; slen = dlength-9; /* multifeed name */ if (slen > MAXNAM){ memcpy(name, mbuf, MAXNAM); if (chan){ memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, MAXNAM); } } else if (slen) { memcpy(name, mbuf, int(slen)); if (chan){ memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, MAXNAM); } } if (verb){ if (chan) cerr << chan->name << endl; else cerr << name << endl; } } break; } case 0x4b:/* NVOD reference */ if (verb) cerr << "NVOD reference descriptor" << endl; break; case 0x4c:/* time shifted service */ if (verb) cerr << "time shifted service descriptor" << endl; break; case 0x4d: /* short event */ if (verb) cerr << "short event descriptor" << endl; break; case 0x4e: /* extended event */ if (verb) cerr << "extended event descriptor" << endl; break; case 0x4f: /* time shifted event */ if (verb) cerr << "time shifted event descriptor" << endl; break; case 0x50: /* component event */ if (verb) cerr << "component event descriptor" << endl; break; case 0x51: /* mosaic */ if (verb) cerr << "mosaic descriptor" << endl; break; case 0x52: /* stream identufier */ if (verb) cerr << "stream identifier descriptor" << endl; break; case 0x53: /* CA identifier */ if (verb) cerr << "CA identifier descriptor" << endl; break; case 0x54: /* content */ if (verb) cerr << "content descriptor" << endl; break; case 0x55: /* parental rating*/ if (verb) cerr << "parental rating descriptor" << endl; break; case 0x56: /* teletext */ if (verb) cerr << "teletext descriptor" << endl; if (!chan) break; if (chan->tmppid != NOPID){ chan->ttpid = chan->tmppid; } break; case 0x57: /* telephone */ if (verb) cerr << "telephone descriptor" << endl; break; case 0x58: /* local time offset */ if (verb) cerr << "local time offset descriptor" << endl; break; case 0x59: /* subtitle */ if (verb) cerr << "subtitle descriptor" << endl; if (!chan) break; if (chan->tmppid != NOPID){ chan->subpid = chan->tmppid; } break; case 0x5a: /* terrestrial delivery system */ if (!tp) tp=&dtp; tp->type = FE_OFDM; if (verb){ cerr << "Terrestrial delivery system descriptor" << endl; cerr << *tp; } break; case 0x5b: /* multilingual network name */ if (verb) cerr << "multilingual network name descriptor" << endl; break; case 0x5c: /* multilingual bouquet name */ if (verb) cerr << "multilingual bouquet name descriptor" << endl; break; case 0x5d: /* multilingual service name */ if (verb) cerr << "multilingual service name descriptor" << endl; break; case 0x5e: /* multilingual component */ if (verb) cerr << "multilingual component descriptor" << endl; break; case 0x5f: /* private data specifier */ if (verb) cerr << "private data specifier descriptor" << endl; break; case 0x60: /* service move */ if (verb) cerr << "service move descriptor" << endl; break; case 0x61: /* short smoothing buffer */ if (verb) cerr << "short smoothing buffer descriptor" << endl; break; case 0x62: /* frequency list */ if (verb) cerr << "frequency list descriptor" << endl; break; case 0x63: /* partial transport stream */ if (verb) cerr << "partial transport stream descriptor" << endl; break; case 0x64: /* data broadcast */ if (verb) cerr << "data broadcast descriptor" << endl; break; case 0x65: /* CA system */ if (verb) cerr << "CA system descriptor" << endl; break; case 0x66: /* data broadcast id */ if (verb) cerr << "data broadcast id descriptor" << endl; break; case 0x67: /* transport stream offset */ if (verb) cerr << "transport stream descriptor" << endl; break; case 0x68: /* DSNG */ if (verb) cerr << "DSNG descriptor" << endl; break; case 0x69: /* PDC */ if (verb) cerr << "PDC descriptor" << endl; break; case 0x6a: /* AC3 */ if (verb) cerr << "AC3 descriptor" << endl; if (!chan) break; if (chan->tmppid != NOPID){ chan->ac3pid = chan->tmppid; } break; case 0x6b: /* ancillary data */ if (verb) cerr << "ancillary data descriptor" << endl; break; case 0x6c: /* cell list */ if (verb) cerr << "cell list descriptor" << endl; break; case 0x6d: /* cell frequency link */ if (verb) cerr << "cell frequency link descriptor" << endl; break; case 0x6e: /* announcement support */ if (verb) cerr << "announcement support descriptor" << endl; break; default: //show_buf(buf,dlength); break; } int c=0; c += dlength+2; if ( c < length) c += parse_descriptor(chan, buf+c, length-c, verb); if (ctmppid = NOPID; return length; } int DVB::parse_pmt(Channel *chan, uint8_t *buf) { int slen, ilen, eslen, c; uint16_t epid; if (buf[0] != 0x02) return -1; slen = (((buf[1]&0x03) << 8) | buf[2]) +3; ilen = ((buf[10]&0x03) <<8) | buf[11]; chan->pcrpid = get_pid(buf+8); c = 12; if (ilen) c+=parse_descriptor(chan, buf+c, ilen); if (c-12< ilen){ cerr << "Hmm error in descriptor parsing" << endl; } // show_buf(buf,slen); while (c < slen-4){ eslen = ((buf[c+3]&0x03) <<8) | buf[c+4]; epid = get_pid(buf+c+1); switch (buf[c]) { case 1: case 2: if (chan->vpid == NOPID) chan->vpid = epid; break; case 3: case 4: { int afound = 0; uint16_t apid = epid; chan->last_apidn = -1; if (chan->apidnum>=MAXAPIDS) { cerr << "Need more apids\n"; break; } for (int i = 0; i < chan->apidnum; i++){ if ( apid == chan->apids[i]){ afound = 1; chan->last_apidn = i; break; } } if (! afound){ chan->apids[chan->apidnum++] = apid; chan->last_apidn = chan->apidnum-1; } break; } case 6: chan->tmppid = epid; break; /* case 5: cerr << "private service 0x" << hex << int(buf[c]) << " for service id 0x" << chan->pnr << " with pid 0x"<< epid << dec<< endl; break; default: cerr << "other service 0x" << hex << int(buf[c]) << " for service id 0x" << chan->pnr << " with pid 0x"<< epid << dec<< endl; break; */ } c += 5; if (eslen) c += parse_descriptor(chan, buf+c, eslen); } return 0; } int DVB::parse_pat(Channel *chan, uint8_t *buf) { int slen, i, nprog; int found = 0; uint8_t *prog; uint16_t prog_pid = 0, pnr = 0; slen = (((buf[1]&0x03) << 8) | buf[2]); nprog = (slen - 9) / 4; prog = buf+ 8; for (i = 0; i < nprog; i++){ pnr = (prog[0] << 8)|prog[1]; if ( chan->pnr == pnr ){ prog_pid = get_pid(prog+2); found = 1; break; } prog += 4; } if (found) found = prog_pid; return found; } /* void DVB::parse_nit(Transponder *tp, uint8_t *buf) { int slen, i, nprog; int found = 0; slen = (((buf[1]&0x0f) << 8) | buf[2]); } int DVB::check_nit(Transponder *tp) { int found = 0; uint16_t prog_pid = 0; uint8_t buf[MAXSECSIZE], msec=0, sec=0; if (no_open) return -1; time_t count = time(0)+2; while (sec<=msec && !found && count > time(0)) { if (GetSection(buf, 0x10, 0x40, sec, msec)>0){ sec++; found = parse_nit(tp, buf); } } if (!found) return -1; return 0; } */ void DVB::check_all_pids() { if (no_open) return; for (int i = 0; i < num[CHAN]; i++){ cerr << "checking " << chans[i].name << endl; SetChannel(i); } } int DVB::check_pids(Channel *chan) { int found = 0; int oldnum; uint16_t prog_pid = 0; uint8_t buf[MAXSECSIZE], msec=0, sec=0; if (no_open) return -1; oldnum=chan->apidnum; time_t count = time(0)+4; while (sec<=msec && !found && count > time(0)) { if (GetSection(buf, 0, 0, sec, msec)>0 && !buf[0]){ sec++; found = parse_pat(chan,buf); } } if (!found) return -1; prog_pid = found; chan->apidnum = 0; sec = 0; msec = 0; count = time(0)+4; while (sec<=msec && count > time(0)) { if (GetSection(buf,prog_pid, 2, sec, msec)>0){ sec++; parse_pmt(chan, buf); if(count < time(0)) break; } } if (!chan->apidnum) chan->apidnum=oldnum; chan->checked = 1; return 0; } int DVB::get_all_progs(uint16_t *progbuf, uint16_t *pnrbuf, int length) { int nfound = 0, oldone = 0, j; uint8_t buf[MAXSECSIZE], msec=0, sec=0; uint16_t prog_pid = 0, pnr = 0; int slen; uint8_t *prog; if (no_open) return -1; time_t count = time(0)+4; while (sec<=msec && count > time(0)) { if (GetSection(buf, 0, 0, sec, msec)>0 && !buf[0]){ sec++; slen = (((buf[1]&0x0f) << 8) | buf[2]); slen -= 11; prog = buf+ 8; while (slen>0){ pnr = (prog[0] << 8)|prog[1]; prog_pid = get_pid(prog+2); oldone = 0; for(j=0; j time(0)) { if (GetSection(buf,prog_pid, 2, sec, msec)>0){ sec++; parse_pmt(&chan,buf); if(count < time(0)) break; } } *ttpid = chan.ttpid; *vpid = chan.vpid; apidnum = chan.apidnum; if (apidnum && apidnum <= MAXAPIDS){ memcpy(apids, chan.apids, apidnum * sizeof (uint16_t)); if (apids_name) memcpy(apids_name, chan.apids_name, apidnum * sizeof (uint8_t)*4); } return found+apidnum; } uint16_t DVB::find_pnr(uint16_t svpid, uint16_t sapid) { int nfound = 0; int pfound = 0; uint16_t progs[100]; uint16_t pnrs[100]; uint16_t vpid; uint16_t ttpid; uint16_t apids[MAXAPIDS]; if (no_open) return 0; nfound = get_all_progs(progs, pnrs, 100); for(int i=0; i < nfound; i++){ if ( (pfound = get_pids(progs[i], &vpid, apids, &ttpid)) ){ if(svpid != NOPID && vpid == svpid ) return pnrs[i]; else if ( svpid == NOPID ){ for (int j=0; j time(0)) { if (GetSection(buf, 0x11, 0x42, sec, msec)>0){ sec++; slen = (((buf[1]&0x0f) << 8) | buf[2]) +3; tsid = (buf[3]<<8)|buf[4+1]; if (tp) tp->tsid = tsid; c = 11; while (c < slen-4){ pnr = (buf[c]<<8)|buf[c+1]; chan->has_eit = -1; chan->pres_follow = -1; if (buf[c+2] & 0x02) chan->has_eit = 0; if (buf[c+2] & 0x01) chan->pres_follow = 0; c+=3; ca=(buf[c]&0x10)>>4; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; if ( chan->pnr == pnr && ilen ){ chan->type=ca; c+=parse_descriptor(chan, &buf[c], ilen); } else c+=ilen; } } } } int DVB::scan_sdts(int *chs, int n) { int slen, ilen, c; uint8_t buf[MAXSECSIZE], msec=0, sec=0; uint16_t pnr; uint8_t ca; int *check; uint16_t tsid; Transponder *tp; if (n>MAX_TRANS_CHAN || n <0) return -1; if (no_open) return -1; check = new int[n]; tp = find_tp(&chans[chs[0]]); for (int i=0; i time(0)) { if (GetSection(buf, 0x11, 0x42, sec, msec)>0){ sec++; slen = (((buf[1]&0x0f) << 8) | buf[2]); tsid = (buf[3]<<8)|buf[4+1]; if (tp) tp->tsid = tsid; c = 11; while (c < slen-4){ pnr = (buf[c]<<8)|buf[c+1]; c+=3; ca=(buf[c]&0x10)>>4; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; int ce=0; for (int cl=0; cl < n; cl++){ if (chans[chs[cl]].pnr == pnr ){ ce=parse_descriptor(&chans[chs[cl]],buf+c, ilen); check[cl]=1; chans[chs[cl]].type=ca; continue; } } if (ce < ilen) cerr << "Error in descriptor parsing" << endl; c+=ilen; } } } int found=0; for (int i=0; i < n; i++) found+=check[i]; delete [] check; return found; } int eit_cb(uint8_t *buf, int l, int pnr, int c_n, uint8_t *t) { cout << "Type: " << c_n << " PNR:" << pnr << " Time: " << hex << int(t[2]) << ":" << int(t[3]) << "." << int(t[4]) << dec << endl; for (int i=0; i < l/16+1; i++){ cout << "0x" << HEX(4) << i << dec << " "; for (int j=0; j < 16; j++){ if (j+i*16 < l) cout << HEX(2) << int(buf[j+i*16]) << dec << " "; else cout << " "; } for (int j=0; j < 16 && j+i*16 < l; j++){ uint8_t c = (char)buf[j+i*16]; switch ((int)c) { case 0x01 ... 0x1f: case 0x7f ... 0xa0: case 0x00: cout << "." ; break; default: cout << char(c) ; break; } } cout << endl; } cout << endl; cout << endl; if (c_n && l>10) return 1; else return 0; } void DVB::scan_pf_eit(Channel *chan, int (*callback)(uint8_t *data, int l, int pnr, int c_n, uint8_t *t) = eit_cb) { int slen, ilen, c, t; uint8_t buf[MAXSECSIZE], msec=0, sec=0; uint16_t pnr = NOID; int8_t ver; int c_n; int done=0; if (no_open) return; time_t count = time(0)+5; while ( !done && count > time(0)) { if (GetSection(buf, 0x12, 0x4e, sec, msec)>0){ sec++; c = 1; slen = (((buf[c]&0x0f) << 8) | buf[c+1]) +3; c += 2; pnr = (buf[c]<<8)|buf[c+1]; c += 2; ver = buf[c] & 0x3E; c_n = buf[c] & 0x01; c += 8; if (pnr == chan->pnr){ while (c < slen-4){ t = c+3; c += 10; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; done = callback(buf+c, ilen, pnr, c_n, buf+t); c+=ilen; } } } } } void DVB::scan_pf_eit(int chnr, int (*callback)(uint8_t *data, int l, int pnr, int c_n, uint8_t *t) = eit_cb) { if (no_open) return; if (chnr>=num[CHAN] || chnr < 0) return; scan_pf_eit(&chans[chnr], callback); } void DVB::scan_pf_eit(int chnr) { if (no_open) return; if (chnr>=num[CHAN] || chnr < 0) return; scan_pf_eit(&chans[chnr]); } int DVB::SetChannel(Channel *chan, char* apref, uint16_t *apidp, uint16_t *vpidp) { int i; int scan = 0; uint16_t apid=0, vpid=0; if (no_open) return -1; if (chan->pnr == NOPID && (chan->vpid != NOPID || chan->apids[0] != NOPID)) chan->pnr = find_pnr(chan->vpid, chan->apids[0]); int c=0; if (chan->pnr) if (chan->vpid == NOPID){ check_pids(chan); scan=1; while (chan->apidnum == 0 && c<10) { check_pids(chan); c++; } } vpid = chan->vpid; if (chan->apidnum){ if (apref){ int found = 0; for (i=0; i < chan->apidnum; i++){ if (!strncasecmp(chan->apids_name+4*i, apref,3)){ found=1; break; } } if (found) apid = chan->apids[i]; else apid = chan->apids[0]; } else apid = chan->apids[0]; } if (vpid != NOPID) set_vpid(vpid); set_apid(apid); set_pcrpid(chan->pcrpid); if (chan->ttpid != NOPID) set_ttpid(chan->ttpid); if (scan) scan_sdt(chan); if (fdvb >= 0){ struct tm *lt; time_t t; t = time(0); lt = localtime(&t); ostringstream fstr; osd.Clear(); fstr << setw(2) << setfill('0') << lt->tm_hour << ":" << setw(2) << setfill('0') << lt->tm_min << " "; if (chan->name[0]) fstr << chan->name; else if (chan->prov_name[0]) fstr << chan->prov_name; else fstr << "Channel " << dec << chan->id; fstr << ends; osd.Text(0, 0, 0, 1, fstr.str().data()); osd.Show(); } if (vpidp) *vpidp = vpid; if (apidp) *apidp = apid; // scan_pf_eit(chan); if (vpid==NOPID && apid == NOPID) return -2; return 0; } int DVB::SetChannel(int chnr, char* apref, uint16_t *apidp, uint16_t *vpidp, bool tune) { if (no_open) return -1; if (chnr>=num[CHAN] || chnr < 0) return -1; if(tune) { get_front(); if (SetTP(chans[chnr].tpid, chans[chnr].satid) < 0) return -1; } stop_apid(); stop_vpid(); stop_ttpid(); stop_pcrpid(); if(tune && (set_front()<0)) return -1; return SetChannel(&chans[chnr], apref, apidp, vpidp); } int DVB::SetChannel(uint16_t sid, uint16_t onid, uint16_t tpid, uint16_t satid) { int chnr; Channel *chan=0; if (no_open) return -1; for (chnr=0; chnrtpid; if (onid==NOID) onid=chan->onid; if (satid==NOID) satid=chan->satid; get_front(); if (SetTP(tpid, satid) < 0) return -1; if (set_front() < 0) return -1; set_vpid(chan->vpid); set_apid(chan->apids[0]); set_ttpid(chan->ttpid); set_pcrpid(chan->pcrpid); return chnr; } int DVB::GetChannel(int chnr, struct channel *) { int i; Channel *chan=0; Transponder *tp=0; Sat *sat=0; Lnb *lnb=0; if (chnr>=num[CHAN]) return -1; chan=&chans[chnr]; tp = find_tp(chan); if (!tp) return -1; sat = find_sat(tp); if (!sat) return -1; for (i=0; ilnbid) { lnb=&lnbs[i]; break; } if (!lnb || no_open) return -1; if (set_front() < 0) return -1; return 0; } int DVB::AddLNB(int id, int t, uint l1, uint l2, uint sl, int dnr, int dis, int sw) { if (num[LNB]>=maxs[LNB]) return -1; for (int i=0; i< num[LNB]; i++){ if (lnbs[i].id == id && lnbs[i].diseqcnr == dnr){ cerr << "Warning: LNB already defined:" << endl; cerr << "ID: " << id << " DISEQCNR: " << dnr << endl; return -1; } } lnbs[num[LNB]].init(t, l1, l2, sl, dnr, dis, sw); lnbs[num[LNB]].id=id; num[LNB]++; return 0; } int DVB::AddTP(Transponder &tp) { if (num[TRANS]>=maxs[TRANS]) return -1; if (tp.id == NOID){ max_tpid++; tp.id = max_tpid; } else if (tp.id > max_tpid) max_tpid = tp.id; for (int i=0; i= 0; i--){ if (chan.tpid == tps[i].id){ chan.satid = tps[i].satid; return; } } } int DVB::AddChannel(Channel &chan) { int i; if (num[CHAN]>=maxs[CHAN]) return -1; if ( chan.satid == NOID) find_satid(chan); for (i=0; i=maxs[SAT]) return -1; if (!sat.id) sat.id=num[SAT]; for (i=0; i MAX_TRANS_CHAN){ cerr << "found too many channels "<< nfound << endl; cerr << "resetting to"<< MAX_TRANS_CHAN << endl; nfound = MAX_TRANS_CHAN; } for(int i=0; i < nfound; i++){ Channel chan; int cn; int anum=0; vpid = NOPID; ttpid= NOPID; if ( show ){ if (!(get_pids(progs[i], &vpid, apids, &ttpid, apids_name) && vpid != NOPID)) continue; } else anum = get_pids(progs[i], &vpid, apids, &ttpid, apids_name); chan.pnr = pnrs[i]; chan.satid = satid; chan.tpid = tpid; chan.vpid = vpid; chan.apidnum = anum; if (anum && anum < MAXAPIDS){ memcpy(chan.apids, apids, anum*sizeof(uint16_t)); memcpy(chan.apids_name, apids_name, anum*sizeof(uint8_t)*4); } chan.checked = 1; chan.ttpid = ttpid; if (show){ if (SetChannel(&chan) < 0) return 0; sleep(2); } if ((cn=AddChannel(chan))==num[CHAN]-1){ chs[n]=cn; n++; if (verbose) cerr << "."; } } if (n > MAX_TRANS_CHAN){ cerr << "counted too many channels "<< n << endl; cerr << "resetting to"<< MAX_TRANS_CHAN << endl; n = MAX_TRANS_CHAN; } if (!show){ int count = 0; int res=0; while ((res=scan_sdts(chs,n))< n && res>0 && count < 2) count++; } if (verbose){ cerr << endl; for (int i=0; i < n; i++){ cerr << "Found " << chans[chs[i]]; } cerr << dec; } return n; } int DVB::search_in_TP(Transponder &tp, int show, int verbose) { if (no_open) return -1; return search_in_TP(tp.id, tp.satid, show, verbose); } void DVB::set_outtype(dvb_outtype type) { outtype = type; } dvb_outtype DVB::get_outtype(void) { return outtype; } ostream &operator<<(ostream &stream, DVB &x) { int i,j,k,l; switch(x.outtype){ default: case LIBDVB_OUT: for (i=0; ivpid == NOPID) continue; if(!strlen(chan->name)) continue; stream << chan->name << ":"; switch (tp->type){ case FE_QPSK: lnb = x.find_lnb(sat); if(!lnb) continue; stream << tp->freq/1000 << ":"; if (tp->pol) stream << "h:"; else stream << "v:"; stream << lnb->diseqcnr << ":" << tp->srate/1000 << ":" << fec_name[tp->fec] << ":"; break; case FE_QAM: stream << tp->freq << ":" << inv_name[tp->inversion] << ":" << tp->srate << ":" << fec_name[tp->fec] << ":" << qam_name[tp->mod] << ":"; break; case FE_OFDM: stream << tp->freq << ":" << inv_name[tp->inversion] << ":" << bw_name[tp->band] << ":" << fec_name[tp->hp_rate] << ":" << fec_name[tp->lp_rate] << ":" << qam_name[tp->mod] << ":" << mode_name[tp->transmode] << ":" << guard_name[tp->guard] << ":" << hierarchy_name[tp->hierarchy] << ":"; break; } stream << chan->vpid << ":" << chan->apids[0] << ":" << chan->pnr << endl; } break; case VDR_OUT: for (i=0; i< x.num[CHAN]; i++){ Channel *chan = &x.chans[i]; Transponder *tp = x.find_tp(chan); Sat *sat = x.find_sat(chan); Lnb *lnb=NULL; if(chan->vpid == NOPID) continue; if(!strlen(chan->name)) continue; stream << chan->name << ":"; switch (tp->type){ case FE_QPSK: lnb = x.find_lnb(sat); if(!lnb) continue; stream << tp->freq/1000 << ":"; if (tp->pol) stream << "h:"; else stream << "v:"; stream << "S" << hex << sat->id/16 << "." << hex << (sat->id & 0x0F) << "E:" << dec << tp->srate/1000 << ":"; break; case FE_QAM: stream << tp->freq/1000000 << ":M" << vdr_qam_name[tp->mod] << ":C:" << tp->srate/1000 << ":"; break; case FE_OFDM: stream << tp->freq << "I" << vdr_inv_name[tp->inversion] << "B" << vdr_bw_name[tp->band] << "C" << vdr_fec_name[tp->hp_rate] << "D" << vdr_fec_name[tp->lp_rate] << "M" << vdr_qam_name[tp->mod] << "T" << vdr_mode_name[tp->transmode] << "G" << vdr_guard_name[tp->guard] << "Y" << vdr_hierarchy_name[tp->hierarchy] << ":T:27500:"; break; } if (chan->pcrpid != NOPID && chan->pcrpid != chan->vpid) stream << chan->vpid << "+" << chan->pcrpid << ":"; else stream << chan->vpid << ":"; stream << chan->apids[0]; for (l = 1; l < chan->apidnum; l++) stream << "," << chan->apids[l]; if (chan->ac3pid != NOPID) stream << ";" << chan->ac3pid; stream << ":" << chan->ttpid; if(chan->capid != NOPID) stream << ":1"; stream << ":" << chan->pnr << ":0:0:0" << endl; } break; case MYTH_OUT: break; } return stream; } int check_for_vdr_zap(int *f, istream &ins) { string s; int c=0; while (!c && ! ins.eof()){ c=0; getline (ins, s); for (unsigned int i = 0; i < s.length();i++) if (s[i] == ':') c++; if (c < 2 ) c= 0; } // cerr << c << endl; switch (c){ case 12: { char *namebuf; int freq; sscanf(s.c_str(), "%a[^:]:%d ",&namebuf, &freq); free(namebuf); if (freq < 1000000){ *f = DVB_VDR; } else { *f = DVB_ZAPT; } return 1; } break; case 7: *f = DVB_ZAPC; return 1; break; case 8: *f = DVB_ZAPS; return 1; break; case 11: *f = DVB_ZAPT; return 1; break; default: return 0; } } int DVB::check_input_format(istream &ins) { streampos pos = ins.tellg(); int found = 0; char *test_keys[]={ "LNB","TRANSPONDER","CHANNEL","SAT","> keybuf; if ( strncmp(keybuf, test_keys[SATCO_START],7) ) n=findkey(keybuf, test_keys); else n = SATCO_START; switch (n){ case LNB: case TRANS: case CHAN: case SAT: found = 1; f = DVB_ORIG; break; case NOKIA_START: found = 1; f = DVB_NOKIA; break; case XML_START: found = 1; f = DVB_XML; break; case SATCO_START: found = 1; f = DVB_SATCO; break; default: ins.seekg(pos); found = check_for_vdr_zap(&f, ins); if (! found){ cerr << "Error: " << keybuf << " is not a valid keyword at " << endl; exit(0); } } } ins.seekg(pos); return f; } void DVB::read_original(istream &ins) { char *names[] = { "LNB","TRANSPONDER","CHANNEL","SAT", NULL }; while(!ins.eof()){ char keybuf[MAXNAM]; ins.width(MAXNAM); ins >> keybuf; int n=findkey(keybuf, names); if (n<0) { cerr << endl << "Error: " << keybuf << " is not a valid keyword at " << endl; exit(0); } else { if (num[n]< maxs[n]){ switch (n){ case LNB: { Lnb lnb; lnb.name[0]='\0'; ins >> lnb; cerr << "."; AddLNB(lnb.id, lnb.type, lnb.lof1, lnb.lof2, lnb.slof, lnb.diseqcnr, lnb.diseqcid, lnb.swiid); front_type = lnb.type; break; } case TRANS: { Transponder tp; ins >> tp; AddTP(tp); break; } case CHAN: { Channel chan; ins >> chan; AddChannel(chan); break; } case SAT: { Sat sat; ins >> sat; AddSat(sat); break; } } } else { cerr << "not enough channels" << endl; break; } } } cerr << " done" << endl; } istream &operator>>(istream &ins, DVB &x) { int format = x.check_input_format(ins); switch(format){ case DVB_ORIG: cerr << "Reading libdvb format" << endl; x.read_original(ins); break; case DVB_NOKIA: { cerr << "Reading Nokia format" << endl; nokiaconv cc(&x); cc.lnb_sat.n = 4; cc.lnb_sat.diseqc[0] = 0; cc.lnb_sat.diseqc[1] = 1; cc.lnb_sat.diseqc[2] = 2; cc.lnb_sat.diseqc[3] = 3; strncpy(cc.lnb_sat.sat_names[0],"Astra",5); cc.lnb_sat.satid[0]=0x0192; strncpy(cc.lnb_sat.sat_names[1],"HotBird",7); cc.lnb_sat.satid[1]=0x0130; strncpy(cc.lnb_sat.sat_names[2],"Sirius",6); cc.lnb_sat.satid[2]=0x0050; cerr << "Reading NOKIA format" << endl; cc.dvb->front_type = FE_QPSK; ins >> cc; break; } case DVB_XML: { cerr << "Reading XML format" << endl; xmlconv cc(&x); cc.lnb_sat.n = 4; cc.lnb_sat.diseqc[0] = 0; cc.lnb_sat.diseqc[1] = 1; cc.lnb_sat.diseqc[2] = 2; cc.lnb_sat.diseqc[3] = 3; strncpy(cc.lnb_sat.sat_names[0],"Astra",6); cc.lnb_sat.satid[0]=0x0192; strncpy(cc.lnb_sat.sat_names[1],"HotBird",7); cc.lnb_sat.satid[1]=0x0130; strncpy(cc.lnb_sat.sat_names[2],"Sirius",6); cc.lnb_sat.satid[2]=0x0050; cerr << "Reading XML format" << endl; cc.dvb->front_type = FE_QPSK; ins >> cc; break; } case DVB_SATCO: { cerr << "Reading satco format" << endl; satcoconv cc(&x); cc.nlnb = 0; cc.dvb->front_type = FE_QPSK; ins >> cc; break; } case DVB_VDR: { cerr << "Reading VDR format" << endl; vdrconv cc(&x); ins >> cc; break; } case DVB_ZAPS: { cerr << "Reading ZAP Sat format" << endl; zapconv cc(&x); cc.dvb->front_type = FE_QPSK; ins >> cc; break; } case DVB_ZAPC: { cerr << "Reading ZAP Cable format" << endl; zapconv cc(&x); cc.dvb->front_type = FE_QAM; ins >> cc; break; } case DVB_ZAPT: { cerr << "Reading ZAP ter. format" << endl; zapconv cc(&x); cc.dvb->front_type = FE_OFDM; ins >> cc; break; } default: cerr << "Unknown format. Can't open dvbrc. Exiting" << endl; exit(1); } return ins; } void hdump(uint8_t *buf, int n) { int i; for (i=0; i>16; if (fdvb >= 0) { osd.FillBlock(x, y, x+w-1-sep, y+h-1, col1); osd.FillBlock(x+w-1-sep, y, 515, y+h-1, col2); } } int DVB::SetFullFilter(uint16_t pid) { char devname[80]; sprintf(devname,DEMUX_DEV,adapter,minor); struct dmx_pes_filter_params pesFilterParams; int fd_section=open(devname, O_RDWR|O_NONBLOCK); if (fd_section < 0) return fd_section; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_TS_TAP; pesFilterParams.pes_type = DMX_PES_OTHER; pesFilterParams.flags = DMX_IMMEDIATE_START; if (pid == NOPID )pesFilterParams.pid = DMX_FULL_TS_PID; else pesFilterParams.pid = pid; if (ioctl(fd_section, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { printf("Could not set PES filter\n"); close(fd_section); return -1; } return fd_section; } uint16_t DVB::SetFilter(uint16_t pid, uint16_t section, uint16_t mode) { struct dmx_sct_filter_params secFilterParams; char devname[80]; sprintf(devname,DEMUX_DEV,adapter,minor); int fd_section=open(devname, O_RDWR|mode); secFilterParams.pid=pid; memset(&secFilterParams.filter.filter, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mask, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mode, 0, DMX_FILTER_SIZE); secFilterParams.timeout = 0; secFilterParams.flags= secflags; secFilterParams.filter.filter[0]=(section>>8)&0xff; secFilterParams.filter.mask[0]=section&0xff; if (ioctl(fd_section, DMX_SET_FILTER, &secFilterParams) < 0) return 0xffff; return fd_section; } int DVB::SetFilter(uint16_t pid, uint8_t *filter, uint8_t *mask, uint32_t timeout, uint32_t flags) { struct dmx_sct_filter_params secFilterParams; char devname[80]; sprintf(devname,DEMUX_DEV,adapter,minor); int fd_section=open(devname, O_RDWR|flags); secFilterParams.pid=pid; memset(&secFilterParams.filter.filter, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mask, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mode, 0, DMX_FILTER_SIZE); secFilterParams.timeout = timeout; secFilterParams.flags= secflags; for (int i = 0; i < DMX_FILTER_SIZE; i++){ secFilterParams.filter.filter[i]=filter[i]; secFilterParams.filter.mask[i]=mask[i]; } if (ioctl(fd_section, DMX_SET_FILTER, &secFilterParams) < 0) return 0xffff; return fd_section; } int DVB::CloseFilter(int h) { if (no_open) return -1; close(h); return 0; } int DVB::GetSection(uint8_t *buf, ushort PID, uint8_t sec, uint8_t secnum, uint8_t &msecnum) { int seclen=0; uint16_t handle, pid; uint8_t section, sectionnum=0xff, maxsec=0; struct pollfd pfd; int loopc = 0; if (no_open) return -1; if ((handle=SetFilter(PID, (sec<<8)|0x00ff, 0))==0xffff) return -1; do { seclen=0; pfd.fd = handle; pfd.events=POLLIN; if (poll(&pfd, 1, 2000)==0) { break; } loopc++; pid = PID; read(handle, buf, MAXSECSIZE); seclen = 0; seclen |= ((buf[1] & 0x0F) << 8); seclen |= (buf[2] & 0xFF); seclen+=3; section=buf[0]; sectionnum=buf[6]; maxsec=buf[7]; } while ( loopc < maxsec*2 && (section != sec || pid != PID || sectionnum != secnum)); msecnum=maxsec; CloseFilter(handle); return seclen; } int DVB::GetSection(uint8_t *buf, uint16_t PID, uint8_t *filter, uint8_t *mask, uint8_t secnum, uint8_t &msecnum) { int seclen=0; uint16_t handle, pid; uint8_t section, sectionnum=0xff, maxsec=0; struct pollfd pfd; int loopc = 0; if (no_open) return -1; if ((handle=SetFilter(PID, filter, mask, 0, 0))==0xffff) return -1; do { seclen=0; pfd.fd=handle; pfd.events=POLLIN; if (poll(&pfd, 1, 20000)==0) break; loopc++; pid = PID; read(handle, buf, MAXSECSIZE); seclen = 0; seclen |= ((buf[1] & 0x0F) << 8); seclen |= (buf[2] & 0xFF); seclen+=3; section=buf[0]; sectionnum=buf[6]; maxsec=buf[7]; } while (loopc < maxsec*2 && ((section&mask[0]!=filter[0]) || pid!=PID || sectionnum!=secnum)); msecnum=maxsec; CloseFilter(handle); return seclen; } int DVB::GetSection(uint8_t *buf, uint16_t PID, uint8_t TID, uint16_t TIDExt, uint16_t FilterTIDExt, uint8_t secnum, uint8_t &msecnum) { uint8_t filter[16], mask[16]; if (no_open) return -1; memset(filter, 0, 16); memset(mask, 0, 16); filter[0]=TID; mask[0]=0xff; if (TIDExt!=0xffff) { filter[1]=(TIDExt>>8); filter[2]=TIDExt&0xff; mask[1]=(FilterTIDExt>>8); mask[2]=FilterTIDExt&0xff; } return GetSection(buf, PID, filter, mask, secnum, msecnum); } void DVB::get_front(void) { if (no_open) return; set_vpid(0); set_apid(0); set_ttpid(0); set_pcrpid(0); voltage = SEC_VOLTAGE_13; tone = SEC_TONE_OFF; } int DVB::check_frontend() { return chck_frontend(fd_frontend, &festat); } int DVB::tune_it(struct dvb_frontend_parameters *front_param) { int chk=0; if (no_open) return -1; lastclock = times(&ts); if (ioctl(fd_frontend, FE_SET_FRONTEND, front_param) <0){ perror("setfront front"); return -1; } if (showtime) cerr << "set frontend time: " << double(times(&ts)-lastclock)/ double(sysconf(_SC_CLK_TCK)) << "s" << endl; lastclock = times(&ts); chk=check_frontend(); if (showtime) cerr << "check frontend time: " << double(times(&ts)-lastclock)/ double(sysconf(_SC_CLK_TCK)) << "s" << endl; if (!chk){ chk = check_frontend(); if (!chk){ cerr << "Tuning failed" << endl; return -1; } } return 0; } int DVB::set_front(void) { if (no_open) return -1; set_vpid(0); set_apid(0); set_pcrpid(0); set_ttpid(0); if (front_type==FE_QPSK) set_diseqc(); usleep(10000); int c=0; int ret=0; while (c<1 && (ret=tune_it(&front_param))<0){ c++; usleep(10000); if (front_type==FE_QPSK) toggle_diseqc(); } return ret; } void DVB::set_diseqc() { if (ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF) <0) perror("FE_SET_TONE failed"); if (ioctl(fd_frontend, FE_SET_VOLTAGE, voltage) <0) perror("FE_SET_VOLTAGE failed"); usleep(15000); if(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &dcmd) < 0) perror("FE_DISEQC_SEND_MASTER_CMD failed"); usleep(15000); if(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, burst) <0) perror("FE_DISEQC_SEND_BURST failed"); usleep(15000); if(ioctl(fd_frontend, FE_SET_TONE, tone) < 0) perror("FE_SET_TONE failed"); usleep(15000); } void DVB::toggle_diseqc() { uint8_t old = dcmd.msg[3]; dcmd.msg[3] ^= (old & 0x0C); set_diseqc(); dcmd.msg[3] = old; set_diseqc(); } void DVB::set_diseqc_nb(int nr) { if (no_open) return; dcmd.msg[0]=0xe0; dcmd.msg[1]=0x10; dcmd.msg[2]=0x38; dcmd.msg[3]=0xF0 | ((nr * 4) & 0x0F) | ((tone == SEC_TONE_ON) ? 1 : 0) | ((voltage==SEC_VOLTAGE_18) ? 2 : 0); dcmd.msg[4]=0x00; dcmd.msg[5]=0x00; dcmd.msg_len=4; burst=(nr&1) ? SEC_MINI_B : SEC_MINI_A; } void DVB::set_ttpid(ushort ttpid) { if (no_open) return; if(set_ttpid_fd(ttpid, fd_demuxtt) < 0) { printf("PID=%04x\n", ttpid); perror("set_ttpid"); } } void DVB::stop_ttpid() { stop_pid_fd(fd_demuxtt); } void DVB::set_vpid(ushort vpid) { if (no_open) return; if(set_vpid_fd(vpid, fd_demuxv) < 0) perror("set_vpid"); } void DVB::stop_vpid() { stop_pid_fd(fd_demuxv); } void DVB::set_apid(ushort apid) { if (no_open) return; if(set_apid_fd(apid, fd_demuxa) < 0) perror("set_apid"); } void DVB::stop_apid() { stop_pid_fd(fd_demuxa); } void DVB::set_pcrpid(ushort pcrpid) { if (no_open) return; if(set_pcrpid_fd(pcrpid, fd_demuxpcr) < 0) perror("set_pcrpid"); } void DVB::stop_pcrpid() { stop_pid_fd(fd_demuxpcr); } // Functions enabling the user to set the demuxes independently. int DVB::set_vpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_VIDEO; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_apid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_AUDIO; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_pcrpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_PCR; pesFilterParamsP.flags = secflags; if (dvr_enabled==2) { ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); return 0; } else return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_ttpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_TELETEXT; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_otherpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = DMX_PES_OTHER; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } void DVB::stop_pid_fd(int fd) { ioctl(fd, DMX_STOP, 0); } istream &operator>>(istream &ins, nokiaconv &x) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; char dummy; int current_sat = -1; int current_tp = -1; int dint; enum { NSAT=0, NNET, NTRP, NCHAN, NEND}; static char *nokiakeys[]={ ":SAT", ":NET", ":TRP", ":CHN", ":END", NULL }; while(!ins.eof()){ streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, nokiakeys); if (n<0) { ins.seekg(pos); break; } switch(n){ case NSAT: { double did; int id=0; int lnbid = 5; int found = 0; getname(sname,ins); //cerr << "Satellite \"" << sname << "\"" << endl; for(int i=0; i < x.lnb_sat.n; i++){ if (!strcmp(x.lnb_sat.sat_names[i],sname)){ lnbid = x.lnb_sat.diseqc[i]; id = x.lnb_sat.satid[i]; found = 1; break; } } x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); ins >> did; current_sat = x.dvb->AddSat( id, lnbid, sname, 10700000 , 12700000); ins >> dummy; break; } case NNET: getname(sname,ins); //cerr << " Network \"" << sname << "\""<< endl; ins >> dint; break; case NTRP: { Transponder trans; trans.inversion = INVERSION_OFF; ins >> dec >> trans.id; ins >> trans.freq; ins >> trans.srate; ins >> dint; ins >> dummy; if (dummy == 'H') trans.pol = 1; if (dummy == 'V') trans.pol = 0; ins >> dint; trans.satid = x.dvb->sats[current_sat].id; trans.type = FE_QPSK; trans.freq *= 10; trans.srate *= 100; ins >> dint; ins >> dummy; ins >> dint; switch (dint){ case 2: trans.fec = FEC_1_2; break; case 3: trans.fec = FEC_2_3; break; case 4: trans.fec = FEC_3_4; break; case 6: trans.fec = FEC_5_6; break; case 8: trans.fec = FEC_7_8; break; } current_tp = x.dvb->AddTP(trans); //cerr << " Transponder "<< trans.id << endl; break; } case NCHAN: { Channel chan; int cnum; getname(sname,ins); strncpy(chan.name, sname, maxname); ins >> chan.pnr; ins >> dummy; if (dummy == 'T'){ ins.ignore(20, ':'); ins.seekg(ins.tellg()-streampos(1)); chan.satid = x.dvb->sats[current_sat].id; chan.tpid = x.dvb->tps[current_tp].id; cnum = x.dvb->AddChannel(chan); //cerr << " Channel "<< sname // << " (" << cnum << ")" << endl; } else { if (dummy == 'R'){ ins.ignore(20, ':'); ins.seekg(ins.tellg()-streampos(1)); } else { ins.seekg(pos); ins.ignore(80,0x0a); } } break; } case NEND: //cerr << "ALL DONE" << endl; return ins; } } return ins; } #define SATCOLEN 129 istream &operator>>(istream &ins, satcoconv &x) { char satline[SATCOLEN]; char posn[5]; char freqn[10]; char sname[19]; int current_sat = -1; int current_tp = -1; while(!ins.eof()){ Transponder trans; int id=0; int lnbid=0; int found = 0; trans.inversion = INVERSION_OFF; ins.get(satline,SATCOLEN); // get full satco line if (strncmp(satline,"SATCODX103",10)){ if (ins.eof()) return ins; cerr << "Wrong SATCODX format: " << endl; return ins; } if (satline[28]!='T') continue; if (strncmp(satline+29,"MPG2",4) ) continue; strncpy(sname,satline+10,18); sname[18]=0; for(int i=0; i < x.dvb->num[SAT]; i++){ if (!strncmp(x.dvb->sats[i].name, sname,18)){ lnbid = x.dvb->sats[i].lnbid; id = x.dvb->sats[i].id; found = 1; break; } } if (!found){ lnbid = x.nlnb++; x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); strncpy(posn,satline+51,4); posn[4]=0; id = strtol(posn,(char **)NULL,16); current_sat = x.dvb->AddSat( id, lnbid, sname, 10700000 , 12700000); } trans.id = NOID; switch (satline[42]){ case '1': case '3': trans.pol = 1; break; case '0': case '2': trans.pol = 0; } trans.satid = x.dvb->sats[current_sat].id; trans.type = FE_QPSK; strncpy(freqn,satline+33,9); freqn[8]=0; trans.freq = strtol(freqn,(char **)NULL,10)*10; strncpy(freqn,satline+69,5); freqn[5]=0; trans.srate = strtol(freqn,(char **)NULL,10)*1000; switch (satline[74]){ case '0': trans.fec = FEC_AUTO; break; case '1': trans.fec = FEC_1_2; break; case '2': trans.fec = FEC_2_3; break; case '3': trans.fec = FEC_3_4; break; case '5': trans.fec = FEC_5_6; break; case '7': trans.fec = FEC_7_8; break; } found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq && x.dvb->tps[i].pol == trans.pol){ current_tp = x.dvb->tps[i].id; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); Channel chan; int cnum; strncpy(chan.name, satline+43, 8); strncpy(chan.name+8, satline+115, 12); chan.name[20] = 0; strncpy(freqn,satline+88,5); freqn[5]=0; chan.pnr = strtol(freqn,(char **)NULL,10)/10; chan.satid = x.dvb->sats[current_sat].id; chan.tpid = x.dvb->tps[current_tp].id; cnum = x.dvb->AddChannel(chan); } return ins; } istream &operator>>(istream &ins, vdrconv &x) { char sname[MAXNAM]; while (!ins.eof()){ Transponder trans; int current_sat = -1; int current_tp = -1; Channel chan; string s; char *namebuf = NULL; char *sourcebuf = NULL; char *parambuf = NULL; char *vpidbuf = NULL; char *apidbuf = NULL; char *caidbuf = NULL; int freq, srate; int tpid; int sid, nid, tid,rid; int id=0; int lnbid=0; int found = 0; int nlen = 0; int cnum; int nlnb=0; int nsat=0; getline(ins,s); int fields = sscanf(s.c_str(), "%a[^:]:%d :%a[^:]:%a[^:] :%d :%a[^:]:%a[^:]:%d :%a[^:]:%d :%d :%d :%d ", &namebuf, &freq, ¶mbuf, &sourcebuf, &srate, &vpidbuf, &apidbuf, &tpid,&caidbuf, &sid, &nid, &tid, &rid); if (fields <9) continue; trans.srate = srate*1000; trans.fec = FEC_AUTO; trans.id = NOID; nlen = strlen(namebuf); if (nlen > MAXNAM) nlen = MAXNAM-1; for (int k=0; k< nlen; k++){ if(namebuf[k] == ',') { nlen = k; break; } } if(caidbuf[0] != '0') chan.type=1; dvb2txt(chan.name, namebuf, nlen); chan.name[nlen] = 0; chan.pnr = sid; { int vpid=0; int pcrpid=0; int apid1=0; int apid2=0; int dpid1=0; int dpid2=0; char *p = strchr(vpidbuf, '+'); if (p) *p++ = 0; sscanf(vpidbuf, "%d", &vpid); if (p) { sscanf(p, "%d", &pcrpid); chan.pcrpid = (uint16_t)pcrpid; } chan.vpid = (uint16_t)vpid; p = strchr(apidbuf, ';'); if (p) *p++ = 0; sscanf(apidbuf, "%d ,%d ", &apid1, &apid2); chan.apids[0] = apid1; chan.apidnum = 1; if (apid2){ chan.apidnum = 2; chan.apids[1] = apid2; } if (p){ sscanf(p, "%d ,%d ", &dpid1, &dpid2); chan.ac3pid = dpid1; } } switch(sourcebuf[0]){ case 'S': x.dvb->front_type = FE_QPSK; trans.type = FE_QPSK; trans.freq = freq*1000; switch(parambuf[0]){ case 'h': case 'H': trans.pol = 1; break; case 'v': case 'V': trans.pol = 0; break; } nlen = strlen(sourcebuf+1)-1; if (nlen > MAXNAM) nlen = MAXNAM-1; strncpy(sname,sourcebuf+1,nlen); sname[nlen]=0; for(int i=0; i < x.dvb->num[SAT]; i++){ if (!strncmp(x.dvb->sats[i].name, sname,nlen)){ lnbid = x.dvb->sats[i].lnbid; id = x.dvb->sats[i].id; found = 1; current_sat = i; break; } } if (!found){ lnbid = nlnb++; x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); id = nsat++; current_sat = x.dvb->AddSat( id, lnbid, sname, 10700000 , 12700000); } trans.satid = x.dvb->sats[current_sat].id; found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq && x.dvb->tps[i].pol == trans.pol){ current_tp = i; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); break; case 'C': x.dvb->front_type = FE_QAM; trans.type = FE_QAM; trans.freq = freq*1000000; { char *s = parambuf; char *b; while (s && *s) { switch(*s){ case 'M': case 'm': switch(strtol(s+1,&b,10)){ case 0: trans.qam = QPSK; break; case 16: trans.qam = QAM_16; break; case 32: trans.qam = QAM_32; break; case 64: trans.qam = QAM_64; break; case 128: trans.qam = QAM_128; break; case 256: trans.qam = QAM_256; break; default: trans.qam = QAM_AUTO; break; } s = b; break; default: cerr << "Error reading parameters " << s << endl; break; } } } if (x.dvb->num[SAT]){ found =1; current_sat = 0; } if (!found){ lnbid = nlnb++; x.dvb->AddLNB(lnbid, 2, 0, 0, 0, lnbid, NOID, NOID); id = nsat++; current_sat = x.dvb->AddSat( id, lnbid, "DVBC", 350000000 , 500000000); } trans.satid = x.dvb->sats[current_sat].id; found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq){ current_tp = i; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); break; case 'T': x.dvb->front_type = FE_OFDM; trans.type = FE_OFDM; trans.freq = freq; { char *s = parambuf; char *b; while (s && *s) { switch(*s){ case 'Y': case 'y': switch(strtol(s+1,&b,10)){ case 0: trans.hierarchy = HIERARCHY_NONE; break; case 1: trans.hierarchy = HIERARCHY_1; break; case 2: trans.hierarchy = HIERARCHY_2; break; case 4: trans.hierarchy = HIERARCHY_4; break; default: trans.hierarchy = HIERARCHY_AUTO; break; } s = b; break; case 'M': case 'm': switch(strtol(s+1,&b,10)){ case 0: trans.mod = QPSK; break; case 16: trans.mod = QAM_16; break; case 32: trans.mod = QAM_32; break; case 64: trans.mod = QAM_64; break; case 128: trans.mod = QAM_128; break; case 256: trans.mod = QAM_256; break; default: trans.mod = QAM_AUTO; break; } s = b; break; case 'I': case 'i': if (atoi(s+1)){ trans.inversion = INVERSION_ON; } else { trans.inversion = INVERSION_ON; } s+=2; break; case 'b': case 'B': switch(strtol(s+1,&b,10)){ case 6: trans.band = BANDWIDTH_6_MHZ; break; case 7: trans.band = BANDWIDTH_7_MHZ; break; case 8: trans.band = BANDWIDTH_8_MHZ; break; default: trans.band = BANDWIDTH_AUTO; break; } s = b; break; case 'c': case 'C': switch(strtol(s+1,&b,10)){ case 0: trans.hp_rate = FEC_NONE; break; case 12: trans.hp_rate = FEC_1_2; break; case 23: trans.hp_rate = FEC_2_3; break; case 34: trans.hp_rate = FEC_3_4; break; case 45: trans.hp_rate = FEC_4_5; break; case 56: trans.hp_rate = FEC_5_6; break; case 67: trans.hp_rate = FEC_6_7; break; case 78: trans.hp_rate = FEC_7_8; break; case 89: trans.hp_rate = FEC_8_9; break; default: trans.hp_rate = FEC_AUTO; break; } s = b; break; case 'D': case 'd': switch(strtol(s+1,&b,10)){ case 0: trans.lp_rate = FEC_NONE; break; case 12: trans.lp_rate = FEC_1_2; break; case 23: trans.lp_rate = FEC_2_3; break; case 34: trans.lp_rate = FEC_3_4; break; case 45: trans.lp_rate = FEC_4_5; break; case 56: trans.lp_rate = FEC_5_6; break; case 67: trans.lp_rate = FEC_6_7; break; case 78: trans.lp_rate = FEC_7_8; break; case 89: trans.lp_rate = FEC_8_9; break; default: trans.lp_rate = FEC_AUTO; break; } s = b; break; case 'G': case 'g': switch(strtol(s+1,&b,10)){ case 4: trans.guard = GUARD_INTERVAL_1_4; break; case 8: trans.guard = GUARD_INTERVAL_1_8; break; case 16: trans.guard = GUARD_INTERVAL_1_16; break; case 32: trans.guard = GUARD_INTERVAL_1_32; break; default: trans.guard = GUARD_INTERVAL_AUTO; break; } s = b; break; case 'T': switch(strtol(s+1,&b,10)){ case 2: trans.transmode = TRANSMISSION_MODE_2K; break; case 8: trans.transmode = TRANSMISSION_MODE_8K; break; default: trans.transmode = TRANSMISSION_MODE_AUTO; break; } s=b; break; default: cerr << "Error reading parameters " << s << endl; break; } } } if (x.dvb->num[SAT]){ found =1; current_sat = 0; } if (!found){ lnbid = nlnb++; x.dvb->AddLNB(lnbid, 2, 0, 0, 0, lnbid, NOID, NOID); id = nsat++; current_sat = x.dvb->AddSat( id, lnbid, "DVBT", 630000000 , 900000000); } trans.satid = x.dvb->sats[current_sat].id; found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq){ current_tp = i; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); break; } chan.satid = x.dvb->sats[current_sat].id; chan.tpid = x.dvb->tps[current_tp].id; cnum = x.dvb->AddChannel(chan); free(namebuf); free(sourcebuf); free(parambuf); free(vpidbuf); free(apidbuf); free(caidbuf); } return ins; } istream &operator>>(istream &ins, zapconv &x) { while (!ins.eof()){ Transponder trans; int current_sat = -1; int current_tp = -1; Channel chan; char *namebuf = NULL; int id=0; int lnbid=0; int found = 0; int nlen = 0; int nsat=0; string s; getline(ins,s); switch(x.dvb->front_type){ case FE_QPSK: { char sname[MAXNAM]; int freq; char *pol; int srate, diseqc, vpid, apid,st, sid; int fields = sscanf(s.c_str(), "%a[^:]:%d :%a[^:]:%d :%d :%d :%d :%d :%d", &namebuf, &freq, &pol, &diseqc, &srate, &vpid,&apid,&st,&sid); if (fields <7) continue; trans.type = FE_QPSK; trans.freq = freq*1000; switch(pol[0]){ case 'h': case 'H': trans.pol = 1; break; case 'v': case 'V': trans.pol = 0; break; } trans.srate = srate*1000; chan.apids[0] = apid; chan.apidnum= 1; chan.vpid = vpid; chan.pnr = sid; nlen = strlen(namebuf); if (nlen > MAXNAM) nlen = MAXNAM-1; dvb2txt(chan.name, namebuf, nlen); chan.name[nlen] = 0; free(pol); sprintf(sname,"SAT%d",nsat); for(int i=0; i < x.dvb->num[SAT]; i++){ if (!strncmp(x.dvb->sats[i].name, sname,nlen)){ lnbid = x.dvb->sats[i].lnbid; id = x.dvb->sats[i].id; found = 1; current_sat = i; break; } } if (!found){ lnbid = diseqc; x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); id = nsat++; current_sat = x.dvb->AddSat( id, lnbid, sname, 10700000 , 12700000); } trans.satid = x.dvb->sats[current_sat].id; found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq && x.dvb->tps[i].pol == trans.pol){ current_tp = i; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); } break; case FE_QAM: { int freq; char *inv, *fec, *qam; int srate, vpid, apid; int fields = sscanf(s.c_str(), "%a[^:]:%d :%a[^:]:%d :%a[^:] :%a[^:] :%d :%d", &namebuf, &freq, &inv, &srate, &fec, &qam, &vpid,&apid); if (fields <7) continue; trans.type = FE_QAM; trans.freq = freq; trans.srate = srate; chan.apids[0] = apid; chan.apidnum= 1; chan.vpid = vpid; chan.pnr = NOID; trans.inversion = INVERSION_AUTO; for (int in = 0; in < 3; in++){ if (! strncmp(inv_name[in], inv, strlen(inv_name[in]))){ switch(in){ case 0: trans.inversion = INVERSION_OFF; break; case 1: trans.inversion = INVERSION_ON; break; case 2: trans.inversion = INVERSION_AUTO; break; } break; } } trans.fec = FEC_AUTO; for (int fe = 0; fe < 10; fe++){ if (! strncmp(fec_name[fe], fec, strlen(fec_name[fe]))){ switch(fe){ case 0: trans.fec = FEC_NONE; break; case 1: trans.fec = FEC_1_2; break; case 2: trans.fec = FEC_2_3; break; case 3: trans.fec = FEC_3_4; break; case 4: trans.fec = FEC_4_5; break; case 5: trans.fec = FEC_5_6; break; case 6: trans.fec = FEC_6_7; break; case 7: trans.fec = FEC_7_8; break; case 8: trans.fec = FEC_8_9; break; case 9: trans.fec = FEC_AUTO; break; } break; } } for (int qa = 0; qa < 10; qa++){ if (! strncmp(qam_name[qa], qam, strlen(qam_name[qa]))){ switch(qa){ case 0: trans.qam = QPSK; break; case 1: trans.qam = QAM_16; break; case 2: trans.qam = QAM_32; break; case 3: trans.qam = QAM_64; break; case 4: trans.qam = QAM_128; break; case 5: trans.qam = QAM_256; break; case 6: trans.qam = QAM_AUTO; break; } break; } } nlen = strlen(namebuf); if (nlen > MAXNAM) nlen = MAXNAM-1; dvb2txt(chan.name, namebuf, nlen); chan.name[nlen] = 0; free(inv); free(fec); free(qam); if (x.dvb->num[SAT]){ found =1; current_sat = 0; } if (!found){ lnbid = 1; x.dvb->AddLNB(lnbid, 2, 0, 0, 0, lnbid, NOID, NOID); id = nsat++; current_sat = x.dvb->AddSat( id, lnbid, "DVBC", 350000000 , 500000000); } trans.satid = x.dvb->sats[current_sat].id; found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq){ current_tp = i; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); } break; case FE_OFDM: { int freq; char *inv, *fech, *fecl, *qam, *transm, *guard, *hier, *band; int vpid, apid, sid; int fields = sscanf(s.c_str(), "%a[^:]:%d :%a[^:]:%a[^:] :%a[^:] :%a[^:] :%a[^:] :%a[^:] :%a[^:] :%a[^:] :%d :%d :%d", &namebuf, &freq, &inv, &band, &fech,&fecl, &qam, &transm, &guard, &hier, &vpid,&apid,&sid); if (fields <12) continue; trans.type = FE_QAM; trans.freq = freq; chan.apids[0] = apid; chan.apidnum= 1; chan.vpid = vpid; chan.pnr = sid; trans.inversion = INVERSION_AUTO; for (int in = 0; in < 3; in++){ if (! strncmp(inv_name[in], inv, strlen(inv_name[in]))){ switch(in){ case 0: trans.inversion = INVERSION_OFF; break; case 1: trans.inversion = INVERSION_ON; break; case 2: trans.inversion = INVERSION_AUTO; break; } break; } } for (int ba = 0; ba < 4; ba++){ if (! strncmp(bw_name[ba], band, strlen(bw_name[ba]))){ switch(ba){ case 0: trans.band = BANDWIDTH_8_MHZ; break; case 1: trans.band = BANDWIDTH_7_MHZ; break; case 2: trans.band = BANDWIDTH_6_MHZ; break; case 3: trans.band = BANDWIDTH_AUTO; break; } break; } } trans.hp_rate = FEC_AUTO; for (int fe = 0; fe < 10; fe++){ if (! strncmp(fec_name[fe], fech, strlen(fec_name[fe]))){ switch(fe){ case 0: trans.hp_rate = FEC_NONE; break; case 1: trans.hp_rate = FEC_1_2; break; case 2: trans.hp_rate = FEC_2_3; break; case 3: trans.hp_rate = FEC_3_4; break; case 4: trans.hp_rate = FEC_4_5; break; case 5: trans.hp_rate = FEC_5_6; break; case 6: trans.hp_rate = FEC_6_7; break; case 7: trans.hp_rate = FEC_7_8; break; case 8: trans.hp_rate = FEC_8_9; break; case 9: trans.hp_rate = FEC_AUTO; break; } break; } } trans.lp_rate = FEC_AUTO; for (int fe = 0; fe < 10; fe++){ if (! strncmp(fec_name[fe], fecl, strlen(fec_name[fe]))){ switch(fe){ case 0: trans.lp_rate = FEC_NONE; break; case 1: trans.lp_rate = FEC_1_2; break; case 2: trans.lp_rate = FEC_2_3; break; case 3: trans.lp_rate = FEC_3_4; break; case 4: trans.lp_rate = FEC_4_5; break; case 5: trans.lp_rate = FEC_5_6; break; case 6: trans.lp_rate = FEC_6_7; break; case 7: trans.lp_rate = FEC_7_8; break; case 8: trans.lp_rate = FEC_8_9; break; case 9: trans.lp_rate = FEC_AUTO; break; } break; } } for (int qa = 0; qa < 10; qa++){ if (! strncmp(qam_name[qa], qam, strlen(qam_name[qa]))){ switch(qa){ case 0: trans.mod = QPSK; break; case 1: trans.mod = QAM_16; break; case 2: trans.mod = QAM_32; break; case 3: trans.mod = QAM_64; break; case 4: trans.mod = QAM_128; break; case 5: trans.mod = QAM_256; break; case 6: trans.mod = QAM_AUTO; break; } break; } } for (int ga = 0; ga < 5; ga++){ if (! strncmp(guard_name[ga], guard, strlen(guard_name[ga]))){ switch(ga){ case 0: trans.guard = GUARD_INTERVAL_1_32; break; case 1: trans.guard = GUARD_INTERVAL_1_16; break; case 2: trans.guard = GUARD_INTERVAL_1_8; break; case 3: trans.guard = GUARD_INTERVAL_1_4; break; case 4: trans.guard = GUARD_INTERVAL_AUTO; break; } break; } } for (int hi = 0; hi < 5; hi++){ if (! strncmp(hierarchy_name[hi], hier, strlen(hierarchy_name[hi]))){ switch(hi){ case 0: trans.hierarchy = HIERARCHY_NONE; break; case 1: trans.hierarchy = HIERARCHY_1; break; case 2: trans.hierarchy = HIERARCHY_2; break; case 3: trans.hierarchy = HIERARCHY_4; break; case 4: trans.hierarchy = HIERARCHY_AUTO; break; } break; } } for (int tr = 0; tr < 3; tr++){ if (! strncmp(mode_name[tr], transm, strlen(mode_name[tr]))){ switch(tr){ case 0: trans.transmode = TRANSMISSION_MODE_2K; break; case 1: trans.transmode = TRANSMISSION_MODE_8K; break; case 2: trans.transmode = TRANSMISSION_MODE_AUTO; break; } break; } } nlen = strlen(namebuf); if (nlen > MAXNAM) nlen = MAXNAM-1; dvb2txt(chan.name, namebuf, nlen); chan.name[nlen] = 0; free(inv); free(band); free(fech); free(fecl); free(qam); free(transm); free(guard); free(hier); if (x.dvb->num[SAT]){ found =1; current_sat = 0; } if (!found){ lnbid = 1; x.dvb->AddLNB(lnbid, 2, 0, 0, 0, lnbid, NOID, NOID); id = nsat++; current_sat = x.dvb->AddSat( id, lnbid, "DVBT", 630000000 , 900000000); } trans.satid = x.dvb->sats[current_sat].id; found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq){ current_tp = i; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); } break; } chan.satid = x.dvb->sats[current_sat].id; chan.tpid = x.dvb->tps[current_tp].id; x.dvb->AddChannel(chan); } return ins; } static int get_keylen(istream &ins, char *keybuf) { streampos pos = ins.tellg(); int klen = strlen(keybuf); if (klen>2 && keybuf[1]!= '/' && keybuf[0]=='<' && keybuf[klen-1]=='>'){ keybuf[klen-2]='\0'; klen--; ins.seekg(pos-streampos(2)); } return klen; } static int find_xml_key(istream &ins, char *keybuf, char *keys[]) { char *s; int n; streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; int klen = get_keylen(ins, keybuf); s=keybuf; while (s[0] != '=' && s != keybuf+klen)s++; s[0]=0; ins.seekg(pos + streampos((s-keybuf) +1) ); // go past = n=findkey(keybuf, keys); if (n<0) { ins.seekg(pos); cerr << "Unknown tag: " << keybuf << endl; } return n; } int xmlconv::read_sat(istream &ins, int csat) { int n=-1; int lnbid=-1; int satid; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XSATN, XSLNB, XSATID, XTRANS, XSATEND, XEND, XNEND}; static char *xsat[]={ "name", "lnb", "id", "", ">", "/>", NULL }; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xsat)) < 0) break; switch(n){ case XSATN: getname(sname,ins); break; case XSLNB: ins >> satid; break; case XTRANS: if (csat >= 0) read_trans(ins, csat); else return -1; break; case XSATID: ins >> satid; break; case XSATEND: return 0; break; case XEND: if (satid >=0 && lnbid >= 0) csat = dvb->AddSat(satid, lnbid, sname, 10700000 , 12700000); break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_trans(istream &ins, int csat) { int n=-1; int ctp=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XTYPE=0, XFREQ, XSRATE, XPOL, XFEC, XSERV, XTRANSEND, XEND, XNEND }; static char *xtrans[]={ "type", "freq", "srate", "polarity", "fec", "", ">", "/>", NULL }; Transponder trans; trans.satid = dvb->sats[csat].id; trans.fec = FEC_AUTO; trans.id = NOID; trans.inversion = INVERSION_OFF; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xtrans)) < 0) break; switch(n){ case XTYPE: getname(sname,ins); switch(sname[0]){ case 'S': trans.type = FE_QPSK; break; case 'T': trans.type = FE_OFDM; break; case 'C': trans.type = FE_QAM; break; } break; case XFREQ: getname(sname,ins); trans.freq=atoi(sname); break; case XSRATE: getname(sname,ins); trans.srate=atoi(sname); break; case XPOL: getname(sname,ins); if (sname[0] == 'H') trans.pol = 1; if (sname[0] == 'V') trans.pol = 0; break; case XFEC: int dint; getname(sname,ins); dint = atoi(sname); switch (dint){ case 2: trans.fec = FEC_1_2; break; case 3: trans.fec = FEC_2_3; break; case 4: trans.fec = FEC_3_4; break; case 6: trans.fec = FEC_5_6; break; case 8: trans.fec = FEC_7_8; break; } break; case XSERV: if (ctp>=0) read_serv(ins,ctp,csat); break; case XTRANSEND: return 0; break; case XEND: ctp = dvb->AddTP(trans); break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_serv(istream &ins, int ctp, int csat) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XSID=0, XCA, XDESC, XSTREAM, XSERVEND, XEND, XNEND }; static char *xserv[]={ "id", "ca", "", ">", "/>", "sats[csat].id; chan.tpid = dvb->tps[ctp].id; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xserv)) < 0) break; switch(n){ case XSID: getname(sname,ins); chan.pnr = atoi(sname); nchan = dvb->AddChannel(chan); break; case XCA: getname(sname,ins); if (nchan >= 0) dvb->chans[nchan].type = atoi(sname); else chan.type = atoi(sname); break; case XDESC: if (nchan>=0) read_desc(ins, nchan); else return -1; break; case XSTREAM: if (nchan>=0) read_stream(ins,nchan); else return -1; break; case XSERVEND: return 0; break; case XEND: break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_desc(istream &ins, int nchan) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XTAG=0, XTYPE, XPROV, XSNAME, XDESCEND, XEND, XNEND}; static char *xdesc[]={ "tag", "type", "provider_name", "service_name", "", ">", "/>", NULL }; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xdesc)) < 0) break; switch(n){ case XTAG: getname(sname,ins); break; case XTYPE: getname(sname,ins); break; case XPROV: getname(sname,ins); break; case XSNAME: getname(sname,ins); dvb2txt(dvb->chans[nchan].name,sname,MAXNAM); break; case XDESCEND: return 0; break; case XEND: break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_stream(istream &ins, int nchan) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; int type = -1; int apids = 0; uint16_t pid = NOPID; enum { XTYPE, XPID, XISO, XSTREAMEND, XEND, XNEND }; static char *xstream[]={ "type", "pid", "", ">", "/>", "chans[nchan].vpid = pid; break; case 3: case 4: if (pid == NOPID) break; apids = dvb->chans[nchan].apidnum; if (apids >= MAXAPIDS) break; dvb->chans[nchan].apidnum++; dvb->chans[nchan].apids[apids]=pid; break; case 6: if (pid != NOPID) dvb->chans[nchan].ttpid = pid; break; } break; case XSTREAMEND: return 0; break; case XEND: break; case XNEND: return 0; break; case XISO: read_iso639(ins, nchan, apids); break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_iso639(istream &ins, int nchan, int apids) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XTYPE, XLAN,XISOEND, XEND, XNEND }; static char *xiso[]={ "type", "language", "", ">", "/>", NULL }; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xiso)) < 0) break; switch(n){ case XTYPE: getname(sname,ins); break; case XLAN: getname(sname,ins); strncpy(dvb->chans[nchan].apids_name+apids*4, sname, 4); break; case XISOEND: return 0; break; case XEND: break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::skip_tag(istream &ins, char *tag) { char sname[MAXNAM*2]; char endtag[MAXNAM]; int found = 0; streampos pos = ins.tellg(); ostringstream etag; etag << "" << ends; strncpy(endtag, etag.str().data(),MAXNAM); int tlen = strlen(endtag)-1; // cerr << "find: " << endtag << endl; ins.width(2*MAXNAM); ins >> sname; if (sname[0] == '>') while(!found){ if (!strncmp(sname,endtag,tlen)) found=1; else ins >> sname; } else { ins.seekg(pos); ins.ignore(1000,'>'); pos = ins.tellg(); ins.seekg(pos-streampos(2)); ins >> sname; if (sname[0] == '/') ins.seekg(pos); else while(!found){ if (!strncmp(sname,endtag,tlen)) found=1; else ins >> sname; } } return 0; } istream &operator>>(istream &ins, xmlconv &x) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; int current_sat = -1; int nsat = 0; enum { XMLSTART=0, XSAT, XNSAT, XLNB, XEND, XNEND}; static char *xmltags[]={ "", "", "/>", NULL}; while(!ins.eof()){ streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, xmltags); if (n<0) { ins.seekg(pos); cerr << "Unknown tag: " << keybuf << endl; break; } switch(n){ case XMLSTART: cerr << "xml start found" << endl; ins.ignore(80,'>'); break; case XNSAT: { int clnb; int lnbid = 5; int satid = -1; if (nsat > XML_MAX_SAT) break; strncpy(sname,x.lnb_sat.sat_names[nsat],MAXNAM); lnbid = x.lnb_sat.diseqc[nsat]; clnb = x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); satid = x.lnb_sat.satid[nsat]; current_sat = x.dvb->AddSat(satid, lnbid, sname, 10700000 , 12700000); nsat++; x.read_sat(ins, current_sat); break; } case XSAT: { cerr << "no sat name" << endl; x.read_sat(ins, -1); break; } case XLNB: break; default: x.skip_tag(ins,keybuf); break; } } return ins; } int get_dvbrc(char *path, DVB &dv, int dev, int len) { ifstream dvbin; dvbin.open(path); if (!dvbin){ const char *home = getenv("HOME"); const char *file = ".dvbrc"; ostringstream str; str << home << "/" << file ; if (dev) str << "." << dev ; str << ends; strncpy(path,str.str().data(),len); cerr << "Using default "<< path << endl; dvbin.clear(); dvbin.open(path); } if (dvbin) { cerr << endl; dvbin >> dv; return 1; } else { cerr << " failed" << endl; ostringstream str; str << "/etc/dvb/dvbrc"; if (dev) str << "." << dev ; str << ends; strncpy(path,str.str().data(),len); cerr << "Using default "<< path << endl; dvbin.clear(); dvbin.open(path); if (dvbin) { cerr << endl; dvbin >> dv; return 1; } else cerr << " failed" << endl; } return 0; } int set_dvbrc(char *path, DVB &dv, int dev, int len) { ofstream dvbout; dvbout.open(path); if (!dvbout){ cerr << "Using default dvbrc." << endl; const char *home = getenv("HOME"); const char *file = ".dvbrc"; ostringstream str; str << home << "/" << file ; if (dev) str << "." << dev ; str << ends; strncpy(path, str.str().data(),len); dvbout.clear(); dvbout.open(path); } if (dvbout) { dvbout << dv; return 1; } return 0; } #define SFREQ 11700000 #define LHI 10600000 #define LLO 9750000 #define IPACKS 2048 void set_diseqc(int fdf, int snum, fe_sec_voltage_t v, fe_sec_tone_mode_t t) { struct dvb_diseqc_master_cmd dcmd; fe_sec_mini_cmd_t b; int hi_lo; int pol; if (snum >= 0) fprintf(stderr,"Setting diseqc %d \n",snum); hi_lo = (t == SEC_TONE_ON) ? 1 : 0; pol = (v==SEC_VOLTAGE_18) ? 2:0; dcmd.msg[0]=0xe0; dcmd.msg[1]=0x10; dcmd.msg[2]=0x38; dcmd.msg[3] = 0xf0 | (((snum* 4) & 0x0f) | hi_lo | pol); dcmd.msg[4]=0x00; dcmd.msg[5]=0x00; dcmd.msg_len=4; b = (snum &1) ? SEC_MINI_B : SEC_MINI_A; if (snum >= 0) ioctl(fdf, FE_SET_TONE, SEC_TONE_OFF); ioctl(fdf, FE_SET_VOLTAGE, v); if (snum >= 0) { usleep(15 * 1000); ioctl(fdf, FE_DISEQC_SEND_MASTER_CMD, &dcmd); usleep(15 * 1000); ioctl(fdf, FE_DISEQC_SEND_BURST, b); usleep(15 * 1000); } ioctl(fdf, FE_SET_TONE, t); } int tune(int fdf, uint32_t freq, uint32_t sr, fe_code_rate_t fec, fe_spectral_inversion_t inv=INVERSION_OFF) { struct dvb_frontend_parameters tune; tune.frequency = freq; tune.inversion = inv; tune.u.qpsk.symbol_rate = sr; if (!fec) tune.u.qpsk.fec_inner = FEC_AUTO; else tune.u.qpsk.fec_inner = fec; if (ioctl(fdf, FE_SET_FRONTEND, &tune) == -1) { perror("FE_SET_FRONTEND failed"); return -1; } return 0; } int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum, fe_code_rate_t fec) { fe_sec_voltage_t v; fe_sec_tone_mode_t t; uint32_t f; fprintf(stderr,"%d %d %d %d %d\n",freq,pol,sr,snum,fec); if (freq >= SFREQ){ f = freq - LHI; t = SEC_TONE_ON; } else { f = freq - LLO; t = SEC_TONE_OFF; } v = pol ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13; set_diseqc(fdf, snum, v, t); return tune(fdf, f, sr, fec); } void set_pes_filt(int fd,uint16_t pes_pid) { struct dmx_pes_filter_params pesFilterParams; pesFilterParams.pid = pes_pid; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_TS_TAP; pesFilterParams.pes_type = DMX_PES_OTHER; pesFilterParams.flags = secflags; if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) perror("DMX SET PES FILTER:"); } void DVB::AddECM(Channel *chan, uint8_t *data, int length) { int i; ecm_t *ecm = &chan->ecm; uint16_t sysid = chan->casystem; uint16_t pid = chan->capid; if (ecm->num>=MAX_ECM) return; for (i=0; i< ecm->num; i++) if ((ecm->sysid[i]==sysid) && (ecm->pid[i]==pid)) return ; ecm->sysid[ecm->num]=sysid; ecm->pid[ecm->num]=pid; if (length <= MAX_ECM_DESC){ ecm->length[ecm->num] = (uint16_t)length; memcpy((char *)(ecm->data)+(ecm->num*MAX_ECM_DESC), (char *)data, length); } ecm->num++; } int DVB::check_ecm(Channel *chan) { int found = 0; uint16_t prog_pid = 0; uint8_t buf[MAXSECSIZE], msec=0, sec=0; if (no_open) return -1; time_t count = time(0)+10; while (sec<=msec && !found && count > time(0)) { if (GetSection(buf, 0, 0, sec, msec)>0 && !buf[0]){ sec++; found = parse_pat(chan,buf); } } if (!found) return -1; prog_pid = found; sec = 0; msec = 0; while (sec<=msec && count > time(0)) { if (GetSection(buf,prog_pid, 2, sec, msec)>0){ sec++; parse_pmt(chan, buf); if(count < time(0)) break; } } return 0; } struct in_addr getaddress (const char *name) { struct in_addr in; struct hostent *hp = gethostbyname (name); //fprintf(stderr,"Looking up host %s\n", name); if (hp) memcpy (&in.s_addr, hp->h_addr_list[0], sizeof (in.s_addr)); else { fprintf(stderr, "couldn't find address of %s\n", name); exit (1); } return in; } int tcp_client_connect(const char *hostname, int sckt) { int sock; struct sockaddr_in name; int dummy=-1; name.sin_family = AF_INET; name.sin_port = htons (sckt); name.sin_addr = getaddress(hostname); do { if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1){ perror("socket"); exit(1); } //fprintf(stderr,"Trying to connect...\n"); if((dummy = connect(sock, (struct sockaddr *)&name, sizeof(name))) == ECONNREFUSED){ perror("connect"); exit(1); } if(dummy){ sleep(1); close(sock); } } while(dummy); // fprintf(stderr,"Connection established.\n"); return sock; } int udp_client_connect(const char *filename) { int sock; struct sockaddr_un name; int dummy=-1; name.sun_family = AF_UNIX; snprintf(name.sun_path, 108, "%s", filename); do { if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1){ perror("socket"); exit(1); } fprintf(stderr,"Trying to connect...\n"); if((dummy = connect(sock, (struct sockaddr *)&name, sizeof(name))) == ECONNREFUSED){ perror("connect"); exit(1); } if(dummy){ sleep(1); close(sock); } } while(dummy); fprintf(stderr,"Connection established.\n"); return sock; } void client_send_msg(int fd, uint8_t *msg, int size) { int sent = send(fd,msg,size,0); if(sent == -1) { perror("send"); exit(1); } // fprintf(stderr,"%d bytes sent.\n",sent); } int chck_frontend (int fefd, frontend_stat *festat) { fe_status_t status; int i; uint16_t snr, signal; uint32_t ber, uncorrected_blocks; for (i = 0; i < 3; i++) { usleep (300000); if (ioctl(fefd, FE_READ_STATUS, &status) == -1) { perror("FE_READ_STATUS failed"); return 0; } if (ioctl(fefd, FE_READ_SIGNAL_STRENGTH, &signal) == -1) signal = 0; if (ioctl(fefd, FE_READ_SNR, &snr) == -1) snr = 0; if (ioctl(fefd, FE_READ_BER, &ber) == -1) ber = 0; if (ioctl(fefd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1) uncorrected_blocks = 0; if (status & FE_HAS_LOCK) return 1; } return 0; } #define PAT_SCAN 0x01 #define PMT_SCAN 0x02 #define SDT_SCAN 0x04 #define EIT_SCAN 0x08 #define SCANNING 0x20 #define SET_AGAIN 0x40 #define SCAN_DONE 0x80 #define MAX_PIDS 100 int DVB::scan_tp(uint16_t tpid, uint16_t satid, int timeout, int verbose) { int seclen=0; uint8_t section, sectionnum=0xff; uint8_t buf[MAXSECSIZE]; struct pollfd pfd[MAX_PIDS]; uint16_t pids[MAX_PIDS]; uint16_t pnr[MAX_PIDS]; uint8_t pid_state[MAX_PIDS]; int filter_fds[MAX_PIDS]; uint8_t sec[MAX_PIDS]; uint8_t secn[MAX_PIDS]; uint8_t maxsec[MAX_PIDS]; time_t timeo[MAX_PIDS]; int active = 0; int pidf = 0; uint16_t tsid; int oldcf=0; int eitn=0; if (timeout < 0) timeout = 5000; for (int i=0; i< num[CHAN]; i++) if (chans[i].tpid == tpid && chans[i].satid == satid) oldcf++; memset(pids, 0, MAX_PIDS*sizeof(uint16_t)); memset(sec, 0, MAX_PIDS*sizeof(uint8_t)); memset(secn, 0, MAX_PIDS*sizeof(uint8_t)); memset(maxsec, 0, MAX_PIDS*sizeof(uint8_t)); memset(pid_state, 0, MAX_PIDS*sizeof(uint8_t)); memset(filter_fds, -1, MAX_PIDS*sizeof(int)); for (int i=0; i= maxsec[i]){ active--; if (verbose){ if (pid_state[i] & PAT_SCAN) cerr << " Stop PAT timeout" << endl; if (pid_state[i] & SDT_SCAN) cerr << " Stop SDT timeout" << endl; if (pid_state[i] & EIT_SCAN) cerr << " Stop EIT timeout" << endl; if (pid_state[i] & PMT_SCAN) cerr << " Stop PMT 0x" << pids[i] << " timeout" << endl; } pid_state[i] = SCAN_DONE; } } if (np && (pid_state[i] & SCANNING) && (pfd[i].events & POLLIN)){ seclen=0; if (read(filter_fds[i], buf, MAXSECSIZE) < 3) continue; seclen |= ((buf[1] & 0x03) << 8); seclen |= (buf[2] & 0xFF); seclen += 3; section = buf[0]; sectionnum = buf[6]; if (secn[i] != sectionnum) continue; maxsec[i] = buf[7]; secn[i]++; switch(pid_state[i] & 0x0F){ case PAT_SCAN: { int c = 8; seclen -= 12; while (seclen>0){ uint16_t npid= (buf[c] << 8)|buf[c+1]; if (npid){ pnr[pidf] = npid; pid_state[pidf] |= SET_AGAIN; pids[pidf] = get_pid(buf+c+2); pid_state[pidf] |= PMT_SCAN; sec[pidf] = 0x02; pidf++; } seclen -= 4; c += 4; } if (secn[i] > maxsec[i]){ pids[pidf] = 0x12; sec[pidf] = 0x4e; pid_state[pidf] |= (EIT_SCAN | SET_AGAIN); pidf++; } break; } case PMT_SCAN: { Channel chan; if (buf[0]!=0x02) break; chan.pnr = pnr[i]; chan.satid = satid; chan.tpid = tpid; int j = AddChannel(chan); parse_pmt(&chans[j], buf); break; } case SDT_SCAN: { Channel *schan; int c = 11; uint16_t ilen=0; tsid = (buf[3]<<8)|buf[4+1]; for (int t=0; t< num[TRANS]; t++){ if (tps[t].id == tpid && tps[t].satid == satid){ tps[t].tsid = tsid; } } while (c < seclen-4){ uint16_t npnr; npnr = (buf[c]<<8)|buf[c+1]; if(npnr){ Channel chan; int found=0; chan.satid = satid; chan.tpid = tpid; chan.pnr = npnr; schan = &chan; for (int j = 0; j has_eit = -1; schan->pres_follow = -1; if (buf[c+2] & 0x02) schan->has_eit = 0; if (buf[c+2] & 0x01) schan->pres_follow = 0; c+=3; schan->type=(buf[c]&0x10)>>4; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; c+=parse_descriptor(schan, &buf[c], ilen,(verbose>1 ? 0:0)); if (!found && strlen(schan->name)) AddChannel(chan); } } break; } case EIT_SCAN: { int c = 14; uint16_t ilen=0; //show_buf(buf, seclen); while (c < seclen-4){ c += 10; ilen=((buf[c]&0x0f)<<8) |buf[c+1]; c+=2; c+=parse_descriptor(NULL, &buf[c], ilen,(verbose>1 ? 1:0)); } break; } default: break; } if (secn[i] > maxsec[i]){ pfd[i].events = 0; close (filter_fds[i]); active--; if (verbose>1){ if (pid_state[i] & PAT_SCAN) cerr << " Stop PAT" << endl; if (pid_state[i] & SDT_SCAN) cerr << " Stop SDT" << endl; if (pid_state[i] & EIT_SCAN) cerr << " Stop EIT" << endl; if (pid_state[i] & PMT_SCAN) cerr << " Stop PMT 0x" << pids[i] << endl; } pid_state[i] = SCAN_DONE; } } if (pidf>=MAX_PIDS){ cerr << "MAX_PIDS too small" << endl; exit(1); } if (pid_state[i] & SET_AGAIN){ if ((filter_fds[i] = SetFilter(pids[i], (sec[i]<<8)|0x00ff,O_NONBLOCK))==0xffff){ pid_state[i] |= SET_AGAIN; } else { if (verbose>1){ if (pid_state[i] & PAT_SCAN) cerr << " Start PAT scan 0x"; if (pid_state[i] & SDT_SCAN) cerr << " Start SDT scan 0x"; if (pid_state[i] & EIT_SCAN) cerr << " Start EIT scan 0x"; if (pid_state[i] & PMT_SCAN) cerr << " Start PMT scan 0x"; cerr << hex << pids[i] << endl; } active++; pfd[i].fd = filter_fds[i]; pfd[i].events = POLLIN; pid_state[i] &= ~SET_AGAIN; pid_state[i] |= SCANNING; timeo[i] = time(0)+4; if (eitn < 3){ eitn++; pids[pidf] = 0x12; sec[pidf] = 0x4e; pid_state[pidf] |= (EIT_SCAN | SET_AGAIN); pidf++; } } } } } int cf=0; for (int i=0; i< num[CHAN]; i++){ if (chans[i].tpid == tpid && chans[i].satid == satid){ cf++; /* int c = 0; if (chans[i].pnr) if (chans[i].vpid == NOPID) while (chans[i].apidnum == 0 && c<10) { check_pids(&chans[i]); c++; } */ if (verbose) cerr << chans[i]; } } for (int i=0; i1){ cerr << " Start EIT scan 0x"; cerr << hex << pid << endl; } pfd.fd = filter_fd; pfd.events = POLLIN; timeo = time(0)+4; } int np=0; while(!done){ if (!(np = poll(&pfd, 1, timeout))){ cerr << "TIMEOUT" << endl; break; } if (timeo < time(0)){ secn++; if (secn >= maxsec){ done=1; if (verbose){ cerr << " Stop EIT timeout" << endl; } } } if (np && (pfd.events & POLLIN)){ seclen=0; cerr << "found section" << endl; if (read(filter_fd, buf, MAXSECSIZE) < 3) continue; seclen |= ((buf[1] & 0x03) << 8); seclen |= (buf[2] & 0xFF); seclen += 3; section = buf[0]; sectionnum = buf[6]; if (secn != sectionnum) continue; maxsec = buf[7]; secn++; int c = 14; uint16_t ilen=0; //show_buf(buf, seclen); while (c < seclen-4){ c += 10; ilen=((buf[c]&0x0f)<<8) |buf[c+1]; c+=2; c+=parse_descriptor(NULL, &buf[c], ilen, verbose); } if (secn > maxsec){ pfd.events = 0; close (filter_fd); done=1; if (verbose>1){ cerr << " Stop EIT" << endl; } } } } } int DVB::scan_TP(uint16_t tpid, uint16_t satid, int timeout, int verbose) { if (no_open) return -1; if (verbose){ cerr << "Setting Transponder 0x" << HEX(4) << tpid << " "; for (int i = 0; i < num[TRANS]; i++){ if (tps[i].id == tpid){ cerr << dec << tps[i].freq/1000 << (tps[i].pol ? "H":"V") << " " << tps[i].srate/1000 << endl; break; } } } get_front(); if (SetTP(tpid, satid) < 0) return -1; if (set_front() < 0) return -1; if (verbose) cerr << endl << "Starting transponder scan" << endl; return scan_tp(tpid, satid, timeout, verbose); } int DVB::scan_current(int timeout, int verbose) { return scan_tp(1000, 1000, timeout, verbose); } uint8_t hamtab[256] = { 0x01, 0xff, 0x81, 0x01, 0xff, 0x00, 0x01, 0xff, 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07, 0xff, 0x00, 0x01, 0xff, 0x00, 0x80, 0xff, 0x00, 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff, 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07, 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x87, 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff, 0x86, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07, 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09, 0x02, 0x82, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff, 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff, 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x83, 0x03, 0x04, 0xff, 0xff, 0x05, 0x84, 0x04, 0x04, 0xff, 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07, 0xff, 0x05, 0x05, 0x85, 0x04, 0xff, 0xff, 0x05, 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff, 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09, 0x0a, 0xff, 0xff, 0x0b, 0x8a, 0x0a, 0x0a, 0xff, 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff, 0xff, 0x0b, 0x0b, 0x8b, 0x0a, 0xff, 0xff, 0x0b, 0x0c, 0x8c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff, 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07, 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x8d, 0x0d, 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff, 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x89, 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09, 0x88, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09, 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff, 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09, 0x0f, 0xff, 0x8f, 0x0f, 0xff, 0x0e, 0x0f, 0xff, 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff, 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x8e, 0xff, 0x0e, }; uint8_t invtab[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, }; uint8_t deham(uint8_t x, uint8_t y) { return (hamtab[y]<<4)|(0x0f&hamtab[x]); } static int create_dir(const char *path) { int retval; char *bufp, *new_path; struct stat sb; retval=0; if(path && *path) { new_path = strdup(path); for(bufp = new_path+1; *bufp; ++bufp) { if(*bufp == '/') { *bufp = 0; if(stat(new_path,&sb)<0) { retval = mkdir(new_path, 0755); } *bufp = '/'; } } free(new_path); } return retval; } void DVB::add_vtx_line(magazin_t *mag, int line, uint8_t *data, int pnr) { uint8_t c=0; FILE *fd; char fname[1024]; uint8_t buf; if(!line) { mag->valid = 1; memset(mag->pagebuf, ' ', 25*40); mag->pnum = deham(data[0], data[1]); if(mag->pnum == 0xff) return; mag->flags = deham(data[2],data[3])&0x80; mag->flags |= (c&0x40)|((c>>2)&0x20); c = deham(data[6],data[7]); mag->flags |= ((c<<4)&0x10)|((c<<2)&0x08)|(c&0x04) |((c>>1)&0x02)|((c>>4)&0x01); mag->lang = ((c>>5) & 0x07); mag->sub = (deham(data[4],data[5])<<8)| (deham(data[2],data[3])&0x3f7f); } if(mag->valid) { if (line <= 23) memcpy(mag->pagebuf+40*line,data,40); if (line==23) { int pagenumber=(mag->magn*100) + ((mag->pnum>>4)*10) + (mag->pnum & 0x0f); snprintf(fname,1024,"%s/%d_%d_%c_%d/",vtxdir, transponder_freq, transponder_srate, transponder_pol, pnr); create_dir(fname); snprintf(fname,1024,"%s/%d_%d_%c_%d/%d_%d.vtx",vtxdir, transponder_freq, transponder_srate, transponder_pol, pnr,pagenumber, mag->sub&0xff); if ((fd=fopen(fname,"w"))) { fwrite("VTXV4",1,5,fd); buf = 0x01; fwrite(&buf,1,1,fd); buf = mag->magn; fwrite(&buf,1,1,fd); buf = mag->pnum; fwrite(&buf,1,1,fd); buf = 0x00; fwrite(&buf,1,1,fd); fwrite(&buf,1,1,fd); fwrite(&buf,1,1,fd); fwrite(&buf,1,1,fd); fwrite(mag->pagebuf,1,24*40,fd); fclose(fd); } mag->valid=0; } } } libdvb-0.5.5.1/libdvb/devices.cc0000644000175000017500000003014310220016115016212 0ustar mocmmocm00000000000000#include "devices.hh" #include static char *feckeys[]={"NONE", "1/2", "2/3", "3/4", "4/5", "5/6", "6/7", "7/8", "8/9", "AUTO", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; static char *invkeys[]={"OFF", "off", "on", "ON", "AUTO", "auto"}; static fe_spectral_inversion_t invset[]={INVERSION_OFF, INVERSION_OFF, INVERSION_ON, INVERSION_ON, INVERSION_AUTO, INVERSION_AUTO}; enum { TID=0, TNAME, TTYP, TFREQ, TPOL, TQAM, TSRATE, TFEC, TSAT, TONID, TBANDWIDTH, TGUARD_INTERVAL, THIERARCHY, THP_RATE, TLP_RATE, TMODULATION, TTRANSMISSION_MODE, TSID, TINVERSION}; static char *tpkeys[]={ "ID", "NAME", "TYPE", "FREQ", "POL", "QAM", "SRATE", "FEC", "SATID", "ONID","BANDWIDTH", "GUARD_INTERVAL", "HIERARCHY", "HP_RATE", "LP_RATE", "MODULATION", "TRANSMISSION_MODE", "TSID","INVERSION", NULL }; enum { SID=0, SNAME, SLNB, SROTOR, SFMIN, SFMAX}; static char *satkeys[]={ "ID", "NAME", "LNBID", "ROTORID", "FMIN", "FMAX", NULL }; enum {LID=0, LNAME, LTYP, LLOF1, LLOF2, LSLOF, LDIS, LROT, LDISNR}; static char *lnbkeys[]={ "ID", "NAME", "TYPE", "LOF1", "LOF2", "SLOF", "DISEQCID", "ROTORID", "DISEQCNR", NULL }; enum {CID=0, CNAME, CTYP, CVPID , CAPID, CPNR, CPCR, CTP, CTTP, CSID, CSAT, CONID, CBOQ, CPNAME, CNNAME, CANAME, CAC3PID, CSUBPID}; static char *chkeys[]={ "ID", "NAME", "TYPE", "VPID", "APID", "PNR", "PCRPID", "TPID", "TTPID", "SID", "SATID", "ONID", "BID", "PNAME", "NNAME","ANAME", "AC3PID", "SUBPID", NULL }; int findkey(char *name, char *keys[]) { int i=-1; char *key=keys[0]; uint l; while ((key=keys[++i])) { l = strlen(name); if (strlen(key)>l) continue; if(!strncmp(name, key, l)){ return i; } } return -1; } void getname(char *name,istream &ins, char startc, char stopc) { char cdummy[MAXNAM+2]; uint8_t l; streampos p,p2; if (startc) ins.ignore(1000, startc); p=ins.tellg(); ins.get(cdummy,MAXNAM+1); // get full channel name ins.seekg(p); ins.ignore(1000, stopc); p2=ins.tellg(); if ( (l = p2-p-streampos(1)) > MAXNAM) l=MAXNAM; strncpy(name,cdummy,l); name[l]='\0'; } ostream &operator<<(ostream &stream, Lnb &lnb) { stream << "LNB " << "ID " << hex << lnb.id; if (lnb.name[0]) stream << " NAME \"" << lnb.name << "\""; stream << " TYPE " << dec << lnb.type << " "; if (lnb.type == FE_QPSK){ if (lnb.lof1) stream << " LOF1 " << dec << lnb.lof1; if (lnb.lof2) stream << " LOF2 " << dec << lnb.lof2; if (lnb.slof) stream << " SLOF " << dec << lnb.slof; if (lnb.diseqcnr!=-1) stream << " DISEQCNR " << dec << lnb.diseqcnr; if (lnb.diseqcid!=NOID) stream << " DISEQCID " << hex << lnb.diseqcid; if (lnb.swiid!=NOID) stream << " SWITCHID " << hex << lnb.swiid; } stream << "\n"; return stream; }; ostream &operator<<(ostream &stream, Sat &sat) { stream << " SAT " << "ID " << hex << sat.id; if (sat.name[0]) stream << " NAME \"" << sat.name << "\""; stream << " LNBID " << hex << sat.lnbid; stream << " FMIN " << dec << sat.fmin; stream << " FMAX " << dec << sat.fmax; if (sat.rotorid!=NOID) stream << " ROTORID " << hex << sat.rotorid; stream << "\n"; return stream; }; ostream &operator<<(ostream &stream, Transponder &tp) { stream << " TRANSPONDER " << "ID " << HEX(4) << tp.id; if (tp.tsid!=NOID) stream << " TSID " << HEX(4) << tp.tsid; if (tp.satid!=NOID) stream << " SATID " << HEX(4) << tp.satid; stream << " TYPE " << hex << tp.type; if (tp.name[0]) stream << " NAME \"" << tp.name << "\""; stream << " FREQ " << dec << tp.freq; if (tp.type == FE_QPSK) stream << " POL " << (tp.pol ? "H" : "V" ) ; if (tp.type == FE_QAM) stream << " QAM " << dec << tp.qam; if (tp.type == FE_QPSK || tp.type == FE_QAM) { stream << " SRATE " << dec << tp.srate; stream << " FEC " << feckeys[tp.fec]; } if (tp.type == FE_OFDM){ stream << " BANDWIDTH " << dec << tp.band; stream << " HP_RATE " << dec << tp.hp_rate; stream << " LP_RATE " << dec << tp.lp_rate; stream << " MODULATION " << dec << tp.mod; stream << " TRANSMISSION_MODE " << dec << tp.transmode; stream << " GUARD_INTERVAL " << dec << tp.guard; stream << " HIERARCHY " << dec << tp.hierarchy; } switch(tp.inversion){ case INVERSION_OFF: stream << " INVERSION off"; break; case INVERSION_ON: stream << " INVERSION on"; break; case INVERSION_AUTO: stream << " INVERSION auto"; break; } stream << "\n"; return stream; }; ostream &operator<<(ostream &stream, Channel &ch) { stream << " CHANNEL"; stream << " ID " << hex << ch.id; if (ch.name[0]) stream << " NAME \"" << ch.name << "\""; if (ch.prov_name[0]) stream << " PNAME \"" << ch.prov_name << "\""; if (ch.net_name[0]) stream << " NNAME \"" << ch.net_name << "\""; stream << " SATID " << hex << ch.satid; stream << " TPID " << hex << ch.tpid; stream << " SID " << hex << ch.pnr; stream << " TYPE " << hex << ch.type; if (ch.vpid!=NOPID) stream << " VPID " << hex << ch.vpid; for (int i=0; i 0){ stream << " ANAME \"" << (char *)(ch.apids_name+i*4) << "\""; } } if (ch.ttpid && ch.ttpid!=NOPID) // don't know where pid 0 comes from stream << " TTPID " << hex << ch.ttpid; if (ch.pmtpid!=NOPID) stream << " PMTPID " << hex << ch.pmtpid; if (ch.pcrpid!=NOPID) stream << " PCRPID " << hex << ch.pcrpid; if (ch.ac3pid!=NOPID) stream << " AC3PID " << hex << ch.ac3pid; if (ch.subpid!=NOPID) stream << " SUBPID " << hex << ch.subpid; if (ch.onid!=NOID) stream << " ONID " << hex << ch.onid; if (ch.bid!=NOID) stream << " BID " << hex << ch.bid; stream << "\n"; return stream; }; istream &operator>>(istream &ins, Sat &x){ int n; char keybuf[MAXNAM]; while(!ins.eof()) { streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, satkeys); if (n<0) { ins.seekg(pos); break; } switch (n) { case SID: ins >> hex >> x.id; break; case SNAME: getname(x.name,ins); break; case SLNB: ins >> hex >> x.lnbid; break; case SROTOR: ins >> hex >> x.rotorid; break; case SFMIN: ins >> dec >> x.fmin; break; case SFMAX: ins >> dec >> x.fmax; break; } } if (x.id==NOID || x.lnbid==NOID || x.fmin==0 || x.fmax==0 ){ cerr << "Error: Not enough information for SAT" << endl; exit(1); } return ins; } istream &operator>>(istream &ins, Lnb &x){ int n; char keybuf[MAXNAM]; while(!ins.eof()) { streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, lnbkeys); if (n<0) { ins.seekg(pos); break; } else { switch (n) { case LID: ins >> hex >> x.id; break; case LNAME: getname(x.name,ins); break; case LTYP: ins >> x.type; break; case LLOF1: ins >> dec >> x.lof1; break; case LLOF2: ins >> dec >> x.lof2; break; case LSLOF: ins >> dec >> x.slof; break; case LDIS: ins >> hex >> x.diseqcid; break; case LDISNR: ins >> dec >> x.diseqcnr; break; } } } if (x.id==NOID || x.type==-1){ cerr << "Error: Not enough information for LNB" << endl; exit(1); } return ins; } istream &operator>>(istream &ins, Transponder &x){ int n; char keybuf[MAXNAM]; x.fec = (int) FEC_AUTO; x.inversion = INVERSION_OFF; while(!ins.eof()) { streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, tpkeys); if (n<0) { ins.seekg(pos); break; } switch (n) { case TID: ins >> hex >> x.id; break; case TSID: ins >> hex >> x.tsid; break; case TNAME: getname(x.name,ins); break; case TTYP: ins >> dec >> x.type; break; case TFREQ: ins >> dec >> x.freq; break; case TPOL: { ins.width(MAXNAM); ins >> keybuf; if (keybuf[0]=='H') { x.pol=1; break; } if (keybuf[0]=='V') { x.pol=0; break; } ins.seekg(pos); return ins; if (!x.type) x.type = FE_QPSK; } break; case TQAM: ins >> x.qam; if (!x.type) x.type = FE_QAM; break; case TSRATE: ins >> dec >> x.srate; break; case TONID: ins >> hex >> x.onid; break; case TFEC: ins.width(MAXNAM); ins >> keybuf; x.fec = findkey(keybuf, feckeys); if (x.fec > int(FEC_AUTO) ) x.fec -= (int(FEC_AUTO) + 1); if ((x.fec < 0) || (x.fec > int(FEC_AUTO))) x.fec = FEC_AUTO; break; case TSAT: ins >> hex >> x.satid; break; case TBANDWIDTH: ins >> dec >> x.band; if (!x.type) x.type = FE_OFDM; break; case THP_RATE: ins.width(MAXNAM); ins >> keybuf; x.hp_rate = findkey(keybuf, feckeys); if (x.hp_rate > int(FEC_AUTO) ) x.hp_rate -= (int(FEC_AUTO) + 1); if ((x.hp_rate < 0) || (x.hp_rate > int(FEC_AUTO))) x.hp_rate = FEC_AUTO; break; case TLP_RATE: ins.width(MAXNAM); ins >> keybuf; x.lp_rate = findkey(keybuf, feckeys); if (x.lp_rate > int(FEC_AUTO) ) x.lp_rate -= (int(FEC_AUTO) + 1); if ((x.lp_rate < 0) || (x.lp_rate > int(FEC_AUTO))) x.lp_rate = FEC_AUTO; break; case TMODULATION: ins >> dec >> x.mod; break; case TTRANSMISSION_MODE: ins >> dec >> x.transmode; break; case TGUARD_INTERVAL: ins >> dec >> x.guard; break; case THIERARCHY: ins >> dec >> x.hierarchy; break; case TINVERSION: { int inv; ins.width(MAXNAM); ins >> keybuf; inv = findkey(keybuf, invkeys); x.inversion = invset[inv]; break; } } } if (x.id==NOID || x.freq==0 ){ cerr << "Error: Not enough information for TRANSPONDER" << endl; exit(1); } return ins; } istream &operator>>(istream &ins, Channel &x){ int n; char keybuf[MAXNAM]; while(!ins.eof()) { streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, chkeys); if (n<0) { ins.seekg(pos); break; } switch (n) { case CID: ins >> hex >> x.id; break; case CSAT: ins >> hex >> x.satid; break; case CONID: ins >> hex >> x.onid; break; case CBOQ: ins >> hex >> x.bid; break; case CNAME: getname(x.name,ins); break; case CPNAME: getname(x.prov_name,ins); break; case CNNAME: getname(x.net_name,ins); break; case CTYP: ins >> dec >> x.type; break; case CVPID: ins >> hex >> x.vpid; break; case CTTP: ins >> hex >> x.ttpid; break; case CAC3PID: ins >> hex >> x.ac3pid; break; case CSUBPID: ins >> hex >> x.subpid; break; case CAPID: if (x.apidnum>=MAXAPIDS) break; ins >> hex >> x.apids[x.apidnum]; x.apidnum++; break; case CANAME: { char n[MAXNAM+1]; if (!x.apidnum) break; getname(n,ins); if (x.apidnum <= MAXAPIDS){ memset((char *)(x.apids_name+(x.apidnum-1)*4),0,4); memcpy((char *)(x.apids_name+(x.apidnum-1)*4),n,3); } break; } case CPNR: case CSID: ins >> hex >> x.pnr; break; case CPCR: ins >> hex >> x.pcrpid; break; case CTP: ins >> hex >> x.tpid; break; }; } if (x.id==NOID || x.type==-1 || x.tpid==NOPID || (x.pnr==NOPID && (x.vpid==NOPID|| x.apids[0]==NOPID)) ){ cerr << "Error: Not enough information for CHANNEL " << x << endl; exit(1); } return ins; } istream &operator>>(istream &ins, Bouquet &x){ return ins; } istream &operator>>(istream &ins, DiSEqC &x){ return ins; } istream &operator>>(istream &ins, Rotor &x){ return ins; } libdvb-0.5.5.1/libdvb/OSD.c0000644000175000017500000000703610220016115015057 0ustar mocmmocm00000000000000#include #include #include #include int OSDClose(int dev) { osd_cmd_t dc; dc.cmd=OSD_Close; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDOpen(int dev, int x0, int y0, int x1, int y1, int BitPerPixel, int mix) { osd_cmd_t dc; dc.cmd=OSD_Open; dc.x0=x0; dc.y0=y0; dc.x1=x1; dc.y1=y1; dc.data=0; dc.color=BitPerPixel&0xf; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDShow(int dev) { osd_cmd_t dc; dc.cmd=OSD_Show; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDHide(int dev) { osd_cmd_t dc; dc.cmd=OSD_Hide; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDClear(int dev) { osd_cmd_t dc; dc.cmd=OSD_Clear; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDFill(int dev, int color) { osd_cmd_t dc; dc.cmd=OSD_Fill; dc.color=color; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDSetColor(int dev, int color, int r, int g, int b, int op) { osd_cmd_t dc; dc.cmd=OSD_SetColor; dc.color=color; dc.x0=r; dc.y0=g; dc.x1=b; dc.y1=op; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDText(int dev, int x, int y, int size, int color, const char *text) { osd_cmd_t dc; dc.cmd=OSD_Text; dc.x0=x; dc.y0=y; dc.x1=size; // fontsize (1, 2 or 3) dc.data=(char *)text; dc.color=color; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDSetPalette(int dev, int first, int last, unsigned char *data) { osd_cmd_t dc; dc.cmd=OSD_SetPalette; dc.color=first; dc.x0=last; dc.data=data; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDSetTrans(int dev, int trans) { osd_cmd_t dc; dc.cmd=OSD_SetTrans; dc.color=trans; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDSetPixel(int dev, int x, int y, unsigned int color) { osd_cmd_t dc; dc.cmd=OSD_SetPixel; dc.x0=x; dc.y0=y; dc.color=color; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDGetPixel(int dev, int x, int y) { osd_cmd_t dc; dc.cmd=OSD_GetPixel; dc.x0=x; dc.y0=y; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDSetRow(int dev, int x, int y, int x1, unsigned char *data) { osd_cmd_t dc; dc.cmd=OSD_SetRow; dc.x0=x; dc.y0=y; dc.x1=x1; dc.data=data; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDSetBlock(int dev, int x, int y, int x1, int y1, int inc, unsigned char *data) { int size; osd_cmd_t dc; size= dc.cmd=OSD_SetBlock; dc.x0=x; dc.y0=y; dc.x1=x1; dc.y1=y1; dc.color=inc; dc.data=data; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDFillRow(int dev, int x, int y, int x1, int color) { osd_cmd_t dc; dc.cmd=OSD_FillRow; dc.x0=x; dc.y0=y; dc.x1=x1; dc.color=color; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDFillBlock(int dev, int x, int y, int x1, int y1, int color) { osd_cmd_t dc; dc.cmd=OSD_FillBlock; dc.x0=x; dc.y0=y; dc.x1=x1; dc.y1=y1; dc.color=color; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDLine(int dev, int x, int y, int x1, int y1, int color) { osd_cmd_t dc; dc.cmd=OSD_Line; dc.x0=x; dc.y0=y; dc.x1=x1; dc.y1=y1; dc.color=color; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDQuery(int dev) { osd_cmd_t dc; dc.cmd=OSD_Query; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDSetWindow(int dev, int win) { osd_cmd_t dc; dc.cmd=OSD_SetWindow; dc.x0=win; return ioctl(dev, OSD_SEND_CMD, &dc); } int OSDMoveWindow(int dev, int x, int y) { osd_cmd_t dc; dc.cmd=OSD_MoveWindow; dc.x0=x; dc.y0=y; return ioctl(dev, OSD_SEND_CMD, &dc); } libdvb-0.5.5.1/libdvb/.#DVB.cc.1.560000644000175000017500000026514010220016115015723 0ustar mocmmocm00000000000000#include static const char *vdr_inv_name [] = { "0", "1", "999" }; static const char *vdr_fec_name [] = { "0", "12", "23", "34", "45", "56", "67", "78", "89", "999" }; static const char *vdr_qam_name [] = { "0", "16", "32", "64", "128", "256", "999" }; static const char *vdr_bw_name [] = { "8", "7", "6", "999" }; static const char *vdr_mode_name [] = { "2", "8", "999" }; static const char *vdr_guard_name [] = { "32", "16", "8", "4", "999" }; static const char *vdr_hierarchy_name [] = { "0", "1", "2", "4", "999" }; static const char *fec_name [] = { "FEC_NONE", "FEC_1_2", "FEC_2_3", "FEC_3_4", "FEC_4_5", "FEC_5_6", "FEC_6_7", "FEC_7_8", "FEC_8_9", "FEC_AUTO" }; static const char *inv_name [] = { "INVERSION_OFF", "INVERSION_ON", "INVERSION_AUTO" }; static const char *qam_name [] = { "QPSK", "QAM_16", "QAM_32", "QAM_64", "QAM_128", "QAM_256", "QAM_AUTO" }; static const char *bw_name [] = { "BANDWIDTH_8_MHZ", "BANDWIDTH_7_MHZ", "BANDWIDTH_6_MHZ", "BANDWIDTH_AUTO" }; static const char *mode_name [] = { "TRANSMISSION_MODE_2K", "TRANSMISSION_MODE_8K", "TRANSMISSION_MODE_AUTO" }; static const char *guard_name [] = { "GUARD_INTERVAL_1_32", "GUARD_INTERVAL_1_16", "GUARD_INTERVAL_1_8", "GUARD_INTERVAL_1_4", "GUARD_INTERVAL_AUTO" }; static const char *hierarchy_name [] = { "HIERARCHY_NONE", "HIERARCHY_1", "HIERARCHY_2", "HIERARCHY_4", "HIERARCHY_AUTO" }; static const fe_code_rate_t ftab [8] = { FEC_AUTO, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_NONE, FEC_NONE }; static const fe_modulation_t qtab [6] = { QAM_AUTO, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256 }; void dvb2txt(char *out, char *in, int l) { uint8_t len; len = (uint8_t) l; if (len > MAXNAM) len=MAXNAM; if (strlen(in) < (size_t)len) len = (int)strlen(in); uint8_t *txt=(uint8_t *) in; if (!len) return; switch (*txt) { case 0x01 ... 0x0f: txt++; len--; break; case 0x10: txt+=3; len-=3; break; } while (len>0) { switch(*txt) { case '\"': case 0x01 ... 0x1f: case 0x7f ... 0xa0: len--; txt++; break; case 0x00: len=1; default: *(out++)=(char) *(txt++); len--; break; } } } void show_buf(uint8_t *buf, int length) { fprintf(stderr,"\n"); for (int i=0; i 0) close(fd_frontend); if (fd_demuxa > 0) close(fd_demuxa); if (fd_demuxv > 0) close(fd_demuxv); if (fd_demuxpcr > 0) close(fd_demuxpcr); if (fd_demuxtt > 0) close(fd_demuxtt); char devname[80]; set_vtxdir(VTXDIR); dvr_enabled = 0; sprintf(devname,FRONT_DEV,adapter,minor); fd_frontend=open(devname, O_RDWR); if (fd_frontend < 0) { cerr << "Could not open " << devname << endl; front_type=-1; perror(devname); fd_frontend = -1; failed = 1; } ioctl(fd_frontend, FE_GET_INFO, &feinfo); front_type=feinfo.type; sprintf(devname,DEMUX_DEV,adapter,minor); fd_demuxtt=open(devname, O_RDWR); if (fd_demuxtt < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxtt = -1; failed = 1; } fd_demuxa=open(devname, O_RDWR); if (fd_demuxa < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxa = -1; failed = 1; } fd_demuxpcr=open(devname, O_RDWR); if (fd_demuxpcr < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxpcr = -1; failed = 1; } fd_demuxv=open(devname, O_RDWR); if (fd_demuxv < 0) { cerr << "Could not open " << devname << endl; perror(devname); fd_demuxv = -1; failed = 1; } } Transponder *DVB::find_tp(unsigned int tpid, unsigned int satid) { Transponder *tp=NULL; int i; for (i=0; itpid) { tp=&tps[i]; break; } return tp; } Sat *DVB::find_sat(Transponder *tp) { Sat *sat=NULL; int i; for (i=0; isatid) { sat=&sats[i]; break; } return sat; } Sat *DVB::find_sat(Channel *chan) { Sat *sat=NULL; int i; for (i=0; isatid) { sat=&sats[i]; break; } return sat; } Lnb *DVB::find_lnb(Sat *sat) { Lnb *lnb=NULL; int i; for (i=0; ilnbid) { lnb=&lnbs[i]; break; } return lnb; } int DVB::SetTP(unsigned int tpid, unsigned int satid) { int i; Transponder *tp=0; Sat *sat=0; Lnb *lnb=0; if (no_open) return -1; tp = find_tp(tpid, satid); if (!tp) { fprintf(stderr,"Transponder not found!\n"); return -1; } for (i=0; isatid) { sat=&sats[i]; break; } } if (!sat){ fprintf(stderr,"Satellite not found!\n"); return -1; } for (i=0; ilnbid) { lnb=&lnbs[i]; break; } if (!lnb){ fprintf(stderr,"LNB not found!\n"); return -1; } switch (front_type) { case FE_QPSK: if (tp->freq < lnb->slof) { front_param.frequency = (tp->freq - lnb->lof1); tone = SEC_TONE_OFF; } else { front_param.frequency = (tp->freq - lnb->lof2); tone = SEC_TONE_ON; } if (tp->pol) voltage = SEC_VOLTAGE_18; else voltage = SEC_VOLTAGE_13; set_diseqc_nb(lnb->diseqcnr); front_param.u.qpsk.symbol_rate = tp->srate; front_param.u.qpsk.fec_inner = (fe_code_rate_t)tp->fec; front_param.inversion = tp->inversion; transponder_srate = tp->srate; transponder_pol = tp->pol ? 'H':'V'; break; case FE_QAM: front_param.frequency = tp->freq; front_param.inversion = tp->inversion; front_param.u.qam.symbol_rate = tp->srate; front_param.u.qam.fec_inner = (fe_code_rate_t)tp->fec; front_param.u.qam.modulation=(fe_modulation_t) (tp->qam+1); transponder_srate = tp->srate; break; case FE_OFDM: front_param.frequency = tp->freq; front_param.inversion = tp->inversion; front_param.u.ofdm.bandwidth = (fe_bandwidth_t)tp->band; front_param.u.ofdm.code_rate_HP = (fe_code_rate_t)tp->hp_rate; front_param.u.ofdm.code_rate_LP = (fe_code_rate_t)tp->lp_rate; front_param.u.ofdm.constellation = (fe_modulation_t)tp->mod; front_param.u.ofdm.transmission_mode = (fe_transmit_mode_t)tp->transmode; front_param.u.ofdm.guard_interval = (fe_guard_interval_t)tp->guard; front_param.u.ofdm.hierarchy_information = (fe_hierarchy_t)tp->hierarchy; break; } transponder_freq = tp->freq; return 0; } static uint16_t get_pid(uint8_t *pid) { uint16_t pp; pp = (pid[0] & 0x1f) << 8; pp |= pid[1] &0xff; return pp; } static uint32_t bcd32_trafo(uint8_t *buf){ return ((buf[0] >> 4) & 0x0f) * 10000000UL + (buf[0] & 0x0f) * 1000000UL + ((buf[1] >> 4) & 0x0f) * 100000UL + (buf[1] & 0x0f) * 10000UL + ((buf[2] >> 4) & 0x0f) * 1000UL + (buf[2] & 0x0f) * 100UL + ((buf[3] >> 4) & 0x0f) * 10UL + (buf[3] & 0x0f); } int DVB::parse_descriptor(Channel *chan, uint8_t *buf, int length, int verb=0, Transponder *tp=NULL) { int dlength; Transponder dtp; if (!length) return 0; dlength = buf[1]; if (verb) cerr << "desc 0x" << int(buf[0]) << endl; switch(buf[0]){ case 0x0a: if (!chan) break; if (dlength==4 && chan->last_apidn>=0 && chan->last_apidn < MAXAPIDS){ memcpy(chan->apids_name+chan->last_apidn*4,buf+2, 3); } break; case 0x09: uint16_t casys; uint16_t capid; if (verb) cerr << "ECM descriptor" << endl; if (!dlength) break; if (!chan) break; casys =(buf[2]<<8)|buf[3]; capid = get_pid(buf+4); /* if ((dlength>17 && casys==0x100) || casys == 0xb00){ capid = get_pid(buf+19); } */ chan->casystem = casys; chan->capid = capid; AddECM(chan, buf, dlength+2); if (chan->ecm_callback) chan->ecm_callback(chan); break; case 0x40: //network name descriptor { uint8_t slen=0; char name[MAXNAM+1]; if (verb) cerr << "network name descriptor" << endl; if (!chan) break; memset (name,0,MAXNAM+1); slen = buf[1]; if (slen > MAXNAM){ memcpy(name,(char*)(buf+2), MAXNAM); memset(chan->net_name, 0, MAXNAM+1); dvb2txt(chan->net_name,name, MAXNAM); } else if (slen) { memcpy(name,(char*)(buf+2), int(slen)); memset(chan->net_name, 0, MAXNAM+1); dvb2txt(chan->net_name,name, int(slen)); } break; } case 0x41:/* service list */ if (verb) cerr << "service list descriptor" << endl; break; case 0x42:/* stuffing */ if (verb) cerr << "stuffing descriptor" << endl; break; case 0x43:/* satellite delivery system */ if (!tp) tp = &dtp; tp->type = FE_QPSK; tp->freq = 10*bcd32_trafo(buf+2); tp->srate = 10*bcd32_trafo(buf+9); tp->fec = ftab[buf[12] & 0x07]; tp->pol = (buf[8] >> 5) & 0x03; tp->orbpos = ((buf[6] >> 4) & 0x0f) * 1000 + (buf[6] & 0x0f) * 100 + ((buf[7] >> 4) & 0x0f) * 10 + (buf[7] & 0x0f); if (buf[8] >> 7) tp->orbpos = -tp->orbpos; if (verb){ cerr << "Satellite delivery system descriptor " << tp->orbpos << endl; cerr << *tp; } break; case 0x44:/* cable delivery system */ if (!tp) tp=&dtp; tp->type = FE_QAM; tp->freq = 100*bcd32_trafo(buf+2); tp->srate = 10*bcd32_trafo(buf+9); tp->fec = ftab[buf[12] & 0x07]; if ((buf[8] & 0x0f)<= 5) tp->qam = qtab[buf[8] & 0x0f]; else tp->qam = QAM_AUTO; if (verb){ cerr << "Cable delivery system descriptor" << endl; cerr << *tp; } break; case 0x45:/* VBI data */ if (verb) cerr << "VBI data descriptor" << endl; break; case 0x46:/* VBI teletext */ if (verb) cerr << "VBI teletext descriptor" << endl; break; case 0x47:/* bouquet name */ if (verb) cerr << "bouquet name descriptor" << endl; break; case 0x48: /* service desc */ { uint8_t slen=0; char name[MAXNAM+1]; uint8_t *mbuf = buf; if (verb) cerr << "service descriptor" << endl; if (!chan) break; memset (name,0,MAXNAM+1); mbuf += 3; slen = *mbuf; /* provider name */ mbuf++; if (slen > MAXNAM){ memcpy(name, mbuf, MAXNAM); memset(chan->prov_name, 0, MAXNAM+1); dvb2txt(chan->prov_name,name, MAXNAM); } else if (slen) { memcpy(name, mbuf, int(slen)); memset(chan->prov_name, 0, MAXNAM+1); dvb2txt(chan->prov_name,name, int(slen)); } mbuf += slen; /* service name */ slen = *mbuf; mbuf++; if (!slen) break; memset (name,0,MAXNAM+1); if (slen > MAXNAM){ memcpy(name,mbuf, MAXNAM); memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, MAXNAM); } else if(slen>0){ memcpy(name, mbuf, int(slen)); memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, int(slen)); } if (verb) cerr << chan->name << endl; } break; case 0x49:/* country availability */ if (verb) cerr << "country availability descriptor" << endl; break; case 0x4a: /*linkage*/ if (verb) cerr << "linkage descriptor "<< int(buf[8]) << endl; switch (buf[8]){ case 0xb0: /* Multifeed */ { uint16_t ts_id, sid; ts_id = (buf[2] << 8)|buf[3]; sid = (buf[6] << 8)|buf[7]; if (verb) cerr << HEX(2)<< ts_id << " " << HEX(2) << sid << endl; chan = NULL; for (int i = 0; i < num[CHAN]; i++){ if (chans[i].pnr == sid){ chan = &chans[i]; break; } } uint8_t slen=0; char name[MAXNAM+1]; uint8_t *mbuf = buf; memset (name,0,MAXNAM+1); mbuf += 9; slen = dlength-9; /* multifeed name */ if (slen > MAXNAM){ memcpy(name, mbuf, MAXNAM); if (chan){ memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, MAXNAM); } } else if (slen) { memcpy(name, mbuf, int(slen)); if (chan){ memset(chan->name, 0, MAXNAM+1); dvb2txt(chan->name,name, MAXNAM); } } if (verb){ if (chan) cerr << chan->name << endl; else cerr << name << endl; } } break; } case 0x4b:/* NVOD reference */ if (verb) cerr << "NVOD reference descriptor" << endl; break; case 0x4c:/* time shifted service */ if (verb) cerr << "time shifted service descriptor" << endl; break; case 0x4d: /* short event */ if (verb) cerr << "short event descriptor" << endl; break; case 0x4e: /* extended event */ if (verb) cerr << "extended event descriptor" << endl; break; case 0x4f: /* time shifted event */ if (verb) cerr << "time shifted event descriptor" << endl; break; case 0x50: /* component event */ if (verb) cerr << "component event descriptor" << endl; break; case 0x51: /* mosaic */ if (verb) cerr << "mosaic descriptor" << endl; break; case 0x52: /* stream identufier */ if (verb) cerr << "stream identifier descriptor" << endl; break; case 0x53: /* CA identifier */ if (verb) cerr << "CA identifier descriptor" << endl; break; case 0x54: /* content */ if (verb) cerr << "content descriptor" << endl; break; case 0x55: /* parental rating*/ if (verb) cerr << "parental rating descriptor" << endl; break; case 0x56: /* teletext */ if (verb) cerr << "teletext descriptor" << endl; if (!chan) break; if (chan->tmppid != NOPID){ chan->ttpid = chan->tmppid; } break; case 0x57: /* telephone */ if (verb) cerr << "telephone descriptor" << endl; break; case 0x58: /* local time offset */ if (verb) cerr << "local time offset descriptor" << endl; break; case 0x59: /* subtitle */ if (verb) cerr << "subtitle descriptor" << endl; if (!chan) break; if (chan->tmppid != NOPID){ chan->subpid = chan->tmppid; } break; case 0x5a: /* terrestrial delivery system */ if (!tp) tp=&dtp; tp->type = FE_OFDM; if (verb){ cerr << "Terrestrial delivery system descriptor" << endl; cerr << *tp; } break; case 0x5b: /* multilingual network name */ if (verb) cerr << "multilingual network name descriptor" << endl; break; case 0x5c: /* multilingual bouquet name */ if (verb) cerr << "multilingual bouquet name descriptor" << endl; break; case 0x5d: /* multilingual service name */ if (verb) cerr << "multilingual service name descriptor" << endl; break; case 0x5e: /* multilingual component */ if (verb) cerr << "multilingual component descriptor" << endl; break; case 0x5f: /* private data specifier */ if (verb) cerr << "private data specifier descriptor" << endl; break; case 0x60: /* service move */ if (verb) cerr << "service move descriptor" << endl; break; case 0x61: /* short smoothing buffer */ if (verb) cerr << "short smoothing buffer descriptor" << endl; break; case 0x62: /* frequency list */ if (verb) cerr << "frequency list descriptor" << endl; break; case 0x63: /* partial transport stream */ if (verb) cerr << "partial transport stream descriptor" << endl; break; case 0x64: /* data broadcast */ if (verb) cerr << "data broadcast descriptor" << endl; break; case 0x65: /* CA system */ if (verb) cerr << "CA system descriptor" << endl; break; case 0x66: /* data broadcast id */ if (verb) cerr << "data broadcast id descriptor" << endl; break; case 0x67: /* transport stream offset */ if (verb) cerr << "transport stream descriptor" << endl; break; case 0x68: /* DSNG */ if (verb) cerr << "DSNG descriptor" << endl; break; case 0x69: /* PDC */ if (verb) cerr << "PDC descriptor" << endl; break; case 0x6a: /* AC3 */ if (verb) cerr << "AC3 descriptor" << endl; if (!chan) break; if (chan->tmppid != NOPID){ chan->ac3pid = chan->tmppid; } break; case 0x6b: /* ancillary data */ if (verb) cerr << "ancillary data descriptor" << endl; break; case 0x6c: /* cell list */ if (verb) cerr << "cell list descriptor" << endl; break; case 0x6d: /* cell frequency link */ if (verb) cerr << "cell frequency link descriptor" << endl; break; case 0x6e: /* announcement support */ if (verb) cerr << "announcement support descriptor" << endl; break; default: //show_buf(buf,dlength); break; } int c=0; c += dlength+2; if ( c < length) c += parse_descriptor(chan, buf+c, length-c, verb); if (ctmppid = NOPID; return length; } int DVB::parse_pmt(Channel *chan, uint8_t *buf) { int slen, ilen, eslen, c; uint16_t epid; if (buf[0] != 0x02) return -1; slen = (((buf[1]&0x03) << 8) | buf[2]) +3; ilen = ((buf[10]&0x03) <<8) | buf[11]; chan->pcrpid = get_pid(buf+8); c = 12; if (ilen) c+=parse_descriptor(chan, buf+c, ilen); if (c-12< ilen){ cerr << "Hmm error in descriptor parsing" << endl; } // show_buf(buf,slen); while (c < slen-4){ eslen = ((buf[c+3]&0x03) <<8) | buf[c+4]; epid = get_pid(buf+c+1); switch (buf[c]) { case 1: case 2: if (chan->vpid == NOPID) chan->vpid = epid; break; case 3: case 4: { int afound = 0; uint16_t apid = epid; chan->last_apidn = -1; if (chan->apidnum>=MAXAPIDS) { cerr << "Need more apids\n"; break; } for (int i = 0; i < chan->apidnum; i++){ if ( apid == chan->apids[i]){ afound = 1; chan->last_apidn = i; break; } } if (! afound){ chan->apids[chan->apidnum++] = apid; chan->last_apidn = chan->apidnum-1; } break; } case 6: chan->tmppid = epid; break; /* case 5: cerr << "private service 0x" << hex << int(buf[c]) << " for service id 0x" << chan->pnr << " with pid 0x"<< epid << dec<< endl; break; default: cerr << "other service 0x" << hex << int(buf[c]) << " for service id 0x" << chan->pnr << " with pid 0x"<< epid << dec<< endl; break; */ } c += 5; if (eslen) c += parse_descriptor(chan, buf+c, eslen); } return 0; } int DVB::parse_pat(Channel *chan, uint8_t *buf) { int slen, i, nprog; int found = 0; uint8_t *prog; uint16_t prog_pid = 0, pnr = 0; slen = (((buf[1]&0x03) << 8) | buf[2]); nprog = (slen - 9) / 4; prog = buf+ 8; for (i = 0; i < nprog; i++){ pnr = (prog[0] << 8)|prog[1]; if ( chan->pnr == pnr ){ prog_pid = get_pid(prog+2); found = 1; break; } prog += 4; } if (found) found = prog_pid; return found; } /* void DVB::parse_nit(Transponder *tp, uint8_t *buf) { int slen, i, nprog; int found = 0; slen = (((buf[1]&0x0f) << 8) | buf[2]); } int DVB::check_nit(Transponder *tp) { int found = 0; uint16_t prog_pid = 0; uint8_t buf[MAXSECSIZE], msec=0, sec=0; if (no_open) return -1; time_t count = time(0)+2; while (sec<=msec && !found && count > time(0)) { if (GetSection(buf, 0x10, 0x40, sec, msec)>0){ sec++; found = parse_nit(tp, buf); } } if (!found) return -1; return 0; } */ void DVB::check_all_pids() { if (no_open) return; for (int i = 0; i < num[CHAN]; i++){ cerr << "checking " << chans[i].name << endl; SetChannel(i); } } int DVB::check_pids(Channel *chan) { int found = 0; int oldnum; uint16_t prog_pid = 0; uint8_t buf[MAXSECSIZE], msec=0, sec=0; if (no_open) return -1; oldnum=chan->apidnum; time_t count = time(0)+4; while (sec<=msec && !found && count > time(0)) { if (GetSection(buf, 0, 0, sec, msec)>0 && !buf[0]){ sec++; found = parse_pat(chan,buf); } } if (!found) return -1; prog_pid = found; chan->apidnum = 0; sec = 0; msec = 0; count = time(0)+4; while (sec<=msec && count > time(0)) { if (GetSection(buf,prog_pid, 2, sec, msec)>0){ sec++; parse_pmt(chan, buf); if(count < time(0)) break; } } if (!chan->apidnum) chan->apidnum=oldnum; chan->checked = 1; return 0; } int DVB::get_all_progs(uint16_t *progbuf, uint16_t *pnrbuf, int length) { int nfound = 0, oldone = 0, j; uint8_t buf[MAXSECSIZE], msec=0, sec=0; uint16_t prog_pid = 0, pnr = 0; int slen; uint8_t *prog; if (no_open) return -1; time_t count = time(0)+4; while (sec<=msec && count > time(0)) { if (GetSection(buf, 0, 0, sec, msec)>0 && !buf[0]){ sec++; slen = (((buf[1]&0x0f) << 8) | buf[2]); slen -= 11; prog = buf+ 8; while (slen>0){ pnr = (prog[0] << 8)|prog[1]; prog_pid = get_pid(prog+2); oldone = 0; for(j=0; j time(0)) { if (GetSection(buf,prog_pid, 2, sec, msec)>0){ sec++; parse_pmt(&chan,buf); if(count < time(0)) break; } } *ttpid = chan.ttpid; *vpid = chan.vpid; apidnum = chan.apidnum; if (apidnum && apidnum <= MAXAPIDS){ memcpy(apids, chan.apids, apidnum * sizeof (uint16_t)); if (apids_name) memcpy(apids_name, chan.apids_name, apidnum * sizeof (uint8_t)*4); } return found+apidnum; } uint16_t DVB::find_pnr(uint16_t svpid, uint16_t sapid) { int nfound = 0; int pfound = 0; uint16_t progs[100]; uint16_t pnrs[100]; uint16_t vpid; uint16_t ttpid; uint16_t apids[MAXAPIDS]; if (no_open) return 0; nfound = get_all_progs(progs, pnrs, 100); for(int i=0; i < nfound; i++){ if ( (pfound = get_pids(progs[i], &vpid, apids, &ttpid)) ){ if(svpid != NOPID && vpid == svpid ) return pnrs[i]; else if ( svpid == NOPID ){ for (int j=0; j time(0)) { if (GetSection(buf, 0x11, 0x42, sec, msec)>0){ sec++; slen = (((buf[1]&0x0f) << 8) | buf[2]) +3; tsid = (buf[3]<<8)|buf[4+1]; if (tp) tp->tsid = tsid; c = 11; while (c < slen-4){ pnr = (buf[c]<<8)|buf[c+1]; chan->has_eit = -1; chan->pres_follow = -1; if (buf[c+2] & 0x02) chan->has_eit = 0; if (buf[c+2] & 0x01) chan->pres_follow = 0; c+=3; ca=(buf[c]&0x10)>>4; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; if ( chan->pnr == pnr && ilen ){ chan->type=ca; c+=parse_descriptor(chan, &buf[c], ilen); } else c+=ilen; } } } } int DVB::scan_sdts(int *chs, int n) { int slen, ilen, c; uint8_t buf[MAXSECSIZE], msec=0, sec=0; uint16_t pnr; uint8_t ca; int *check; uint16_t tsid; Transponder *tp; if (n>MAX_TRANS_CHAN || n <0) return -1; if (no_open) return -1; check = new int[n]; tp = find_tp(&chans[chs[0]]); for (int i=0; i time(0)) { if (GetSection(buf, 0x11, 0x42, sec, msec)>0){ sec++; slen = (((buf[1]&0x0f) << 8) | buf[2]); tsid = (buf[3]<<8)|buf[4+1]; if (tp) tp->tsid = tsid; c = 11; while (c < slen-4){ pnr = (buf[c]<<8)|buf[c+1]; c+=3; ca=(buf[c]&0x10)>>4; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; int ce=0; for (int cl=0; cl < n; cl++){ if (chans[chs[cl]].pnr == pnr ){ ce=parse_descriptor(&chans[chs[cl]],buf+c, ilen); check[cl]=1; chans[chs[cl]].type=ca; continue; } } if (ce < ilen) cerr << "Error in descriptor parsing" << endl; c+=ilen; } } } int found=0; for (int i=0; i < n; i++) found+=check[i]; delete [] check; return found; } int eit_cb(uint8_t *buf, int l, int pnr, int c_n, uint8_t *t) { cout << "Type: " << c_n << " PNR:" << pnr << " Time: " << hex << int(t[2]) << ":" << int(t[3]) << "." << int(t[4]) << dec << endl; for (int i=0; i < l/16+1; i++){ cout << "0x" << HEX(4) << i << dec << " "; for (int j=0; j < 16; j++){ if (j+i*16 < l) cout << HEX(2) << int(buf[j+i*16]) << dec << " "; else cout << " "; } for (int j=0; j < 16 && j+i*16 < l; j++){ uint8_t c = (char)buf[j+i*16]; switch ((int)c) { case 0x01 ... 0x1f: case 0x7f ... 0xa0: case 0x00: cout << "." ; break; default: cout << char(c) ; break; } } cout << endl; } cout << endl; cout << endl; if (c_n && l>10) return 1; else return 0; } void DVB::scan_pf_eit(Channel *chan, int (*callback)(uint8_t *data, int l, int pnr, int c_n, uint8_t *t) = eit_cb) { int slen, ilen, c, t; uint8_t buf[MAXSECSIZE], msec=0, sec=0; uint16_t pnr = NOID; int8_t ver; int c_n; int done=0; if (no_open) return; time_t count = time(0)+5; while ( !done && count > time(0)) { if (GetSection(buf, 0x12, 0x4e, sec, msec)>0){ sec++; c = 1; slen = (((buf[c]&0x0f) << 8) | buf[c+1]) +3; c += 2; pnr = (buf[c]<<8)|buf[c+1]; c += 2; ver = buf[c] & 0x3E; c_n = buf[c] & 0x01; c += 8; if (pnr == chan->pnr){ while (c < slen-4){ t = c+3; c += 10; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; done = callback(buf+c, ilen, pnr, c_n, buf+t); c+=ilen; } } } } } void DVB::scan_pf_eit(int chnr, int (*callback)(uint8_t *data, int l, int pnr, int c_n, uint8_t *t) = eit_cb) { if (no_open) return; if (chnr>=num[CHAN] || chnr < 0) return; scan_pf_eit(&chans[chnr], callback); } void DVB::scan_pf_eit(int chnr) { if (no_open) return; if (chnr>=num[CHAN] || chnr < 0) return; scan_pf_eit(&chans[chnr]); } int DVB::SetChannel(Channel *chan, char* apref, uint16_t *apidp, uint16_t *vpidp) { int i; int scan = 0; uint16_t apid=0, vpid=0; if (no_open) return -1; if (chan->pnr == NOPID && (chan->vpid != NOPID || chan->apids[0] != NOPID)) chan->pnr = find_pnr(chan->vpid, chan->apids[0]); int c=0; if (chan->pnr) if (chan->vpid == NOPID){ check_pids(chan); scan=1; while (chan->apidnum == 0 && c<10) { check_pids(chan); c++; } } vpid = chan->vpid; if (chan->apidnum){ if (apref){ int found = 0; for (i=0; i < chan->apidnum; i++){ if (!strncasecmp(chan->apids_name+4*i, apref,3)){ found=1; break; } } if (found) apid = chan->apids[i]; else apid = chan->apids[0]; } else apid = chan->apids[0]; } if (vpid != NOPID) set_vpid(vpid); set_apid(apid); set_pcrpid(chan->pcrpid); if (chan->ttpid != NOPID) set_ttpid(chan->ttpid); if (scan) scan_sdt(chan); if (fdvb >= 0){ struct tm *lt; time_t t; t = time(0); lt = localtime(&t); ostringstream fstr; osd.Clear(); fstr << setw(2) << setfill('0') << lt->tm_hour << ":" << setw(2) << setfill('0') << lt->tm_min << " "; if (chan->name[0]) fstr << chan->name; else if (chan->prov_name[0]) fstr << chan->prov_name; else fstr << "Channel " << dec << chan->id; fstr << ends; osd.Text(0, 0, 0, 1, fstr.str().data()); osd.Show(); } if (vpidp) *vpidp = vpid; if (apidp) *apidp = apid; // scan_pf_eit(chan); if (vpid==NOPID && apid == NOPID) return -2; return 0; } int DVB::SetChannel(int chnr, char* apref, uint16_t *apidp, uint16_t *vpidp, bool tune) { if (no_open) return -1; if (chnr>=num[CHAN] || chnr < 0) return -1; if(tune) { get_front(); if (SetTP(chans[chnr].tpid, chans[chnr].satid) < 0) return -1; } stop_apid(); stop_vpid(); stop_ttpid(); stop_pcrpid(); if(tune && (set_front()<0)) return -1; return SetChannel(&chans[chnr], apref, apidp, vpidp); } int DVB::SetChannel(uint16_t sid, uint16_t onid, uint16_t tpid, uint16_t satid) { int chnr; Channel *chan=0; if (no_open) return -1; for (chnr=0; chnrtpid; if (onid==NOID) onid=chan->onid; if (satid==NOID) satid=chan->satid; get_front(); if (SetTP(tpid, satid) < 0) return -1; if (set_front() < 0) return -1; set_vpid(chan->vpid); set_apid(chan->apids[0]); set_ttpid(chan->ttpid); set_pcrpid(chan->pcrpid); return chnr; } int DVB::GetChannel(int chnr, struct channel *) { int i; Channel *chan=0; Transponder *tp=0; Sat *sat=0; Lnb *lnb=0; if (chnr>=num[CHAN]) return -1; chan=&chans[chnr]; tp = find_tp(chan); if (!tp) return -1; sat = find_sat(tp); if (!sat) return -1; for (i=0; ilnbid) { lnb=&lnbs[i]; break; } if (!lnb || no_open) return -1; if (set_front() < 0) return -1; return 0; } int DVB::AddLNB(int id, int t, uint l1, uint l2, uint sl, int dnr, int dis, int sw) { if (num[LNB]>=maxs[LNB]) return -1; for (int i=0; i< num[LNB]; i++){ if (lnbs[i].id == id && lnbs[i].diseqcnr == dnr){ cerr << "Warning: LNB already defined:" << endl; cerr << "ID: " << id << " DISEQCNR: " << dnr << endl; return -1; } } lnbs[num[LNB]].init(t, l1, l2, sl, dnr, dis, sw); lnbs[num[LNB]].id=id; num[LNB]++; return 0; } int DVB::AddTP(Transponder &tp) { if (num[TRANS]>=maxs[TRANS]) return -1; if (tp.id == NOID){ max_tpid++; tp.id = max_tpid; } else if (tp.id > max_tpid) max_tpid = tp.id; for (int i=0; i= 0; i--){ if (chan.tpid == tps[i].id){ chan.satid = tps[i].satid; return; } } } int DVB::AddChannel(Channel &chan) { int i; if (num[CHAN]>=maxs[CHAN]) return -1; if ( chan.satid == NOID) find_satid(chan); for (i=0; i=maxs[SAT]) return -1; if (!sat.id) sat.id=num[SAT]; for (i=0; i MAX_TRANS_CHAN){ cerr << "found too many channels "<< nfound << endl; cerr << "resetting to"<< MAX_TRANS_CHAN << endl; nfound = MAX_TRANS_CHAN; } for(int i=0; i < nfound; i++){ Channel chan; int cn; int anum=0; vpid = NOPID; ttpid= NOPID; if ( show ){ if (!(get_pids(progs[i], &vpid, apids, &ttpid, apids_name) && vpid != NOPID)) continue; } else anum = get_pids(progs[i], &vpid, apids, &ttpid, apids_name); chan.pnr = pnrs[i]; chan.satid = satid; chan.tpid = tpid; chan.vpid = vpid; chan.apidnum = anum; if (anum && anum < MAXAPIDS){ memcpy(chan.apids, apids, anum*sizeof(uint16_t)); memcpy(chan.apids_name, apids_name, anum*sizeof(uint8_t)*4); } chan.checked = 1; chan.ttpid = ttpid; if (show){ if (SetChannel(&chan) < 0) return 0; sleep(2); } if ((cn=AddChannel(chan))==num[CHAN]-1){ chs[n]=cn; n++; if (verbose) cerr << "."; } } if (n > MAX_TRANS_CHAN){ cerr << "counted too many channels "<< n << endl; cerr << "resetting to"<< MAX_TRANS_CHAN << endl; n = MAX_TRANS_CHAN; } if (!show){ int count = 0; int res=0; while ((res=scan_sdts(chs,n))< n && res>0 && count < 2) count++; } if (verbose){ cerr << endl; for (int i=0; i < n; i++){ cerr << "Found " << chans[chs[i]]; } cerr << dec; } return n; } int DVB::search_in_TP(Transponder &tp, int show, int verbose) { if (no_open) return -1; return search_in_TP(tp.id, tp.satid, show, verbose); } ostream &operator<<(ostream &stream, DVB &x) { int i,j,k,l; switch(x.outtype){ default: case LIBDVB_OUT: for (i=0; ivpid == NOPID) continue; if(!strlen(chan->name)) continue; stream << chan->name << ":"; switch (tp->type){ case FE_QPSK: lnb = x.find_lnb(sat); if(!lnb) continue; stream << tp->freq/1000 << ":"; if (tp->pol) stream << "h:"; else stream << "v:"; stream << lnb->diseqcnr << ":" << tp->srate/1000 << ":" << fec_name[tp->fec] << ":"; break; case FE_QAM: stream << tp->freq << ":" << inv_name[tp->inversion] << ":" << tp->srate << ":" << fec_name[tp->fec] << ":" << qam_name[tp->mod] << ":"; break; case FE_OFDM: stream << tp->freq << ":" << inv_name[tp->inversion] << ":" << bw_name[tp->band] << ":" << fec_name[tp->hp_rate] << ":" << fec_name[tp->lp_rate] << ":" << qam_name[tp->mod] << ":" << mode_name[tp->transmode] << ":" << guard_name[tp->guard] << ":" << hierarchy_name[tp->hierarchy] << ":"; break; } stream << chan->vpid << ":" << chan->apids[0] << ":" << chan->pnr << endl; } break; case VDR_OUT: for (i=0; i< x.num[CHAN]; i++){ Channel *chan = &x.chans[i]; Transponder *tp = x.find_tp(chan); Sat *sat = x.find_sat(chan); Lnb *lnb=NULL; if(chan->vpid == NOPID) continue; if(!strlen(chan->name)) continue; stream << chan->name << ":"; switch (tp->type){ case FE_QPSK: lnb = x.find_lnb(sat); if(!lnb) continue; stream << tp->freq/1000 << ":"; if (tp->pol) stream << "h:"; else stream << "v:"; stream << "S" << hex << sat->id/16 << "." << hex << (sat->id & 0x0F) << "E:" << dec << tp->srate/1000 << ":"; break; case FE_QAM: stream << tp->freq/1000000 << ":M" << vdr_qam_name[tp->mod] << ":C:" << tp->srate/1000 << ":"; break; case FE_OFDM: stream << tp->freq << "I" << vdr_inv_name[tp->inversion] << "B" << vdr_bw_name[tp->band] << "C" << vdr_fec_name[tp->hp_rate] << "D" << vdr_fec_name[tp->lp_rate] << "M" << vdr_qam_name[tp->mod] << "T" << vdr_mode_name[tp->transmode] << "G" << vdr_guard_name[tp->guard] << "Y" << vdr_hierarchy_name[tp->hierarchy] << ":T:27500:"; break; } if (chan->pcrpid != chan->vpid) stream << chan->vpid << "+" << chan->pcrpid << ":"; else stream << chan->vpid << ":"; stream << chan->apids[0]; for (l = 1; l < chan->apidnum; l++) stream << "," << chan->apids[l]; if (chan->ac3pid != NOPID) stream << ";" << chan->ac3pid; stream << ":" << chan->ttpid; if(chan->capid != NOPID) stream << ":1"; stream << ":" << chan->pnr << ":0:0:0" << endl; } break; case MYTH_OUT: break; } return stream; } int DVB::check_input_format(istream &ins) { streampos pos = ins.tellg(); int found = 0; char *test_keys[]={ "LNB","TRANSPONDER","CHANNEL","SAT","> keybuf; if ( strncmp(keybuf, test_keys[SATCO_START],7) ) n=findkey(keybuf, test_keys); else n = SATCO_START; switch (n){ case LNB: case TRANS: case CHAN: case SAT: found = 1; f = DVB_ORIG; break; case NOKIA_START: found = 1; f = DVB_NOKIA; break; case XML_START: found = 1; f = DVB_XML; break; case SATCO_START: found = 1; f = DVB_SATCO; break; default: cerr << "Error: " << keybuf << " is not a valid keyword at " << endl; exit(0); } } ins.seekg(pos); return f; } void DVB::read_original(istream &ins) { char *names[] = { "LNB","TRANSPONDER","CHANNEL","SAT", NULL }; cerr << "Reading original format "; while(!ins.eof()){ char keybuf[MAXNAM]; ins.width(MAXNAM); ins >> keybuf; int n=findkey(keybuf, names); if (n<0) { cerr << endl << "Error: " << keybuf << " is not a valid keyword at " << endl; exit(0); } else { if (num[n]< maxs[n]){ switch (n){ case LNB: { Lnb lnb; lnb.name[0]='\0'; ins >> lnb; cerr << "."; AddLNB(lnb.id, lnb.type, lnb.lof1, lnb.lof2, lnb.slof, lnb.diseqcnr, lnb.diseqcid, lnb.swiid); break; } case TRANS: { Transponder tp; ins >> tp; AddTP(tp); break; } case CHAN: { Channel chan; ins >> chan; AddChannel(chan); break; } case SAT: { Sat sat; ins >> sat; AddSat(sat); break; } } } else { cerr << "not enough channels" << endl; break; } } } cerr << " done" << endl; } istream &operator>>(istream &ins, DVB &x) { int format = x.check_input_format(ins); switch(format){ case DVB_ORIG: x.read_original(ins); break; case DVB_NOKIA: { nokiaconv cc(&x); cc.lnb_sat.n = 4; cc.lnb_sat.diseqc[0] = 0; cc.lnb_sat.diseqc[1] = 1; cc.lnb_sat.diseqc[2] = 2; cc.lnb_sat.diseqc[3] = 3; strncpy(cc.lnb_sat.sat_names[0],"Astra",5); cc.lnb_sat.satid[0]=0x0192; strncpy(cc.lnb_sat.sat_names[1],"HotBird",7); cc.lnb_sat.satid[1]=0x0130; strncpy(cc.lnb_sat.sat_names[2],"Sirius",6); cc.lnb_sat.satid[2]=0x0050; cerr << "Reading NOKIA format" << endl; ins >> cc; break; } case DVB_XML: { xmlconv cc(&x); cc.lnb_sat.n = 4; cc.lnb_sat.diseqc[0] = 0; cc.lnb_sat.diseqc[1] = 1; cc.lnb_sat.diseqc[2] = 2; cc.lnb_sat.diseqc[3] = 3; strncpy(cc.lnb_sat.sat_names[0],"Astra",6); cc.lnb_sat.satid[0]=0x0192; strncpy(cc.lnb_sat.sat_names[1],"HotBird",7); cc.lnb_sat.satid[1]=0x0130; strncpy(cc.lnb_sat.sat_names[2],"Sirius",6); cc.lnb_sat.satid[2]=0x0050; cerr << "Reading XML format" << endl; ins >> cc; break; } case DVB_SATCO: { satcoconv cc(&x); cc.nlnb = 0; cc.dvb->front_type = FE_QPSK; ins >> cc; break; } default: cerr << "Unknown format. Can't open dvbrc. Exiting" << endl; exit(1); } return ins; } void hdump(uint8_t *buf, int n) { int i; for (i=0; i>16; if (fdvb >= 0) { osd.FillBlock(x, y, x+w-1-sep, y+h-1, col1); osd.FillBlock(x+w-1-sep, y, 515, y+h-1, col2); } } int DVB::SetFullFilter(uint16_t pid) { char devname[80]; sprintf(devname,DEMUX_DEV,adapter,minor); struct dmx_pes_filter_params pesFilterParams; int fd_section=open(devname, O_RDWR|O_NONBLOCK); if (fd_section < 0) return fd_section; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_TS_TAP; pesFilterParams.pes_type = DMX_PES_OTHER; pesFilterParams.flags = DMX_IMMEDIATE_START; if (pid == NOPID )pesFilterParams.pid = DMX_FULL_TS_PID; else pesFilterParams.pid = pid; if (ioctl(fd_section, DMX_SET_PES_FILTER, &pesFilterParams) < 0) { printf("Could not set PES filter\n"); close(fd_section); return -1; } return fd_section; } uint16_t DVB::SetFilter(uint16_t pid, uint16_t section, uint16_t mode) { struct dmx_sct_filter_params secFilterParams; char devname[80]; sprintf(devname,DEMUX_DEV,adapter,minor); int fd_section=open(devname, O_RDWR|mode); secFilterParams.pid=pid; memset(&secFilterParams.filter.filter, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mask, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mode, 0, DMX_FILTER_SIZE); secFilterParams.timeout = 0; secFilterParams.flags= secflags; secFilterParams.filter.filter[0]=(section>>8)&0xff; secFilterParams.filter.mask[0]=section&0xff; if (ioctl(fd_section, DMX_SET_FILTER, &secFilterParams) < 0) return 0xffff; return fd_section; } int DVB::SetFilter(uint16_t pid, uint8_t *filter, uint8_t *mask, uint32_t timeout, uint32_t flags) { struct dmx_sct_filter_params secFilterParams; char devname[80]; sprintf(devname,DEMUX_DEV,adapter,minor); int fd_section=open(devname, O_RDWR|flags); secFilterParams.pid=pid; memset(&secFilterParams.filter.filter, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mask, 0, DMX_FILTER_SIZE); memset(&secFilterParams.filter.mode, 0, DMX_FILTER_SIZE); secFilterParams.timeout = timeout; secFilterParams.flags= secflags; for (int i = 0; i < DMX_FILTER_SIZE; i++){ secFilterParams.filter.filter[i]=filter[i]; secFilterParams.filter.mask[i]=mask[i]; } if (ioctl(fd_section, DMX_SET_FILTER, &secFilterParams) < 0) return 0xffff; return fd_section; } int DVB::CloseFilter(int h) { if (no_open) return -1; close(h); return 0; } int DVB::GetSection(uint8_t *buf, ushort PID, uint8_t sec, uint8_t secnum, uint8_t &msecnum) { int seclen=0; uint16_t handle, pid; uint8_t section, sectionnum=0xff, maxsec=0; struct pollfd pfd; int loopc = 0; if (no_open) return -1; if ((handle=SetFilter(PID, (sec<<8)|0x00ff, 0))==0xffff) return -1; do { seclen=0; pfd.fd = handle; pfd.events=POLLIN; if (poll(&pfd, 1, 2000)==0) { break; } loopc++; pid = PID; read(handle, buf, MAXSECSIZE); seclen = 0; seclen |= ((buf[1] & 0x0F) << 8); seclen |= (buf[2] & 0xFF); seclen+=3; section=buf[0]; sectionnum=buf[6]; maxsec=buf[7]; } while ( loopc < maxsec*2 && (section != sec || pid != PID || sectionnum != secnum)); msecnum=maxsec; CloseFilter(handle); return seclen; } int DVB::GetSection(uint8_t *buf, uint16_t PID, uint8_t *filter, uint8_t *mask, uint8_t secnum, uint8_t &msecnum) { int seclen=0; uint16_t handle, pid; uint8_t section, sectionnum=0xff, maxsec=0; struct pollfd pfd; int loopc = 0; if (no_open) return -1; if ((handle=SetFilter(PID, filter, mask, 0, 0))==0xffff) return -1; do { seclen=0; pfd.fd=handle; pfd.events=POLLIN; if (poll(&pfd, 1, 20000)==0) break; loopc++; pid = PID; read(handle, buf, MAXSECSIZE); seclen = 0; seclen |= ((buf[1] & 0x0F) << 8); seclen |= (buf[2] & 0xFF); seclen+=3; section=buf[0]; sectionnum=buf[6]; maxsec=buf[7]; } while (loopc < maxsec*2 && ((section&mask[0]!=filter[0]) || pid!=PID || sectionnum!=secnum)); msecnum=maxsec; CloseFilter(handle); return seclen; } int DVB::GetSection(uint8_t *buf, uint16_t PID, uint8_t TID, uint16_t TIDExt, uint16_t FilterTIDExt, uint8_t secnum, uint8_t &msecnum) { uint8_t filter[16], mask[16]; if (no_open) return -1; memset(filter, 0, 16); memset(mask, 0, 16); filter[0]=TID; mask[0]=0xff; if (TIDExt!=0xffff) { filter[1]=(TIDExt>>8); filter[2]=TIDExt&0xff; mask[1]=(FilterTIDExt>>8); mask[2]=FilterTIDExt&0xff; } return GetSection(buf, PID, filter, mask, secnum, msecnum); } void DVB::get_front(void) { if (no_open) return; set_vpid(0); set_apid(0); set_ttpid(0); set_pcrpid(0); voltage = SEC_VOLTAGE_13; tone = SEC_TONE_OFF; } int DVB::check_frontend() { if (weak) return weak_chck_frontend(fd_frontend, &festat); else return chck_frontend(fd_frontend, &festat); } int DVB::tune_it(struct dvb_frontend_parameters *front_param) { int chk=0; weak = inweak; if (no_open) return -1; lastclock = times(&ts); if (ioctl(fd_frontend, FE_SET_FRONTEND, front_param) <0){ perror("setfront front"); return -1; } if (showtime) cerr << "set frontend time: " << double(times(&ts)-lastclock)/ double(sysconf(_SC_CLK_TCK)) << "s" << endl; lastclock = times(&ts); chk=check_frontend(); if (showtime) cerr << "check frontend time: " << double(times(&ts)-lastclock)/ double(sysconf(_SC_CLK_TCK)) << "s" << endl; if (!chk){ weak = 1; chk = check_frontend(); weak = inweak; if (!chk){ cerr << "Tuning failed" << endl; return -1; } } return 0; } int DVB::set_front(void) { if (no_open) return -1; set_vpid(0); set_apid(0); set_pcrpid(0); set_ttpid(0); if (front_type==FE_QPSK) set_diseqc(); usleep(10000); int c=0; int ret=0; while (c<3 && (ret=tune_it(&front_param))<0){ c++; usleep(10000); if (front_type==FE_QPSK) toggle_diseqc(); } return ret; } void DVB::set_diseqc() { ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF); ioctl(fd_frontend, FE_SET_VOLTAGE, voltage); usleep(15000); if(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &dcmd) < 0) perror("set_lnb"); usleep(15000); if(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, burst) < 0) perror("set_lnb"); usleep(15000); if(ioctl(fd_frontend, FE_SET_TONE, tone) < 0) perror("set_lnb"); usleep(15000); } void DVB::toggle_diseqc() { uint8_t old = dcmd.msg[3]; dcmd.msg[3] ^= (old & 0x0C); set_diseqc(); dcmd.msg[3] = old; set_diseqc(); } void DVB::set_diseqc_nb(int nr) { if (no_open) return; dcmd.msg[0]=0xe0; dcmd.msg[1]=0x10; dcmd.msg[2]=0x38; dcmd.msg[3]=0xF0 | ((nr * 4) & 0x0F) | ((tone == SEC_TONE_ON) ? 1 : 0) | ((voltage==SEC_VOLTAGE_18) ? 2 : 0); dcmd.msg[4]=0x00; dcmd.msg[5]=0x00; dcmd.msg_len=4; burst=(nr&1) ? SEC_MINI_B : SEC_MINI_A; } void DVB::set_ttpid(ushort ttpid) { if (no_open) return; if(set_ttpid_fd(ttpid, fd_demuxtt) < 0) { printf("PID=%04x\n", ttpid); perror("set_ttpid"); } } void DVB::stop_ttpid() { stop_pid_fd(fd_demuxtt); } void DVB::set_vpid(ushort vpid) { if (no_open) return; if(set_vpid_fd(vpid, fd_demuxv) < 0) perror("set_vpid"); } void DVB::stop_vpid() { stop_pid_fd(fd_demuxv); } void DVB::set_apid(ushort apid) { if (no_open) return; if(set_apid_fd(apid, fd_demuxa) < 0) perror("set_apid"); } void DVB::stop_apid() { stop_pid_fd(fd_demuxa); } void DVB::set_pcrpid(ushort pcrpid) { if (no_open) return; if(set_pcrpid_fd(pcrpid, fd_demuxpcr) < 0) perror("set_pcrpid"); } void DVB::stop_pcrpid() { stop_pid_fd(fd_demuxpcr); } // Functions enabling the user to set the demuxes independently. int DVB::set_vpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_VIDEO; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_apid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_AUDIO; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_pcrpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_PCR; pesFilterParamsP.flags = secflags; if (dvr_enabled==2) { ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); return 0; } else return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_ttpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = (dvr_enabled==2) ? DMX_PES_OTHER : DMX_PES_TELETEXT; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } int DVB::set_otherpid_fd(ushort pid, int fd) { if (pid == NOPID || !pid) return 0; pesFilterParamsP.pid = pid; pesFilterParamsP.input = DMX_IN_FRONTEND; pesFilterParamsP.output = (dvr_enabled) ? DMX_OUT_TS_TAP : DMX_OUT_DECODER; pesFilterParamsP.pes_type = DMX_PES_OTHER; pesFilterParamsP.flags = secflags; return ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParamsP); } void DVB::stop_pid_fd(int fd) { ioctl(fd, DMX_STOP, 0); } istream &operator>>(istream &ins, nokiaconv &x) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; char dummy; int current_sat = -1; int current_tp = -1; int dint; enum { NSAT=0, NNET, NTRP, NCHAN, NEND}; static char *nokiakeys[]={ ":SAT", ":NET", ":TRP", ":CHN", ":END", NULL }; while(!ins.eof()){ streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, nokiakeys); if (n<0) { ins.seekg(pos); break; } switch(n){ case NSAT: { double did; int id=0; int lnbid = 5; int found = 0; getname(sname,ins); //cerr << "Satellite \"" << sname << "\"" << endl; for(int i=0; i < x.lnb_sat.n; i++){ if (!strcmp(x.lnb_sat.sat_names[i],sname)){ lnbid = x.lnb_sat.diseqc[i]; id = x.lnb_sat.satid[i]; found = 1; break; } } x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); ins >> did; current_sat = x.dvb->AddSat( id, lnbid, sname, 10700000 , 12700000); ins >> dummy; break; } case NNET: getname(sname,ins); //cerr << " Network \"" << sname << "\""<< endl; ins >> dint; break; case NTRP: { Transponder trans; trans.inversion = INVERSION_OFF; ins >> dec >> trans.id; ins >> trans.freq; ins >> trans.srate; ins >> dint; ins >> dummy; if (dummy == 'H') trans.pol = 1; if (dummy == 'V') trans.pol = 0; ins >> dint; trans.satid = x.dvb->sats[current_sat].id; trans.type = FE_QPSK; trans.freq *= 10; trans.srate *= 100; ins >> dint; ins >> dummy; ins >> dint; switch (dint){ case 2: trans.fec = FEC_1_2; break; case 3: trans.fec = FEC_2_3; break; case 4: trans.fec = FEC_3_4; break; case 6: trans.fec = FEC_5_6; break; case 8: trans.fec = FEC_7_8; break; } current_tp = x.dvb->AddTP(trans); //cerr << " Transponder "<< trans.id << endl; break; } case NCHAN: { Channel chan; int cnum; getname(sname,ins); strncpy(chan.name, sname, maxname); ins >> chan.pnr; ins >> dummy; if (dummy == 'T'){ ins.ignore(20, ':'); ins.seekg(ins.tellg()-streampos(1)); chan.satid = x.dvb->sats[current_sat].id; chan.tpid = x.dvb->tps[current_tp].id; cnum = x.dvb->AddChannel(chan); //cerr << " Channel "<< sname // << " (" << cnum << ")" << endl; } else { if (dummy == 'R'){ ins.ignore(20, ':'); ins.seekg(ins.tellg()-streampos(1)); } else { ins.seekg(pos); ins.ignore(80,0x0a); } } break; } case NEND: //cerr << "ALL DONE" << endl; return ins; } } return ins; } #define SATCOLEN 129 istream &operator>>(istream &ins, satcoconv &x) { char satline[SATCOLEN]; char posn[5]; char freqn[10]; char sname[19]; int current_sat = -1; int current_tp = -1; while(!ins.eof()){ Transponder trans; int id=0; int lnbid=0; int found = 0; trans.inversion = INVERSION_OFF; ins.get(satline,SATCOLEN); // get full satco line if (strncmp(satline,"SATCODX103",10)){ if (ins.eof()) return ins; cerr << "Wrong SATCODX format: " << endl; return ins; } if (satline[28]!='T') continue; if (strncmp(satline+29,"MPG2",4) ) continue; strncpy(sname,satline+10,18); sname[18]=0; for(int i=0; i < x.dvb->num[SAT]; i++){ if (!strncmp(x.dvb->sats[i].name, sname,18)){ lnbid = x.dvb->sats[i].lnbid; id = x.dvb->sats[i].id; found = 1; break; } } if (!found){ lnbid = x.nlnb++; x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); strncpy(posn,satline+51,4); posn[4]=0; id = strtol(posn,(char **)NULL,16); current_sat = x.dvb->AddSat( id, lnbid, sname, 10700000 , 12700000); } trans.id = NOID; switch (satline[42]){ case '1': case '3': trans.pol = 1; break; case '0': case '2': trans.pol = 0; } trans.satid = x.dvb->sats[current_sat].id; trans.type = FE_QPSK; strncpy(freqn,satline+33,9); freqn[8]=0; trans.freq = strtol(freqn,(char **)NULL,10)*10; strncpy(freqn,satline+69,5); freqn[5]=0; trans.srate = strtol(freqn,(char **)NULL,10)*1000; switch (satline[74]){ case '0': trans.fec = FEC_AUTO; break; case '1': trans.fec = FEC_1_2; break; case '2': trans.fec = FEC_2_3; break; case '3': trans.fec = FEC_3_4; break; case '5': trans.fec = FEC_5_6; break; case '7': trans.fec = FEC_7_8; break; } found = 0; for(int i=0; i < x.dvb->num[TRANS]; i++){ if (x.dvb->tps[i].freq == trans.freq && x.dvb->tps[i].pol == trans.pol){ current_tp = x.dvb->tps[i].id; found = 1; break; } } if (!found) current_tp = x.dvb->AddTP(trans); Channel chan; int cnum; strncpy(chan.name, satline+43, 8); strncpy(chan.name+8, satline+115, 12); chan.name[20] = 0; strncpy(freqn,satline+88,5); freqn[5]=0; chan.pnr = strtol(freqn,(char **)NULL,10)/10; chan.satid = x.dvb->sats[current_sat].id; chan.tpid = x.dvb->tps[current_tp].id; cnum = x.dvb->AddChannel(chan); } return ins; } static int get_keylen(istream &ins, char *keybuf) { streampos pos = ins.tellg(); int klen = strlen(keybuf); if (klen>2 && keybuf[1]!= '/' && keybuf[0]=='<' && keybuf[klen-1]=='>'){ keybuf[klen-2]='\0'; klen--; ins.seekg(pos-streampos(2)); } return klen; } static int find_xml_key(istream &ins, char *keybuf, char *keys[]) { char *s; int n; streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; int klen = get_keylen(ins, keybuf); s=keybuf; while (s[0] != '=' && s != keybuf+klen)s++; s[0]=0; ins.seekg(pos + streampos((s-keybuf) +1) ); // go past = n=findkey(keybuf, keys); if (n<0) { ins.seekg(pos); cerr << "Unknown tag: " << keybuf << endl; } return n; } int xmlconv::read_sat(istream &ins, int csat) { int n=-1; int lnbid=-1; int satid; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XSATN, XSLNB, XSATID, XTRANS, XSATEND, XEND, XNEND}; static char *xsat[]={ "name", "lnb", "id", "", ">", "/>", NULL }; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xsat)) < 0) break; switch(n){ case XSATN: getname(sname,ins); break; case XSLNB: ins >> satid; break; case XTRANS: if (csat >= 0) read_trans(ins, csat); else return -1; break; case XSATID: ins >> satid; break; case XSATEND: return 0; break; case XEND: if (satid >=0 && lnbid >= 0) csat = dvb->AddSat(satid, lnbid, sname, 10700000 , 12700000); break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_trans(istream &ins, int csat) { int n=-1; int ctp=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XTYPE=0, XFREQ, XSRATE, XPOL, XFEC, XSERV, XTRANSEND, XEND, XNEND }; static char *xtrans[]={ "type", "freq", "srate", "polarity", "fec", "", ">", "/>", NULL }; Transponder trans; trans.satid = dvb->sats[csat].id; trans.fec = FEC_AUTO; trans.id = NOID; trans.inversion = INVERSION_OFF; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xtrans)) < 0) break; switch(n){ case XTYPE: getname(sname,ins); switch(sname[0]){ case 'S': trans.type = FE_QPSK; break; case 'T': trans.type = FE_OFDM; break; case 'C': trans.type = FE_QAM; break; } break; case XFREQ: getname(sname,ins); trans.freq=atoi(sname); break; case XSRATE: getname(sname,ins); trans.srate=atoi(sname); break; case XPOL: getname(sname,ins); if (sname[0] == 'H') trans.pol = 1; if (sname[0] == 'V') trans.pol = 0; break; case XFEC: int dint; getname(sname,ins); dint = atoi(sname); switch (dint){ case 2: trans.fec = FEC_1_2; break; case 3: trans.fec = FEC_2_3; break; case 4: trans.fec = FEC_3_4; break; case 6: trans.fec = FEC_5_6; break; case 8: trans.fec = FEC_7_8; break; } break; case XSERV: if (ctp>=0) read_serv(ins,ctp,csat); break; case XTRANSEND: return 0; break; case XEND: ctp = dvb->AddTP(trans); break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_serv(istream &ins, int ctp, int csat) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XSID=0, XCA, XDESC, XSTREAM, XSERVEND, XEND, XNEND }; static char *xserv[]={ "id", "ca", "", ">", "/>", "sats[csat].id; chan.tpid = dvb->tps[ctp].id; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xserv)) < 0) break; switch(n){ case XSID: getname(sname,ins); chan.pnr = atoi(sname); nchan = dvb->AddChannel(chan); break; case XCA: getname(sname,ins); if (nchan >= 0) dvb->chans[nchan].type = atoi(sname); else chan.type = atoi(sname); break; case XDESC: if (nchan>=0) read_desc(ins, nchan); else return -1; break; case XSTREAM: if (nchan>=0) read_stream(ins,nchan); else return -1; break; case XSERVEND: return 0; break; case XEND: break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_desc(istream &ins, int nchan) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XTAG=0, XTYPE, XPROV, XSNAME, XDESCEND, XEND, XNEND}; static char *xdesc[]={ "tag", "type", "provider_name", "service_name", "", ">", "/>", NULL }; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xdesc)) < 0) break; switch(n){ case XTAG: getname(sname,ins); break; case XTYPE: getname(sname,ins); break; case XPROV: getname(sname,ins); break; case XSNAME: getname(sname,ins); dvb2txt(dvb->chans[nchan].name,sname,MAXNAM); break; case XDESCEND: return 0; break; case XEND: break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_stream(istream &ins, int nchan) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; int type = -1; int apids = 0; uint16_t pid = NOPID; enum { XTYPE, XPID, XISO, XSTREAMEND, XEND, XNEND }; static char *xstream[]={ "type", "pid", "", ">", "/>", "chans[nchan].vpid = pid; break; case 3: case 4: if (pid == NOPID) break; apids = dvb->chans[nchan].apidnum; if (apids >= MAXAPIDS) break; dvb->chans[nchan].apidnum++; dvb->chans[nchan].apids[apids]=pid; break; case 6: if (pid != NOPID) dvb->chans[nchan].ttpid = pid; break; } break; case XSTREAMEND: return 0; break; case XEND: break; case XNEND: return 0; break; case XISO: read_iso639(ins, nchan, apids); break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::read_iso639(istream &ins, int nchan, int apids) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; enum { XTYPE, XLAN,XISOEND, XEND, XNEND }; static char *xiso[]={ "type", "language", "", ">", "/>", NULL }; while(!ins.eof()){ if ( (n = find_xml_key( ins, keybuf, xiso)) < 0) break; switch(n){ case XTYPE: getname(sname,ins); break; case XLAN: getname(sname,ins); strncpy(dvb->chans[nchan].apids_name+apids*4, sname, 4); break; case XISOEND: return 0; break; case XEND: break; case XNEND: return 0; break; default: skip_tag(ins,keybuf); break; } } return 0; } int xmlconv::skip_tag(istream &ins, char *tag) { char sname[MAXNAM*2]; char endtag[MAXNAM]; int found = 0; streampos pos = ins.tellg(); ostringstream etag; etag << "" << ends; strncpy(endtag, etag.str().data(),MAXNAM); int tlen = strlen(endtag)-1; // cerr << "find: " << endtag << endl; ins.width(2*MAXNAM); ins >> sname; if (sname[0] == '>') while(!found){ if (!strncmp(sname,endtag,tlen)) found=1; else ins >> sname; } else { ins.seekg(pos); ins.ignore(1000,'>'); pos = ins.tellg(); ins.seekg(pos-streampos(2)); ins >> sname; if (sname[0] == '/') ins.seekg(pos); else while(!found){ if (!strncmp(sname,endtag,tlen)) found=1; else ins >> sname; } } return 0; } istream &operator>>(istream &ins, xmlconv &x) { int n=-1; char keybuf[MAXNAM]; char sname[MAXNAM]; int current_sat = -1; int nsat = 0; enum { XMLSTART=0, XSAT, XNSAT, XLNB, XEND, XNEND}; static char *xmltags[]={ "", "", "/>", NULL}; while(!ins.eof()){ streampos pos = ins.tellg(); ins.width(MAXNAM); ins >> keybuf; n=findkey(keybuf, xmltags); if (n<0) { ins.seekg(pos); cerr << "Unknown tag: " << keybuf << endl; break; } switch(n){ case XMLSTART: cerr << "xml start found" << endl; ins.ignore(80,'>'); break; case XNSAT: { int clnb; int lnbid = 5; int satid = -1; if (nsat > XML_MAX_SAT) break; strncpy(sname,x.lnb_sat.sat_names[nsat],MAXNAM); lnbid = x.lnb_sat.diseqc[nsat]; clnb = x.dvb->AddLNB(lnbid, 1, 9750000, 10600000, 11700000, lnbid, NOID, NOID); satid = x.lnb_sat.satid[nsat]; current_sat = x.dvb->AddSat(satid, lnbid, sname, 10700000 , 12700000); nsat++; x.read_sat(ins, current_sat); break; } case XSAT: { cerr << "no sat name" << endl; x.read_sat(ins, -1); break; } case XLNB: break; default: x.skip_tag(ins,keybuf); break; } } return ins; } int get_dvbrc(char *path, DVB &dv, int dev, int len) { ifstream dvbin; dvbin.open(path); if (!dvbin){ const char *home = getenv("HOME"); const char *file = ".dvbrc"; ostringstream str; str << home << "/" << file ; if (dev) str << "." << dev ; str << ends; strncpy(path,str.str().data(),len); cerr << "Using default "<< path << endl; dvbin.clear(); dvbin.open(path); } if (dvbin) { cerr << endl; dvbin >> dv; return 1; } else { cerr << " failed" << endl; ostringstream str; str << "/etc/dvb/dvbrc" << ends; strncpy(path,str.str().data(),len); cerr << "Using default "<< path << endl; dvbin.clear(); dvbin.open(path); if (dvbin) { cerr << endl; dvbin >> dv; return 1; } else cerr << " failed" << endl; } return 0; } int set_dvbrc(char *path, DVB &dv, int dev, int len) { ofstream dvbout; dvbout.open(path); if (!dvbout){ cerr << "Using default dvbrc." << endl; const char *home = getenv("HOME"); const char *file = ".dvbrc"; ostringstream str; str << home << "/" << file ; if (dev) str << "." << dev ; str << ends; strncpy(path, str.str().data(),len); dvbout.clear(); dvbout.open(path); } if (dvbout) { dvbout << dv; return 1; } return 0; } #define SFREQ 11700000 #define LHI 10600000 #define LLO 9750000 #define IPACKS 2048 void set_diseqc(int fdf, int snum, fe_sec_voltage_t v, fe_sec_tone_mode_t t) { struct dvb_diseqc_master_cmd dcmd; fe_sec_mini_cmd_t b; int hi_lo; int pol; if (snum >= 0) fprintf(stderr,"Setting diseqc %d \n",snum); hi_lo = (t == SEC_TONE_ON) ? 1 : 0; pol = (v==SEC_VOLTAGE_18) ? 2:0; dcmd.msg[0]=0xe0; dcmd.msg[1]=0x10; dcmd.msg[2]=0x38; dcmd.msg[3] = 0xf0 | (((snum* 4) & 0x0f) | hi_lo | pol); dcmd.msg[4]=0x00; dcmd.msg[5]=0x00; dcmd.msg_len=4; b = (snum &1) ? SEC_MINI_B : SEC_MINI_A; if (snum >= 0) ioctl(fdf, FE_SET_TONE, SEC_TONE_OFF); ioctl(fdf, FE_SET_VOLTAGE, v); if (snum >= 0) { usleep(15 * 1000); ioctl(fdf, FE_DISEQC_SEND_MASTER_CMD, &dcmd); usleep(15 * 1000); ioctl(fdf, FE_DISEQC_SEND_BURST, b); usleep(15 * 1000); } ioctl(fdf, FE_SET_TONE, t); } int tune(int fdf, uint32_t freq, uint32_t sr, fe_code_rate_t fec, fe_spectral_inversion_t inv=INVERSION_OFF) { struct dvb_frontend_parameters tune; tune.frequency = freq; tune.inversion = inv; tune.u.qpsk.symbol_rate = sr; if (!fec) tune.u.qpsk.fec_inner = FEC_AUTO; else tune.u.qpsk.fec_inner = fec; if (ioctl(fdf, FE_SET_FRONTEND, &tune) == -1) { perror("FE_SET_FRONTEND failed"); return -1; } return 0; } int set_sfront(int fdf, uint32_t freq, uint32_t pol, uint32_t sr , int snum, fe_code_rate_t fec) { fe_sec_voltage_t v; fe_sec_tone_mode_t t; uint32_t f; fprintf(stderr,"%d %d %d %d %d\n",freq,pol,sr,snum,fec); if (freq >= SFREQ){ f = freq - LHI; t = SEC_TONE_ON; } else { f = freq - LLO; t = SEC_TONE_OFF; } v = pol ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13; set_diseqc(fdf, snum, v, t); return tune(fdf, f, sr, fec); } void set_pes_filt(int fd,uint16_t pes_pid) { struct dmx_pes_filter_params pesFilterParams; pesFilterParams.pid = pes_pid; pesFilterParams.input = DMX_IN_FRONTEND; pesFilterParams.output = DMX_OUT_TS_TAP; pesFilterParams.pes_type = DMX_PES_OTHER; pesFilterParams.flags = secflags; if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) perror("DMX SET PES FILTER:"); } void DVB::AddECM(Channel *chan, uint8_t *data, int length) { int i; ecm_t *ecm = &chan->ecm; uint16_t sysid = chan->casystem; uint16_t pid = chan->capid; if (ecm->num>=MAX_ECM) return; for (i=0; i< ecm->num; i++) if ((ecm->sysid[i]==sysid) && (ecm->pid[i]==pid)) return ; ecm->sysid[ecm->num]=sysid; ecm->pid[ecm->num]=pid; if (length <= MAX_ECM_DESC){ ecm->length[ecm->num] = (uint16_t)length; memcpy((char *)(ecm->data)+(ecm->num*MAX_ECM_DESC), (char *)data, length); } ecm->num++; } int DVB::check_ecm(Channel *chan) { int found = 0; uint16_t prog_pid = 0; uint8_t buf[MAXSECSIZE], msec=0, sec=0; if (no_open) return -1; time_t count = time(0)+10; while (sec<=msec && !found && count > time(0)) { if (GetSection(buf, 0, 0, sec, msec)>0 && !buf[0]){ sec++; found = parse_pat(chan,buf); } } if (!found) return -1; prog_pid = found; sec = 0; msec = 0; while (sec<=msec && count > time(0)) { if (GetSection(buf,prog_pid, 2, sec, msec)>0){ sec++; parse_pmt(chan, buf); if(count < time(0)) break; } } return 0; } struct in_addr getaddress (const char *name) { struct in_addr in; struct hostent *hp = gethostbyname (name); //fprintf(stderr,"Looking up host %s\n", name); if (hp) memcpy (&in.s_addr, hp->h_addr_list[0], sizeof (in.s_addr)); else { fprintf(stderr, "couldn't find address of %s\n", name); exit (1); } return in; } int tcp_client_connect(const char *hostname, int sckt) { int sock; struct sockaddr_in name; int dummy=-1; name.sin_family = AF_INET; name.sin_port = htons (sckt); name.sin_addr = getaddress(hostname); do { if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1){ perror("socket"); exit(1); } //fprintf(stderr,"Trying to connect...\n"); if((dummy = connect(sock, (struct sockaddr *)&name, sizeof(name))) == ECONNREFUSED){ perror("connect"); exit(1); } if(dummy){ sleep(1); close(sock); } } while(dummy); // fprintf(stderr,"Connection established.\n"); return sock; } int udp_client_connect(const char *filename) { int sock; struct sockaddr_un name; int dummy=-1; name.sun_family = AF_UNIX; snprintf(name.sun_path, 108, "%s", filename); do { if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1){ perror("socket"); exit(1); } fprintf(stderr,"Trying to connect...\n"); if((dummy = connect(sock, (struct sockaddr *)&name, sizeof(name))) == ECONNREFUSED){ perror("connect"); exit(1); } if(dummy){ sleep(1); close(sock); } } while(dummy); fprintf(stderr,"Connection established.\n"); return sock; } void client_send_msg(int fd, uint8_t *msg, int size) { int sent = send(fd,msg,size,0); if(sent == -1) { perror("send"); exit(1); } // fprintf(stderr,"%d bytes sent.\n",sent); } int weak_chck_frontend (int fefd, frontend_stat *festat) { fe_status_t status; int i; for (i = 0; i < 10; i++) { usleep (300000); if (ioctl(fefd, FE_READ_STATUS, &status) == -1) { perror("FE_READ_STATUS failed"); return 0; } if (status & FE_HAS_LOCK) return 1; } return 0; } int chck_frontend (int fefd, frontend_stat *festat) { fe_status_t status; uint16_t snr, strength; uint32_t ber, u_blocks; struct dvb_frontend_event event; struct pollfd pfd[1]; int sta; usleep(500000); pfd[0].fd = fefd; pfd[0].events = POLLIN; event.status = (fe_status_t) 0; while (((event.status & FE_TIMEDOUT)==0) && ((event.status & FE_HAS_LOCK)==0)) { if (poll(pfd,1,2000)){ if (pfd[0].revents & POLLIN){ if ((sta = ioctl(fefd, FE_GET_EVENT, &event)) < 0){ if (errno != EOVERFLOW) { perror("FE_GET_EVENT"); return 0; } } } } } if (event.status & FE_HAS_LOCK){ ioctl(fefd, FE_READ_STATUS, &status); ioctl(fefd, FE_READ_SNR, &snr); ioctl(fefd, FE_READ_SIGNAL_STRENGTH, &strength); ioctl(fefd, FE_READ_BER, &ber); ioctl(fefd, FE_READ_UNCORRECTED_BLOCKS, &u_blocks); } else return 0; // fprintf (stderr, "status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ", // status, strength, snr, ber, u_blocks); festat->status = status; festat->snr = snr; festat->strength = strength; festat->ber = ber; festat->u_blocks = u_blocks; if (status & FE_HAS_LOCK) return 1; return 0; } #define PAT_SCAN 0x01 #define PMT_SCAN 0x02 #define SDT_SCAN 0x04 #define EIT_SCAN 0x08 #define SCANNING 0x20 #define SET_AGAIN 0x40 #define SCAN_DONE 0x80 #define MAX_PIDS 100 int DVB::scan_tp(uint16_t tpid, uint16_t satid, int timeout, int verbose) { int seclen=0; uint8_t section, sectionnum=0xff; uint8_t buf[MAXSECSIZE]; struct pollfd pfd[MAX_PIDS]; uint16_t pids[MAX_PIDS]; uint16_t pnr[MAX_PIDS]; uint8_t pid_state[MAX_PIDS]; int filter_fds[MAX_PIDS]; uint8_t sec[MAX_PIDS]; uint8_t secn[MAX_PIDS]; uint8_t maxsec[MAX_PIDS]; time_t timeo[MAX_PIDS]; int active = 0; int pidf = 0; uint16_t tsid; int oldcf=0; int eitn=0; if (timeout < 0) timeout = 5000; for (int i=0; i< num[CHAN]; i++) if (chans[i].tpid == tpid && chans[i].satid == satid) oldcf++; memset(pids, 0, MAX_PIDS*sizeof(uint16_t)); memset(sec, 0, MAX_PIDS*sizeof(uint8_t)); memset(secn, 0, MAX_PIDS*sizeof(uint8_t)); memset(maxsec, 0, MAX_PIDS*sizeof(uint8_t)); memset(pid_state, 0, MAX_PIDS*sizeof(uint8_t)); memset(filter_fds, -1, MAX_PIDS*sizeof(int)); for (int i=0; i= maxsec[i]){ active--; if (verbose){ if (pid_state[i] & PAT_SCAN) cerr << " Stop PAT timeout" << endl; if (pid_state[i] & SDT_SCAN) cerr << " Stop SDT timeout" << endl; if (pid_state[i] & EIT_SCAN) cerr << " Stop EIT timeout" << endl; if (pid_state[i] & PMT_SCAN) cerr << " Stop PMT 0x" << pids[i] << " timeout" << endl; } pid_state[i] = SCAN_DONE; } } if (np && (pid_state[i] & SCANNING) && (pfd[i].events & POLLIN)){ seclen=0; if (read(filter_fds[i], buf, MAXSECSIZE) < 3) continue; seclen |= ((buf[1] & 0x03) << 8); seclen |= (buf[2] & 0xFF); seclen += 3; section = buf[0]; sectionnum = buf[6]; if (secn[i] != sectionnum) continue; maxsec[i] = buf[7]; secn[i]++; switch(pid_state[i] & 0x0F){ case PAT_SCAN: { int c = 8; seclen -= 12; while (seclen>0){ uint16_t npid= (buf[c] << 8)|buf[c+1]; if (npid){ pnr[pidf] = npid; pid_state[pidf] |= SET_AGAIN; pids[pidf] = get_pid(buf+c+2); pid_state[pidf] |= PMT_SCAN; sec[pidf] = 0x02; pidf++; } seclen -= 4; c += 4; } if (secn[i] > maxsec[i]){ pids[pidf] = 0x12; sec[pidf] = 0x4e; pid_state[pidf] |= (EIT_SCAN | SET_AGAIN); pidf++; } break; } case PMT_SCAN: { Channel chan; if (buf[0]!=0x02) break; chan.pnr = pnr[i]; chan.satid = satid; chan.tpid = tpid; int j = AddChannel(chan); parse_pmt(&chans[j], buf); break; } case SDT_SCAN: { Channel *schan; int c = 11; uint16_t ilen=0; tsid = (buf[3]<<8)|buf[4+1]; for (int t=0; t< num[TRANS]; t++){ if (tps[t].id == tpid && tps[t].satid == satid){ tps[t].tsid = tsid; } } while (c < seclen-4){ uint16_t npnr; npnr = (buf[c]<<8)|buf[c+1]; if(npnr){ Channel chan; int found=0; chan.satid = satid; chan.tpid = tpid; chan.pnr = npnr; schan = &chan; for (int j = 0; j has_eit = -1; schan->pres_follow = -1; if (buf[c+2] & 0x02) schan->has_eit = 0; if (buf[c+2] & 0x01) schan->pres_follow = 0; c+=3; schan->type=(buf[c]&0x10)>>4; ilen=((buf[c]&0x0f)<<8)|buf[c+1]; c+=2; c+=parse_descriptor(schan, &buf[c], ilen,(verbose>1 ? 0:0)); if (!found && strlen(schan->name)) AddChannel(chan); } } break; } case EIT_SCAN: { int c = 14; uint16_t ilen=0; //show_buf(buf, seclen); while (c < seclen-4){ c += 10; ilen=((buf[c]&0x0f)<<8) |buf[c+1]; c+=2; c+=parse_descriptor(NULL, &buf[c], ilen,(verbose>1 ? 1:0)); } break; } default: break; } if (secn[i] > maxsec[i]){ pfd[i].events = 0; close (filter_fds[i]); active--; if (verbose>1){ if (pid_state[i] & PAT_SCAN) cerr << " Stop PAT" << endl; if (pid_state[i] & SDT_SCAN) cerr << " Stop SDT" << endl; if (pid_state[i] & EIT_SCAN) cerr << " Stop EIT" << endl; if (pid_state[i] & PMT_SCAN) cerr << " Stop PMT 0x" << pids[i] << endl; } pid_state[i] = SCAN_DONE; } } if (pidf>=MAX_PIDS){ cerr << "MAX_PIDS too small" << endl; exit(1); } if (pid_state[i] & SET_AGAIN){ if ((filter_fds[i] = SetFilter(pids[i], (sec[i]<<8)|0x00ff,O_NONBLOCK))==0xffff){ pid_state[i] |= SET_AGAIN; } else { if (verbose>1){ if (pid_state[i] & PAT_SCAN) cerr << " Start PAT scan 0x"; if (pid_state[i] & SDT_SCAN) cerr << " Start SDT scan 0x"; if (pid_state[i] & EIT_SCAN) cerr << " Start EIT scan 0x"; if (pid_state[i] & PMT_SCAN) cerr << " Start PMT scan 0x"; cerr << hex << pids[i] << endl; } active++; pfd[i].fd = filter_fds[i]; pfd[i].events = POLLIN; pid_state[i] &= ~SET_AGAIN; pid_state[i] |= SCANNING; timeo[i] = time(0)+4; if (eitn < 3){ eitn++; pids[pidf] = 0x12; sec[pidf] = 0x4e; pid_state[pidf] |= (EIT_SCAN | SET_AGAIN); pidf++; } } } } } int cf=0; for (int i=0; i< num[CHAN]; i++){ if (chans[i].tpid == tpid && chans[i].satid == satid){ cf++; /* int c = 0; if (chans[i].pnr) if (chans[i].vpid == NOPID) while (chans[i].apidnum == 0 && c<10) { check_pids(&chans[i]); c++; } */ if (verbose) cerr << chans[i]; } } for (int i=0; i1){ cerr << " Start EIT scan 0x"; cerr << hex << pid << endl; } pfd.fd = filter_fd; pfd.events = POLLIN; timeo = time(0)+4; } int np=0; while(!done){ if (!(np = poll(&pfd, 1, timeout))){ cerr << "TIMEOUT" << endl; break; } if (timeo < time(0)){ secn++; if (secn >= maxsec){ done=1; if (verbose){ cerr << " Stop EIT timeout" << endl; } } } if (np && (pfd.events & POLLIN)){ seclen=0; cerr << "found section" << endl; if (read(filter_fd, buf, MAXSECSIZE) < 3) continue; seclen |= ((buf[1] & 0x03) << 8); seclen |= (buf[2] & 0xFF); seclen += 3; section = buf[0]; sectionnum = buf[6]; if (secn != sectionnum) continue; maxsec = buf[7]; secn++; int c = 14; uint16_t ilen=0; //show_buf(buf, seclen); while (c < seclen-4){ c += 10; ilen=((buf[c]&0x0f)<<8) |buf[c+1]; c+=2; c+=parse_descriptor(NULL, &buf[c], ilen, verbose); } if (secn > maxsec){ pfd.events = 0; close (filter_fd); done=1; if (verbose>1){ cerr << " Stop EIT" << endl; } } } } } int DVB::scan_TP(uint16_t tpid, uint16_t satid, int timeout, int verbose) { if (no_open) return -1; if (verbose){ cerr << "Setting Transponder 0x" << HEX(4) << tpid << " "; for (int i = 0; i < num[TRANS]; i++){ if (tps[i].id == tpid){ cerr << dec << tps[i].freq/1000 << (tps[i].pol ? "H":"V") << " " << tps[i].srate/1000 << endl; break; } } } get_front(); if (SetTP(tpid, satid) < 0) return -1; if (set_front() < 0) return -1; if (verbose) cerr << endl << "Starting transponder scan" << endl; return scan_tp(tpid, satid, timeout, verbose); } int DVB::scan_current(int timeout, int verbose) { return scan_tp(1000, 1000, timeout, verbose); } uint8_t hamtab[256] = { 0x01, 0xff, 0x81, 0x01, 0xff, 0x00, 0x01, 0xff, 0xff, 0x02, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x07, 0xff, 0x00, 0x01, 0xff, 0x00, 0x80, 0xff, 0x00, 0x06, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x03, 0xff, 0xff, 0x0c, 0x01, 0xff, 0x04, 0xff, 0xff, 0x07, 0x06, 0xff, 0xff, 0x07, 0xff, 0x07, 0x07, 0x87, 0x06, 0xff, 0xff, 0x05, 0xff, 0x00, 0x0d, 0xff, 0x86, 0x06, 0x06, 0xff, 0x06, 0xff, 0xff, 0x07, 0xff, 0x02, 0x01, 0xff, 0x04, 0xff, 0xff, 0x09, 0x02, 0x82, 0xff, 0x02, 0xff, 0x02, 0x03, 0xff, 0x08, 0xff, 0xff, 0x05, 0xff, 0x00, 0x03, 0xff, 0xff, 0x02, 0x03, 0xff, 0x03, 0xff, 0x83, 0x03, 0x04, 0xff, 0xff, 0x05, 0x84, 0x04, 0x04, 0xff, 0xff, 0x02, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x07, 0xff, 0x05, 0x05, 0x85, 0x04, 0xff, 0xff, 0x05, 0x06, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x03, 0xff, 0xff, 0x0c, 0x01, 0xff, 0x0a, 0xff, 0xff, 0x09, 0x0a, 0xff, 0xff, 0x0b, 0x8a, 0x0a, 0x0a, 0xff, 0x08, 0xff, 0xff, 0x0b, 0xff, 0x00, 0x0d, 0xff, 0xff, 0x0b, 0x0b, 0x8b, 0x0a, 0xff, 0xff, 0x0b, 0x0c, 0x8c, 0xff, 0x0c, 0xff, 0x0c, 0x0d, 0xff, 0xff, 0x0c, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x07, 0xff, 0x0c, 0x0d, 0xff, 0x0d, 0xff, 0x8d, 0x0d, 0x06, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x0d, 0xff, 0x08, 0xff, 0xff, 0x09, 0xff, 0x09, 0x09, 0x89, 0xff, 0x02, 0x0f, 0xff, 0x0a, 0xff, 0xff, 0x09, 0x88, 0x08, 0x08, 0xff, 0x08, 0xff, 0xff, 0x09, 0x08, 0xff, 0xff, 0x0b, 0xff, 0x0e, 0x03, 0xff, 0xff, 0x0c, 0x0f, 0xff, 0x04, 0xff, 0xff, 0x09, 0x0f, 0xff, 0x8f, 0x0f, 0xff, 0x0e, 0x0f, 0xff, 0x08, 0xff, 0xff, 0x05, 0xff, 0x0e, 0x0d, 0xff, 0xff, 0x0e, 0x0f, 0xff, 0x0e, 0x8e, 0xff, 0x0e, }; uint8_t invtab[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, }; uint8_t deham(uint8_t x, uint8_t y) { return (hamtab[y]<<4)|(0x0f&hamtab[x]); } static int create_dir(const char *path) { int retval; char *bufp, *new_path; struct stat sb; retval=0; if(path && *path) { new_path = strdup(path); for(bufp = new_path+1; *bufp; ++bufp) { if(*bufp == '/') { *bufp = 0; if(stat(new_path,&sb)<0) { retval = mkdir(new_path, 0755); } *bufp = '/'; } } free(new_path); } return retval; } void DVB::add_vtx_line(magazin_t *mag, int line, uint8_t *data, int pnr) { uint8_t c=0; FILE *fd; char fname[1024]; uint8_t buf; if(!line) { mag->valid = 1; memset(mag->pagebuf, ' ', 25*40); mag->pnum = deham(data[0], data[1]); if(mag->pnum == 0xff) return; mag->flags = deham(data[2],data[3])&0x80; mag->flags |= (c&0x40)|((c>>2)&0x20); c = deham(data[6],data[7]); mag->flags |= ((c<<4)&0x10)|((c<<2)&0x08)|(c&0x04) |((c>>1)&0x02)|((c>>4)&0x01); mag->lang = ((c>>5) & 0x07); mag->sub = (deham(data[4],data[5])<<8)| (deham(data[2],data[3])&0x3f7f); } if(mag->valid) { if (line <= 23) memcpy(mag->pagebuf+40*line,data,40); if (line==23) { int pagenumber=(mag->magn*100) + ((mag->pnum>>4)*10) + (mag->pnum & 0x0f); snprintf(fname,1024,"%s/%d_%d_%c_%d/",vtxdir, transponder_freq, transponder_srate, transponder_pol, pnr); create_dir(fname); snprintf(fname,1024,"%s/%d_%d_%c_%d/%d_%d.vtx",vtxdir, transponder_freq, transponder_srate, transponder_pol, pnr,pagenumber, mag->sub&0xff); if ((fd=fopen(fname,"w"))) { fwrite("VTXV4",1,5,fd); buf = 0x01; fwrite(&buf,1,1,fd); buf = mag->magn; fwrite(&buf,1,1,fd); buf = mag->pnum; fwrite(&buf,1,1,fd); buf = 0x00; fwrite(&buf,1,1,fd); fwrite(&buf,1,1,fd); fwrite(&buf,1,1,fd); fwrite(&buf,1,1,fd); fwrite(mag->pagebuf,1,24*40,fd); fclose(fd); } mag->valid=0; } } } libdvb-0.5.5.1/libdvbci/0000755000175000017500000000000010220016115014574 5ustar mocmmocm00000000000000libdvb-0.5.5.1/libdvbci/Makefile0000644000175000017500000000053210220016115016234 0ustar mocmmocm00000000000000 include ../config.mk CI_OBJS=ci.o ci2.o LIBS=-L./ -lpthread DVB_LIBS=libdvbci.a main: $(DVB_LIBS) libdvbci.a: $(CI_OBJS) ar -rcs libdvbci.a $(CI_OBJS) ci.o: ci.cc ../include/ci.hh $(CXX) $(INCLUDES) $(CFLAGS) -c $< .c.o: $(CC) $(INCLUDES) $(CFLAGS) -c $< .cc.o: $(CXX) $(INCLUDES) $(CFLAGS) -c $< clean: -rm -f *.o $(DVB_LIBS) *~ libdvb-0.5.5.1/libdvbci/ci.cc0000644000175000017500000014100710220016115015501 0ustar mocmmocm00000000000000/* * ci.cc: Common Interface * * Copyright (C) 2000 Klaus Schmidinger * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at kls@cadsoft.de * * The project's page is at http://www.cadsoft.de/people/kls/vdr * */ /* XXX TODO - update CA descriptors in case they change XXX*/ #include "ci.hh" #include #include #include #include #include #include #include #include #include #include #include // Application Object Tags: #define AOT_NONE 0x000000 #define AOT_PROFILE_ENQ 0x9F8010 #define AOT_PROFILE 0x9F8011 #define AOT_PROFILE_CHANGE 0x9F8012 #define AOT_APPLICATION_INFO_ENQ 0x9F8020 #define AOT_APPLICATION_INFO 0x9F8021 #define AOT_ENTER_MENU 0x9F8022 #define AOT_CA_INFO_ENQ 0x9F8030 #define AOT_CA_INFO 0x9F8031 #define AOT_CA_PMT 0x9F8032 #define AOT_CA_PMT_REPLY 0x9F8033 #define AOT_TUNE 0x9F8400 #define AOT_REPLACE 0x9F8401 #define AOT_CLEAR_REPLACE 0x9F8402 #define AOT_ASK_RELEASE 0x9F8403 #define AOT_DATE_TIME_ENQ 0x9F8440 #define AOT_DATE_TIME 0x9F8441 #define AOT_CLOSE_MMI 0x9F8800 #define AOT_DISPLAY_CONTROL 0x9F8801 #define AOT_DISPLAY_REPLY 0x9F8802 #define AOT_TEXT_LAST 0x9F8803 #define AOT_TEXT_MORE 0x9F8804 #define AOT_KEYPAD_CONTROL 0x9F8805 #define AOT_KEYPRESS 0x9F8806 #define AOT_ENQ 0x9F8807 #define AOT_ANSW 0x9F8808 #define AOT_MENU_LAST 0x9F8809 #define AOT_MENU_MORE 0x9F880A #define AOT_MENU_ANSW 0x9F880B #define AOT_LIST_LAST 0x9F880C #define AOT_LIST_MORE 0x9F880D #define AOT_SUBTITLE_SEGMENT_LAST 0x9F880E #define AOT_SUBTITLE_SEGMENT_MORE 0x9F880F #define AOT_DISPLAY_MESSAGE 0x9F8810 #define AOT_SCENE_END_MARK 0x9F8811 #define AOT_SCENE_DONE 0x9F8812 #define AOT_SCENE_CONTROL 0x9F8813 #define AOT_SUBTITLE_DOWNLOAD_LAST 0x9F8814 #define AOT_SUBTITLE_DOWNLOAD_MORE 0x9F8815 #define AOT_FLUSH_DOWNLOAD 0x9F8816 #define AOT_DOWNLOAD_REPLY 0x9F8817 #define AOT_COMMS_CMD 0x9F8C00 #define AOT_CONNECTION_DESCRIPTOR 0x9F8C01 #define AOT_COMMS_REPLY 0x9F8C02 #define AOT_COMMS_SEND_LAST 0x9F8C03 #define AOT_COMMS_SEND_MORE 0x9F8C04 #define AOT_COMMS_RCV_LAST 0x9F8C05 #define AOT_COMMS_RCV_MORE 0x9F8C06 #ifndef MALLOC #define MALLOC(type, size) (type *)malloc(sizeof(type) * (size)) #endif #ifndef esyslog static int SysLogLevel = 3; #define esyslog(a...) void( (SysLogLevel > 0) ? void(fprintf(stderr, a)), void(fprintf(stderr, "\n")) : void() ) #define isyslog(a...) void( (SysLogLevel > 1) ? void(fprintf(stderr, a)), void(fprintf(stderr, "\n")) : void() ) #define dsyslog(a...) void( (SysLogLevel > 2) ? void(fprintf(stderr, a)), void(fprintf(stderr, "\n")) : void() ) #define LOG_ERROR esyslog("ERROR (%s,%d): %m", __FILE__, __LINE__) #define LOG_ERROR_STR(s) esyslog("ERROR: %s: %m", s) #endif // Set these to 'true' for debug output: static bool DumpTPDUDataTransfer = false; static bool DebugProtocol = false; static bool _connected = false; #define dbgprotocol(a...) if (DebugProtocol) fprintf(stderr, a) #define OK 0 #define TIMEOUT -1 #define ERROR -2 // --- Workarounds ----------------------------------------------------------- // The Irdeto AllCAM 4.7 (and maybe others, too) does not react on AOT_ENTER_MENU // during the first few seconds of a newly established connection #define WRKRND_TIME_BEFORE_ENTER_MENU 15 // seconds // --- Helper functions ------------------------------------------------------ #define SIZE_INDICATOR 0x80 ssize_t safe_read(int filedes, void *buffer, size_t size) { for (;;) { ssize_t p = read(filedes, buffer, size); if (p < 0 && errno == EINTR) { dsyslog("EINTR while reading from file handle %d - retrying", filedes); continue; } return p; } } static const uint8_t *GetLength(const uint8_t *Data, int &Length) ///< Gets the length field from the beginning of Data. ///< \return Returns a pointer to the first byte after the length and ///< stores the length value in Length. { Length = *Data++; if ((Length & SIZE_INDICATOR) != 0) { int l = Length & ~SIZE_INDICATOR; Length = 0; for (int i = 0; i < l; i++) Length = (Length << 8) | *Data++; } return Data; } static uint8_t *SetLength(uint8_t *Data, int Length) ///< Sets the length field at the beginning of Data. ///< \return Returns a pointer to the first byte after the length. { uint8_t *p = Data; if (Length < 128) *p++ = Length; else { int n = sizeof(Length); for (int i = n - 1; i >= 0; i--) { int b = (Length >> (8 * i)) & 0xFF; if (p != Data || b) *++p = b; } *Data = (p - Data) | SIZE_INDICATOR; p++; } return p; } static char *CopyString(int Length, const uint8_t *Data) ///< Copies the string at Data. ///< \return Returns a pointer to a newly allocated string. { char *s = MALLOC(char, Length + 1); strncpy(s, (char *)Data, Length); s[Length] = 0; return s; } static char *GetString(int &Length, const uint8_t **Data) ///< Gets the string at Data. ///< \return Returns a pointer to a newly allocated string, or NULL in case of error. ///< Upon return Length and Data represent the remaining data after the string has been skipped. { if (Length > 0 && Data && *Data) { int l = 0; const uint8_t *d = GetLength(*Data, l); char *s = CopyString(l, d); Length -= d - *Data + l; *Data = d + l; return s; } return NULL; } // --- cMutex ---------------------------------------------------------------- cMutex::cMutex(void) { lockingPid = 0; locked = 0; pthread_mutex_init(&mutex, NULL); } cMutex::~cMutex() { pthread_mutex_destroy(&mutex); } void cMutex::Lock(void) { if (getpid() != lockingPid || !locked) { pthread_mutex_lock(&mutex); lockingPid = getpid(); } locked++; } void cMutex::Unlock(void) { if (!--locked) { lockingPid = 0; pthread_mutex_unlock(&mutex); } } // --- cMutexLock ------------------------------------------------------------ cMutexLock::cMutexLock(cMutex *Mutex) { mutex = NULL; locked = false; Lock(Mutex); } cMutexLock::~cMutexLock() { if (mutex && locked) mutex->Unlock(); } bool cMutexLock::Lock(cMutex *Mutex) { if (Mutex && !mutex) { mutex = Mutex; Mutex->Lock(); locked = true; return true; } return false; } // --- cTPDU ----------------------------------------------------------------- #define MAX_TPDU_SIZE 2048 #define MAX_TPDU_DATA (MAX_TPDU_SIZE - 4) #define DATA_INDICATOR 0x80 #define T_SB 0x80 #define T_RCV 0x81 #define T_CREATE_TC 0x82 #define T_CTC_REPLY 0x83 #define T_DELETE_TC 0x84 #define T_DTC_REPLY 0x85 #define T_REQUEST_TC 0x86 #define T_NEW_TC 0x87 #define T_TC_ERROR 0x88 #define T_DATA_LAST 0xA0 #define T_DATA_MORE 0xA1 class cTPDU { private: int size; uint8_t data[MAX_TPDU_SIZE]; const uint8_t *GetData(const uint8_t *Data, int &Length); public: cTPDU(void) { size = 0; } cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length = 0, const uint8_t *Data = NULL); uint8_t Slot(void) { return data[0]; } uint8_t Tcid(void) { return data[1]; } uint8_t Tag(void) { return data[2]; } const uint8_t *Data(int &Length) { return GetData(data + 3, Length); } uint8_t Status(void); int Write(int fd); int Read(int fd); void Dump(bool Outgoing); }; cTPDU::cTPDU(uint8_t Slot, uint8_t Tcid, uint8_t Tag, int Length, const uint8_t *Data) { size = 0; data[0] = Slot; data[1] = Tcid; data[2] = Tag; switch (Tag) { case T_RCV: case T_CREATE_TC: case T_CTC_REPLY: case T_DELETE_TC: case T_DTC_REPLY: case T_REQUEST_TC: data[3] = 1; // length data[4] = Tcid; size = 5; break; case T_NEW_TC: case T_TC_ERROR: if (Length == 1) { data[3] = 2; // length data[4] = Tcid; data[5] = Data[0]; size = 6; } else esyslog("ERROR: illegal data length for TPDU tag 0x%02X: %d", Tag, Length); break; case T_DATA_LAST: case T_DATA_MORE: if (Length <= MAX_TPDU_DATA) { uint8_t *p = data + 3; p = SetLength(p, Length + 1); *p++ = Tcid; if (Length) memcpy(p, Data, Length); size = Length + (p - data); } else esyslog("ERROR: illegal data length for TPDU tag 0x%02X: %d", Tag, Length); break; default: esyslog("ERROR: unknown TPDU tag: 0x%02X", Tag); } } int cTPDU::Write(int fd) { Dump(true); if (size) return write(fd, data, size) == size ? OK : ERROR; esyslog("ERROR: attemp to write TPDU with zero size"); return ERROR; } int cTPDU::Read(int fd) { size = safe_read(fd, data, sizeof(data)); if (size < 0) { esyslog("ERROR: %m"); size = 0; return ERROR; } Dump(false); return OK; } void cTPDU::Dump(bool Outgoing) { if (DumpTPDUDataTransfer) { #define MAX_DUMP 256 fprintf(stderr, "%s ", Outgoing ? "-->" : "<--"); for (int i = 0; i < size && i < MAX_DUMP; i++) fprintf(stderr, "%02X ", data[i]); fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : ""); if (!Outgoing) { fprintf(stderr, " "); for (int i = 0; i < size && i < MAX_DUMP; i++) fprintf(stderr, "%2c ", isprint(data[i]) ? data[i] : '.'); fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : ""); } } } const uint8_t *cTPDU::GetData(const uint8_t *Data, int &Length) { if (size) { Data = GetLength(Data, Length); if (Length) { Length--; // the first byte is always the tcid return Data + 1; } } return NULL; } uint8_t cTPDU::Status(void) { if (size >= 4 && data[size - 4] == T_SB && data[size - 3] == 2) { //XXX test tcid??? return data[size - 1]; } return 0; } // --- cCiTransportConnection ------------------------------------------------ enum eState { stIDLE, stCREATION, stACTIVE, stDELETION }; class cCiTransportConnection { friend class cCiTransportLayer; private: int fd; uint8_t slot; uint8_t tcid; eState state; cTPDU *tpdu; int lastResponse; bool dataAvailable; void Init(int Fd, uint8_t Slot, uint8_t Tcid); int SendTPDU(uint8_t Tag, int Length = 0, const uint8_t *Data = NULL); int RecvTPDU(void); int CreateConnection(void); int Poll(void); eState State(void) { return state; } int LastResponse(void) { return lastResponse; } bool DataAvailable(void) { return dataAvailable; } public: cCiTransportConnection(void); ~cCiTransportConnection(); int Slot(void) const { return slot; } int SendData(int Length, const uint8_t *Data); int RecvData(void); const uint8_t *Data(int &Length); //XXX Close() }; cCiTransportConnection::cCiTransportConnection(void) { tpdu = NULL; Init(-1, 0, 0); } cCiTransportConnection::~cCiTransportConnection() { delete tpdu; } void cCiTransportConnection::Init(int Fd, uint8_t Slot, uint8_t Tcid) { fd = Fd; slot = Slot; tcid = Tcid; state = stIDLE; if (fd >= 0 && !tpdu) tpdu = new cTPDU; lastResponse = ERROR; dataAvailable = false; //XXX Clear()??? } int cCiTransportConnection::SendTPDU(uint8_t Tag, int Length, const uint8_t *Data) { cTPDU TPDU(slot, tcid, Tag, Length, Data); return TPDU.Write(fd); } #define CAM_READ_TIMEOUT 3500 // ms int cCiTransportConnection::RecvTPDU(void) { struct pollfd pfd[1]; pfd[0].fd = fd; pfd[0].events = POLLIN; lastResponse = ERROR; if (poll(pfd, 1, CAM_READ_TIMEOUT) && (pfd[0].revents & POLLIN) && tpdu->Read(fd) == OK && tpdu->Tcid() == tcid) { switch (state) { case stIDLE: break; case stCREATION: if (tpdu->Tag() == T_CTC_REPLY) { dataAvailable = tpdu->Status() & DATA_INDICATOR; state = stACTIVE; lastResponse = tpdu->Tag(); } break; case stACTIVE: switch (tpdu->Tag()) { case T_SB: case T_DATA_LAST: case T_DATA_MORE: case T_REQUEST_TC: break; case T_DELETE_TC: if (SendTPDU(T_DTC_REPLY) != OK) return ERROR; Init(fd, slot, tcid); break; default: return ERROR; } dataAvailable = tpdu->Status() & DATA_INDICATOR; lastResponse = tpdu->Tag(); break; case stDELETION: if (tpdu->Tag() == T_DTC_REPLY) { Init(fd, slot, tcid); //XXX Status()??? lastResponse = tpdu->Tag(); } break; } } else { esyslog("ERROR: CAM: Read failed: slot %d, tcid %d\n", slot, tcid); Init(-1, slot, tcid); } return lastResponse; } int cCiTransportConnection::SendData(int Length, const uint8_t *Data) { while (state == stACTIVE && Length > 0) { uint8_t Tag = T_DATA_LAST; int l = Length; if (l > MAX_TPDU_DATA) { Tag = T_DATA_MORE; l = MAX_TPDU_DATA; } if (SendTPDU(Tag, l, Data) != OK || RecvTPDU() != T_SB) break; Length -= l; Data += l; } return Length ? ERROR : OK; } int cCiTransportConnection::RecvData(void) { if (SendTPDU(T_RCV) == OK) return RecvTPDU(); return ERROR; } const uint8_t *cCiTransportConnection::Data(int &Length) { return tpdu->Data(Length); } #define MAX_CONNECT_RETRIES 20 int cCiTransportConnection::CreateConnection(void) { if (state == stIDLE) { if (SendTPDU(T_CREATE_TC) == OK) { state = stCREATION; if (RecvTPDU() == T_CTC_REPLY) { _connected=true; return OK; // the following is a workaround for CAMs that don't quite follow the specs... } else { for (int i = 0; i < MAX_CONNECT_RETRIES; i++) { dsyslog("CAM: retrying to establish connection"); if (RecvTPDU() == T_CTC_REPLY) { dsyslog("CAM: connection established"); _connected=true; return OK; } } return ERROR; } } } return ERROR; } int cCiTransportConnection::Poll(void) { if (state == stACTIVE) { if (SendTPDU(T_DATA_LAST) == OK) return RecvTPDU(); } return ERROR; } // --- cCiTransportLayer ----------------------------------------------------- #define MAX_CI_CONNECT 16 // maximum possible value is 254 class cCiTransportLayer { private: int fd; int numSlots; cCiTransportConnection tc[MAX_CI_CONNECT]; public: cCiTransportLayer(int Fd, int NumSlots); cCiTransportConnection *NewConnection(int Slot); bool ResetSlot(int Slot); bool ModuleReady(int Slot); cCiTransportConnection *Process(int Slot); }; cCiTransportLayer::cCiTransportLayer(int Fd, int NumSlots) { fd = Fd; numSlots = NumSlots; for (int s = 0; s < numSlots; s++) ResetSlot(s); } cCiTransportConnection *cCiTransportLayer::NewConnection(int Slot) { for (int i = 0; i < MAX_CI_CONNECT; i++) { if (tc[i].State() == stIDLE) { dbgprotocol("Creating connection: slot %d, tcid %d\n", Slot, i + 1); tc[i].Init(fd, Slot, i + 1); if (tc[i].CreateConnection() == OK) return &tc[i]; break; } } return NULL; } bool cCiTransportLayer::ResetSlot(int Slot) { dbgprotocol("Resetting slot %d...", Slot); if (ioctl(fd, CA_RESET, 1 << Slot) != -1) { dbgprotocol("ok.\n"); return true; } else esyslog("ERROR: can't reset CAM slot %d: %m", Slot); dbgprotocol("failed!\n"); return false; } bool cCiTransportLayer::ModuleReady(int Slot) { ca_slot_info_t sinfo; sinfo.num = Slot; if (ioctl(fd, CA_GET_SLOT_INFO, &sinfo) != -1) return sinfo.flags & CA_CI_MODULE_READY; else esyslog("ERROR: can't get info on CAM slot %d: %m", Slot); return false; } cCiTransportConnection *cCiTransportLayer::Process(int Slot) { for (int i = 0; i < MAX_CI_CONNECT; i++) { cCiTransportConnection *Tc = &tc[i]; if (Tc->Slot() == Slot) { switch (Tc->State()) { case stCREATION: case stACTIVE: if (!Tc->DataAvailable()) { if (Tc->Poll() != OK) ;//XXX continue; } switch (Tc->LastResponse()) { case T_REQUEST_TC: //XXX break; case T_DATA_MORE: case T_DATA_LAST: case T_CTC_REPLY: case T_SB: if (Tc->DataAvailable()) Tc->RecvData(); break; case TIMEOUT: case ERROR: default: //XXX Tc->state = stIDLE;//XXX Init()??? return NULL; break; } //XXX this will only work with _one_ transport connection per slot! return Tc; break; default: ; } } } return NULL; } // -- cCiSession ------------------------------------------------------------- // Session Tags: #define ST_SESSION_NUMBER 0x90 #define ST_OPEN_SESSION_REQUEST 0x91 #define ST_OPEN_SESSION_RESPONSE 0x92 #define ST_CREATE_SESSION 0x93 #define ST_CREATE_SESSION_RESPONSE 0x94 #define ST_CLOSE_SESSION_REQUEST 0x95 #define ST_CLOSE_SESSION_RESPONSE 0x96 // Session Status: #define SS_OK 0x00 #define SS_NOT_ALLOCATED 0xF0 // Resource Identifiers: #define RI_RESOURCE_MANAGER 0x00010041 #define RI_APPLICATION_INFORMATION 0x00020041 #define RI_CONDITIONAL_ACCESS_SUPPORT 0x00030041 #define RI_HOST_CONTROL 0x00200041 #define RI_DATE_TIME 0x00240041 #define RI_MMI 0x00400041 class cCiSession { private: int sessionId; int resourceId; cCiTransportConnection *tc; protected: int GetTag(int &Length, const uint8_t **Data); const uint8_t *GetData(const uint8_t *Data, int &Length); int SendData(int Tag, int Length = 0, const uint8_t *Data = NULL); public: cCiSession(int SessionId, int ResourceId, cCiTransportConnection *Tc); virtual ~cCiSession(); const cCiTransportConnection *Tc(void) { return tc; } int SessionId(void) { return sessionId; } int ResourceId(void) { return resourceId; } virtual bool HasUserIO(void) { return false; } virtual bool Process(int Length = 0, const uint8_t *Data = NULL); }; cCiSession::cCiSession(int SessionId, int ResourceId, cCiTransportConnection *Tc) { sessionId = SessionId; resourceId = ResourceId; tc = Tc; } cCiSession::~cCiSession() { } int cCiSession::GetTag(int &Length, const uint8_t **Data) ///< Gets the tag at Data. ///< \return Returns the actual tag, or AOT_NONE in case of error. ///< Upon return Length and Data represent the remaining data after the tag has been skipped. { if (Length >= 3 && Data && *Data) { int t = 0; for (int i = 0; i < 3; i++) t = (t << 8) | *(*Data)++; Length -= 3; return t; } return AOT_NONE; } const uint8_t *cCiSession::GetData(const uint8_t *Data, int &Length) { Data = GetLength(Data, Length); return Length ? Data : NULL; } int cCiSession::SendData(int Tag, int Length, const uint8_t *Data) { uint8_t buffer[2048]; uint8_t *p = buffer; *p++ = ST_SESSION_NUMBER; *p++ = 0x02; *p++ = (sessionId >> 8) & 0xFF; *p++ = sessionId & 0xFF; *p++ = (Tag >> 16) & 0xFF; *p++ = (Tag >> 8) & 0xFF; *p++ = Tag & 0xFF; p = SetLength(p, Length); if (p - buffer + Length < int(sizeof(buffer))) { memcpy(p, Data, Length); p += Length; return tc->SendData(p - buffer, buffer); } esyslog("ERROR: CAM: data length (%d) exceeds buffer size", Length); return ERROR; } bool cCiSession::Process(int Length, const uint8_t *Data) { return true; } // -- cCiResourceManager ----------------------------------------------------- class cCiResourceManager : public cCiSession { private: int state; public: cCiResourceManager(int SessionId, cCiTransportConnection *Tc); virtual bool Process(int Length = 0, const uint8_t *Data = NULL); }; cCiResourceManager::cCiResourceManager(int SessionId, cCiTransportConnection *Tc) :cCiSession(SessionId, RI_RESOURCE_MANAGER, Tc) { dbgprotocol("New Resource Manager (session id %d)\n", SessionId); state = 0; } bool cCiResourceManager::Process(int Length, const uint8_t *Data) { if (Data) { int Tag = GetTag(Length, &Data); switch (Tag) { case AOT_PROFILE_ENQ: { dbgprotocol("%d: <== Profile Enquiry\n", SessionId()); int resources[] = { htonl(RI_RESOURCE_MANAGER), htonl(RI_APPLICATION_INFORMATION), htonl(RI_CONDITIONAL_ACCESS_SUPPORT), htonl(RI_DATE_TIME), htonl(RI_MMI) }; dbgprotocol("%d: ==> Profile\n", SessionId()); SendData(AOT_PROFILE, sizeof(resources), (uint8_t*)resources); state = 3; } break; case AOT_PROFILE: { dbgprotocol("%d: <== Profile\n", SessionId()); if (state == 1) { int l = 0; const uint8_t *d = GetData(Data, l); if (l > 0 && d) esyslog("CI resource manager: unexpected data"); dbgprotocol("%d: ==> Profile Change\n", SessionId()); SendData(AOT_PROFILE_CHANGE); state = 2; } else { esyslog("ERROR: CI resource manager: unexpected tag %06X in state %d", Tag, state); } } break; default: esyslog("ERROR: CI resource manager: unknown tag %06X", Tag); return false; } } else if (state == 0) { dbgprotocol("%d: ==> Profile Enq\n", SessionId()); SendData(AOT_PROFILE_ENQ); state = 1; } return true; } // --- cCiApplicationInformation --------------------------------------------- class cCiApplicationInformation : public cCiSession { private: int state; time_t creationTime; uint8_t applicationType; uint16_t applicationManufacturer; uint16_t manufacturerCode; char *menuString; public: cCiApplicationInformation(int SessionId, cCiTransportConnection *Tc); virtual ~cCiApplicationInformation(); virtual bool Process(int Length = 0, const uint8_t *Data = NULL); bool EnterMenu(void); }; cCiApplicationInformation::cCiApplicationInformation(int SessionId, cCiTransportConnection *Tc) :cCiSession(SessionId, RI_APPLICATION_INFORMATION, Tc) { dbgprotocol("New Application Information (session id %d)\n", SessionId); state = 0; creationTime = time(NULL); menuString = NULL; } cCiApplicationInformation::~cCiApplicationInformation() { free(menuString); } bool cCiApplicationInformation::Process(int Length, const uint8_t *Data) { if (Data) { int Tag = GetTag(Length, &Data); switch (Tag) { case AOT_APPLICATION_INFO: { dbgprotocol("%d: <== Application Info\n", SessionId()); int l = 0; const uint8_t *d = GetData(Data, l); if ((l -= 1) < 0) break; applicationType = *d++; if ((l -= 2) < 0) break; applicationManufacturer = ntohs(*(uint16_t *)d); d += 2; if ((l -= 2) < 0) break; manufacturerCode = ntohs(*(uint16_t *)d); d += 2; free(menuString); menuString = GetString(l, &d); isyslog("CAM: %s, %02X, %04X, %04X", menuString, applicationType, applicationManufacturer, manufacturerCode);//XXX make externally accessible! } state = 2; break; default: esyslog("ERROR: CI application information: unknown tag %06X", Tag); return false; } } else if (state == 0) { dbgprotocol("%d: ==> Application Info Enq\n", SessionId()); SendData(AOT_APPLICATION_INFO_ENQ); state = 1; } return true; } bool cCiApplicationInformation::EnterMenu(void) { if (state == 2 && time(NULL) - creationTime > WRKRND_TIME_BEFORE_ENTER_MENU) { dbgprotocol("%d: ==> Enter Menu\n", SessionId()); SendData(AOT_ENTER_MENU); return true;//XXX } return false; } // --- cCiConditionalAccessSupport ------------------------------------------- #define MAXCASYSTEMIDS 16 class cCiConditionalAccessSupport : public cCiSession { private: int state; int numCaSystemIds; unsigned short caSystemIds[MAXCASYSTEMIDS + 1]; // list is zero terminated! public: cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc); virtual bool Process(int Length = 0, const uint8_t *Data = NULL); const unsigned short *GetCaSystemIds(void) { return caSystemIds; } bool SendPMT(cCiCaPmt &CaPmt); }; cCiConditionalAccessSupport::cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc) :cCiSession(SessionId, RI_CONDITIONAL_ACCESS_SUPPORT, Tc) { dbgprotocol("New Conditional Access Support (session id %d)\n", SessionId); state = 0; caSystemIds[numCaSystemIds = 0] = 0; } bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data) { if (Data) { int Tag = GetTag(Length, &Data); switch (Tag) { case AOT_CA_INFO: { dbgprotocol("%d: <== Ca Info", SessionId()); int l = 0; const uint8_t *d = GetData(Data, l); while (l > 1) { unsigned short id = ((unsigned short)(*d) << 8) | *(d + 1); dbgprotocol(" %04X", id); d += 2; l -= 2; if (numCaSystemIds < MAXCASYSTEMIDS) { caSystemIds[numCaSystemIds++] = id; caSystemIds[numCaSystemIds] = 0; } else esyslog("ERROR: too many CA system IDs!"); } dbgprotocol("\n"); } state = 2; break; default: esyslog("ERROR: CI conditional access support: unknown tag %06X", Tag); return false; } } else if (state == 0) { dbgprotocol("%d: ==> Ca Info Enq\n", SessionId()); SendData(AOT_CA_INFO_ENQ); state = 1; } return true; } bool cCiConditionalAccessSupport::SendPMT(cCiCaPmt &CaPmt) { if (state == 2) { SendData(AOT_CA_PMT, CaPmt.length, CaPmt.capmt); return true; } return false; } // --- cCiDateTime ----------------------------------------------------------- class cCiDateTime : public cCiSession { private: int interval; time_t lastTime; bool SendDateTime(void); public: cCiDateTime(int SessionId, cCiTransportConnection *Tc); virtual bool Process(int Length = 0, const uint8_t *Data = NULL); }; cCiDateTime::cCiDateTime(int SessionId, cCiTransportConnection *Tc) :cCiSession(SessionId, RI_DATE_TIME, Tc) { interval = 0; lastTime = 0; dbgprotocol("New Date Time (session id %d)\n", SessionId); } bool cCiDateTime::SendDateTime(void) { time_t t = time(NULL); struct tm tm_gmt; struct tm tm_loc; if (gmtime_r(&t, &tm_gmt) && localtime_r(&t, &tm_loc)) { int Y = tm_gmt.tm_year; int M = tm_gmt.tm_mon + 1; int D = tm_gmt.tm_mday; int L = (M == 1 || M == 2) ? 1 : 0; int MJD = 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001); #define DEC2BCD(d) (((d / 10) << 4) + (d % 10)) struct tTime { unsigned short mjd; uint8_t h, m, s; short offset; }; tTime T = { mjd : htons(MJD), h : DEC2BCD(tm_gmt.tm_hour), m : DEC2BCD(tm_gmt.tm_min), s : DEC2BCD(tm_gmt.tm_sec), offset : htons(tm_loc.tm_gmtoff / 60) }; dbgprotocol("%d: ==> Date Time\n", SessionId()); SendData(AOT_DATE_TIME, 7, (uint8_t*)&T); //XXX return value of all SendData() calls??? return true; } return false; } bool cCiDateTime::Process(int Length, const uint8_t *Data) { if (Data) { int Tag = GetTag(Length, &Data); switch (Tag) { case AOT_DATE_TIME_ENQ: { interval = 0; int l = 0; const uint8_t *d = GetData(Data, l); if (l > 0) interval = *d; dbgprotocol("%d: <== Date Time Enq, interval = %d\n", SessionId(), interval); lastTime = time(NULL); return SendDateTime(); } break; default: esyslog("ERROR: CI date time: unknown tag %06X", Tag); return false; } } else if (interval && time(NULL) - lastTime > interval) { lastTime = time(NULL); return SendDateTime(); } return true; } // --- cCiMMI ---------------------------------------------------------------- // Display Control Commands: #define DCC_SET_MMI_MODE 0x01 #define DCC_DISPLAY_CHARACTER_TABLE_LIST 0x02 #define DCC_INPUT_CHARACTER_TABLE_LIST 0x03 #define DCC_OVERLAY_GRAPHICS_CHARACTERISTICS 0x04 #define DCC_FULL_SCREEN_GRAPHICS_CHARACTERISTICS 0x05 // MMI Modes: #define MM_HIGH_LEVEL 0x01 #define MM_LOW_LEVEL_OVERLAY_GRAPHICS 0x02 #define MM_LOW_LEVEL_FULL_SCREEN_GRAPHICS 0x03 // Display Reply IDs: #define DRI_MMI_MODE_ACK 0x01 #define DRI_LIST_DISPLAY_CHARACTER_TABLES 0x02 #define DRI_LIST_INPUT_CHARACTER_TABLES 0x03 #define DRI_LIST_GRAPHIC_OVERLAY_CHARACTERISTICS 0x04 #define DRI_LIST_FULL_SCREEN_GRAPHIC_CHARACTERISTICS 0x05 #define DRI_UNKNOWN_DISPLAY_CONTROL_CMD 0xF0 #define DRI_UNKNOWN_MMI_MODE 0xF1 #define DRI_UNKNOWN_CHARACTER_TABLE 0xF2 // Enquiry Flags: #define EF_BLIND 0x01 // Answer IDs: #define AI_CANCEL 0x00 #define AI_ANSWER 0x01 class cCiMMI : public cCiSession { private: char *GetText(int &Length, const uint8_t **Data); cCiMenu *menu; cCiEnquiry *enquiry; public: cCiMMI(int SessionId, cCiTransportConnection *Tc); virtual ~cCiMMI(); virtual bool Process(int Length = 0, const uint8_t *Data = NULL); virtual bool HasUserIO(void) { return menu || enquiry; } cCiMenu *Menu(void); cCiEnquiry *Enquiry(void); bool SendMenuAnswer(uint8_t Selection); bool SendAnswer(const char *Text); }; cCiMMI::cCiMMI(int SessionId, cCiTransportConnection *Tc) :cCiSession(SessionId, RI_MMI, Tc) { dbgprotocol("New MMI (session id %d)\n", SessionId); menu = NULL; enquiry = NULL; } cCiMMI::~cCiMMI() { delete menu; delete enquiry; } char *cCiMMI::GetText(int &Length, const uint8_t **Data) ///< Gets the text at Data. ///< \return Returns a pointer to a newly allocated string, or NULL in case of error. ///< Upon return Length and Data represent the remaining data after the text has been skipped. { int Tag = GetTag(Length, Data); if (Tag == AOT_TEXT_LAST) { char *s = GetString(Length, Data); dbgprotocol("%d: <== Text Last '%s'\n", SessionId(), s); return s; } else esyslog("CI MMI: unexpected text tag: %06X", Tag); return NULL; } bool cCiMMI::Process(int Length, const uint8_t *Data) { if (Data) { int Tag = GetTag(Length, &Data); switch (Tag) { case AOT_DISPLAY_CONTROL: { dbgprotocol("%d: <== Display Control\n", SessionId()); int l = 0; const uint8_t *d = GetData(Data, l); if (l > 0) { switch (*d) { case DCC_SET_MMI_MODE: if (l == 2 && *++d == MM_HIGH_LEVEL) { struct tDisplayReply { uint8_t id; uint8_t mode; }; tDisplayReply dr = { id : DRI_MMI_MODE_ACK, mode : MM_HIGH_LEVEL }; dbgprotocol("%d: ==> Display Reply\n", SessionId()); SendData(AOT_DISPLAY_REPLY, 2, (uint8_t *)&dr); } break; default: esyslog("CI MMI: unsupported display control command %02X", *d); return false; } } } break; case AOT_LIST_LAST: case AOT_MENU_LAST: { dbgprotocol("%d: <== Menu Last\n", SessionId()); delete menu; menu = new cCiMenu(this, Tag == AOT_MENU_LAST); int l = 0; const uint8_t *d = GetData(Data, l); if (l > 0) { // since the specification allows choiceNb to be undefined it is useless, so let's just skip it: d++; l--; if (l > 0) menu->titleText = GetText(l, &d); if (l > 0) menu->subTitleText = GetText(l, &d); if (l > 0) menu->bottomText = GetText(l, &d); while (l > 0) { char *s = GetText(l, &d); if (s) { if (!menu->AddEntry(s)) free(s); } else break; } } } break; case AOT_ENQ: { dbgprotocol("%d: <== Enq\n", SessionId()); delete enquiry; enquiry = new cCiEnquiry(this); int l = 0; const uint8_t *d = GetData(Data, l); if (l > 0) { uint8_t blind = *d++; //XXX GetByte()??? l--; enquiry->blind = blind & EF_BLIND; enquiry->expectedLength = *d++; l--; // I really wonder why there is no text length field here... enquiry->text = CopyString(l, d); } } break; default: esyslog("ERROR: CI MMI: unknown tag %06X", Tag); return false; } } return true; } cCiMenu *cCiMMI::Menu(void) { cCiMenu *m = menu; menu = NULL; return m; } cCiEnquiry *cCiMMI::Enquiry(void) { cCiEnquiry *e = enquiry; enquiry = NULL; return e; } bool cCiMMI::SendMenuAnswer(uint8_t Selection) { dbgprotocol("%d: ==> Menu Answ\n", SessionId()); SendData(AOT_MENU_ANSW, 1, &Selection); //XXX return value of all SendData() calls??? return true; } bool cCiMMI::SendAnswer(const char *Text) { dbgprotocol("%d: ==> Answ\n", SessionId()); struct tAnswer { uint8_t id; char text[256]; };//XXX tAnswer answer; answer.id = Text ? AI_ANSWER : AI_CANCEL; if (Text) strncpy(answer.text, Text, sizeof(answer.text)); SendData(AOT_ANSW, Text ? strlen(Text) + 1 : 1, (uint8_t *)&answer); //XXX return value of all SendData() calls??? return true; } // --- cCiMenu --------------------------------------------------------------- cCiMenu::cCiMenu(cCiMMI *MMI, bool Selectable) { mmi = MMI; selectable = Selectable; titleText = subTitleText = bottomText = NULL; numEntries = 0; } cCiMenu::~cCiMenu() { free(titleText); free(subTitleText); free(bottomText); for (int i = 0; i < numEntries; i++) free(entries[i]); } bool cCiMenu::AddEntry(char *s) { if (numEntries < MAX_CIMENU_ENTRIES) { entries[numEntries++] = s; return true; } return false; } bool cCiMenu::Select(int Index) { if (mmi && -1 <= Index && Index < numEntries) return mmi->SendMenuAnswer(Index + 1); return false; } bool cCiMenu::Cancel(void) { return Select(-1); } // --- cCiEnquiry ------------------------------------------------------------ cCiEnquiry::cCiEnquiry(cCiMMI *MMI) { mmi = MMI; text = NULL; blind = false;; expectedLength = 0;; } cCiEnquiry::~cCiEnquiry() { free(text); } bool cCiEnquiry::Reply(const char *s) { return mmi ? mmi->SendAnswer(s) : false; } bool cCiEnquiry::Cancel(void) { return Reply(NULL); } // --- cCiCaPmt -------------------------------------------------------------- // Ca Pmt List Management: #define CPLM_MORE 0x00 #define CPLM_FIRST 0x01 #define CPLM_LAST 0x02 #define CPLM_ONLY 0x03 #define CPLM_ADD 0x04 #define CPLM_UPDATE 0x05 // Ca Pmt Cmd Ids: #define CPCI_OK_DESCRAMBLING 0x01 #define CPCI_OK_MMI 0x02 #define CPCI_QUERY 0x03 #define CPCI_NOT_SELECTED 0x04 cCiCaPmt::cCiCaPmt(int ProgramNumber) { length = 0; capmt[length++] = CPLM_ONLY; capmt[length++] = (ProgramNumber >> 8) & 0xFF; capmt[length++] = ProgramNumber & 0xFF; capmt[length++] = 0x01; // version_number, current_next_indicator - apparently vn doesn't matter, but cni must be 1 esInfoLengthPos = length; capmt[length++] = 0x00; // program_info_length H (at program level) capmt[length++] = 0x00; // program_info_length L } void cCiCaPmt::AddPid(int Pid) { //XXX buffer overflow check??? capmt[length++] = 0x00; //XXX stream_type (apparently doesn't matter) capmt[length++] = (Pid >> 8) & 0xFF; capmt[length++] = Pid & 0xFF; esInfoLengthPos = length; capmt[length++] = 0x00; // ES_info_length H (at ES level) capmt[length++] = 0x00; // ES_info_length L } void cCiCaPmt::AddCaDescriptor(int Length, uint8_t *Data) { if (esInfoLengthPos) { if (length + Length < int(sizeof(capmt))) { capmt[length++] = CPCI_OK_DESCRAMBLING; memcpy(capmt + length, Data, Length); length += Length; int l = length - esInfoLengthPos - 2; capmt[esInfoLengthPos] = (l >> 8) & 0xFF; capmt[esInfoLengthPos + 1] = l & 0xFF; } else esyslog("ERROR: buffer overflow in CA descriptor"); esInfoLengthPos = 0; } else esyslog("ERROR: adding CA descriptor without Pid!"); } // -- cCiHandler ------------------------------------------------------------- cCiHandler::cCiHandler(int Fd, int NumSlots) { numSlots = NumSlots; newCaSupport = false; hasUserIO = false; for (int i = 0; i < MAX_CI_SESSION; i++) sessions[i] = NULL; tpl = new cCiTransportLayer(Fd, numSlots); tc = NULL; } cCiHandler::~cCiHandler() { for (int i = 0; i < MAX_CI_SESSION; i++) delete sessions[i]; delete tpl; } cCiHandler *cCiHandler::CreateCiHandler(const char *FileName) { int fd_ca = open(FileName, O_RDWR); if (fd_ca >= 0) { ca_caps_t Caps; if (ioctl(fd_ca, CA_GET_CAP, &Caps) == 0) { int NumSlots = Caps.slot_num; if (NumSlots > 0) { //XXX dsyslog("CAM: found %d CAM slots", NumSlots); // TODO let's do this only once we can be sure that there _really_ is a CAM adapter! if (Caps.slot_type == CA_CI_LINK) return new cCiHandler(fd_ca, NumSlots); else isyslog("CAM doesn't support link layer interface"); } else esyslog("ERROR: no CAM slots found"); } else LOG_ERROR_STR(FileName); close(fd_ca); } return NULL; } int cCiHandler::ResourceIdToInt(const uint8_t *Data) { return (ntohl(*(int *)Data)); } bool cCiHandler::Send(uint8_t Tag, int SessionId, int ResourceId, int Status) { uint8_t buffer[16]; uint8_t *p = buffer; *p++ = Tag; *p++ = 0x00; // will contain length if (Status >= 0) *p++ = Status; if (ResourceId) { *(int *)p = htonl(ResourceId); p += 4; } *(short *)p = htons(SessionId); p += 2; buffer[1] = p - buffer - 2; // length return tc && tc->SendData(p - buffer, buffer) == OK; } cCiSession *cCiHandler::GetSessionBySessionId(int SessionId) { for (int i = 0; i < MAX_CI_SESSION; i++) { if (sessions[i] && sessions[i]->SessionId() == SessionId) return sessions[i]; } return NULL; } cCiSession *cCiHandler::GetSessionByResourceId(int ResourceId, int Slot) { for (int i = 0; i < MAX_CI_SESSION; i++) { if (sessions[i] && sessions[i]->Tc()->Slot() == Slot && sessions[i]->ResourceId() == ResourceId) return sessions[i]; } return NULL; } cCiSession *cCiHandler::CreateSession(int ResourceId) { if (!GetSessionByResourceId(ResourceId, tc->Slot())) { for (int i = 0; i < MAX_CI_SESSION; i++) { if (!sessions[i]) { switch (ResourceId) { case RI_RESOURCE_MANAGER: return sessions[i] = new cCiResourceManager(i + 1, tc); case RI_APPLICATION_INFORMATION: return sessions[i] = new cCiApplicationInformation(i + 1, tc); case RI_CONDITIONAL_ACCESS_SUPPORT: newCaSupport = true; return sessions[i] = new cCiConditionalAccessSupport(i + 1, tc); case RI_HOST_CONTROL: break; //XXX case RI_DATE_TIME: return sessions[i] = new cCiDateTime(i + 1, tc); case RI_MMI: return sessions[i] = new cCiMMI(i + 1, tc); } } } } return NULL; } bool cCiHandler::OpenSession(int Length, const uint8_t *Data) { if (Length == 6 && *(Data + 1) == 0x04) { int ResourceId = ResourceIdToInt(Data + 2); dbgprotocol("OpenSession %08X\n", ResourceId); switch (ResourceId) { case RI_RESOURCE_MANAGER: case RI_APPLICATION_INFORMATION: case RI_CONDITIONAL_ACCESS_SUPPORT: case RI_HOST_CONTROL: case RI_DATE_TIME: case RI_MMI: { cCiSession *Session = CreateSession(ResourceId); if (Session) { Send(ST_OPEN_SESSION_RESPONSE, Session->SessionId(), Session->ResourceId(), SS_OK); return true; } esyslog("ERROR: can't create session for resource identifier: %08X", ResourceId); } default: esyslog("ERROR: unknown resource identifier: %08X", ResourceId); } } return false; } bool cCiHandler::CloseSession(int SessionId) { dbgprotocol("CloseSession %08X\n", SessionId); cCiSession *Session = GetSessionBySessionId(SessionId); if (Session && sessions[SessionId - 1] == Session) { delete Session; sessions[SessionId - 1] = NULL; Send(ST_CLOSE_SESSION_RESPONSE, SessionId, 0, SS_OK); return true; } else { esyslog("ERROR: unknown session id: %d", SessionId); Send(ST_CLOSE_SESSION_RESPONSE, SessionId, 0, SS_NOT_ALLOCATED); } return false; } int cCiHandler::CloseAllSessions(int Slot) { int result = 0; for (int i = 0; i < MAX_CI_SESSION; i++) { if (sessions[i] && sessions[i]->Tc()->Slot() == Slot) { CloseSession(sessions[i]->SessionId()); result++; } } return result; } bool cCiHandler::Process(void) { bool result = true; cMutexLock MutexLock(&mutex); for (int Slot = 0; Slot < numSlots; Slot++) { tc = tpl->Process(Slot); if (tc) { int Length; const uint8_t *Data = tc->Data(Length); if (Data && Length > 1) { switch (*Data) { case ST_SESSION_NUMBER: if (Length > 4) { int SessionId = ntohs(*(short *)&Data[2]); cCiSession *Session = GetSessionBySessionId(SessionId); if (Session) Session->Process(Length - 4, Data + 4); else esyslog("ERROR: unknown session id: %d", SessionId); } break; case ST_OPEN_SESSION_REQUEST: OpenSession(Length, Data); break; case ST_CLOSE_SESSION_REQUEST: if (Length == 4) CloseSession(ntohs(*(short *)&Data[2])); break; case ST_CREATE_SESSION_RESPONSE: //XXX fall through to default case ST_CLOSE_SESSION_RESPONSE: //XXX fall through to default default: esyslog("ERROR: unknown session tag: %02X", *Data); } } } else if (CloseAllSessions(Slot)) { tpl->ResetSlot(Slot); result = false; } else if (tpl->ModuleReady(Slot)) { dbgprotocol("Module ready in slot %d\n", Slot); tpl->NewConnection(Slot); } } bool UserIO = false; for (int i = 0; i < MAX_CI_SESSION; i++) { if (sessions[i] && sessions[i]->Process()) UserIO |= sessions[i]->HasUserIO(); } hasUserIO = UserIO; if (newCaSupport) newCaSupport = result = false; // triggers new SetCaPmt at caller! return result; } bool cCiHandler::EnterMenu(int Slot) { cMutexLock MutexLock(&mutex); cCiApplicationInformation *api = (cCiApplicationInformation *)GetSessionByResourceId(RI_APPLICATION_INFORMATION, Slot); return api ? api->EnterMenu() : false; } cCiMenu *cCiHandler::GetMenu(void) { cMutexLock MutexLock(&mutex); for (int Slot = 0; Slot < numSlots; Slot++) { cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI, Slot); if (mmi) return mmi->Menu(); } return NULL; } cCiEnquiry *cCiHandler::GetEnquiry(void) { cMutexLock MutexLock(&mutex); for (int Slot = 0; Slot < numSlots; Slot++) { cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI, Slot); if (mmi) return mmi->Enquiry(); } return NULL; } const unsigned short *cCiHandler::GetCaSystemIds(int Slot) { cMutexLock MutexLock(&mutex); cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot); return cas ? cas->GetCaSystemIds() : NULL; } bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot) { cMutexLock MutexLock(&mutex); cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot); return cas && cas->SendPMT(CaPmt); } bool cCiHandler::Reset(int Slot) { cMutexLock MutexLock(&mutex); CloseAllSessions(Slot); return tpl->ResetSlot(Slot); } bool cCiHandler::connected() const { return _connected; } int tcp_listen(struct sockaddr_in *name,int sckt, unsigned long address) { int sock; name->sin_family = AF_INET; name->sin_port = htons (sckt); name->sin_addr.s_addr = address; if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1){ perror("ip socket"); return (-1); } if(bind(sock, (struct sockaddr *) name, sizeof(struct sockaddr)) == -1){ perror("bind"); return (-2); } if (listen(sock, 10)){ perror("listen"); return (-3); } return sock; } int udp_listen(struct sockaddr_un *name, char const * const filename) { int sock; name->sun_family = AF_UNIX; snprintf(name->sun_path, 108, "%s", filename); if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) == -1){ perror("ip socket"); return (-1); } if(bind(sock, (struct sockaddr *) name, sizeof(struct sockaddr)) == -1){ perror("bind"); return (-2); } if (listen(sock, 10)){ perror("listen"); return (-3); } return sock; } int accept_tcp(int ip_sock,struct sockaddr_in *ip_name) { socklen_t len; int conn; len = (socklen_t) sizeof(struct sockaddr); if((conn = accept(ip_sock, (struct sockaddr *)ip_name, &len)) < 0) { perror("accept"); return -1; } fprintf(stderr,"New connection established.\n"); return conn; } int accept_udp(int ip_sock,struct sockaddr_un *ip_name) { socklen_t len; int conn; len = (socklen_t) sizeof(struct sockaddr); if((conn = accept(ip_sock, (struct sockaddr *)ip_name, &len)) < 0) { perror("accept"); return -1; } fprintf(stderr,"New connection established.\n"); return conn; } libdvb-0.5.5.1/libdvbci/ci2.c0000644000175000017500000001753210220016115015425 0ustar mocmmocm00000000000000#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Application Object Tags: #define AOT_NONE 0x000000 #define AOT_PROFILE_ENQ 0x9F8010 #define AOT_PROFILE 0x9F8011 #define AOT_PROFILE_CHANGE 0x9F8012 #define AOT_APPLICATION_INFO_ENQ 0x9F8020 #define AOT_APPLICATION_INFO 0x9F8021 #define AOT_ENTER_MENU 0x9F8022 #define AOT_CA_INFO_ENQ 0x9F8030 #define AOT_CA_INFO 0x9F8031 #define AOT_CA_PMT 0x9F8032 #define AOT_CA_PMT_REPLY 0x9F8033 #define AOT_TUNE 0x9F8400 #define AOT_REPLACE 0x9F8401 #define AOT_CLEAR_REPLACE 0x9F8402 #define AOT_ASK_RELEASE 0x9F8403 #define AOT_DATE_TIME_ENQ 0x9F8440 #define AOT_DATE_TIME 0x9F8441 #define AOT_CLOSE_MMI 0x9F8800 #define AOT_DISPLAY_CONTROL 0x9F8801 #define AOT_DISPLAY_REPLY 0x9F8802 #define AOT_TEXT_LAST 0x9F8803 #define AOT_TEXT_MORE 0x9F8804 #define AOT_KEYPAD_CONTROL 0x9F8805 #define AOT_KEYPRESS 0x9F8806 #define AOT_ENQ 0x9F8807 #define AOT_ANSW 0x9F8808 #define AOT_MENU_LAST 0x9F8809 #define AOT_MENU_MORE 0x9F880A #define AOT_MENU_ANSW 0x9F880B #define AOT_LIST_LAST 0x9F880C #define AOT_LIST_MORE 0x9F880D #define AOT_SUBTITLE_SEGMENT_LAST 0x9F880E #define AOT_SUBTITLE_SEGMENT_MORE 0x9F880F #define AOT_DISPLAY_MESSAGE 0x9F8810 #define AOT_SCENE_END_MARK 0x9F8811 #define AOT_SCENE_DONE 0x9F8812 #define AOT_SCENE_CONTROL 0x9F8813 #define AOT_SUBTITLE_DOWNLOAD_LAST 0x9F8814 #define AOT_SUBTITLE_DOWNLOAD_MORE 0x9F8815 #define AOT_FLUSH_DOWNLOAD 0x9F8816 #define AOT_DOWNLOAD_REPLY 0x9F8817 #define AOT_COMMS_CMD 0x9F8C00 #define AOT_CONNECTION_DESCRIPTOR 0x9F8C01 #define AOT_COMMS_REPLY 0x9F8C02 #define AOT_COMMS_SEND_LAST 0x9F8C03 #define AOT_COMMS_SEND_MORE 0x9F8C04 #define AOT_COMMS_RCV_LAST 0x9F8C05 #define AOT_COMMS_RCV_MORE 0x9F8C06 struct ca_info { int sys_num; uint16_t sys_id[256]; char app_name[256]; }; static void dump(uint8_t *D, int len) { int i; for (i=0; i2)&&(dlen+i<=dslen)) { for (j=0; jsys_num; j++) if (cai->sys_id[j]==((buf[i+2]<<8)|buf[i+3])) break; if (j==cai->sys_num) continue; memcpy(out+olen+3, buf+i, dlen); olen+=dlen; } } olen=olen?olen+1:0; out[0]=(olen>>8); out[1]=(olen&0xff); return olen+2; } static int convert_pmt(struct ca_info *cai, uint8_t *out, uint8_t *buf, uint8_t list, uint8_t cmd) { int slen, dslen, o, i; slen=(((buf[1]&0x03)<<8)|buf[2])+3; out[0]=list; out[1]=buf[3]; out[2]=buf[4]; out[3]=buf[5]; dslen=((buf[10]&0x0f)<<8)|buf[11]; o=4+convert_desc(cai, out+4, buf+12, dslen, cmd); for (i=dslen+12; i4)) continue; out[o++]=buf[i]; out[o++]=buf[i+1]; out[o++]=buf[i+2]; o+=convert_desc(cai, out+o, buf+i+5, dslen, cmd); } return o; } int get_sec(int fd, uint8_t *buf, uint16_t ppid, uint8_t table) { struct dmx_sct_filter_params f; memset(&f, 0, sizeof(f)); f.pid = ppid; f.filter.filter[0] = table; f.filter.mask[0] = 0xFF; f.timeout = 2000; f.flags = DMX_IMMEDIATE_START; if (ioctl(fd, DMX_SET_FILTER, &f) < 0) return -1; return read(fd, buf, 4096); } static uint16_t get_pmt_pid(uint8_t *pat, uint16_t pnr) { int slen=(((pat[1]&0x03)<<8)|pat[2])+3, i; for (i=8; i=0; i--) if ((length>>(i<<3))&0xff) break; for (n+=i, *(*lf)++=n|0x80; i>=0; i--) *(*lf)++=(length>>(i<<3))&0xff; } return n; } int ci_send_obj(int fd, uint32_t tag, uint8_t *buf, uint16_t len) { ca_msg_t msg; uint8_t *p=msg.msg; *p++=(tag>>16)&0xff; *p++=(tag>>8)&0xff; *p++=tag&0xff; ci_write_length(&p, len); if (buf) memcpy(p, buf, len); msg.index=0; msg.type=CA_CI; msg.length=p-msg.msg+len; dump(msg.msg, msg.length); return ioctl(fd, CA_SEND_MSG, &msg); } int ci_getmsg(int fd, int slot, uint8_t *buf) { ca_msg_t msg; int res; res=ioctl(fd, CA_GET_MSG, &msg); if (res<0) return res; memcpy(buf, &msg.msg, msg.length); dump(buf, msg.length); return msg.length; } int ci_get_ca_info(int fd, int slot, struct ca_info *cai) { uint8_t buf[256], *p=buf+3; int len, i; ci_send_obj(fd, AOT_CA_INFO_ENQ, NULL, 0); if ((len=ci_getmsg(fd, slot, buf))<=8) return -1; printf("CA systems : "); len=ci_read_length(&p); cai->sys_num=p[0]; for (i=0; isys_num; i++) { cai->sys_id[i]=(p[1+i*2]<<8)|p[2+i*2]; printf("%04x ", cai->sys_id[i]); } printf("\n"); return 0; } int ci_get_app_info(int fd, int slot,struct ca_info *cai) { uint8_t answ[256], *p=answ+3; int len; //ci_send(fd, 0x01, 0x0000, NULL, 0); ci_send_obj(fd, AOT_APPLICATION_INFO_ENQ, NULL, 0); if ((len=ci_getmsg(fd, slot, answ))<=8) return -1; answ[len-1]=0; len=ci_read_length(&p); strncpy(cai->app_name, p+5, 256); printf("module: %s, app type %02x, app manf %04x\n", p+5, p[0], (p[1]<<8)|p[2]); return 0; } int ci_enable_pnr(int fd, int ci, int slot, uint16_t pnr) { uint8_t buf[4096], pmt[4096]; struct ca_info cai; uint16_t pid; int len; ci_get_info(ci); ci_get_app_info(ci,slot, &cai); ci_get_ca_info(ci, slot, &cai); if (!(pid=get_pmt(fd, pnr))) return -1; if ((len=get_sec(fd, buf, pid, 0x02))<0) return len; len=convert_pmt(&cai, pmt, buf, 3, 1); printf("CA_PMT[%d] = ", len); dump(pmt, len); ci_send_obj(ci, AOT_CA_PMT, pmt, len); return 0; } int ci_reset(int fd, int slot) { struct ca_info cai; ci_get_info(fd); ci_get_app_info(fd,slot, &cai); ci_get_ca_info(fd, slot, &cai); if (ioctl(fd, CA_RESET, 1 << slot) != -1) { return 0; } else return -1; } int ci_send_menu_answer(int fd, int slot, uint8_t answ) { return ci_send_obj(fd, AOT_MENU_ANSW, &answ, 1); } int ci_cancel_menu(int fd, int slot) { return ci_send_menu_answer(fd,slot,0); } int ci_menu_select(int fd, int slot, uint8_t sl) { return ci_send_menu_answer(fd,slot,sl); } int ci_enter_menu(int fd, int slot) { int re; ci_send_obj(fd, AOT_CLOSE_MMI, NULL, 0); re= ci_send_obj(fd, AOT_ENTER_MENU, NULL, 0); sleep(3); return re; } libdvb-0.5.5.1/libdvbmpeg/0000755000175000017500000000000010220016115015131 5ustar mocmmocm00000000000000libdvb-0.5.5.1/libdvbmpeg/.cvsignore0000644000175000017500000000001010220016115017120 0ustar mocmmocm00000000000000.depend libdvb-0.5.5.1/libdvbmpeg/Makefile0000644000175000017500000000132310220016115016570 0ustar mocmmocm00000000000000 include ../config.mk DCFLAGS = $(CFLAGS) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE MFLAG = -M OBJS = ctools.o ringbuffy.o transform.o cpptools.o SRC = $(wildcard *.c) CPPSRC = $(wildcard *.cpp) CSRC = $(wildcard *.cc) INCS = -I../include all: libdvbmpegtools.a .PHONY: depend clean install uninstall clean: - rm -f *.o *~ *.a .depend libdvbmpegtools.a: $(OBJS) ar -rcs libdvbmpegtools.a $(OBJS) %.o: %.cc $(CXX) -c $(DCFLAGS) $(INCLUDES) $(DEFINES) $< %.o: %.cpp $(CXX) -c $(DCFLAGS) $(INCLUDES) $(DEFINES) $< %.o: %.c $(CC) -c $(DCFLAGS) $(INCLUDES) $(DEFINES) $< .depend: $(CXX) $(DEFINES) $(MFLAG) $(SRC) $(CSRC) $(CPPSRC) $(INCLUDES)> .depend include .depend libdvb-0.5.5.1/libdvbmpeg/cpptools.cc0000644000175000017500000005230510220016115017310 0ustar mocmmocm00000000000000/* * dvb-mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * Copyright (C) 2002 Marcus Metzler * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at mocm@metzlerbros.de */ #include "cpptools.hh" #define HEX(N) "0x" << hex << setw(2) << setfill('0') \ << int(N) << " " << dec #define HHEX(N,M) "0x" << hex << setw(M) << setfill('0') \ << int(N) << " " << dec #define LHEX(N,M) "0x" << hex << setw(M) << setfill('0') \ << long(N) << " " << dec #define MAX_SEARCH 1024 * 1024 ostream & operator << (ostream & stream, PES_Packet & x){ if (x.info){ cerr << "PES Packet: " ; switch ( x.p.stream_id ) { case PROG_STREAM_MAP: cerr << "Program Stream Map"; break; case PRIVATE_STREAM2: cerr << "Private Stream 2"; break; case PROG_STREAM_DIR: cerr << "Program Stream Directory"; break; case ECM_STREAM : cerr << "ECM Stream"; break; case EMM_STREAM : cerr << "EMM Stream"; break; case PADDING_STREAM : cerr << "Padding Stream"; break; case DSM_CC_STREAM : cerr << "DSM Stream"; break; case ISO13522_STREAM: cerr << "ISO13522 Stream"; break; case PRIVATE_STREAM1: cerr << "Private Stream 1"; break; case AUDIO_STREAM_S ... AUDIO_STREAM_E: cerr << "Audio Stream " << HEX(x.p.stream_id); break; case VIDEO_STREAM_S ... VIDEO_STREAM_E: cerr << "Video Stream " << HEX(x.p.stream_id); break; } cerr << " MPEG" << x.p.mpeg << endl; if ( x.p.mpeg == 2 ){ cerr << " FLAGS: "; if (x.p.flags1 & SCRAMBLE_FLAGS){ cerr << " SCRAMBLE("; cerr << ((x.p.flags1 & SCRAMBLE_FLAGS)>>4); cerr << ")"; } if (x.p.flags1 & PRIORITY_FLAG) cerr << " PRIORITY"; if (x.p.flags1 & DATA_ALIGN_FLAG) cerr << " DATA_ALIGN"; if (x.p.flags1 & COPYRIGHT_FLAG) cerr << " COPYRIGHT"; if (x.p.flags1 & ORIGINAL_FLAG) cerr << " ORIGINAL"; if (x.p.flags2 & PTS_DTS_FLAGS){ cerr << " PTS_DTS("; cerr << ((x.p.flags2 & PTS_DTS_FLAGS)>>6); cerr << ")"; } if (x.p.flags2 & ESCR_FLAG) cerr << " ESCR"; if (x.p.flags2 & ES_RATE_FLAG) cerr << " ES_RATE"; if (x.p.flags2 & DSM_TRICK_FLAG) cerr << " DSM_TRICK"; if (x.p.flags2 & ADD_CPY_FLAG) cerr << " ADD_CPY"; if (x.p.flags2 & PES_CRC_FLAG) cerr << " CRC"; if (x.p.flags2 & PES_EXT_FLAG) cerr << " EXT"; cerr << endl; if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY) cerr << " PTS: " << LHEX(ntohl(x.WPTS()),8) << "(h" << int(x.high_pts()) << ")" << endl; else if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){ cerr << " PTS: " << LHEX(ntohl(x.WPTS()),8) << "(h" << int(x.high_pts()) << ")"; cerr << " DTS: " << LHEX(ntohl(x.WDTS()),8) << "(h" << int(x.high_dts()) << ")" << endl; } /* if (x.p.flags2 & ESCR_FLAG) if (x.p.flags2 & ES_RATE_FLAG) if (x.p.flags2 & DSM_TRICK_FLAG) if (x.p.flags2 & ADD_CPY_FLAG) if (x.p.flags2 & PES_CRC_FLAG) if (x.p.flags2 & PES_EXT_FLAG){ if (x.p.priv_flags & PRIVATE_DATA) stream.write(x.p.pes_priv_data,16); if (x.p.priv_flags & HEADER_FIELD){ stream.write(&x.p.pack_field_length,1); x.p.pack_header = new uint8_t[x.p.pack_field_length]; stream.write(x.p.pack_header, x.p.pack_field_length); } if ( x.p.priv_flags & PACK_SEQ_CTR){ stream.write(&x.p.pck_sqnc_cntr,1); stream.write(&x.p.org_stuff_length,1); } if ( x.p.priv_flags & P_STD_BUFFER) stream.write(x.p.p_std,2); if ( x.p.priv_flags & PES_EXT_FLAG2){ stream.write(&x.p.pes_ext_lngth,1); x.p.pes_ext = new uint8_t[x.p.pes_ext_lngth]; stream.write(x.p.pes_ext, x.p.pes_ext_lngth); } } } else { if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY) stream.write(x.p.pts,5); else if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){ stream.write(x.p.pts,5); stream.write(x.p.dts,5); } */ } cerr << endl << endl; return stream; } int l = x.p.length+x.p.pes_hlength+9; uint8_t buf[l]; int length = cwrite_pes(buf,&(x.p),l); stream.write((char *)buf,length); return stream; } static unsigned int find_length(istream & stream){ streampos p = 0; streampos start = 0; streampos q = 0; int found = 0; uint8_t sync4[4]; start = stream.tellg(); start -=2; stream.seekg(start); while ( !stream.eof() && !found ){ p = stream.tellg(); stream.read((char *)&sync4,4); if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { switch ( sync4[3] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: found = 1; break; default: q = stream.tellg(); break; } } } q = stream.tellg(); stream.seekg(streampos(2)+start); if (found) return (unsigned int)(q-start)-4-2; else return (unsigned int)(q-start)-2; } istream & operator >> (istream & stream, PES_Packet & x){ uint8_t sync4[4]; int found=0; int done=0; streampos p = 0; while (!stream.eof() && !found) { p = stream.tellg(); stream.read((char *)&sync4,4); if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { x.p.stream_id = sync4[3]; switch ( sync4[3] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : found = 1; stream.read((char *)x.p.llength,2); x.setlength(); if (!x.p.length){ x.p.length = find_length(stream); x.Nlength(); } stream.read((char *)x.p.pes_pckt_data,x.p.length); done = 1; break; case PADDING_STREAM : found = 1; stream.read((char *)x.p.llength,2); x.setlength(); if (!x.p.length){ x.p.length = find_length(stream); x.Nlength(); } x.p.padding = x.p.length; stream.read((char *)x.p.pes_pckt_data,x.p.length); done = 1; break; case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: stream.read((char *)x.p.llength,2); x.setlength(); if (!x.p.length){ x.p.length = find_length(stream); x.Nlength(); } found = 1; break; default: stream.seekg(p+streampos(1)); break; } } else stream.seekg(p+streampos(1)); } if ( found && !done) { p = stream.tellg(); stream.read((char *)&x.p.flags1,1); if ( (x.p.flags1 & 0xC0) == 0x80 ) x.p.mpeg = 2; else x.p.mpeg = 1; if ( x.p.mpeg == 2 ){ stream.read((char *)&x.p.flags2,1); stream.read((char *)&x.p.pes_hlength,1); if ((int)x.p.length > x.p.pes_hlength+3) x.p.length -=x.p.pes_hlength+3; else return stream; uint8_t count = x.p.pes_hlength; if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ stream.read((char *)x.p.pts,5); count -=5; } else if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){ stream.read((char *)x.p.pts,5); stream.read((char *)x.p.dts,5); count -= 10; } if (x.p.flags2 & ESCR_FLAG){ stream.read((char *)x.p.escr,6); count -= 6; } if (x.p.flags2 & ES_RATE_FLAG){ stream.read((char *)x.p.es_rate,3); count -= 6; } if (x.p.flags2 & DSM_TRICK_FLAG){ stream.read((char *)&x.p.trick,1); count -= 1; } if (x.p.flags2 & ADD_CPY_FLAG){ stream.read((char *)&x.p.add_cpy,1); count -= 1; } if (x.p.flags2 & PES_CRC_FLAG){ stream.read((char *)x.p.prev_pes_crc,2); count -= 2; } if (x.p.flags2 & PES_EXT_FLAG){ stream.read((char *)&x.p.priv_flags,1); count -= 1; if (x.p.priv_flags & PRIVATE_DATA){ stream.read((char *)x.p.pes_priv_data,16); count -= 16; } if (x.p.priv_flags & HEADER_FIELD){ stream.read((char *)&x.p.pack_field_length,1); x.p.pack_header = new uint8_t[x.p.pack_field_length]; stream.read((char *)x.p.pack_header, x.p.pack_field_length); count -= 1+x.p.pack_field_length; } if ( x.p.priv_flags & PACK_SEQ_CTR){ stream.read((char *)&x.p.pck_sqnc_cntr,1); stream.read((char *)&x.p.org_stuff_length,1); count -= 2; } if ( x.p.priv_flags & P_STD_BUFFER){ stream.read((char *)x.p.p_std,2); count -= 2; } if ( x.p.priv_flags & PES_EXT_FLAG2){ stream.read((char *)&x.p.pes_ext_lngth,1); x.p.pes_ext = new uint8_t[x.p.pes_ext_lngth]; stream.read((char *)x.p.pes_ext, x.p.pes_ext_lngth); count -= 1+x.p.pes_ext_lngth; } } x.p.stuffing = count; uint8_t dummy; for(int i = 0; i< count ;i++) stream.read((char *)&dummy,1); } else { uint8_t check; x.p.mpeg1_pad = 1; check = x.p.flags1; while (check == 0xFF){ stream.read((char *)&check,1); x.p.mpeg1_pad++; } if ( (check & 0xC0) == 0x40){ stream.read((char *)&check,1); x.p.mpeg1_pad++; stream.read((char *)&check,1); x.p.mpeg1_pad++; } x.p.flags2 = 0; x.p.length -= x.p.mpeg1_pad; stream.seekg(p); if ( (check & 0x30)){ x.p.length ++; x.p.mpeg1_pad --; if (check == x.p.flags1){ x.p.pes_hlength = 0; } else { x.p.mpeg1_headr = new uint8_t[x.p.mpeg1_pad]; x.p.pes_hlength = x.p.mpeg1_pad; stream.read((char *)x.p.mpeg1_headr, x.p.mpeg1_pad); } x.p.flags2 = (check & 0xF0) << 2; if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ stream.read((char *)x.p.pts,5); x.p.length -= 5; x.p.pes_hlength += 5; } else if ((x.p.flags2 & PTS_DTS_FLAGS) == PTS_DTS){ stream.read((char *)x.p.pts,5); stream.read((char *)x.p.dts,5); x.p.length -= 10; x.p.pes_hlength += 10; } } else { x.p.mpeg1_headr = new uint8_t[x.p.mpeg1_pad]; x.p.pes_hlength = x.p.mpeg1_pad; stream.read((char *)x.p.mpeg1_headr,x.p.mpeg1_pad); } } stream.read((char *)x.p.pes_pckt_data,x.p.length); } return stream; } ostream & operator << (ostream & stream, TS_Packet & x){ uint8_t buf[TS_SIZE]; int length = cwrite_ts(buf,&(x.p),TS_SIZE); stream.write((char *)buf,length); return stream; } istream & operator >> (istream & stream, TS_Packet & x){ uint8_t sync; int found=0; streampos p,q; sync=0; while (!stream.eof() && !found) { stream.read((char *)&sync,1); if (sync == 0x47) found = 1; } stream.read((char *)x.p.pid,2); stream.read((char *)&x.p.flags,1); x.p.count = x.p.flags & COUNT_MASK; if (!(x.p.flags & ADAPT_FIELD) && (x.p.flags & PAYLOAD)){ //no adapt. field only payload stream.read((char *)x.p.data,184); x.p.rest = 184; return stream; } if ( x.p.flags & ADAPT_FIELD ) { // adaption field stream.read((char *)&x.p.adapt_length,1); if (x.p.adapt_length){ p = stream.tellg(); stream.read((char *)&x.p.adapt_flags,1); if ( x.p.adapt_flags & PCR_FLAG ) stream.read((char *) x.p.pcr,6); if ( x.p.adapt_flags & OPCR_FLAG ) stream.read((char *) x.p.opcr,6); if ( x.p.adapt_flags & SPLICE_FLAG ) stream.read((char *) &x.p.splice_count,1); if( x.p.adapt_flags & TRANS_PRIV){ stream.read((char *)&x.p.priv_dat_len,1); x.p.priv_dat = new uint8_t[x.p.priv_dat_len]; stream.read((char *)x.p.priv_dat,x.p.priv_dat_len); } if( x.p.adapt_flags & ADAP_EXT_FLAG){ stream.read((char *)&x.p.adapt_ext_len,1); stream.read((char *)&x.p.adapt_eflags,1); if( x.p.adapt_eflags & LTW_FLAG) stream.read((char *)x.p.ltw,2); if( x.p.adapt_eflags & PIECE_RATE) stream.read((char *)x.p.piece_rate,3); if( x.p.adapt_eflags & SEAM_SPLICE) stream.read((char *)x.p.dts,5); } q = stream.tellg(); x.p.stuffing = x.p.adapt_length -(q-p); x.p.rest = 183-x.p.adapt_length; stream.seekg(q+streampos(x.p.stuffing)); if (x.p.flags & PAYLOAD) // payload stream.read((char *)x.p.data,x.p.rest); else stream.seekg(q+streampos(x.p.rest)); } else { x.p.rest = 182; stream.read((char *)x.p.data, 183); return stream; } } return stream; } ostream & operator << (ostream & stream, PS_Packet & x){ uint8_t buf[PS_MAX]; int length = cwrite_ps(buf,&(x.p),PS_MAX); stream.write((char *)buf,length); return stream; } istream & operator >> (istream & stream, PS_Packet & x){ uint8_t headr[4]; int found=0; streampos p = 0; streampos q = 0; int count = 0; p = stream.tellg(); while (!stream.eof() && !found && count < MAX_SEARCH) { stream.read((char *)&headr,4); if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01) if ( headr[3] == 0xBA ) found = 1; else if ( headr[3] == 0xB9 ) break; else stream.seekg(p+streampos(1)); count++; } if (found){ stream.read((char *)x.p.scr,6); if (x.p.scr[0] & 0x40) x.p.mpeg = 2; else x.p.mpeg = 1; if (x.p.mpeg == 2){ stream.read((char *)x.p.mux_rate,3); stream.read((char *)&x.p.stuff_length,1); p = stream.tellg(); stream.seekg(p+streampos(x.p.stuff_length & 3)); } else { x.p.mux_rate[0] = x.p.scr[5]; //mpeg1 scr is only 5 bytes stream.read((char *)x.p.mux_rate+1,2); } p=stream.tellg(); stream.read((char *)headr,4); if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] == 0xBB ) { stream.read((char *)x.p.sheader_llength,2); x.setlength(); if (x.p.mpeg == 2){ stream.read((char *)x.p.rate_bound,3); stream.read((char *)&x.p.audio_bound,1); stream.read((char *)&x.p.video_bound,1); stream.read((char *)&x.p.reserved,1); } stream.read((char *)x.p.data,x.p.sheader_length); } else { stream.seekg(p); x.p.sheader_length = 0; } int i = 0; int done = 0; q = stream.tellg(); PES_Packet pes; do { p=stream.tellg(); stream.read((char *)headr,4); stream.seekg(p); if ( headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] != 0xBA){ pes.init(); stream >> pes; i++; } else done = 1; } while (!stream.eof() && !done); x.p.npes = i; stream.seekg(q); } return stream; } void extract_audio_from_PES(istream &in, ostream &out){ PES_Packet pes; while(!in.eof()){ pes.init(); in >> pes ; if (pes.Stream_ID() == 0xC0) out << pes; } } void extract_video_from_PES(istream &in, ostream &out){ PES_Packet pes; while(!in.eof()){ pes.init(); in >> pes ; if (pes.Stream_ID() == 0xE0) out << pes; } } void extract_es_audio_from_PES(istream &in, ostream &out){ PES_Packet pes; while(!in.eof()){ pes.init(); in >> pes ; if (pes.Stream_ID() == 0xC0) out.write((char *)pes.Data(),pes.Length()); } } void extract_es_video_from_PES(istream &in, ostream &out){ PES_Packet pes; while(!in.eof()){ pes.init(); in >> pes ; if (pes.Stream_ID() == 0xE0) out.write((char *)pes.Data(),pes.Length()); } } #define MAX_PID 20 int TS_PIDS(istream &in, ostream &out){ int pid[MAX_PID]; TS_Packet ts; int npid=0; for (int i=0 ; i> ts; int j; int found = 0; for (j=0;j> 4 | headr[0] << 4; vsize = (headr[1] &0x0F) << 8 | headr[2]; cerr << "SIZE: " << hsize << "x" << vsize << endl; switch(((headr[3]&0xF0) >>4)){ case 1: cerr << "ASPECT: 1:1" << endl; break; case 2: cerr << "ASPECT: 4:3" << endl; break; case 3: cerr << "ASPECT: 16:9" << endl; break; case 4: cerr << "ASPECT: 2.21:1" << endl; break; } switch (int(headr[3]&0x0F)){ case 1: cerr << "FRAMERATE: 23.976" << endl; form = pDUNNO; break; case 2: cerr << "FRAMERATE: 24" << endl; form = pDUNNO; break; case 3: cerr << "FRAMERATE: 25" << endl; form = pPAL; break; case 4: cerr << "FRAMERATE: 29.97" << endl; form = pNTSC; break; case 5: cerr << "FRAMERATE: 30" << endl; form = pNTSC; break; case 6: cerr << "FRAMERATE: 50" << endl; form = pPAL; break; case 7: cerr << "FRAMERATE: 59.94" << endl; form = pNTSC; break; case 8: cerr << "FRAMERATE: 60" << endl; form = pNTSC; break; } int mpeg = 0; found = 0; while (!stream.eof() && !found) { p = stream.tellg(); stream.read((char *)headr,4); if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01) if ( headr[3] == 0xB5 ){ char *profile[] = {"reserved", "High", "Spatially Scalable", "SNR Scalable", "Main", "Simple", "undef", "undef"}; char *level[] = {"res", "res", "res", "res", "High","res", "High 1440", "res", "Main","res", "Low", "res", "res", "res", "res", "res"}; char *chroma[] = {"res", "4:2:0", "4:2:2", "4:4:4:"}; mpeg = 2; stream.read((char *)headr,4); cerr << "PROFILE: " << profile[headr[0] & 0x7] << endl; cerr << "LEVEL: " << level[headr[1]>>4 & 0xF] << endl; cerr << "CHROMA: " << chroma[headr[1]>>1 & 0x3] << endl; found = 1; } else { mpeg = 1; found = 1; } if (! found) stream.seekg(p+streampos(1)); } stream.seekg(q); return (form | mpeg << 4); } int stream_type(istream &fin){ uint8_t headr[4]; streampos p=fin.tellg(); TS_Packet ts; fin >> ts; fin.read((char *)headr,1); fin.seekg(p); if(fin && headr[0] == 0x47){ return TS_STREAM; } PS_Packet ps; fin >> ps; PES_Packet pes; for(int j=0;j < ps.NPES();j++){ fin >> pes; } fin.read((char *)headr,4); fin.seekg(p); if (fin && headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] == 0xBA){ return PS_STREAM; } fin >> pes; fin.read((char *)!headr,4); fin.seekg(p); if (fin && headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 ){ int found = 0; switch ( headr[3] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: found = 1; break; } if (found){ return PES_STREAM; } } return -1; } void analyze(istream &fin) { PS_Packet ps; PES_Packet pes; int fc = 0; char *frames[3] = {"I-Frame","P-Frame","B-Frame"}; while(fin){ uint32_t pts; fin >> ps; cerr << "SCR base: " << hex << setw(5) << setfill('0') \ << ps.SCR_base() << " " << dec << "ext : " << ps.SCR_ext(); cerr << " MUX rate: " << ps.MUX()*50*8/1000000.0 << " Mbit/s "; cerr << "RATE bound: " << ps.Rate()*50*8/1000000.0 << " Mbit/s" << endl; cerr << " Audio bound: " << hex << "0x" << int(ps.P()->audio_bound); cerr << " Video bound: " << hex << "0x" << int(ps.P()->video_bound) << dec << endl; cerr << endl; for (int i=0; i < ps.NPES(); i++){ pes.init(); fin >> pes; pts2pts((uint8_t *)&pts,pes.PTS()); pes.Info() = 1; cerr << pes; uint8_t *buf = pes.P()->pes_pckt_data; int c = 0; int l; switch (pes.P()->stream_id){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: l=pes.P()->length; break; default: l = 0; break; } while ( c < l - 6){ if (buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0xB8) { c += 4; cerr << "TIME hours: " << int((buf[c]>>2)& 0x1F) << " minutes: " << int(((buf[c]<<4)& 0x30)| ((buf[c+1]>>4)& 0x0F)) << " seconds: " << int(((buf[c+1]<<3)& 0x38)| ((buf[c+2]>>5)& 0x0F)) << endl; } if ( buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0x00) { fc++; c += 4; cerr << "picture: " << fc << " (" << frames[((buf[c+1]&0x38) >>3)-1] << ")" << endl << endl; } else c++; } } } } libdvb-0.5.5.1/libdvbmpeg/ctools.c0000644000175000017500000013715410220016115016613 0ustar mocmmocm00000000000000/* * dvb-mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * Copyright (C) 2002 Marcus Metzler * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at mocm@metzlerbros.de, */ #include "ctools.h" #define MAX_SEARCH 1024 * 1024 /* PES */ ssize_t save_read(int fd, void *buf, size_t count) { ssize_t neof = 1; size_t re = 0; while(neof >= 0 && re < count){ neof = read(fd, buf+re, count - re); if (neof > 0) re += neof; else break; } if (neof < 0 && re == 0) return neof; else return re; } void init_pes(pes_packet *p){ p->stream_id = 0; p->llength[0] = 0; p->llength[1] = 0; p->length = 0; p->flags1 = 0x80; p->flags2 = 0; p->pes_hlength = 0; p->trick = 0; p->add_cpy = 0; p->priv_flags = 0; p->pack_field_length = 0; p->pack_header = (uint8_t *) NULL; p->pck_sqnc_cntr = 0; p->org_stuff_length = 0; p->pes_ext_lngth = 0; p->pes_ext = (uint8_t *) NULL; p->pes_pckt_data = (uint8_t *) NULL; p->padding = 0; p->mpeg = 2; // DEFAULT MPEG2 p->mpeg1_pad = 0; p->mpeg1_headr = NULL; p->stuffing = 0; } void kill_pes(pes_packet *p){ if (p->pack_header) free(p->pack_header); if (p->pes_ext) free(p->pes_ext); if (p->pes_pckt_data) free(p->pes_pckt_data); if (p->mpeg1_headr) free(p->mpeg1_headr); init_pes(p); } void setlength_pes(pes_packet *p){ short *ll; ll = (short *) p->llength; p->length = ntohs(*ll); } static void setl_pes(pes_packet *p){ setlength_pes(p); if (p->length) p->pes_pckt_data = (uint8_t *)malloc(p->length); } void nlength_pes(pes_packet *p){ if (p->length <= 0xFFFF){ short *ll = (short *) p->llength; short l = p->length; *ll = htons(l); } else { p->llength[0] =0x00; p->llength[1] =0x00; } } static void nl_pes(pes_packet *p) { nlength_pes(p); p->pes_pckt_data = (uint8_t *) malloc(p->length); } void pts2pts(uint8_t *av_pts, uint8_t *pts) { av_pts[0] = ((pts[0] & 0x06) << 5) | ((pts[1] & 0xFC) >> 2); av_pts[1] = ((pts[1] & 0x03) << 6) | ((pts[2] & 0xFC) >> 2); av_pts[2] = ((pts[2] & 0x02) << 6) | ((pts[3] & 0xFE) >> 1); av_pts[3] = ((pts[3] & 0x01) << 7) | ((pts[4] & 0xFE) >> 1); } int cwrite_pes(uint8_t *buf, pes_packet *p, long length){ int count,i; uint8_t dummy; int more = 0; uint8_t headr[3] = { 0x00, 0x00 , 0x01}; if (length < p->length+p->pes_hlength){ fprintf(stderr,"Wrong buffer size in cwrite_pes\n"); exit(1); } memcpy(buf,headr,3); count = 3; buf[count] = p->stream_id; count++; switch ( p->stream_id ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : buf[count] = p->llength[0]; count++; buf[count] = p->llength[1]; count++; memcpy(buf+count,p->pes_pckt_data,p->length); count += p->length; break; case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: buf[count] = p->llength[0]; count++; buf[count] = p->llength[1]; count++; more = 1; break; } if ( more ) { if ( p->mpeg == 2 ){ memcpy(buf+count,&p->flags1,1); count++; memcpy(buf+count,&p->flags2,1); count++; memcpy(buf+count,&p->pes_hlength,1); count++; if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(buf+count,p->pts,5); count += 5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(buf+count,p->pts,5); count += 5; memcpy(buf+count,p->dts,5); count += 5; } if (p->flags2 & ESCR_FLAG){ memcpy(buf+count,p->escr,6); count += 6; } if (p->flags2 & ES_RATE_FLAG){ memcpy(buf+count,p->es_rate,3); count += 3; } if (p->flags2 & DSM_TRICK_FLAG){ memcpy(buf+count,&p->trick,1); count++; } if (p->flags2 & ADD_CPY_FLAG){ memcpy(buf+count,&p->add_cpy,1); count++; } if (p->flags2 & PES_CRC_FLAG){ memcpy(buf+count,p->prev_pes_crc,2); count += 2; } if (p->flags2 & PES_EXT_FLAG){ memcpy(buf+count,&p->priv_flags,1); count++; if (p->priv_flags & PRIVATE_DATA){ memcpy(buf+count,p->pes_priv_data,16); count += 16; } if (p->priv_flags & HEADER_FIELD){ memcpy(buf+count,&p->pack_field_length, 1); count++; memcpy(buf+count,p->pack_header, p->pack_field_length); count += p->pack_field_length; } if ( p->priv_flags & PACK_SEQ_CTR){ memcpy(buf+count,&p->pck_sqnc_cntr,1); count++; memcpy(buf+count,&p->org_stuff_length, 1); count++; } if ( p->priv_flags & P_STD_BUFFER){ memcpy(buf+count,p->p_std,2); count += 2; } if ( p->priv_flags & PES_EXT_FLAG2){ memcpy(buf+count,&p->pes_ext_lngth,1); count++; memcpy(buf+count,p->pes_ext, p->pes_ext_lngth); count += p->pes_ext_lngth; } } dummy = 0xFF; for (i=0;istuffing;i++) { memcpy(buf+count,&dummy,1); count++; } } else { if (p->mpeg1_pad){ memcpy(buf+count,p->mpeg1_headr,p->mpeg1_pad); count += p->mpeg1_pad; } if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(buf+count,p->pts,5); count += 5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(buf+count,p->pts,5); count += 5; memcpy(buf+count,p->dts,5); count += 5; } } memcpy(buf+count,p->pes_pckt_data,p->length); count += p->length; } return count; } void write_pes(int fd, pes_packet *p){ long length; uint8_t *buf; int l = p->length+p->pes_hlength; buf = (uint8_t *) malloc(l); length = cwrite_pes(buf,p,l); write(fd,buf,length); free(buf); } static unsigned int find_length(int f){ uint64_t p = 0; uint64_t start = 0; uint64_t q = 0; int found = 0; uint8_t sync4[4]; int neof = 1; start = lseek(f,0,SEEK_CUR); start -=2; lseek(f,start,SEEK_SET); while ( neof > 0 && !found ){ p = lseek(f,0,SEEK_CUR); neof = save_read(f,&sync4,4); if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { switch ( sync4[3] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: found = 1; break; default: q = lseek(f,0,SEEK_CUR); break; } } } q = lseek(f,0,SEEK_CUR); lseek(f,start+2,SEEK_SET); if (found) return (unsigned int)(q-start)-4-2; else return (unsigned int)(q-start-2); } void cread_pes(char *buf, pes_packet *p){ uint8_t count, dummy, check; int i; uint64_t po = 0; int c=0; switch ( p->stream_id ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : memcpy(p->pes_pckt_data,buf+c,p->length); return; break; case PADDING_STREAM : p->padding = p->length; memcpy(p->pes_pckt_data,buf+c,p->length); return; break; case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: break; default: return; break; } po = c; memcpy(&p->flags1,buf+c,1); c++; if ( (p->flags1 & 0xC0) == 0x80 ) p->mpeg = 2; else p->mpeg = 1; if ( p->mpeg == 2 ){ memcpy(&p->flags2,buf+c,1); c++; memcpy(&p->pes_hlength,buf+c,1); c++; p->length -=p->pes_hlength+3; count = p->pes_hlength; if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(p->pts,buf+c,5); c += 5; count -=5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(p->pts,buf+c,5); c += 5; memcpy(p->dts,buf+c,5); c += 5; count -= 10; } if (p->flags2 & ESCR_FLAG){ memcpy(p->escr,buf+c,6); c += 6; count -= 6; } if (p->flags2 & ES_RATE_FLAG){ memcpy(p->es_rate,buf+c,3); c += 3; count -= 3; } if (p->flags2 & DSM_TRICK_FLAG){ memcpy(&p->trick,buf+c,1); c += 1; count -= 1; } if (p->flags2 & ADD_CPY_FLAG){ memcpy(&p->add_cpy,buf+c,1); c++; count -= 1; } if (p->flags2 & PES_CRC_FLAG){ memcpy(p->prev_pes_crc,buf+c,2); c += 2; count -= 2; } if (p->flags2 & PES_EXT_FLAG){ memcpy(&p->priv_flags,buf+c,1); c++; count -= 1; if (p->priv_flags & PRIVATE_DATA){ memcpy(p->pes_priv_data,buf+c,16); c += 16; count -= 16; } if (p->priv_flags & HEADER_FIELD){ memcpy(&p->pack_field_length,buf+c,1); c++; p->pack_header = (uint8_t *) malloc(p->pack_field_length); memcpy(p->pack_header,buf+c, p->pack_field_length); c += p->pack_field_length; count -= 1+p->pack_field_length; } if ( p->priv_flags & PACK_SEQ_CTR){ memcpy(&p->pck_sqnc_cntr,buf+c,1); c++; memcpy(&p->org_stuff_length,buf+c,1); c++; count -= 2; } if ( p->priv_flags & P_STD_BUFFER){ memcpy(p->p_std,buf+c,2); c += 2; count -= 2; } if ( p->priv_flags & PES_EXT_FLAG2){ memcpy(&p->pes_ext_lngth,buf+c,1); c++; p->pes_ext = (uint8_t *) malloc(p->pes_ext_lngth); memcpy(p->pes_ext,buf+c, p->pes_ext_lngth); c += p->pes_ext_lngth; count -= 1+p->pes_ext_lngth; } } p->stuffing = count; for(i = 0; i< count ;i++){ memcpy(&dummy,buf+c,1); c++; } } else { p->mpeg1_pad = 1; check = p->flags1; while (check == 0xFF){ memcpy(&check,buf+c,1); c++; p->mpeg1_pad++; } if ( (check & 0xC0) == 0x40){ memcpy(&check,buf+c,1); c++; p->mpeg1_pad++; memcpy(&check,buf+c,1); c++; p->mpeg1_pad++; } p->flags2 = 0; p->length -= p->mpeg1_pad; c = po; if ( (check & 0x30)){ p->length ++; p->mpeg1_pad --; if (check == p->flags1){ p->pes_hlength = 0; } else { p->mpeg1_headr = (uint8_t *) malloc(p->mpeg1_pad); p->pes_hlength = p->mpeg1_pad; memcpy(p->mpeg1_headr,buf+c, p->mpeg1_pad); c += p->mpeg1_pad; } p->flags2 = (check & 0xF0) << 2; if ((p->flags2 & PTS_DTS_FLAGS) == PTS_ONLY){ memcpy(p->pts,buf+c,5); c += 5; p->length -= 5; p->pes_hlength += 5; } else if ((p->flags2 & PTS_DTS_FLAGS) == PTS_DTS){ memcpy(p->pts,buf+c,5); c += 5; memcpy(p->dts,buf+c,5); c += 5; p->length -= 10; p->pes_hlength += 10; } } else { p->mpeg1_headr = (uint8_t *) malloc(p->mpeg1_pad); p->pes_hlength = p->mpeg1_pad; memcpy(p->mpeg1_headr,buf+c, p->mpeg1_pad); c += p->mpeg1_pad; } } memcpy(p->pes_pckt_data,buf+c,p->length); } int read_pes(int f, pes_packet *p){ uint8_t sync4[4]; int found=0; uint64_t po = 0; int neof = 1; uint8_t *buf; while (neof > 0 && !found) { po = lseek(f,0,SEEK_CUR); if (po < 0) return -1; if ((neof = save_read(f,&sync4,4)) < 4) return -1; if (sync4[0] == 0x00 && sync4[1] == 0x00 && sync4[2] == 0x01) { p->stream_id = sync4[3]; switch ( sync4[3] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: if((neof = save_read(f,p->llength,2)) < 2) return -1; setl_pes(p); if (!p->length){ p->length = find_length(f); nl_pes(p); } found = 1; break; default: if (lseek(f,po+1,SEEK_SET) < po+1) return -1; break; } } else if(lseek(f,po+1,SEEK_SET) < po+1) return -1; } if (!found || !p->length) return 0; if (p->length >0){ buf = (uint8_t *) malloc(p->length); if((neof = save_read(f,buf,p->length))< p->length) return -1; cread_pes((char *)buf,p); free(buf); } else return 0; return neof; } /* Transport Stream */ void init_ts(ts_packet *p){ p->pid[0] = 0; p->pid[1] = 0; p->flags = 0; p->count = 0; p->adapt_length = 0; p->adapt_flags = 0; p->splice_count = 0; p->priv_dat_len = 0; p->priv_dat = NULL; p->adapt_ext_len = 0; p->adapt_eflags = 0; p->rest = 0; p->stuffing = 0; } void kill_ts(ts_packet *p){ if (p->priv_dat) free(p->priv_dat); init_ts(p); } unsigned short pid_ts(ts_packet *p) { return get_pid(p->pid); } int cwrite_ts(uint8_t *buf, ts_packet *p, long length){ long count,i; uint8_t sync,dummy; sync = 0x47; memcpy(buf,&sync,1); count = 1; memcpy(buf+count,p->pid,2); count += 2; memcpy(buf+count,&p->flags,1); count++; if (! (p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ memcpy(buf+count,p->data,184); count += 184; } else { memcpy(buf+count,&p->adapt_length,1); count++; memcpy(buf+count,&p->adapt_flags,1); count++; if ( p->adapt_flags & PCR_FLAG ){ memcpy(buf+count, p->pcr,6); count += 6; } if ( p->adapt_flags & OPCR_FLAG ){ memcpy(buf+count, p->opcr,6); count += 6; } if ( p->adapt_flags & SPLICE_FLAG ){ memcpy(buf+count, &p->splice_count,1); count++; } if( p->adapt_flags & TRANS_PRIV){ memcpy(buf+count,&p->priv_dat_len,1); count++; memcpy(buf+count,p->priv_dat,p->priv_dat_len); count += p->priv_dat_len; } if( p->adapt_flags & ADAP_EXT_FLAG){ memcpy(buf+count,&p->adapt_ext_len,1); count++; memcpy(buf+count,&p->adapt_eflags,1); count++; if( p->adapt_eflags & LTW_FLAG){ memcpy(buf+count,p->ltw,2); count += 2; } if( p->adapt_eflags & PIECE_RATE){ memcpy(buf+count,p->piece_rate,3); count += 3; } if( p->adapt_eflags & SEAM_SPLICE){ memcpy(buf+count,p->dts,5); count += 5; } } dummy = 0xFF; for(i=0; i < p->stuffing ; i++){ memcpy(buf+count,&dummy,1); count++; } if (p->flags & PAYLOAD){ memcpy(buf+count,p->data,p->rest); count += p->rest; } } return count; } void write_ts(int fd, ts_packet *p){ long length; uint8_t buf[TS_SIZE]; length = cwrite_ts(buf,p,TS_SIZE); write(fd,buf,length); } int read_ts (int f, ts_packet *p){ uint8_t sync; int found=0; uint64_t po,q; int neof = 1; sync=0; while (neof > 0 && !found) { neof = save_read(f,&sync,1); if (sync == 0x47) found = 1; } neof = save_read(f,p->pid,2); neof = save_read(f,&p->flags,1); p->count = p->flags & COUNT_MASK; if (!(p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ //no adapt. field only payload neof = save_read(f,p->data,184); p->rest = 184; return neof; } if ( p->flags & ADAPT_FIELD ) { // adaption field neof = save_read(f,&p->adapt_length,1); po = lseek(f,0,SEEK_CUR); neof = save_read(f,&p->adapt_flags,1); if ( p->adapt_flags & PCR_FLAG ) neof = save_read(f, p->pcr,6); if ( p->adapt_flags & OPCR_FLAG ) neof = save_read(f, p->opcr,6); if ( p->adapt_flags & SPLICE_FLAG ) neof = save_read(f, &p->splice_count,1); if( p->adapt_flags & TRANS_PRIV){ neof = save_read(f,&p->priv_dat_len,1); p->priv_dat = (uint8_t *) malloc(p->priv_dat_len); neof = save_read(f,p->priv_dat,p->priv_dat_len); } if( p->adapt_flags & ADAP_EXT_FLAG){ neof = save_read(f,&p->adapt_ext_len,1); neof = save_read(f,&p->adapt_eflags,1); if( p->adapt_eflags & LTW_FLAG) neof = save_read(f,p->ltw,2); if( p->adapt_eflags & PIECE_RATE) neof = save_read(f,p->piece_rate,3); if( p->adapt_eflags & SEAM_SPLICE) neof = save_read(f,p->dts,5); } q = lseek(f,0,SEEK_CUR); p->stuffing = p->adapt_length -(q-po); p->rest = 183-p->adapt_length; lseek(f,q+p->stuffing,SEEK_SET); if (p->flags & PAYLOAD) // payload neof = save_read(f,p->data,p->rest); else lseek(f,q+p->rest,SEEK_SET); } return neof; } void cread_ts (char *buf, ts_packet *p, long length){ uint8_t sync; int found=0; uint64_t po,q; long count=0; sync=0; while (count < length && !found) { sync=buf[count]; count++; if (sync == 0x47) found = 1; } memcpy(p->pid,buf+count,2); count += 2; p->flags = buf[count]; count++; p->count = p->flags & COUNT_MASK; if (!(p->flags & ADAPT_FIELD) && (p->flags & PAYLOAD)){ //no adapt. field only payload memcpy(p->data,buf+count,184); p->rest = 184; return; } if ( p->flags & ADAPT_FIELD ) { // adaption field p->adapt_length = buf[count]; count++; po = count; memcpy(&p->adapt_flags,buf+count,1); count++; if ( p->adapt_flags & PCR_FLAG ){ memcpy( p->pcr,buf+count,6); count += 6; } if ( p->adapt_flags & OPCR_FLAG ){ memcpy( p->opcr,buf+count,6); count += 6; } if ( p->adapt_flags & SPLICE_FLAG ){ memcpy( &p->splice_count,buf+count,1); count++; } if( p->adapt_flags & TRANS_PRIV){ memcpy(&p->priv_dat_len,buf+count,1); count++; p->priv_dat = (uint8_t *) malloc(p->priv_dat_len); memcpy(p->priv_dat,buf+count,p->priv_dat_len); count += p->priv_dat_len; } if( p->adapt_flags & ADAP_EXT_FLAG){ memcpy(&p->adapt_ext_len,buf+count,1); count++; memcpy(&p->adapt_eflags,buf+count,1); count++; if( p->adapt_eflags & LTW_FLAG){ memcpy(p->ltw,buf+count,2); count += 2; } if( p->adapt_eflags & PIECE_RATE){ memcpy(p->piece_rate,buf+count,3); count += 3; } if( p->adapt_eflags & SEAM_SPLICE){ memcpy(p->dts,buf+count,5); count += 5; } } q = count; p->stuffing = p->adapt_length -(q-po); p->rest = 183-p->adapt_length; count = q+p->stuffing; if (p->flags & PAYLOAD){ // payload memcpy(p->data,buf+count,p->rest); count += p->rest; } else count = q+p->rest; } } /* Program Stream */ void init_ps(ps_packet *p) { p->stuff_length=0xF8; p->data = NULL; p->sheader_length = 0; p->audio_bound = 0; p->video_bound = 0; p->npes = 0; p->mpeg = 2; } void kill_ps(ps_packet *p) { if (p->data) free(p->data); init_ps(p); } void setlength_ps(ps_packet *p) { short *ll; ll = (short *) p->sheader_llength; if (p->mpeg == 2) p->sheader_length = ntohs(*ll) - 6; else p->sheader_length = ntohs(*ll); } static void setl_ps(ps_packet *p) { setlength_ps(p); p->data = (uint8_t *) malloc(p->sheader_length); } int mux_ps(ps_packet *p) { uint32_t mux = 0; uint8_t *i = (uint8_t *)&mux; i[1] = p->mux_rate[0]; i[2] = p->mux_rate[1]; i[3] = p->mux_rate[2]; mux = ntohl(mux); mux = (mux >>2); return mux; } int rate_ps(ps_packet *p) { uint32_t rate=0; uint8_t *i= (uint8_t *) &rate; i[1] = p->rate_bound[0] & 0x7F; i[2] = p->rate_bound[1]; i[3] = p->rate_bound[2]; rate = ntohl(rate); rate = (rate >> 1); return rate; } uint32_t scr_base_ps(ps_packet *p) // only 32 bit!! { uint32_t base = 0; uint8_t *buf = (uint8_t *)&base; buf[0] |= (long int)((p->scr[0] & 0x18) << 3); buf[0] |= (long int)((p->scr[0] & 0x03) << 4); buf[0] |= (long int)((p->scr[1] & 0xF0) >> 4); buf[1] |= (long int)((p->scr[1] & 0x0F) << 4); buf[1] |= (long int)((p->scr[2] & 0xF0) >> 4); buf[2] |= (long int)((p->scr[2] & 0x08) << 4); buf[2] |= (long int)((p->scr[2] & 0x03) << 5); buf[2] |= (long int)((p->scr[3] & 0xF8) >> 3); buf[3] |= (long int)((p->scr[3] & 0x07) << 5); buf[3] |= (long int)((p->scr[4] & 0xF8) >> 3); base = ntohl(base); return base; } uint16_t scr_ext_ps(ps_packet *p) { short ext = 0; ext = (short)(p->scr[5] >> 1); ext += (short) (p->scr[4] & 0x03) * 128; return ext; } int cwrite_ps(uint8_t *buf, ps_packet *p, long length) { long count,i; uint8_t headr1[4] = {0x00, 0x00, 0x01, 0xBA }; uint8_t headr2[4] = {0x00, 0x00, 0x01, 0xBB }; uint8_t buffy = 0xFF; memcpy(buf,headr1,4); count = 4; if (p->mpeg == 2){ memcpy(buf+count,p->scr,6); count += 6; memcpy(buf+count,p->mux_rate,3); count += 3; memcpy(buf+count,&p->stuff_length,1); count++; for(i=0; i< (p->stuff_length & 3); i++){ memcpy(buf+count,&buffy,1); count++; } } else { memcpy(buf+count,p->scr,5); count += 5; memcpy(buf+count,p->mux_rate,3); count += 3; } if (p->sheader_length){ memcpy(buf+count,headr2,4); count += 4; memcpy(buf+count,p->sheader_llength,2); count += 2; if ( p->mpeg == 2){ memcpy(buf+count,p->rate_bound,3); count += 3; memcpy(buf+count,&p->audio_bound,1); count++; memcpy(buf+count,&p->video_bound,1); count++; memcpy(buf+count,&p->reserved,1); count++; } memcpy(buf+count,p->data,p->sheader_length); count += p->sheader_length; } return count; } void write_ps(int fd, ps_packet *p){ long length; uint8_t buf[PS_MAX]; length = cwrite_ps(buf,p,PS_MAX); write(fd,buf,length); } int read_ps (int f, ps_packet *p){ uint8_t headr[4]; pes_packet pes; int i,done; int found=0; uint64_t po = 0; uint64_t q = 0; long count = 0; int neof = 1; po = lseek(f,0,SEEK_CUR); while (neof > 0 && !found && count < MAX_SEARCH) { neof = save_read(f,&headr,4); if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01){ if ( headr[3] == 0xBA ) found = 1; else if ( headr[3] == 0xB9 ) break; else lseek(f,po+1,SEEK_SET); } count++; } if (found){ neof = save_read(f,p->scr,6); if (p->scr[0] & 0x40) p->mpeg = 2; else p->mpeg = 1; if (p->mpeg == 2){ neof = save_read(f,p->mux_rate,3); neof = save_read(f,&p->stuff_length,1); po = lseek(f,0,SEEK_CUR); lseek(f,po+(p->stuff_length & 3),SEEK_SET); } else { p->mux_rate[0] = p->scr[5]; //mpeg1 scr is only 5 bytes neof = save_read(f,p->mux_rate+1,2); } po = lseek(f,0,SEEK_CUR); neof = save_read(f,headr,4); if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] == 0xBB ) { neof = save_read(f,p->sheader_llength,2); setl_ps(p); if (p->mpeg == 2){ neof = save_read(f,p->rate_bound,3); neof = save_read(f,&p->audio_bound,1); neof = save_read(f,&p->video_bound,1); neof = save_read(f,&p->reserved,1); } neof = save_read(f,p->data,p->sheader_length); } else { lseek(f,po,SEEK_SET); p->sheader_length = 0; } i = 0; done = 0; q = lseek(f,0,SEEK_CUR); do { po = lseek(f,0,SEEK_CUR); neof = save_read(f,headr,4); lseek(f,po,SEEK_SET); if ( headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] != 0xBA){ init_pes(&pes); neof = read_pes(f,&pes); i++; } else done = 1; kill_pes(&pes); } while ( neof > 0 && !done); p->npes = i; lseek(f,q,SEEK_SET); } return neof; } void cread_ps (char *buf, ps_packet *p, long length){ uint8_t *headr; pes_packet pes; int i,done; int found=0; uint64_t po = 0; uint64_t q = 0; long count = 0; long c = 0; po = c; while ( count < length && !found && count < MAX_SEARCH) { headr = (uint8_t *)buf+c; c += 4; if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01){ if ( headr[3] == 0xBA ) found = 1; else if ( headr[3] == 0xB9 ) break; else c = po+1; } count++; } if (found){ memcpy(p->scr,buf+c,6); c += 6; if (p->scr[0] & 0x40) p->mpeg = 2; else p->mpeg = 1; if (p->mpeg == 2){ memcpy(p->mux_rate,buf+c,3); c += 3; memcpy(&p->stuff_length,buf+c,1); c++; po = c; c = po+(p->stuff_length & 3); } else { p->mux_rate[0] = p->scr[5]; //mpeg1 scr is only 5 bytes memcpy(p->mux_rate+1,buf+c,2); c += 2; } po = c; headr = (uint8_t *)buf+c; c += 4; if (headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] == 0xBB ) { memcpy(p->sheader_llength,buf+c,2); c += 2; setl_ps(p); if (p->mpeg == 2){ memcpy(p->rate_bound,buf+c,3); c += 3; memcpy(&p->audio_bound,buf+c,1); c++; memcpy(&p->video_bound,buf+c,1); c++; memcpy(&p->reserved,buf+c,1); c++; } memcpy(p->data,buf+c,p->sheader_length); c += p->sheader_length; } else { c = po; p->sheader_length = 0; } i = 0; done = 0; q = c; do { headr = (uint8_t *)buf+c; if ( headr[0] == 0x00 && headr[1] == 0x00 && headr[2] == 0x01 && headr[3] != 0xBA){ init_pes(&pes); // cread_pes(buf+c,&pes); i++; } else done = 1; kill_pes(&pes); } while (c < length && !done); p->npes = i; c = q; } } /* conversion */ void init_trans(trans *p) { int i; p->found = 0; p->pes = 0; p->is_full = 0; p->pes_start = 0; p->pes_started = 0; p->set = 0; for (i = 0; i < MASKL*MAXFILT ; i++){ p->mask[i] = 0; p->filt[i] = 0; } for (i = 0; i < MAXFILT ; i++){ p->sec[i].found = 0; p->sec[i].length = 0; } } int set_trans_filt(trans *p, int filtn, uint16_t pid, uint8_t *mask, uint8_t *filt, int pes) { int i; int off; if ( filtn > MAXFILT-1 || filtn<0 ) return -1; p->pid[filtn] = pid; if (pes) p->pes |= (tflags)(1 << filtn); else { off = MASKL*filtn; p->pes &= ~((tflags) (1 << filtn) ); for (i = 0; i < MASKL ; i++){ p->mask[off+i] = mask[i]; p->filt[off+i] = filt[i]; } } p->set |= (tflags) (1 << filtn); return 0; } void clear_trans_filt(trans *p,int filtn) { int i; p->set &= ~((tflags) (1 << filtn) ); p->pes &= ~((tflags) (1 << filtn) ); p->is_full &= ~((tflags) (1 << filtn) ); p->pes_start &= ~((tflags) (1 << filtn) ); p->pes_started &= ~((tflags) (1 << filtn) ); for (i = MASKL*filtn; i < MASKL*(filtn+1) ; i++){ p->mask[i] = 0; p->filt[i] = 0; } p->sec[filtn].found = 0; p->sec[filtn].length = 0; } int filt_is_set(trans *p, int filtn) { if (p->set & ((tflags)(1 << filtn))) return 1; return 0; } int pes_is_set(trans *p, int filtn) { if (p->pes & ((tflags)(1 << filtn))) return 1; return 0; } int pes_is_started(trans *p, int filtn) { if (p->pes_started & ((tflags)(1 << filtn))) return 1; return 0; } int pes_is_start(trans *p, int filtn) { if (p->pes_start & ((tflags)(1 << filtn))) return 1; return 0; } int filt_is_ready(trans *p,int filtn) { if (p->is_full & ((tflags)(1 << filtn))) return 1; return 0; } void trans_filt(uint8_t *buf, int count, trans *p) { int c=0; //fprintf(stderr,"trans_filt\n"); while (c < count && p->found <1 ){ if ( buf[c] == 0x47) p->found = 1; c++; p->packet[0] = 0x47; } if (c == count) return; while( c < count && p->found < 188 && p->found > 0 ){ p->packet[p->found] = buf[c]; c++; p->found++; } if (p->found == 188){ p->found = 0; tfilter(p); } if (c < count) trans_filt(buf+c,count-c,p); } void tfilter(trans *p) { int l,c; int tpid; uint8_t flag,flags; uint8_t adapt_length = 0; uint8_t cpid[2]; // fprintf(stderr,"tfilter\n"); cpid[0] = p->packet[1]; cpid[1] = p->packet[2]; tpid = get_pid(cpid); if ( p->packet[1]&0x80){ fprintf(stderr,"Error in TS for PID: %d\n", tpid); } flag = cpid[0]; flags = p->packet[3]; if ( flags & ADAPT_FIELD ) { // adaption field adapt_length = p->packet[4]; } c = 5 + adapt_length - (int)(!(flags & ADAPT_FIELD)); if (flags & PAYLOAD){ for ( l = 0; l < MAXFILT ; l++){ if ( filt_is_set(p,l) ) { if ( p->pid[l] == tpid) { if ( pes_is_set(p,l) ){ if (cpid[0] & PAY_START){ p->pes_started |= (tflags) (1 << l); p->pes_start |= (tflags) (1 << l); } else { p->pes_start &= ~ ((tflags) (1 << l)); } pes_filter(p,l,c); } else { sec_filter(p,l,c); } } } } } } void pes_filter(trans *p, int filtn, int off) { int count,c; uint8_t *buf; if (filtn < 0 || filtn >= MAXFILT) return; count = 188 - off; c = 188*filtn; buf = p->packet+off; if (pes_is_started(p,filtn)){ p->is_full |= (tflags) (1 << filtn); memcpy(p->transbuf+c,buf,count); p->transcount[filtn] = count; } } section *get_filt_sec(trans *p, int filtn) { section *sec; sec = &p->sec[filtn]; p->is_full &= ~((tflags) (1 << filtn) ); return sec; } int get_filt_buf(trans *p, int filtn,uint8_t **buf) { *buf = p->transbuf+188*filtn; p->is_full &= ~((tflags) (1 << filtn) ); return p->transcount[filtn]; } void sec_filter(trans *p, int filtn, int off) { int i,j; int error; int count,c; uint8_t *buf, *secbuf; section *sec; // fprintf(stderr,"sec_filter\n"); if (filtn < 0 || filtn >= MAXFILT) return; count = 188 - off; c = 0; buf = p->packet+off; sec = &p->sec[filtn]; secbuf = sec->payload; if(!filt_is_ready(p,filtn)){ p->is_full &= ~((tflags) (1 << filtn) ); sec->found = 0; sec->length = 0; } if ( !sec->found ){ c = buf[c]+1; if (c >= count) return; sec->id = buf[c]; secbuf[0] = buf[c]; c++; sec->found++; sec->length = 0; } while ( c < count && sec->found < 3){ secbuf[sec->found] = buf[c]; c++; sec->found++; } if (c == count) return; if (!sec->length && sec->found == 3){ sec->length |= ((secbuf[1] & 0x0F) << 8); sec->length |= (secbuf[2] & 0xFF); } while ( c < count && sec->found < sec->length+3){ secbuf[sec->found] = buf[c]; c++; sec->found++; } if ( sec->length && sec->found == sec->length+3 ){ error=0; for ( i = 0; i < MASKL; i++){ if (i > 0 ) j=2+i; else j = 0; error += (sec->payload[j]&p->mask[MASKL*filtn+i])^ (p->filt[MASKL*filtn+i]& p->mask[MASKL*filtn+i]); } if (!error){ p->is_full |= (tflags) (1 << filtn); } if (buf[0]+1 < c ) c=count; } if ( c < count ) sec_filter(p, filtn, off); } #define MULT 1024 void write_ps_headr( ps_packet *p, uint8_t *pts,int fd) { long muxr = 37500; uint8_t audio_bound = 1; uint8_t fixed = 0; uint8_t CSPS = 0; uint8_t audio_lock = 1; uint8_t video_lock = 1; uint8_t video_bound = 1; uint8_t stream1 = 0XC0; uint8_t buffer1_scale = 1; uint32_t buffer1_size = 32; uint8_t stream2 = 0xE0; uint8_t buffer2_scale = 1; uint32_t buffer2_size = 230; init_ps(p); p->mpeg = 2; // SCR = 0 p->scr[0] = 0x44; p->scr[1] = 0x00; p->scr[2] = 0x04; p->scr[3] = 0x00; p->scr[4] = 0x04; p->scr[5] = 0x01; // SCR = PTS p->scr[0] = 0x44 | ((pts[0] >> 3)&0x18) | ((pts[0] >> 4)&0x03); p->scr[1] = 0x00 | ((pts[0] << 4)&0xF0) | ((pts[1] >> 4)&0x0F); p->scr[2] = 0x04 | ((pts[1] << 4)&0xF0) | ((pts[2] >> 4)&0x08) | ((pts[2] >> 5)&0x03); p->scr[3] = 0x00 | ((pts[2] << 3)&0xF8) | ((pts[3] >> 5)&0x07); p->scr[4] = 0x04 | ((pts[3] << 3)&0xF8); p->scr[5] = 0x01; p->mux_rate[0] = (uint8_t)(muxr >> 14); p->mux_rate[1] = (uint8_t)(0xff & (muxr >> 6)); p->mux_rate[2] = (uint8_t)(0x03 | ((muxr & 0x3f) << 2)); p->stuff_length = 0xF8; p->sheader_llength[0] = 0x00; p->sheader_llength[1] = 0x0c; setl_ps(p); p->rate_bound[0] = (uint8_t)(0x80 | (muxr >>15)); p->rate_bound[1] = (uint8_t)(0xff & (muxr >> 7)); p->rate_bound[2] = (uint8_t)(0x01 | ((muxr & 0x7f)<<1)); p->audio_bound = (uint8_t)((audio_bound << 2)|(fixed << 1)|CSPS); p->video_bound = (uint8_t)((audio_lock << 7)| (video_lock << 6)|0x20|video_bound); p->reserved = (uint8_t)(0xFF); p->data[0] = stream2; p->data[1] = (uint8_t) (0xc0 | (buffer2_scale << 5) | (buffer2_size >> 8)); p->data[2] = (uint8_t) (buffer2_size & 0xff); p->data[3] = stream1; p->data[4] = (uint8_t) (0xc0 | (buffer1_scale << 5) | (buffer1_size >> 8)); p->data[5] = (uint8_t) (buffer1_size & 0xff); write_ps(fd, p); kill_ps(p); } void twrite(uint8_t const *buf) { int l = TS_SIZE; int c = 0; int w; while (l){ w = write(STDOUT_FILENO,buf+c,l); if (w>=0){ l-=w; c+=w; } } } void init_p2t(p2t_t *p, void (*fkt)(uint8_t const *buf)) { memset(p->pes,0,TS_SIZE); p->counter = 0; p->pos = 0; p->frags = 0; if (fkt) p->t_out = fkt; else p->t_out = twrite; } void clear_p2t(p2t_t *p) { memset(p->pes,0,TS_SIZE); p->counter = 0; p->pos = 0; p->frags = 0; } long int find_pes_header(uint8_t const *buf, long int length, int *frags) { int c = 0; int found = 0; *frags = 0; while (c < length-3 && !found) { if (buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01) { switch ( buf[c+3] ) { case 0xBA: case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: found = 1; break; default: c++; break; } } else c++; } if (c == length-3 && !found){ if (buf[length-1] == 0x00) *frags = 1; if (buf[length-2] == 0x00 && buf[length-1] == 0x00) *frags = 2; if (buf[length-3] == 0x00 && buf[length-2] == 0x00 && buf[length-1] == 0x01) *frags = 3; return -1; } return c; } void pes_to_ts( uint8_t const *buf, long int length, uint16_t pid, p2t_t *p) { int c,c2,l,add; int check,rest; c = 0; c2 = 0; if (p->frags){ check = 0; switch(p->frags){ case 1: if ( buf[c] == 0x00 && buf[c+1] == 0x01 ){ check = 1; c += 2; } break; case 2: if ( buf[c] == 0x01 ){ check = 1; c++; } break; case 3: check = 1; } if(check){ switch ( buf[c] ) { case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: p->pes[0] = 0x00; p->pes[1] = 0x00; p->pes[2] = 0x01; p->pes[3] = buf[c]; p->pos=4; memcpy(p->pes+p->pos,buf+c,TS_SIZE-4-p->pos); c += TS_SIZE-4-p->pos; p_to_t(p->pes,TS_SIZE-4,pid,&p->counter, p->t_out); clear_p2t(p); break; default: c=0; break; } } p->frags = 0; } if (p->pos){ c2 = find_pes_header(buf+c,length-c,&p->frags); if (c2 >= 0 && c2 < TS_SIZE-4-p->pos){ l = c2+c; } else l = TS_SIZE-4-p->pos; memcpy(p->pes+p->pos,buf,l); c += l; p->pos += l; p_to_t(p->pes,p->pos,pid,&p->counter, p->t_out); clear_p2t(p); } add = 0; while (c < length){ c2 = find_pes_header(buf+c+add,length-c-add,&p->frags); if (c2 >= 0) { c2 += c+add; if (c2 > c){ p_to_t(buf+c,c2-c,pid,&p->counter, p->t_out); c = c2; clear_p2t(p); add = 0; } else add = 1; } else { l = length-c; rest = l % (TS_SIZE-4); l -= rest; p_to_t(buf+c,l,pid,&p->counter, p->t_out); memcpy(p->pes,buf+c+l,rest); p->pos = rest; c = length; } } } void p_to_t( uint8_t const *buf, long int length, uint16_t pid, uint8_t *counter, void (*ts_write)(uint8_t const *)) { int l, pes_start; uint8_t obuf[TS_SIZE]; long int c = 0; pes_start = 0; if ( length > 3 && buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01 ) switch (buf[3]){ case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: pes_start = 1; break; default: break; } while ( c < length ){ memset(obuf,0,TS_SIZE); if (length - c >= TS_SIZE-4){ l = write_ts_header(pid, counter, pes_start , obuf, TS_SIZE-4); memcpy(obuf+l, buf+c, TS_SIZE-l); c += TS_SIZE-l; } else { l = write_ts_header(pid, counter, pes_start , obuf, length-c); memcpy(obuf+l, buf+c, TS_SIZE-l); c = length; } ts_write(obuf); pes_start = 0; } } int write_ps_header(uint8_t *buf, uint32_t SCR, long muxr, uint8_t audio_bound, uint8_t fixed, uint8_t CSPS, uint8_t audio_lock, uint8_t video_lock, uint8_t video_bound, uint8_t stream1, uint8_t buffer1_scale, uint32_t buffer1_size, uint8_t stream2, uint8_t buffer2_scale, uint32_t buffer2_size) { ps_packet p; uint8_t *pts; long lpts; init_ps(&p); lpts = htonl(SCR); pts = (uint8_t *) &lpts; p.mpeg = 2; // SCR = 0 p.scr[0] = 0x44; p.scr[1] = 0x00; p.scr[2] = 0x04; p.scr[3] = 0x00; p.scr[4] = 0x04; p.scr[5] = 0x01; // SCR = PTS p.scr[0] = 0x44 | ((pts[0] >> 3)&0x18) | ((pts[0] >> 4)&0x03); p.scr[1] = 0x00 | ((pts[0] << 4)&0xF0) | ((pts[1] >> 4)&0x0F); p.scr[2] = 0x04 | ((pts[1] << 4)&0xF0) | ((pts[2] >> 4)&0x08) | ((pts[2] >> 5)&0x03); p.scr[3] = 0x00 | ((pts[2] << 3)&0xF8) | ((pts[3] >> 5)&0x07); p.scr[4] = 0x04 | ((pts[3] << 3)&0xF8); p.scr[5] = 0x01; p.mux_rate[0] = (uint8_t)(muxr >> 14); p.mux_rate[1] = (uint8_t)(0xff & (muxr >> 6)); p.mux_rate[2] = (uint8_t)(0x03 | ((muxr & 0x3f) << 2)); p.stuff_length = 0xF8; if (stream1 && stream2){ p.sheader_llength[0] = 0x00; p.sheader_llength[1] = 0x0c; setl_ps(&p); p.rate_bound[0] = (uint8_t)(0x80 | (muxr >>15)); p.rate_bound[1] = (uint8_t)(0xff & (muxr >> 7)); p.rate_bound[2] = (uint8_t)(0x01 | ((muxr & 0x7f)<<1)); p.audio_bound = (uint8_t)((audio_bound << 2)|(fixed << 1)|CSPS); p.video_bound = (uint8_t)((audio_lock << 7)| (video_lock << 6)|0x20|video_bound); p.reserved = (uint8_t)(0xFF >> 1); p.data[0] = stream2; p.data[1] = (uint8_t) (0xc0 | (buffer2_scale << 5) | (buffer2_size >> 8)); p.data[2] = (uint8_t) (buffer2_size & 0xff); p.data[3] = stream1; p.data[4] = (uint8_t) (0xc0 | (buffer1_scale << 5) | (buffer1_size >> 8)); p.data[5] = (uint8_t) (buffer1_size & 0xff); cwrite_ps(buf, &p, PS_HEADER_L2); kill_ps(&p); return PS_HEADER_L2; } else { cwrite_ps(buf, &p, PS_HEADER_L1); kill_ps(&p); return PS_HEADER_L1; } } #define MAX_BASE 80 #define MAX_PATH 256 #define MAX_EXT 10 int break_up_filename(char *name, char *base_name, char *path, char *ext) { int l,i,sstop,sstart; l = strlen(name); sstop = l; sstart = -1; for( i= l-1; i >= 0; i--){ if (sstop == l && name[i] == '.') sstop = i; if (sstart<0 && name[i] == '/') sstart = i+1; } if (sstart < 0) sstart = 0; if (sstop-sstart < MAX_BASE){ strncpy(base_name, name+sstart, sstop-sstart); base_name[sstop-sstart]=0; if(sstart > 0){ if( l - sstop + sstart < MAX_PATH){ strncpy(path, name, sstart); path[sstart] = 0; } else { fprintf(stderr,"PATH too long\n"); return -1; } } else { strcpy(path, "./"); } if(sstop < l){ if( l - sstop -1 < MAX_EXT){ strncpy(ext, name+sstop+1, l-sstop-1); ext[l-sstop-1]=0; } else { fprintf(stderr,"Extension too long\n"); return -1; } } else { strcpy(ext, ""); } } else { fprintf(stderr,"Name too long\n"); return -1; } /* printf("%d %d\n",sstart, sstop); printf("%s %d\n",name, strlen(name)); printf("%s %d\n",base_name, strlen(base_name)); printf("%s %d\n",path,strlen(path)); printf("%s %d\n",ext,strlen(ext)); */ return 0; } int seek_mpg_start(uint8_t *buf, int size) { int found = 0; int c=0; int seq = 0; int mpeg = 0; int mark = 0; while ( !seq ){ while (found != 4){ switch (found) { case 0: if ( buf[c] == 0x00 ) found++; c++; break; case 1: if ( buf[c] == 0x00 ) found++; else found = 0; c++; break; case 2: if ( buf[c] == 0x01 ) found++; else found = 0; if ( buf[c] == 0x00 ) found = 2; c++; break; case 3: if ( (buf[c] & 0xe0) == 0xe0 ) found++; else found = 0; c++; break; } if (c >= size) return -1; } if (found == 4){ mark = c-4; c+=2; if (c >= size) return -1; if ( (buf[c] & 0xC0) == 0x80 ){ mpeg = 2; c += 2; if (c >= size) return -1; c += buf[c]+1; if (c >= size) return -1; } else { mpeg = 1; while( buf[c] == 0xFF ) { c++; if (c >= size) return -1; } if ( (buf[c] & 0xC0) == 0x40) c+=2; if (c >= size) return -1; if ( (buf[c] & 0x30) ){ if ( (buf[c] & 0x30) == 0x20) c+=5; else c+=10; } else c++; if (c >= size) return -1; } if ( buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0xB3 ) seq = 1; } found = 0; } return size-mark; } void write_mpg(int fstart, uint64_t length, int fdin, int fdout) { // uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 }; uint8_t *buf; uint64_t l=0; uint64_t count = 0; struct stat sb; int buf_size; fstat (fdout, &sb); buf_size = sb.st_blksize; buf = (char *) alloca (buf_size + sizeof (int)); lseek(fdin, fstart, SEEK_SET); while ( count < length && (l = read(fdin,buf,buf_size)) >= 0){ if (l > 0) count+=l; write(fdout,buf,l); printf("written %02.2f%%\r",(100.*count)/length); } printf("\n"); //write( fdout, mpeg_end, 4); } #define CHECKBUF (1024*1024) #define ONE_GIG (1024UL*1024UL*1024UL) void split_mpg(char *name, uint64_t size) { char base_name[MAX_BASE]; char path[MAX_PATH]; char ext[MAX_EXT]; char new_name[256]; uint8_t buf[CHECKBUF]; int fdin; int fdout; uint64_t length = 0; uint64_t last; int i; int mark, csize; struct stat sb; if (break_up_filename(name,base_name,path,ext) < 0) exit(1); if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){ fprintf(stderr,"Can't open %s\n",name); exit(1); } fstat (fdin, &sb); length = sb.st_size; if ( length < ONE_GIG ) printf("Filelength = %2.2f MB\n", length/1024./1024.); else printf("Filelength = %2.2f GB\n", length/1024./1024./1024.); if ( length < size ) length = size; printf("Splitting %s into Files with size <= %2.2f MB\n",name, size/1024./1024.); csize = CHECKBUF; read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } last = csize-mark; for ( i = 0 ; i < length/size; i++){ csize = CHECKBUF; if (csize > length-last) csize = length-last; lseek(fdin, last+size-csize, SEEK_SET); read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } sprintf(new_name,"%s-%03d.%s",base_name,i,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, size-mark, fdin, fdout); last = last + size - mark; } sprintf(new_name,"%s-%03d.%s",base_name,i,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, length-last, fdin, fdout); } void cut_mpg(char *name, uint64_t size) { char base_name[MAX_BASE]; char path[MAX_PATH]; char ext[MAX_EXT]; char new_name[256]; uint8_t buf[CHECKBUF]; int fdin; int fdout; uint64_t length = 0; uint64_t last; int mark, csize; struct stat sb; if (break_up_filename(name,base_name,path,ext) < 0) exit(1); if ( (fdin = open(name, O_RDONLY|O_LARGEFILE)) < 0){ fprintf(stderr,"Can't open %s\n",name); exit(1); } fstat (fdin, &sb); length = sb.st_size; if ( length < ONE_GIG ) printf("Filelength = %2.2f MB\n", length/1024./1024.); else printf("Filelength = %2.2f GB\n", length/1024./1024./1024.); if ( length < size ) length = size; printf("Splitting %s into 2 Files with length %.2f MB and %.2f MB\n", name, size/1024./1024., (length-size)/1024./1024.); csize = CHECKBUF; read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } last = csize-mark; if (csize > length-last) csize = length-last; lseek(fdin, last+size-csize, SEEK_SET); read(fdin, buf, csize); if ( (mark = seek_mpg_start(buf,csize)) < 0){ fprintf(stderr,"Couldn't find sequence header\n"); exit(1); } sprintf(new_name,"%s-1.%s",base_name,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, size-mark, fdin, fdout); last = last + size - mark; sprintf(new_name,"%s-2.%s",base_name,ext); printf("writing %s\n",new_name); if ( (fdout = open(new_name,O_WRONLY|O_CREAT|O_TRUNC |O_LARGEFILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP| S_IROTH|S_IWOTH)) < 0){ fprintf(stderr,"Can't open %s\n",new_name); exit(1); } write_mpg(last, length-last, fdin, fdout); } void write_all (int fd, uint8_t *data, int length) { int r; while (length) { if ((r = write(fd, data, length)) > 0) { data += r; length -= r; } } } void read_all (int fd, uint8_t *data, int length) { int c = 0; while(1) { if( read(fd, data+c, 1) == 1) { c++; if(data[c-1] == '\n') { data[c] = 0; break; } } else { fprintf (stderr, "Error reading socket\n"); exit(1); } } } char *url2host (uint8_t *url, char **name, uint32_t *ip, uint32_t *port) { uint8_t *murl; struct hostent *hoste; struct in_addr haddr; int found_ip = 1; if (!(strncmp(url, "http://", 7))) url += 7; *name = strdup(url); if (!(*name)) { *name = NULL; return (NULL); } murl = url; while (*murl && *murl != ':' && *murl != '/') { if ((*murl < '0' || *murl > '9') && *murl != '.') found_ip = 0; murl++; } (*name)[murl - url] = 0; if (found_ip) { if ((*ip = inet_addr(*name)) == INADDR_NONE) return (NULL); } else { if (!(hoste = gethostbyname(*name))) return (NULL); memcpy (&haddr, hoste->h_addr, sizeof(haddr)); *ip = haddr.s_addr; } if (!*murl || *murl == '/') { *port = 80; return (murl); } *port = atoi(++murl); while (*murl && *murl != '/') murl++; return (murl); } #define ACCEPT "Accept: video/mpeg, video/x-mpegurl, */*\r\n" int http_open (char *url) { char purl[1024], *host, req[1024], *sptr; uint32_t ip; uint32_t port; int sock; int reloc, relocnum = 0; struct sockaddr_in server; int mfd; strncpy (purl, url, 1023); purl[1023] = '\0'; do { host = NULL; strcpy (req, "GET "); if (!(sptr = url2host(purl, &host, &ip, &port))) { fprintf (stderr, "Unknown host\n"); exit (1); } strcat (req, sptr); sprintf (req + strlen(req), " HTTP/1.0\r\nUser-Agent: %s/%s\r\n", "whatever", "you want"); if (host) { sprintf(req + strlen(req), "Host: %s:%u\r\n", host, port); free (host); } strcat (req, ACCEPT); strcat (req, "\r\n"); server.sin_port = htons(port); server.sin_family = AF_INET; server.sin_addr.s_addr = ip; if ((sock = socket(PF_INET, SOCK_STREAM, 6)) < 0) { perror ("socket"); exit (1); } if (connect(sock, (struct sockaddr *)&server, sizeof(server))) { perror ("connect"); exit (1); } write_all (sock, req, strlen(req)); if (!(mfd = fileno(fdopen(sock, "rb")))) { perror ("open"); exit (1); } reloc = 0; purl[0] = '\0'; read_all (mfd, req, 1023); if ((sptr = strchr(req, ' '))) { switch (sptr[1]) { case '2': break; case '3': reloc = 1; default: fprintf (stderr, "HTTP req failed:%s", sptr+1); exit (1); } } do { read_all (mfd,req, 1023); if (!strncmp(req, "Location:", 9)) strncpy (purl, req+10, 1023); } while (req[0] != '\r' && req[0] != '\n'); } while (reloc && purl[0] && relocnum++ < 3); if (reloc) { fprintf (stderr, "Too many HTTP relocations.\n"); exit (1); } return sock; } extern int errno; const char * strerrno (void) { return strerror(errno); } libdvb-0.5.5.1/libdvbmpeg/remux.c0000644000175000017500000001051710220016115016441 0ustar mocmmocm00000000000000/* void remux(int fin, int fout, int pack_size, int mult) { Remux rem; uint8_t buf[MAX_PACK_L]; int r = 0; int i; uint8_t mpeg_end[4] = { 0x00, 0x00, 0x01, 0xB9 }; int data_size; rem.pack_size = pack_size; data_size = pack_size - MAX_H_SIZE; refill_buffy(&rem); if ( get_video_info(&rem) < 0 ){ fprintf(stderr,"ERROR: Can't find valid video stream\n"); exit(1); } i = 0; while(! rem.time_off && i < rem.vframen) { if( (rem.time_off = rem.vframe_list[i].time)) break; i++; } if ( get_audio_info(&rem) < 0 ){ fprintf(stderr,"ERROR: Can't find valid audio stream\n"); exit(1); } rem.vpts = rem.vpts_list[0].PTS; rem.vdts = rem.vpts; rem.vpts_off = rem.vpts; rem.apts = rem.apts_list[0].PTS; rem.apts_off = rem.apts; ptsdiff = rem.vpts - rem.apts; if (ptsdiff > 0) rem.vpts_off -= ptsdiff; else rem.apts_off -= -ptsdiff; rem.muxr = (rem.video_info.bit_rate + rem.audio_info.bit_rate)/400; SCR_inc = 1800 * pack_size / rem.muxr; r = 0; while ( rem.vptsn < 2 && !r) r = refill_buffy(&rem); r = 0; while ( rem.aptsn < 2 && !r) r = refill_buffy(&rem); rem.vpts_delay = (uint32_t)(2*90000ULL* (uint64_t)pack_size/rem.muxr); rem.vpts_delay = rem.dts_delay; rem.apts_delay = rem.vpts_delay; vbuf_max = 29440; abuf_max = 4096; vbuf = 0; abuf = 0; pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, 0xC0, 0, 32, 0xE0, 1, 230); pos += write_pes_header( PADDING_STREAM, pack_size-pos, 0, buf+pos,0); pos = rem.pack_size; write( fout, buf, pos); apos = rem.aread; vpos = rem.vread; while( ring_rest(&rem.aud_buffy) && ring_rest(&rem.vid_buffy) ){ uint32_t next_apts; uint32_t next_vdts; int asize, vsize; r1 = 0; r2 = 0; while ( rem.aframen < 2 && !r1) r1 = refill_buffy(&rem); while ( rem.vframen < 2 && !r2) r2 = refill_buffy(&rem); if (r1 && r2) break; if ( !r1 && apos <= rem.aread) apos = rem.aframe_list[1].pos; if ( !r2 && vpos <= rem.vread) vpos = rem.vframe_list[1].pos; apack_size = apos - rem.aread; vpack_size = vpos - rem.vread; next_vdts = (uint32_t)((uint64_t)rem.vdts + rem.vpts_delay - rem.vpts_off) ; ok_video = ( rem.SCR < next_vdts); next_apts = (uint32_t)((uint64_t)rem.apts + rem.apts_delay - rem.apts_off) ; ok_audio = ( rem.SCR < next_apts); asize = (apack_size > data_size ? data_size: apack_size); vsize = (vpack_size > data_size ? data_size: vpack_size); if( vbuf+vsize < vbuf_max && vsize && ok_audio ){ pos = write_video_pes( &rem, buf, &vpack_size); write( fout, buf, pos); vbuf += vpack_size; vbufn = add_pts( vbufl, rem.vdts, vpack_size, 0, vbufn, 0); packets++; } else if ( abuf+asize < abuf_max && asize && ok_video ){ pos = write_audio_pes( &rem, buf, &apack_size); write( fout, buf, pos); abuf += apack_size; abufn = add_pts( abufl, rem.apts, apack_size, 0, abufn, 0); packets++; } else if ( abuf+asize < abuf_max && asize && !ok_audio){ pos = write_audio_pes( &rem, buf, &apack_size); write( fout, buf, pos); abuf += apack_size; abufn = add_pts( abufl, rem.apts, apack_size, 0, abufn, 0); packets++; } else if (vbuf+vsize < vbuf_max && vsize && !ok_video){ pos = write_video_pes( &rem, buf, &vpack_size); write( fout, buf, pos); vbuf += vpack_size; vbufn = add_pts( vbufl, rem.vdts, vpack_size, 0, vbufn, 0); packets++; } else { pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); pos += write_pes_header( PADDING_STREAM, pack_size-pos, 0, buf+pos, 0); write( fout, buf, pos); } if (rem.SCR > rem.vdts+rem.vpts_off -rem.vpts_delay) rem.SCR = rem.vdts-rem.vpts_off; rem.SCR = (uint32_t)((uint64_t) rem.SCR + SCR_inc); if ( rem.apts_off + rem.SCR < rem.apts_delay ) pts_d = 0; else pts_d = (uint64_t) rem.SCR + rem.apts_off - rem.apts_delay; abuf -= del_ptss( abufl, (uint32_t) pts_d, &abufn); if ( rem.vpts_off + rem.SCR < rem.vpts_delay ) pts_d = 0; else pts_d = (uint64_t) rem.SCR + rem.vpts_off - rem.vpts_delay; vbuf -= del_ptss( vbufl, (uint32_t) pts_d, &vbufn); } pos = write_ps_header(buf,rem.SCR,rem.muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); pos += write_pes_header( PADDING_STREAM, pack_size-pos-4, 0, buf+pos, 0); pos = rem.pack_size-4; write( fout, buf, pos); write( fout, mpeg_end, 4); } */ libdvb-0.5.5.1/libdvbmpeg/ringbuffy.c0000644000175000017500000001052710220016115017275 0ustar mocmmocm00000000000000/* Ringbuffer Implementation for gtvscreen Copyright (C) 2000 Marcus Metzler (mocm@metzlerbros.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "ringbuffy.h" int ring_init (ringbuffy *rbuf, int size) { if (size > 0){ rbuf->size = size; if( !(rbuf->buffy = (char *) malloc(sizeof(char)*size)) ){ fprintf(stderr,"Not enough memory for ringbuffy\n"); return -1; } } else { fprintf(stderr,"Wrong size for ringbuffy\n"); return -1; } rbuf->read_pos = 0; rbuf->write_pos = 0; return 0; } void ring_destroy(ringbuffy *rbuf) { free(rbuf->buffy); } int ring_write(ringbuffy *rbuf, char *data, int count) { int diff, free, pos, rest; if (count <=0 ) return 0; pos = rbuf->write_pos; rest = rbuf->size - pos; diff = rbuf->read_pos - pos; free = (diff > 0) ? diff-1 : rbuf->size+diff-1; if ( free <= 0 ) return FULL_BUFFER; if ( free < count ) count = free; if (count >= rest){ memcpy (rbuf->buffy+pos, data, rest); if (count - rest) memcpy (rbuf->buffy, data+rest, count - rest); rbuf->write_pos = count - rest; } else { memcpy (rbuf->buffy+pos, data, count); rbuf->write_pos += count; } return count; } int ring_peek(ringbuffy *rbuf, char *data, int count, long off) { int diff, free, pos, rest; if (count <=0 ) return 0; pos = rbuf->read_pos+off; rest = rbuf->size - pos ; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; if ( free <= 0 ) return FULL_BUFFER; if ( free < count ) count = free; if ( count < rest ){ memcpy(data, rbuf->buffy+pos, count); } else { memcpy(data, rbuf->buffy+pos, rest); if ( count - rest) memcpy(data+rest, rbuf->buffy, count - rest); } return count; } int ring_read(ringbuffy *rbuf, char *data, int count) { int diff, free, pos, rest; if (count <=0 ) return 0; pos = rbuf->read_pos; rest = rbuf->size - pos; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; if ( rest <= 0 ) return 0; if ( free < count ) count = free; if ( count < rest ){ memcpy(data, rbuf->buffy+pos, count); rbuf->read_pos += count; } else { memcpy(data, rbuf->buffy+pos, rest); if ( count - rest) memcpy(data+rest, rbuf->buffy, count - rest); rbuf->read_pos = count - rest; } return count; } int ring_write_file(ringbuffy *rbuf, int fd, int count) { int diff, free, pos, rest, rr; if (count <=0 ) return 0; pos = rbuf->write_pos; rest = rbuf->size - pos; diff = rbuf->read_pos - pos; free = (diff > 0) ? diff-1 : rbuf->size+diff-1; if ( rest <= 0 ) return 0; if ( free < count ) count = free; if (count >= rest){ rr = read (fd, rbuf->buffy+pos, rest); if (rr == rest && count - rest) rr += read (fd, rbuf->buffy, count - rest); if (rr >=0) rbuf->write_pos = (pos + rr) % rbuf->size; } else { rr = read (fd, rbuf->buffy+pos, count); if (rr >=0) rbuf->write_pos += rr; } return rr; } int ring_read_file(ringbuffy *rbuf, int fd, int count) { int diff, free, pos, rest, rr; if (count <=0 ) return 0; pos = rbuf->read_pos; rest = rbuf->size - pos; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; if ( free <= 0 ) return FULL_BUFFER; if ( free < count ) count = free; if (count >= rest){ rr = write (fd, rbuf->buffy+pos, rest); if (rr == rest && count - rest) rr += write (fd, rbuf->buffy, count - rest); if (rr >=0) rbuf->read_pos = (pos + rr) % rbuf->size; } else { rr = write (fd, rbuf->buffy+pos, count); if (rr >=0) rbuf->read_pos += rr; } return rr; } int ring_rest(ringbuffy *rbuf){ int diff, free, pos, rest; pos = rbuf->read_pos; rest = rbuf->size - pos; diff = rbuf->write_pos - pos; free = (diff >= 0) ? diff : rbuf->size+diff; return free; } libdvb-0.5.5.1/libdvbmpeg/transform.c0000644000175000017500000016147710220016115017330 0ustar mocmmocm00000000000000/* * dvb-mpegtools for the Siemens Fujitsu DVB PCI card * * Copyright (C) 2000, 2001 Marcus Metzler * for convergence integrated media GmbH * Copyright (C) 2002 Marcus Metzler * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Or, point your browser to http://www.gnu.org/copyleft/gpl.html * * The author can be reached at marcus@convergence.de, * the project's page is at http://linuxtv.org/dvb/ */ #include "transform.h" #include #include #include "ctools.h" static unsigned int bitrates[3][16] = {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; static uint32_t freq[4] = {441, 480, 320, 0}; static uint8_t tspid0[TS_SIZE] = { 0x47, 0x40, 0x00, 0x10, 0x00, 0x00, 0xb0, 0x11, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x10, 0x00, 0x01, 0xe4, 0x00, 0x2a, 0xd6, 0x1a, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; static uint8_t tspid1[TS_SIZE] = { 0x47, 0x44, 0x00, 0x10, 0x00, 0x02, 0xb0, 0x1c, 0x00, 0x01, 0xcb, 0x00, 0x00, 0xe0, 0xa0, 0xf0, 0x05, 0x48, 0x03, 0x01, 0x00, 0x00, 0x02, 0xe0, 0xa0, 0xf0, 0x00, 0x03, 0xe0, 0x50, 0xf0, 0x00, 0xae, 0xea, 0x4e, 0x48, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; // CRC32 lookup table for polynomial 0x04c11db7 static const uint32_t crc_table[256] = { 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; static uint32_t calc_crc32 (const uint8_t *sec, uint8_t len) { int i; uint32_t crc = 0xffffffff; for (i = 0; i < len; i++) crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *sec++) & 0xff]; return crc; } uint64_t trans_pts_dts(uint8_t *pts) { uint64_t wts; wts = ((uint64_t)((pts[0] & 0x0E) << 5) | ((pts[1] & 0xFC) >> 2)) << 24; wts |= (((pts[1] & 0x03) << 6) | ((pts[2] & 0xFC) >> 2)) << 16; wts |= (((pts[2] & 0x02) << 6) | ((pts[3] & 0xFE) >> 1)) << 8; wts |= (((pts[3] & 0x01) << 7) | ((pts[4] & 0xFE) >> 1)); return wts; } void get_pespts(uint8_t *av_pts,uint8_t *pts) { pts[0] = 0x21 | ((av_pts[0] & 0xC0) >>5); pts[1] = ((av_pts[0] & 0x3F) << 2) | ((av_pts[1] & 0xC0) >> 6); pts[2] = 0x01 | ((av_pts[1] & 0x3F) << 2) | ((av_pts[2] & 0x80) >> 6); pts[3] = ((av_pts[2] & 0x7F) << 1) | ((av_pts[3] & 0x80) >> 7); pts[4] = 0x01 | ((av_pts[3] & 0x7F) << 1); } uint16_t get_pid(uint8_t *pid) { uint16_t pp = 0; pp = (pid[0] & PID_MASK_HI)<<8; pp |= pid[1]; return pp; } int write_ts_header(uint16_t pid, uint8_t *counter, int pes_start, uint8_t *buf, uint8_t length) { int i; int c = 0; int fill; uint8_t tshead[4] = { 0x47, 0x00, 0x00, 0x10}; fill = TS_SIZE-4-length; if (pes_start) tshead[1] = 0x40; if (fill) tshead[3] = 0x30; tshead[1] |= (uint8_t)((pid & 0x1F00) >> 8); tshead[2] |= (uint8_t)(pid & 0x00FF); tshead[3] |= ((*counter)++ & 0x0F) ; memcpy(buf,tshead,4); c+=4; if (fill){ buf[4] = fill-1; c++; if (fill >1){ buf[5] = 0x00; c++; } for ( i = 6; i < fill+4; i++){ buf[i] = 0xFF; c++; } } return c; } int write_pes_header(uint8_t id,int length , long PTS, uint8_t *obuf, int stuffing) { uint8_t le[2]; uint8_t dummy[3]; uint8_t *pts; uint8_t ppts[5]; long lpts; int c; uint8_t headr[3] = {0x00, 0x00, 0x01}; lpts = htonl(PTS); pts = (uint8_t *) &lpts; get_pespts(pts,ppts); c = 0; memcpy(obuf+c,headr,3); c += 3; memcpy(obuf+c,&id,1); c++; le[0] = 0; le[1] = 0; length -= 6+stuffing; le[0] |= ((uint8_t)(length >> 8) & 0xFF); le[1] |= ((uint8_t)(length) & 0xFF); memcpy(obuf+c,le,2); c += 2; if (id == PADDING_STREAM){ memset(obuf+c,0xff,length); c+= length; return c; } dummy[0] = 0x80; dummy[1] = 0; dummy[2] = 0; if (PTS){ dummy[1] |= PTS_ONLY; dummy[2] = 5+stuffing; } memcpy(obuf+c,dummy,3); c += 3; memset(obuf+c,0xFF,stuffing); if (PTS){ memcpy(obuf+c,ppts,5); c += 5; } return c; } void init_p2p(p2p *p, void (*func)(uint8_t *buf, int count, void *p), int repack){ p->found = 0; p->cid = 0; p->mpeg = 0; memset(p->buf,0,MMAX_PLENGTH); p->done = 0; p->fd1 = -1; p->func = func; p->bigend_repack = 0; p->repack = 0; if ( repack < MAX_PLENGTH && repack > 265 ){ p->repack = repack-6; p->bigend_repack = (uint16_t)htons((short) ((repack-6) & 0xFFFF)); } else { fprintf(stderr, "Repack size %d is out of range\n",repack); exit(1); } } void pes_repack(p2p *p) { int count = 0; int repack = p->repack; int rest = p->plength; uint8_t buf[MAX_PLENGTH]; int bfill = 0; int diff; uint16_t length; if (rest < 0) { fprintf(stderr,"Error in repack\n"); return; } if (!repack){ fprintf(stderr,"forgot to set repack size\n"); return; } if (p->plength == repack){ memcpy(p->buf+4,(char *)&p->bigend_repack,2); p->func(p->buf, repack+6, p); return; } buf[0] = 0x00; buf[1] = 0x00; buf[2] = 0x01; buf[3] = p->cid; memcpy(buf+4,(char *)&p->bigend_repack,2); memset(buf+6,0,MAX_PLENGTH-6); if (p->mpeg == 2){ if ( rest > repack){ memcpy(p->buf+4,(char *)&p->bigend_repack,2); p->func(p->buf, repack+6, p); count += repack+6; rest -= repack; } else { memcpy(buf,p->buf,9+p->hlength); bfill = p->hlength; count += 9+p->hlength; rest -= p->hlength+3; } while (rest >= repack-3){ memset(buf+6,0,MAX_PLENGTH-6); buf[6] = 0x80; buf[7] = 0x00; buf[8] = 0x00; memcpy(buf+9,p->buf+count,repack-3); rest -= repack-3; count += repack-3; p->func(buf, repack+6, p); } if (rest){ diff = repack - 3 - rest - bfill; if (!bfill){ buf[6] = 0x80; buf[7] = 0x00; buf[8] = 0x00; } if ( diff < PES_MIN){ length = rest+ diff + bfill+3; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); buf[8] = (uint8_t)(bfill+diff); memset(buf+9+bfill,0xFF,diff); memcpy(buf+9+bfill+diff,p->buf+count,rest); } else { length = rest+ bfill+3; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); memcpy(buf+9+bfill,p->buf+count,rest); bfill += rest+9; write_pes_header( PADDING_STREAM, diff, 0, buf+bfill, 0); } p->func(buf, repack+6, p); } } if (p->mpeg == 1){ if ( rest > repack){ memcpy(p->buf+4,(char *)&p->bigend_repack,2); p->func(p->buf, repack+6, p); count += repack+6; rest -= repack; } else { memcpy(buf,p->buf,6+p->hlength); bfill = p->hlength; count += 6; rest -= p->hlength; } while (rest >= repack-1){ memset(buf+6,0,MAX_PLENGTH-6); buf[6] = 0x0F; memcpy(buf+7,p->buf+count,repack-1); rest -= repack-1; count += repack-1; p->func(buf, repack+6, p); } if (rest){ diff = repack - 1 - rest - bfill; if ( diff < PES_MIN){ length = rest+ diff + bfill+1; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); memset(buf+6,0xFF,diff); if (!bfill){ buf[6+diff] = 0x0F; } memcpy(buf+7+diff,p->buf+count,rest+bfill); } else { length = rest+ bfill+1; buf[4] = (uint8_t)((length & 0xFF00) >> 8); buf[5] = (uint8_t)(length & 0x00FF); if (!bfill){ buf[6] = 0x0F; memcpy(buf+7,p->buf+count,rest); bfill = rest+7; } else { memcpy(buf+6,p->buf+count,rest+bfill); bfill += rest+6; } write_pes_header( PADDING_STREAM, diff, 0, buf+bfill, 0); } p->func(buf, repack+6, p); } } } int filter_pes (uint8_t *buf, int count, p2p *p, int (*func)(p2p *p)) { int l; unsigned short *pl; int c=0; int ret = 1; uint8_t headr[3] = { 0x00, 0x00, 0x01} ; while (c < count && (p->mpeg == 0 || (p->mpeg == 1 && p->found < 7) || (p->mpeg == 2 && p->found < 9)) && (p->found < 5 || !p->done)){ switch ( p->found ){ case 0: case 1: if (buf[c] == 0x00) p->found++; else { if (p->fd1 >= 0) write(p->fd1,buf+c,1); p->found = 0; } c++; break; case 2: if (buf[c] == 0x01) p->found++; else if (buf[c] == 0){ p->found = 2; } else { if (p->fd1 >= 0) write(p->fd1,buf+c,1); p->found = 0; } c++; break; case 3: p->cid = 0; switch (buf[c]){ case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: if (p->fd1 >= 0) write(p->fd1,buf+c,1); p->done = 1; case PRIVATE_STREAM1: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case AUDIO_STREAM_S ... AUDIO_STREAM_E: p->found++; p->cid = buf[c]; c++; break; default: if (p->fd1 >= 0) write(p->fd1,buf+c,1); p->found = 0; break; } break; case 4: if (count-c > 1){ pl = (unsigned short *) (buf+c); p->plength = ntohs(*pl); p->plen[0] = buf[c]; c++; p->plen[1] = buf[c]; c++; p->found+=2; } else { p->plen[0] = buf[c]; p->found++; return 1; } break; case 5: p->plen[1] = buf[c]; c++; pl = (unsigned short *) p->plen; p->plength = ntohs(*pl); p->found++; break; case 6: if (!p->done){ p->flag1 = buf[c]; c++; p->found++; if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; else { p->hlength = 0; p->which = 0; p->mpeg = 1; p->flag2 = 0; } } break; case 7: if ( !p->done && p->mpeg == 2){ p->flag2 = buf[c]; c++; p->found++; } break; case 8: if ( !p->done && p->mpeg == 2){ p->hlength = buf[c]; c++; p->found++; } break; default: break; } } if (!p->plength) p->plength = MMAX_PLENGTH-6; if ( p->done || ((p->mpeg == 2 && p->found >= 9) || (p->mpeg == 1 && p->found >= 7)) ){ switch (p->cid){ case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case PRIVATE_STREAM1: memcpy(p->buf, headr, 3); p->buf[3] = p->cid; memcpy(p->buf+4,p->plen,2); if (p->mpeg == 2 && p->found == 9){ p->buf[6] = p->flag1; p->buf[7] = p->flag2; p->buf[8] = p->hlength; } if (p->mpeg == 1 && p->found == 7){ p->buf[6] = p->flag1; } if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14){ while (c < count && p->found < 14){ p->pts[p->found-9] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; } if (c == count) return 1; } if (p->mpeg == 1 && p->which < 2000){ if (p->found == 7) { p->check = p->flag1; p->hlength = 1; } while (!p->which && c < count && p->check == 0xFF){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; } if ( c == count) return 1; if ( (p->check & 0xC0) == 0x40 && !p->which){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 1; if ( c == count) return 1; p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return 1; } if (p->which == 1){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return 1; } if ( (p->check & 0x30) && p->check != 0xFF){ p->flag2 = (p->check & 0xF0) << 2; p->pts[0] = p->check; p->which = 3; } if ( c == count) return 1; if (p->which > 2){ if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY){ while (c < count && p->which < 7){ p->pts[p->which-2] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->which++; p->hlength++; } if ( c == count) return 1; } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS){ while (c < count && p->which< 12){ if (p->which< 7) p->pts[p->which -2] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->which++; p->hlength++; } if ( c == count) return 1; } p->which = 2000; } } while (c < count && p->found < p->plength+6){ l = count -c; if (l+p->found > p->plength+6) l = p->plength+6-p->found; memcpy(p->buf+p->found, buf+c, l); p->found += l; c += l; } if(p->found == p->plength+6){ if (func(p)){ if (p->fd1 >= 0){ write(p->fd1,p->buf, p->plength+6); } } else ret = 0; } break; } if ( p->done ){ if( p->found + count - c < p->plength+6){ p->found += count-c; c = count; } else { c += p->plength+6 - p->found; p->found = p->plength+6; } } if (p->plength && p->found == p->plength+6) { p->found = 0; p->done = 0; p->plength = 0; memset(p->buf, 0, MAX_PLENGTH); if (c < count) return filter_pes(buf+c, count-c, p, func); } } return ret; } #define SIZE 4096 int audio_pes_filt(p2p *p) { uint8_t off; switch(p->cid){ case PRIVATE_STREAM1: if ( p->cid == p->filter) { off = 9+p->buf[8]; if (p->buf[off] == p->subid){ return 1; } } break; case AUDIO_STREAM_S ... AUDIO_STREAM_E: if ( p->cid == p->filter) return 1; break; default: return 1; break; } return 0; } void filter_audio_from_pes(int fdin, int fdout, uint8_t id, uint8_t subid) { p2p p; int count = 1; uint8_t buf[2048]; init_p2p(&p, NULL, 2048); p.fd1 = -1; p.filter = id; p.subid = subid; while (count > 0){ count = read(fdin,buf,2048); if(filter_pes(buf,count,&p,audio_pes_filt)) write(fdout,buf,2048); } } void pes_filt(p2p *p) { int factor = p->mpeg-1; if ( p->cid == p->filter) { if (p->es) write(p->fd1,p->buf+p->hlength+6+3*factor, p->plength-p->hlength-3*factor); else write(p->fd1,p->buf,p->plength+6); } } void extract_from_pes(int fdin, int fdout, uint8_t id, int es) { p2p p; int count = 1; uint8_t buf[SIZE]; init_p2p(&p, NULL, 2048); p.fd1 = fdout; p.filter = id; p.es = es; while (count > 0){ count = read(fdin,buf,SIZE); get_pes(buf,count,&p,pes_filt); } } void pes_dfilt(p2p *p) { int factor = p->mpeg-1; int fd =0; int head=0; int type = NOPES; int streamid; int c = 6+p->hlength+3*factor; switch ( p->cid ) { case PRIVATE_STREAM1: streamid = p->buf[c]; head = 4; if ((streamid & 0xF8) == 0x80+p->es-1){ fd = p->fd1; type = AC3; } break; case AUDIO_STREAM_S ... AUDIO_STREAM_E: fd = p->fd1; type = AUDIO; break; case VIDEO_STREAM_S ... VIDEO_STREAM_E: fd = p->fd2; type = VIDEO; break; } if (p->es && !p->startv && type == VIDEO){ int found = 0; if ( p->flag2 & PTS_DTS ) p->vpts = trans_pts_dts(p->pts); else return; while ( !found && c+3 < p->plength+6 ){ if ( p->buf[c] == 0x00 && p->buf[c+1] == 0x00 && p->buf[c+2] == 0x01 && p->buf[c+3] == 0xb3) found = 1; else c++; } if (found){ p->startv = 1; write(fd, p->buf+c, p->plength+6-c); } fd = 0; } if ( p->es && !p->starta && type == AUDIO){ int found = 0; if ( p->flag2 & PTS_DTS ) p->apts = trans_pts_dts(p->pts); else return; if (p->startv) while ( !found && c+1 < p->plength+6){ if ( p->buf[c] == 0xFF && (p->buf[c+1] & 0xF8) == 0xF8) found = 1; else c++; } if (found){ p->starta = 1; write(fd, p->buf+c, p->plength+6-c); } fd = 0; } if ( p->es && !p->starta && type == AC3){ if ( p->flag2 & PTS_DTS ) p->apts = trans_pts_dts(p->pts); else return; if (p->startv){ c+= ((p->buf[c+2] << 8)| p->buf[c+3]); p->starta = 1; write(fd, p->buf+c, p->plength+6-c); } fd = 0; } if (fd){ if (p->es) write(fd,p->buf+p->hlength+6+3*factor+head, p->plength-p->hlength-3*factor-head); else write(fd,p->buf,p->plength+6); } } #define PD_SIZE 1024*1024 int64_t pes_dmx( int fdin, int fdouta, int fdoutv, int es) { p2p p; int count = 1; uint8_t buf[PD_SIZE]; uint64_t length = 0; uint64_t l = 0; int verb = 0; int percent, oldPercent = -1; init_p2p(&p, NULL, MAX_PLENGTH-1); p.fd1 = fdouta; p.fd2 = fdoutv; p.es = es; p.startv = 0; p.starta = 0; p.apts=-1; p.vpts=-1; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } while (count > 0){ count = read(fdin,buf,PD_SIZE); l += count; if (verb){ percent = 100 * l / length; if (percent != oldPercent) { fprintf(stderr, "Demuxing %d %%\r", percent); oldPercent = percent; } } get_pes(buf,count,&p,pes_dfilt); } return (int64_t)p.vpts - (int64_t)p.apts; } static void pes_in_ts(p2p *p) { int l, pes_start; uint8_t obuf[TS_SIZE]; long int c = 0; int length = p->plength+6; uint16_t pid; uint8_t *counter; pes_start = 1; switch ( p->cid ) { case AUDIO_STREAM_S ... AUDIO_STREAM_E: pid = p->pida; counter = &p->acounter; break; case VIDEO_STREAM_S ... VIDEO_STREAM_E: pid = p->pidv; counter = &p->acounter; tspid0[3] |= (p->count0++) & 0x0F ; tspid1[3] |= (p->count1++) & 0x0F ; tspid1[24] = p->pidv; tspid1[23] |= (p->pidv >> 8) & 0x3F; tspid1[29] = p->pida; tspid1[28] |= (p->pida >> 8) & 0x3F; p->func(tspid0,188,p); p->func(tspid1,188,p); break; default: return; } while ( c < length ){ memset(obuf,0,TS_SIZE); if (length - c >= TS_SIZE-4){ l = write_ts_header(pid, counter, pes_start , obuf, TS_SIZE-4); memcpy(obuf+l, p->buf+c, TS_SIZE-l); c += TS_SIZE-l; } else { l = write_ts_header(pid, counter, pes_start , obuf, length-c); memcpy(obuf+l, p->buf+c, TS_SIZE-l); c = length; } p->func(obuf,188,p); pes_start = 0; } } static void write_out(uint8_t *buf, int count,void *p) { write(STDOUT_FILENO, buf, count); } void pes_to_ts2( int fdin, int fdout, uint16_t pida, uint16_t pidv) { p2p p; int count = 1; uint8_t buf[SIZE]; uint64_t length = 0; uint64_t l = 0; int verb = 0; init_p2p(&p, NULL, 2048); p.fd1 = fdout; p.pida = pida; p.pidv = pidv; p.acounter = 0; p.vcounter = 0; p.count1 = 0; p.count0 = 0; p.func = write_out; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } while (count > 0){ count = read(fdin,buf,SIZE); l += count; if (verb) fprintf(stderr,"Writing TS %2.2f %%\r", 100.*l/length); get_pes(buf,count,&p,pes_in_ts); } } #define IN_SIZE TS_SIZE*10 #define IPACKS 2048 void find_avpids(int fd, uint16_t *vpid, uint16_t *apid) { uint8_t buf[IN_SIZE]; int count; int i; int off =0; while ( *apid == 0 || *vpid == 0){ count = read(fd, buf, IN_SIZE); for (i = 0; i < count-7; i++){ if (buf[i] == 0x47){ if (buf[i+1] & 0x40){ off = 0; if ( buf[3+i] & 0x20)//adapt field? off = buf[4+i] + 1; switch(buf[i+7+off]){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: *vpid = get_pid(buf+i+1); break; case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: *apid = get_pid(buf+i+1); break; } } i += 187; } if (*apid != 0 && *vpid != 0) break; } } } void find_bavpids(uint8_t *buf, int count, uint16_t *vpid, uint16_t *apid) { int i; int founda = 0; int foundb = 0; int off = 0; *vpid = 0; *apid = 0; for (i = 0; i < count-7; i++){ if (buf[i] == 0x47){ if ((buf[i+1] & 0xF0) == 0x40){ off = 0; if ( buf[3+i] & 0x20) // adaptation field? off = buf[4+i] + 1; if (buf[off+i+4] == 0x00 && buf[off+i+5] == 0x00 && buf[off+i+6] == 0x01){ switch(buf[off+i+7]){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: *vpid = get_pid(buf+i+1); foundb=1; break; case PRIVATE_STREAM1: case AUDIO_STREAM_S ... AUDIO_STREAM_E: *apid = get_pid(buf+i+1); founda=1; break; } } } i += 187; } if (founda && foundb) break; } } void ts_to_pes( int fdin, uint16_t pida, uint16_t pidv, int ps) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; uint16_t pid; uint16_t dummy; ipack pa, pv; ipack *p; if (fdin != STDIN_FILENO && (!pida || !pidv)) find_avpids(fdin, &pidv, &pida); init_ipack(&pa, IPACKS,write_out, ps); init_ipack(&pv, IPACKS,write_out, ps); if ((count = save_read(fdin,mbuf,TS_SIZE))<0) perror("reading"); for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return; } else { memcpy(buf,mbuf+i,TS_SIZE-i); if ((count = save_read(fdin,mbuf,i))<0) perror("reading"); memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; while (count > 0){ if ((count = save_read(fdin,buf+i,IN_SIZE-i)+i)<0) perror("reading"); if (!pidv){ find_bavpids(buf+i, IN_SIZE-i, &pidv, &dummy); if (pidv) fprintf(stderr, "vpid %d (0x%02x)\n", pidv,pidv); } if (!pida){ find_bavpids(buf+i, IN_SIZE-i, &dummy, &pida); if (pida) fprintf(stderr, "apid %d (0x%02x)\n", pida,pida); } if (!pida || !pidv){ fprintf(stderr,"Can't find PIDs\n"); return; } for( i = 0; i < count; i+= TS_SIZE){ uint8_t off = 0; if ( count - i < TS_SIZE) break; pid = get_pid(buf+i+1); if (!(buf[3+i]&0x10)) // no payload? continue; if ( buf[1+i]&0x80){ fprintf(stderr,"Error in TS for PID: %d\n", pid); } if (pid == pidv){ p = &pv; } else { if (pid == pida){ p = &pa; } else continue; } if ( buf[1+i]&0x40) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } } if ( buf[3+i] & 0x20) { // adaptation field? off = buf[4+i] + 1; } instant_repack(buf+4+off+i, TS_SIZE-4-off, p); } i = 0; } } #define INN_SIZE 2*IN_SIZE void insert_pat_pmt( int fdin, int fdout) { uint8_t buf[INN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; uint16_t pida = 0; uint16_t pidv = 0; int written,c; uint8_t c0 = 0; uint8_t c1 = 0; uint8_t pmt_len; uint32_t crc32; find_avpids(fdin, &pidv, &pida); count = save_read(fdin,mbuf,TS_SIZE); for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return; } else { memcpy(buf,mbuf+i,TS_SIZE-i); count = save_read(fdin,mbuf,i); memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; /* length is not correct, but we only create a very small * PMT, so it doesn't matter :-) */ pmt_len = tspid1[7] + 3; while (count > 0){ tspid1[24] = pidv; tspid1[23] |= (pidv >> 8) & 0x3F; tspid1[29] = pida; tspid1[28] |= (pida >> 8) & 0x3F; crc32 = calc_crc32 (&tspid1[5], pmt_len - 4); tspid1[5 + pmt_len - 4] = (crc32 & 0xff000000) >> 24; tspid1[5 + pmt_len - 3] = (crc32 & 0x00ff0000) >> 16; tspid1[5 + pmt_len - 2] = (crc32 & 0x0000ff00) >> 8; tspid1[5 + pmt_len - 1] = (crc32 & 0x000000ff) >> 0; write(fdout,tspid0,188); write(fdout,tspid1,188); count = save_read(fdin,buf+i,INN_SIZE-i); written = 0; while (written < IN_SIZE){ c = write(fdout,buf,INN_SIZE); if (c>0) written += c; } tspid0[3] &= 0xF0 ; tspid0[3] |= (c0++)& 0x0F ; tspid1[3] &= 0xF0 ; tspid1[3] |= (c1++)& 0x0F ; i=0; } } void get_pes (uint8_t *buf, int count, p2p *p, void (*func)(p2p *p)) { int l; unsigned short *pl; int c=0; uint8_t headr[3] = { 0x00, 0x00, 0x01} ; while (c < count && (p->mpeg == 0 || (p->mpeg == 1 && p->found < 7) || (p->mpeg == 2 && p->found < 9)) && (p->found < 5 || !p->done)){ switch ( p->found ){ case 0: case 1: if (buf[c] == 0x00) p->found++; else p->found = 0; c++; break; case 2: if (buf[c] == 0x01) p->found++; else if (buf[c] == 0){ p->found = 2; } else p->found = 0; c++; break; case 3: p->cid = 0; switch (buf[c]){ case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: p->done = 1; case PRIVATE_STREAM1: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case AUDIO_STREAM_S ... AUDIO_STREAM_E: p->found++; p->cid = buf[c]; c++; break; default: p->found = 0; break; } break; case 4: if (count-c > 1){ pl = (unsigned short *) (buf+c); p->plength = ntohs(*pl); p->plen[0] = buf[c]; c++; p->plen[1] = buf[c]; c++; p->found+=2; } else { p->plen[0] = buf[c]; p->found++; return; } break; case 5: p->plen[1] = buf[c]; c++; pl = (unsigned short *) p->plen; p->plength = ntohs(*pl); p->found++; break; case 6: if (!p->done){ p->flag1 = buf[c]; c++; p->found++; if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; else { p->hlength = 0; p->which = 0; p->mpeg = 1; p->flag2 = 0; } } break; case 7: if ( !p->done && p->mpeg == 2){ p->flag2 = buf[c]; c++; p->found++; } break; case 8: if ( !p->done && p->mpeg == 2){ p->hlength = buf[c]; c++; p->found++; } break; default: break; } } if (!p->plength) p->plength = MMAX_PLENGTH-6; if ( p->done || ((p->mpeg == 2 && p->found >= 9) || (p->mpeg == 1 && p->found >= 7)) ){ switch (p->cid){ case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case PRIVATE_STREAM1: memcpy(p->buf, headr, 3); p->buf[3] = p->cid; memcpy(p->buf+4,p->plen,2); if (p->mpeg == 2 && p->found == 9){ p->buf[6] = p->flag1; p->buf[7] = p->flag2; p->buf[8] = p->hlength; } if (p->mpeg == 1 && p->found == 7){ p->buf[6] = p->flag1; } if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14){ while (c < count && p->found < 14){ p->pts[p->found-9] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; } if (c == count) return; } if (p->mpeg == 1 && p->which < 2000){ if (p->found == 7) { p->check = p->flag1; p->hlength = 1; } while (!p->which && c < count && p->check == 0xFF){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; } if ( c == count) return; if ( (p->check & 0xC0) == 0x40 && !p->which){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 1; if ( c == count) return; p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if (p->which == 1){ p->check = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if ( (p->check & 0x30) && p->check != 0xFF){ p->flag2 = (p->check & 0xF0) << 2; p->pts[0] = p->check; p->which = 3; } if ( c == count) return; if (p->which > 2){ if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY){ while (c < count && p->which < 7){ p->pts[p->which-2] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS){ while (c < count && p->which< 12){ if (p->which< 7) p->pts[p->which -2] = buf[c]; p->buf[p->found] = buf[c]; c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } p->which = 2000; } } while (c < count && p->found < p->plength+6){ l = count -c; if (l+p->found > p->plength+6) l = p->plength+6-p->found; memcpy(p->buf+p->found, buf+c, l); p->found += l; c += l; } if(p->found == p->plength+6) func(p); break; } if ( p->done ){ if( p->found + count - c < p->plength+6){ p->found += count-c; c = count; } else { c += p->plength+6 - p->found; p->found = p->plength+6; } } if (p->plength && p->found == p->plength+6) { p->found = 0; p->done = 0; p->plength = 0; memset(p->buf, 0, MAX_PLENGTH); if (c < count) get_pes(buf+c, count-c, p, func); } } return; } void setup_pes2ts( p2p *p, uint32_t pida, uint32_t pidv, void (*ts_write)(uint8_t *buf, int count, void *p)) { init_p2p( p, ts_write, 2048); p->pida = pida; p->pidv = pidv; p->acounter = 0; p->vcounter = 0; p->count1 = 0; p->count0 = 0; } void kpes_to_ts( p2p *p,uint8_t *buf ,int count ) { get_pes(buf,count, p,pes_in_ts); } void setup_ts2pes( p2p *pa, p2p *pv, uint32_t pida, uint32_t pidv, void (*pes_write)(uint8_t *buf, int count, void *p)) { init_p2p( pa, pes_write, 2048); init_p2p( pv, pes_write, 2048); pa->pid = pida; pv->pid = pidv; } void kts_to_pes( p2p *p, uint8_t *buf) // don't need count (=188) { uint8_t off = 0; uint16_t pid = 0; if (!(buf[3]&PAYLOAD)) // no payload? return; pid = get_pid(buf+1); if (pid != p->pid) return; if ( buf[1]&0x80){ fprintf(stderr,"Error in TS for PID: %d\n", pid); } if ( buf[1]&PAY_START) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; pes_repack(p); } } if ( buf[3] & ADAPT_FIELD) { // adaptation field? off = buf[4] + 1; if (off+4 > 187) return; } get_pes(buf+4+off, TS_SIZE-4-off, p , pes_repack); } // instant repack void reset_ipack(ipack *p) { p->found = 0; p->cid = 0; p->plength = 0; p->flag1 = 0; p->flag2 = 0; p->hlength = 0; p->mpeg = 0; p->check = 0; p->which = 0; p->done = 0; p->count = 0; p->size = p->size_orig; } void init_ipack(ipack *p, int size, void (*func)(uint8_t *buf, int size, void *priv), int ps) { if ( !(p->buf = malloc(size)) ){ fprintf(stderr,"Couldn't allocate memory for ipack\n"); exit(1); } p->ps = ps; p->size_orig = size; p->func = func; reset_ipack(p); p->has_ai = 0; p->has_vi = 0; p->start = 0; } void free_ipack(ipack * p) { if (p->buf) free(p->buf); } int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) { uint8_t *headr; int found = 0; int sw; int form = -1; int c = 0; while (found < 4 && c+4 < count){ uint8_t *b; b = mbuf+c; if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 && b[3] == 0xb3) found = 4; else { c++; } } if (! found) return -1; c += 4; if (c+12 >= count) return -1; headr = mbuf+c; vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); sw = (int)((headr[3]&0xF0) >> 4) ; switch( sw ){ case 1: if (pr) fprintf(stderr,"Videostream: ASPECT: 1:1"); vi->aspect_ratio = 100; break; case 2: if (pr) fprintf(stderr,"Videostream: ASPECT: 4:3"); vi->aspect_ratio = 133; break; case 3: if (pr) fprintf(stderr,"Videostream: ASPECT: 16:9"); vi->aspect_ratio = 177; break; case 4: if (pr) fprintf(stderr,"Videostream: ASPECT: 2.21:1"); vi->aspect_ratio = 221; break; case 5 ... 15: if (pr) fprintf(stderr,"Videostream: ASPECT: reserved"); vi->aspect_ratio = 0; break; default: vi->aspect_ratio = 0; return -1; } if (pr) fprintf(stderr," Size = %dx%d",vi->horizontal_size, vi->vertical_size); sw = (int)(headr[3]&0x0F); switch ( sw ) { case 1: if (pr) fprintf(stderr," FRate: 23.976 fps"); vi->framerate = 24000/1001.; form = -1; break; case 2: if (pr) fprintf(stderr," FRate: 24 fps"); vi->framerate = 24; form = -1; break; case 3: if (pr) fprintf(stderr," FRate: 25 fps"); vi->framerate = 25; form = VIDEO_MODE_PAL; break; case 4: if (pr) fprintf(stderr," FRate: 29.97 fps"); vi->framerate = 30000/1001.; form = VIDEO_MODE_NTSC; break; case 5: if (pr) fprintf(stderr," FRate: 30 fps"); vi->framerate = 30; form = VIDEO_MODE_NTSC; break; case 6: if (pr) fprintf(stderr," FRate: 50 fps"); vi->framerate = 50; form = VIDEO_MODE_PAL; break; case 7: if (pr) fprintf(stderr," FRate: 60 fps"); vi->framerate = 60; form = VIDEO_MODE_NTSC; break; } vi->bit_rate = 400*(((headr[4] << 10) & 0x0003FC00UL) | ((headr[5] << 2) & 0x000003FCUL) | (((headr[6] & 0xC0) >> 6) & 0x00000003UL)); if (pr){ fprintf(stderr," BRate: %.2f Mbit/s",(vi->bit_rate)/1000000.); fprintf(stderr,"\n"); } vi->video_format = form; vi->off = c-4; return c-4; } extern unsigned int bitrates[3][16]; extern uint32_t freq[4]; int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) { uint8_t *headr; int found = 0; int c = 0; int fr =0; while (!found && c < count){ uint8_t *b = mbuf+c; if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) found = 1; else { c++; } } if (!found) return -1; if (c+3 >= count) return -1; headr = mbuf+c; ai->layer = (headr[1] & 0x06) >> 1; if (pr) fprintf(stderr,"Audiostream: Layer: %d", 4-ai->layer); ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; if (pr){ if (ai->bit_rate == 0) fprintf (stderr," Bit rate: free"); else if (ai->bit_rate == 0xf) fprintf (stderr," BRate: reserved"); else fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); } fr = (headr[2] & 0x0c ) >> 2; ai->frequency = freq[fr]*100; if (pr){ if (ai->frequency == 3) fprintf (stderr, " Freq: reserved\n"); else fprintf (stderr," Freq: %2.1f kHz\n", ai->frequency/1000.); } ai->off = c; return c; } unsigned int ac3_bitrates[32] = {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, 0,0,0,0,0,0,0,0,0,0,0,0,0}; uint32_t ac3_freq[4] = {480, 441, 320, 0}; uint32_t ac3_frames[3][32] = {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr) { uint8_t *headr; int found = 0; int c = 0; uint8_t frame; int fr = 0; while ( !found && c < count){ uint8_t *b = mbuf+c; if ( b[0] == 0x0b && b[1] == 0x77 ) found = 1; else { c++; } } if (!found){ return -1; } ai->off = c; if (c+5 >= count) return -1; ai->layer = 0; // 0 for AC3 headr = mbuf+c+2; frame = (headr[2]&0x3f); ai->bit_rate = ac3_bitrates[frame>>1]*1000; if (pr) fprintf (stderr," BRate: %d kb/s", ai->bit_rate/1000); fr = (headr[2] & 0xc0 ) >> 6; ai->frequency = freq[fr]*100; if (pr) fprintf (stderr," Freq: %d Hz\n", ai->frequency); ai->framesize = ac3_frames[fr][frame >> 1]; if ((frame & 1) && (fr == 1)) ai->framesize++; ai->framesize = ai->framesize << 1; if (pr) fprintf (stderr," Framesize %d\n", ai->framesize); return c; } void ps_pes(ipack *p) { int check; uint8_t pbuf[PS_HEADER_L2]; static int muxr = 0; static int ai = 0; static int vi = 0; static int start = 0; static uint32_t SCR = 0; if (p->mpeg == 2){ switch(p->buf[3]){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: if (!p->has_vi){ if(get_vinfo(p->buf, p->count, &p->vi,1) >=0) { p->has_vi = 1; vi = p->vi.bit_rate; } } break; case AUDIO_STREAM_S ... AUDIO_STREAM_E: if (!p->has_ai){ if(get_ainfo(p->buf, p->count, &p->ai,1) >=0) { p->has_ai = 1; ai = p->ai.bit_rate; } } break; } if (p->has_vi && vi && !muxr){ muxr = (vi+ai)/400; } if ( start && muxr && (p->buf[7] & PTS_ONLY) && (p->has_ai || p->buf[9+p->buf[8]+4] == 0xb3)){ SCR = trans_pts_dts(p->pts)-3600; check = write_ps_header(pbuf, SCR, muxr, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0); p->func(pbuf, check , p->data); } if (muxr && !start && vi){ SCR = trans_pts_dts(p->pts)-3600; check = write_ps_header(pbuf, SCR, muxr, 1, 0, 0, 1, 1, 1, 0xC0, 0, 64, 0xE0, 1, 460); start = 1; p->func(pbuf, check , p->data); } if (start) p->func(p->buf, p->count, p->data); } } void send_ipack(ipack *p) { int streamid=0; int off; int ac3_off = 0; AudioInfo ai; int nframes= 0; int f=0; if (p->count < 10) return; p->buf[3] = p->cid; p->buf[4] = (uint8_t)(((p->count-6) & 0xFF00) >> 8); p->buf[5] = (uint8_t)((p->count-6) & 0x00FF); if (p->cid == PRIVATE_STREAM1){ off = 9+p->buf[8]; streamid = p->buf[off]; switch (streamid & 0xF8){ case 0x80: ai.off = 0; ac3_off = ((p->buf[off+2] << 8)| p->buf[off+3]); if (ac3_off < p->count) f=get_ac3info(p->buf+off+3+ac3_off, p->count-ac3_off, &ai,0); if ( !f ){ nframes = (p->count-off-3-ac3_off)/ ai.framesize + 1; p->buf[off+1] = nframes; p->buf[off+2] = (ac3_off >> 8)& 0xFF; p->buf[off+3] = (ac3_off)& 0xFF; ac3_off += nframes * ai.framesize - p->count; } break; case 0x20: default: break; } } if (p->ps) ps_pes(p); else p->func(p->buf, p->count, p->data); switch ( p->mpeg ){ case 2: p->buf[6] = 0x80; p->buf[7] = 0x00; p->buf[8] = 0x00; p->count = 9; if (p->cid == PRIVATE_STREAM1){ switch (streamid & 0xF8){ case 0x80: p->count += 4; p->buf[9] = streamid; p->buf[10] = 0; p->buf[11] = (ac3_off >> 8)& 0xFF; p->buf[12] = (ac3_off)& 0xFF; break; case 0x20: p->count += 2; p->buf[9] = 0x20; p->buf[10] = 0; break; } } break; case 1: p->buf[6] = 0x0F; p->count = 7; break; } } static void write_ipack(ipack *p, uint8_t *data, int count) { AudioInfo ai; uint8_t headr[3] = { 0x00, 0x00, 0x01} ; int diff =0; if (p->count < 6){ if (trans_pts_dts(p->pts) > trans_pts_dts(p->last_pts)) memcpy(p->last_pts, p->pts, 5); p->count = 0; memcpy(p->buf+p->count, headr, 3); p->count += 6; } if ( p->size == p->size_orig && p->plength && (diff = 6+p->plength - p->found + p->count +count) > p->size && diff < 3*p->size/2){ p->size = diff/2; // fprintf(stderr,"size: %d \n",p->size); } if (p->cid == PRIVATE_STREAM1 && p->count == p->hlength+9){ switch ((data[0] & 0xF8)){ case 0x80: case 0x20: break; default: { int ac3_off; ac3_off = get_ac3info(data, count, &ai,0); if (ac3_off>=0 && ai.framesize){ p->buf[p->count] = 0x80; p->buf[p->count+1] = (p->size - p->count - 4 - ac3_off)/ ai.framesize + 1; p->buf[p->count+2] = (ac3_off >> 8)& 0xFF; p->buf[p->count+3] = (ac3_off)& 0xFF; p->count+=4; } } break; } } if (p->count + count < p->size){ memcpy(p->buf+p->count, data, count); p->count += count; } else { int rest = p->size - p->count; if (rest < 0) rest = 0; memcpy(p->buf+p->count, data, rest); p->count += rest; // fprintf(stderr,"count: %d \n",p->count); send_ipack(p); if (rest > 0 && count - rest > 0) write_ipack(p, data+rest, count-rest); } } void instant_repack (uint8_t *buf, int count, ipack *p) { int l; unsigned short *pl; int c=0; while (c < count && (p->mpeg == 0 || (p->mpeg == 1 && p->found < 7) || (p->mpeg == 2 && p->found < 9)) && (p->found < 5 || !p->done)){ switch ( p->found ){ case 0: case 1: if (buf[c] == 0x00) p->found++; else p->found = 0; c++; break; case 2: if (buf[c] == 0x01) p->found++; else if (buf[c] == 0){ p->found = 2; } else p->found = 0; c++; break; case 3: p->cid = 0; switch (buf[c]){ case PROG_STREAM_MAP: case PRIVATE_STREAM2: case PROG_STREAM_DIR: case ECM_STREAM : case EMM_STREAM : case PADDING_STREAM : case DSM_CC_STREAM : case ISO13522_STREAM: p->done = 1; case PRIVATE_STREAM1: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case AUDIO_STREAM_S ... AUDIO_STREAM_E: p->found++; p->cid = buf[c]; c++; break; default: p->found = 0; break; } break; case 4: if (count-c > 1){ pl = (unsigned short *) (buf+c); p->plength = ntohs(*pl); p->plen[0] = buf[c]; c++; p->plen[1] = buf[c]; c++; p->found+=2; } else { p->plen[0] = buf[c]; p->found++; return; } break; case 5: p->plen[1] = buf[c]; c++; pl = (unsigned short *) p->plen; p->plength = ntohs(*pl); p->found++; break; case 6: if (!p->done){ p->flag1 = buf[c]; c++; p->found++; if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; else { p->hlength = 0; p->which = 0; p->mpeg = 1; p->flag2 = 0; } } break; case 7: if ( !p->done && p->mpeg == 2){ p->flag2 = buf[c]; c++; p->found++; } break; case 8: if ( !p->done && p->mpeg == 2){ p->hlength = buf[c]; c++; p->found++; } break; default: break; } } if (c == count) return; if (!p->plength) p->plength = MMAX_PLENGTH-6; if ( p->done || ((p->mpeg == 2 && p->found >= 9) || (p->mpeg == 1 && p->found >= 7)) ){ switch (p->cid){ case AUDIO_STREAM_S ... AUDIO_STREAM_E: case VIDEO_STREAM_S ... VIDEO_STREAM_E: case PRIVATE_STREAM1: if (p->mpeg == 2 && p->found == 9){ write_ipack(p, &p->flag1, 1); write_ipack(p, &p->flag2, 1); write_ipack(p, &p->hlength, 1); } if (p->mpeg == 1 && p->found == 7){ write_ipack(p, &p->flag1, 1); } if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14){ while (c < count && p->found < 14){ p->pts[p->found-9] = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; } if (c == count) return; } if (p->mpeg == 1 && p->which < 2000){ if (p->found == 7) { p->check = p->flag1; p->hlength = 1; } while (!p->which && c < count && p->check == 0xFF){ p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; } if ( c == count) return; if ( (p->check & 0xC0) == 0x40 && !p->which){ p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; p->which = 1; if ( c == count) return; p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if (p->which == 1){ p->check = buf[c]; write_ipack(p, buf+c, 1); c++; p->found++; p->hlength++; p->which = 2; if ( c == count) return; } if ( (p->check & 0x30) && p->check != 0xFF){ p->flag2 = (p->check & 0xF0) << 2; p->pts[0] = p->check; p->which = 3; } if ( c == count) return; if (p->which > 2){ if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY){ while (c < count && p->which < 7){ p->pts[p->which-2] = buf[c]; write_ipack(p,buf+c,1); c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS){ while (c < count && p->which< 12){ if (p->which< 7) p->pts[p->which -2] = buf[c]; write_ipack(p,buf+c,1); c++; p->found++; p->which++; p->hlength++; } if ( c == count) return; } p->which = 2000; } } while (c < count && p->found < p->plength+6){ l = count -c; if (l+p->found > p->plength+6) l = p->plength+6-p->found; write_ipack(p, buf+c, l); p->found += l; c += l; } break; } if ( p->done ){ if( p->found + count - c < p->plength+6){ p->found += count-c; c = count; } else { c += p->plength+6 - p->found; p->found = p->plength+6; } } if (p->plength && p->found == p->plength+6) { send_ipack(p); reset_ipack(p); if (c < count) instant_repack(buf+c, count-c, p); } } return; } void write_out_es(uint8_t *buf, int count,void *priv) { ipack *p = (ipack *) priv; uint8_t payl = buf[8]+9+p->start-1; write(p->fd, buf+payl, count-payl); p->start = 1; } void write_out_pes(uint8_t *buf, int count,void *priv) { ipack *p = (ipack *) priv; write(p->fd, buf, count); } int64_t ts_demux(int fdin, int fdv_out,int fda_out,uint16_t pida, uint16_t pidv, int es) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; uint16_t pid; ipack pa, pv; ipack *p; uint8_t *sb; int64_t apts=0; int64_t apos=0; int64_t vpts=0; int64_t vpos=0; int verb = 0; uint64_t length =0; uint64_t l=0; int perc =0; int last_perc =0; if (fdin != STDIN_FILENO) verb = 1; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } if (!pida || !pidv) find_avpids(fdin, &pidv, &pida); if (es){ init_ipack(&pa, MAX_PLENGTH-1,write_out_es, 0); init_ipack(&pv, MAX_PLENGTH-1,write_out_es, 0); } else { init_ipack(&pa, IPACKS,write_out_pes, 0); init_ipack(&pv, IPACKS,write_out_pes, 0); } pa.fd = fda_out; pv.fd = fdv_out; pa.data = (void *)&pa; pv.data = (void *)&pv; count = save_read(fdin,mbuf,TS_SIZE); if (count) l+=count; for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return 0; } else { memcpy(buf,mbuf+i,TS_SIZE-i); count = save_read(fdin,mbuf,i); if (count) l+=count; memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; while (count > 0){ count = save_read(fdin,buf+i,IN_SIZE-i)+i; if (count) l+=count; if (verb && perc >last_perc){ perc = (100*l)/length; fprintf(stderr,"Reading TS %d %%\r",perc); last_perc = perc; } for( i = 0; i < count; i+= TS_SIZE){ uint8_t off = 0; if ( count - i < TS_SIZE) break; pid = get_pid(buf+i+1); if (!(buf[3+i]&0x10)) // no payload? continue; if ( buf[1+i]&0x80){ fprintf(stderr,"Error in TS for PID: %d\n", pid); } if (pid == pidv){ p = &pv; } else { if (pid == pida){ p = &pa; } else continue; } if ( buf[3+i] & 0x20) { // adaptation field? off = buf[4+i] + 1; } if ( buf[1+i]&0x40) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } sb = buf+4+off+i; if( es && !p->start && (sb[7] & PTS_DTS_FLAGS)){ uint8_t *pay = sb+sb[8]+9; int l = TS_SIZE - 13 - off - sb[8]; if ( pid == pidv && (p->start = get_vinfo( pay, l,&p->vi,1)+1) >0 ){ vpts = trans_pts_dts(sb+9); vpos = (int)(l-count+pay); printf("vpts : %fs\n", vpts/90000.); } if ( pid == pida && es==1 && (p->start = get_ainfo( pay, l,&p->ai,1)+1) >0 ){ apts = trans_pts_dts(sb+9); printf("apts : %fs\n", apts/90000.); } if ( pid == pida && es==2 && (p->start = get_ac3info( pay, l,&p->ai,1)+1) >0 ){ apts = trans_pts_dts(sb+9); apos = (int)(l-count+pay); printf("apts : %fs\n", apts/90000.); } } } if (p->start) instant_repack(buf+4+off+i, TS_SIZE-4-off, p); } i = 0; } fprintf(stderr, "VPOS-APOS %d",(int)(vpos-apos)); return (vpts-apts); } void ts2es_opt(int fdin, uint16_t pidv, ipack *p, int verb) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int i; int count = 1; uint64_t length =0; uint64_t l=0; int perc =0; int last_perc =0; uint16_t pid; if (verb) { length = lseek(fdin, 0, SEEK_END); lseek(fdin,0,SEEK_SET); } count = save_read(fdin,mbuf,TS_SIZE); if (count) l+=count; for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); return; } else { memcpy(buf,mbuf+i,TS_SIZE-i); count = save_read(fdin,mbuf,i); if (count) l+=count; memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } count = 1; while (count > 0){ count = save_read(fdin,buf+i,IN_SIZE-i)+i; if (count) l+=count; if (verb && perc >last_perc){ perc = (100*l)/length; fprintf(stderr,"Reading TS %d %%\r",perc); last_perc = perc; } for( i = 0; i < count; i+= TS_SIZE){ uint8_t off = 0; if ( count - i < TS_SIZE) break; pid = get_pid(buf+i+1); if (!(buf[3+i]&0x10)) // no payload? continue; if ( buf[1+i]&0x80){ fprintf(stderr,"Error in TS for PID: %d\n", pid); } if (pid != pidv){ continue; } if ( buf[3+i] & 0x20) { // adaptation field? off = buf[4+i] + 1; } if ( buf[1+i]&0x40) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } } instant_repack(buf+4+off+i, TS_SIZE-4-off, p); } i = 0; } } void ts2es(int fdin, uint16_t pidv) { ipack p; int verb = 0; init_ipack(&p, IPACKS,write_out_es, 0); p.fd = STDOUT_FILENO; p.data = (void *)&p; if (fdin != STDIN_FILENO) verb = 1; ts2es_opt(fdin, pidv, &p, verb); } void change_aspect(int fdin, int fdout, int aspect) { ps_packet ps; pes_packet pes; int neof,i; do { init_ps(&ps); neof = read_ps(fdin,&ps); write_ps(fdout,&ps); for (i = 0; i < ps.npes; i++){ uint8_t *buf; int c = 0; int l; init_pes(&pes); read_pes(fdin, &pes); buf = pes.pes_pckt_data; switch (pes.stream_id){ case VIDEO_STREAM_S ... VIDEO_STREAM_E: l=pes.length; break; default: l = 0; break; } while ( c < l - 6){ if (buf[c] == 0x00 && buf[c+1] == 0x00 && buf[c+2] == 0x01 && buf[c+3] == 0xB3) { c += 4; buf[c+3] &= 0x0f; buf[c+3] |= aspect; } else c++; } write_pes(fdout,&pes); } } while( neof > 0 ); } libdvb-0.5.5.1/sample_progs/0000755000175000017500000000000010220016115015511 5ustar mocmmocm00000000000000libdvb-0.5.5.1/sample_progs/.cvsignore0000644000175000017500000000005010220016115017504 0ustar mocmmocm00000000000000merge_dvb conv satscan cam_test cam_set libdvb-0.5.5.1/sample_progs/Makefile0000644000175000017500000000305410220016115017153 0ustar mocmmocm00000000000000 include ../config.mk LIBS=-L../ DVB_LIBS=libdvb.a libdvbci.a HEADERS=DVB.hh ci.hh devices.hh channel.h SOURCES=Makefile $(HEADERS) DVB.cc ci.cc devices.cc OSD.h OSD.c osd.hh\ merge.cc conv.cc satscan.cc cam_set.cc cam_test.cc quickscan.cc cam_menu.cc RESOURCES=README astrarc hotbirdrc main: $(TEST_PROGS) dump_TS: dump_TS.cc ../libdvb/libdvb.a ../include/DVB.hh $(CXX) $(LIBS) $(INCLUDES) $(CFLAGS) -o dump_TS dump_TS.cc -ldvb -ldvbmpegtools merge_dvb: merge.cc ../libdvb/libdvb.a ../include/DVB.hh $(CXX) $(LIBS) $(INCLUDES) $(CFLAGS) -o merge_dvb merge.cc -ldvb conv: conv.cc ../libdvb/libdvb.a ../include/DVB.hh $(CXX) $(LIBS) $(INCLUDES) $(CFLAGS) -o conv conv.cc -ldvb satscan: satscan.cc ../libdvb/libdvb.a ../include/DVB.hh $(CXX) $(LIBS) $(INCLUDES) $(CFLAGS) -o satscan satscan.cc -ldvb quickscan: quickscan.cc ../libdvb/libdvb.a ../include/DVB.hh $(CXX) $(LIBS) $(INCLUDES) $(CFLAGS) -o quickscan quickscan.cc -ldvb cam_set: cam_set.cc cam_menu.hh ../libdvbci/libdvbci.a ../include/ci.hh $(CXX) $(LIBS) $(INCLUDES) $(CFLAGS) -o cam_set cam_set.cc -ldvbci cam_test: cam_test.cc ../libdvb/libdvb.a ../include/DVB.hh ../include/ci.hh $(CXX) $(LIBS) $(INCLUDES) -o cam_test cam_test.cc -ldvb -ldvbmpegtools cam_menu: cam_menu.cc cam_menu.hh ../libdvb/libdvb.a ../include/DVB.hh $(CXX) $(LIBS) $(INCLUDES) -o cam_menu cam_menu.cc -ldvb status_check: status_check.c $(CC) $(INCLUDES) $(CFLAGS) -o status_check status_check.c .c.o: $(CC) $(INCLUDES) $(CFLAGS) -c $< .cc.o: $(CXX) $(INCLUDES) $(CFLAGS) -c $< clean: -rm -f *.o $(TEST_PROGS) *~ libdvb-0.5.5.1/sample_progs/cam_menu.cc0000644000175000017500000000573510220016115017616 0ustar mocmmocm00000000000000#include #include #include using namespace std; #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cam_menu.hh" #include "DVB.hh" struct termios stored_settings; void set_keypress() { struct termios new_settings; tcgetattr(STDIN_FILENO,&stored_settings); tcgetattr(STDIN_FILENO,&new_settings); new_settings.c_iflag = 0; new_settings.c_lflag &= ~(ICANON | ECHO); new_settings.c_cc[VTIME] = 0; new_settings.c_cc[VMIN] = 0; tcsetattr(STDIN_FILENO, TCSANOW,&new_settings); } void reset_keypress() { tcsetattr(STDIN_FILENO, TCSANOW, &stored_settings); } #define MENU_SOCK 4712 void byebye(int i, void *f) { int fd = (int) f; CamPacket cp(fd, CMENU_CLOSE, 0, NULL); cp.psend(); close(fd); reset_keypress(); } int main(int argc, char **argv) { int c; char *sockname=0; int menu_sock = MENU_SOCK; int handler_fd; struct pollfd pfd[2]; for (;;) { if (-1 == (c = getopt(argc, argv, "s:u:"))) break; switch (c) { case 's': menu_sock=strtol(optarg,(char **) NULL, 0); break; case 'u': sockname = strdup(optarg); break; } } if(sockname) handler_fd = udp_client_connect(sockname); else handler_fd = tcp_client_connect("localhost", menu_sock); on_exit(byebye, (void *)handler_fd); pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; pfd[1].fd = handler_fd; pfd[1].events = POLLIN; set_keypress(); while(1){ if (poll(pfd,2,100)>0){ if ( pfd[0].revents & POLLIN ){ uint8_t sl; int r=read(STDIN_FILENO, &sl, 1); if (r==1){ if (sl == 'r'){ CamPacket cp(handler_fd, CAM_RESET, sl, NULL); cp.psend(); close(handler_fd); if(sockname) handler_fd = udp_client_connect(sockname); else handler_fd = tcp_client_connect("localhost", menu_sock); } else if (sl == 'q'){ cerr << "closing down" << endl; exit(0); } else { CamPacket cp(handler_fd, CMENU_SELECT, sl, NULL); cp.psend(); } cout << char(sl) << endl; } } if ( pfd[1].revents & POLLIN ){ CamPacket cp(handler_fd); cp.preceive(); switch(cp.type()){ case CMENU_TITLE: case CMENU_SUBTITLE: case CMENU_BOTTOMTEXT: case CMENU_ERROR: case CENQUIRY_TEXT: if (cp.length()) cout << cp.Payload() << endl; break; case CMENU_ENTRY: if (cp.length()) cout << cp.extra()+1 << ") " << cp.Payload() << endl; break; case CMENU_NENTRY: cout << cp.length() << " entries" << endl; break; case CENQUIRY_BLIND: break; case CENQUIRY_LENGTH: cout << cp.length() << " enquiry length" << endl; break; case CENQUIRY_REPLY: case CMENU_SELECT: break; } } } } } libdvb-0.5.5.1/sample_progs/cam_menu.hh0000644000175000017500000000574410220016115017630 0ustar mocmmocm00000000000000/* * cam_menu.hh * */ #include #include #ifndef __CAM_MENU_HH #define __CAM_MENU_HH #define MENU_SOCK 4712 typedef enum { CMENU_TITLE, CMENU_SUBTITLE, CMENU_BOTTOMTEXT, CMENU_ENTRY, CMENU_NENTRY, CENQUIRY_TEXT, CENQUIRY_BLIND, CENQUIRY_LENGTH, CENQUIRY_REPLY, CMENU_SELECT, CMENU_ERROR, CMENU_CLOSE, CAM_RESET } cpacket_type; typedef struct campacket_s{ cpacket_type type; int length; int extra; } campacket; class CamPacket{ campacket cp; uint8_t *payload; int fd; int clearp; int read_payload(){ int count = 0; int length = cp.length; int to=0; if (!payload){ payload = new uint8_t [length+1]; clearp = 1; memset(payload,0,length+1); } while(count < length && to<10){ int re; if ((re=read(fd, (char *)(payload+count), length-count))>=0) count+=re; else perror("read_payload"); to++; } if (to==10) return -1; else return 0; } int read_pack(){ int count = 0; int length = sizeof(campacket); int to=0; while(count < length && to<10){ int re; if ((re=read(fd, (char *)(&cp+count), length-count))>=0) count+=re; else perror("read_pack"); to++; } if (to==10) return -1; else return 0; } public: void init(int f, int t, int length, uint8_t *p, int e=-1){ cp.type = cpacket_type(t); cp.length = length; payload = p; fd = f; clearp = 0; cp.extra = e; } void clear(){ init(0, 0, 0, NULL); if (clearp) delete [] payload; } ~CamPacket(){ if (clearp) delete [] payload; } CamPacket(int f){ init(f, 0, 0, NULL); } CamPacket(){ init(0, 0, 0, NULL); } CamPacket(int f, int t, int length, uint8_t *p, int e=-1){ init(f, t, length, p, e); } int psend(){ if (fd <0) return -1; int sent = send(fd,(void *)&cp,sizeof(campacket),0); if(sent < 0){ perror("send"); return sent; } switch (cp.type){ case CMENU_TITLE: case CMENU_SUBTITLE: case CMENU_BOTTOMTEXT: case CMENU_ENTRY: case CENQUIRY_TEXT: case CENQUIRY_REPLY: case CMENU_ERROR: sent = send(fd, payload, cp.length, 0); if(sent < 0){ perror("send"); return -sent; } break; case CMENU_NENTRY: case CENQUIRY_BLIND: case CENQUIRY_LENGTH: case CMENU_SELECT: case CAM_RESET: case CMENU_CLOSE: break; } return 0; } int preceive(){ if (fd<0) return -1; if (read_pack()<0) return -1; switch (cp.type){ case CMENU_TITLE: case CMENU_SUBTITLE: case CMENU_BOTTOMTEXT: case CMENU_ENTRY: case CENQUIRY_TEXT: case CENQUIRY_REPLY: case CMENU_ERROR: if (cp.length) if (read_payload()<0) return -1; break; case CMENU_NENTRY: case CENQUIRY_BLIND: case CENQUIRY_LENGTH: case CMENU_SELECT: case CMENU_CLOSE: case CAM_RESET: break; } return 0; } int type(){ return int(cp.type);} int length(){ return int(cp.length);} int extra(){ return int(cp.extra);} char *Payload(){ return (char *)payload;} }; #endif //__CAM_MENU_HH libdvb-0.5.5.1/sample_progs/cam_set.cc0000644000175000017500000003504310220016115017440 0ustar mocmmocm00000000000000#include #include #include using namespace std; #include #include #include #include #include #include #include #include #include #include #include #include #define TIMEOUT 30 #include "ci.hh" #include "cam_menu.hh" #define CA_DEV "/dev/dvb/adapter%d/ca%d" #define DEMUX_DEV "/dev/dvb/adapter%d/demux%d" #define MENUTIMEOUT 10 enum{SEARCH, NONE,CAM}; #define SERV_SOCK 4711 #define NOPID 0xffff void show_buf(uint8_t *buf, int length) { printf("\n"); for (int i=0; i=0) count+=re; else return re; } return count; } int child_events = 0; void child_sig_handler (int x) { child_events++; cerr << "Signal Handler" << endl; signal (SIGCHLD, child_sig_handler); } enum {MENU_START, MENU_ENQUIRY, MENU_NONE}; #define BLEN 2048 int main(int argc, char **argv) { int c; time_t startt=0; time_t mtime=0; uint16_t length=0; ifstream con(argv[1]); cCiHandler *ciHandler; struct timeval tv; fd_set rfds; char devname[80]; int adapter = 0; int minor = 0; int state = SEARCH; uint8_t buffer[BLEN]; uint16_t vpid=0; uint16_t apid1=0; uint16_t apid2=0; uint16_t dpid1=0; uint16_t sid=0; uint16_t set_sid=0; uint16_t current_vpid=0; uint16_t current_apid1=0; uint16_t current_apid2=0; uint16_t current_dpid1=0; uint16_t current_sid=0; sockaddr_in ip_name1; sockaddr_un udp1; sockaddr_in ip_name2; sockaddr_un udp2; char *sockname1=0; char *sockname2=0; int ip_sock1=-1; int ip_sock2=-1; int conn1=-1; int conn2=-1; bool localonly=false; int timeout=10000; int menustate=MENU_NONE; cCiMenu *ciMenu = NULL; cCiEnquiry *ciEnquiry = NULL; uint8_t mrange = 0; int EnLength = 0; char *input = NULL; int menu_sock = MENU_SOCK; int simple_ci = 0; ca_slot_info_t sinfo; for (;;) { if (-1 == (c = getopt(argc, argv, "a:m:lu:v:s:"))) break; switch (c) { case 'a': adapter = strtol(optarg,(char **) NULL, 0); break; case 'm': minor = strtol(optarg,(char **) NULL, 0); break; case 'l': localonly=true; break; case 'u': sockname1=strdup(optarg); unlink(sockname1); break; case 'v': sockname2=strdup(optarg); unlink(sockname2); break; case 's': menu_sock=strtol(optarg,(char **) NULL, 0); break; } } sprintf(devname,CA_DEV,adapter,minor); int cafd; if ((cafd = open(devname,O_RDONLY))<0){ perror("ca device"); exit(1); } ca_caps_t caps; ioctl(cafd, CA_GET_CAP, &caps); if (caps.slot_num < 1){ cerr << "No CI Slots found" << endl; exit(1); } int cams=0; for (uint32_t i=0; i ip_sock2) ? ip_sock1 : ip_sock2; if (conn1 >= 0){ FD_SET(conn1,&rfds); if (conn1 > check) check =conn1; } if (conn2 >= 0){ FD_SET(conn2,&rfds); if (conn2 > check) check =conn2; } int ret = select(check+1, &rfds, NULL, NULL, &tv); if (ret){ if (FD_ISSET(ip_sock1, &rfds) && conn1 < 0 ){ while( (conn1= (sockname1 ? accept_udp(ip_sock1, (struct sockaddr_un *) &ip_name1) : accept_tcp(ip_sock1, (struct sockaddr_in *) &ip_name1) )) < 0) cerr << "Connection attempt" << endl; cerr << "CI HANDLER: connection established" << endl; continue; } if (FD_ISSET(ip_sock2, &rfds) && conn2 <0){ while( (conn2= (sockname2 ? accept_udp(ip_sock2, (struct sockaddr_un *) &ip_name2) : accept_tcp(ip_sock2, (struct sockaddr_in *) &ip_name2) )) < 0) cerr << "Connection attempt" << endl; cerr << "CAM MENU: connection established" << endl; continue; } if (conn1>=0 && FD_ISSET(conn1, &rfds)){ timeout = 100; my_read(conn1,buffer,12); memcpy(&sid,buffer,2); memcpy(&vpid,buffer+2,2); memcpy(&apid1,buffer+4,2); memcpy(&apid2,buffer+6,2); memcpy(&dpid1,buffer+8,2); memcpy(&length,buffer+10,2); if (sid && !vpid && !apid1 && !apid2 && !dpid1 && !length){ state = CAM; cerr << "state: CAM" << endl; continue; } if (!sid && !vpid && !apid1 && !apid2 && !dpid1 && !length){ close(conn1); conn1=-1; cerr << "CI HANDLER: client hung up" << endl; //state = SEARCH; continue; } if (sid==1 && vpid==1 && apid1==1 && apid2==1 && dpid1==1 && length==1){ cerr << "CI HANDLER: ending handler" << endl; exit(0); } current_sid = sid; current_vpid = vpid; current_apid1 = apid1; current_apid2 = apid2; current_dpid1 = dpid1; if (current_vpid == NOPID){ cerr << "MISSING VIDEO PID" << endl; } if (current_apid1 == NOPID){ cerr << "MISSING AUDIO PID" << endl; } if (length+12 > 2048){ cerr << "section too long" << endl; exit(1); } my_read(conn1,buffer+12,length); cerr << hex << "CI HANDLER: 0x" << current_sid << " 0x" << current_vpid << " 0x" << current_apid1 << " 0x" << current_apid2 << " 0x" << current_dpid1 << " 0x" << length << " |"; for (int i=12 ; iGetCaSystemIds(Slot); if (!caids) continue; do { cerr << "checking " << *caids << endl; if ( sysid == *caids) { int l = length + cam_length[Slot]; if (l <= BLEN) { memcpy(cam_buf+ Slot*BLEN + cam_length[Slot], buffer+12, length); cam_length[Slot] += length; } done=1; } else caids++; count++; } while (!done && *caids && count=0 && FD_ISSET(conn2, &rfds)){ uint8_t sl=0; CamPacket cp(conn2); if (cp.preceive()<0){ close(conn2); conn2=-1; cerr << "CAM MENU: error, closing connection" << endl; mtime = time(0)+MENUTIMEOUT; menustate = MENU_NONE; if (!simple_ci && ciMenu) ciMenu->Cancel(); if (simple_ci) ci_cancel_menu(cafd,0); continue; } if (cp.type() == CAM_RESET){ if ( (!simple_ci && ciHandler && ciHandler->Reset(0)) || (simple_ci && !ci_reset(cafd,0))){ close(conn2); conn2=-1; close(conn1); conn1=-1; cerr << "Resetting CAM" << endl; mtime = 0; menustate = MENU_NONE; state = SEARCH; continue; } } if (cp.type() == CMENU_CLOSE){ close(conn2); conn2=-1; cerr << "Closing Menu Connection" << endl; mtime = time(0)+MENUTIMEOUT; menustate = MENU_NONE; if(!simple_ci && ciMenu) ciMenu->Cancel(); if (simple_ci) ci_cancel_menu(cafd,0); continue; } switch (menustate){ case MENU_NONE: { if (cp.type() != CMENU_SELECT) break; sl = cp.length(); sl -= 48; if (!sl) break; if (sl<= numslot && ((!simple_ci && ciHandler->EnterMenu(sl-1))|| (simple_ci && !ci_enter_menu(cafd,sl-1)))){ cerr << "Enter Menu" << endl; mtime = time(0)+MENUTIMEOUT; } else { char errmsg[21]; strncpy(errmsg,"Can't open CAM menu!",20); errmsg[20]=0; CamPacket cp(conn2, CMENU_ERROR, 21, (uint8_t *)errmsg); cp.psend(); cerr << errmsg << endl; } } break; case MENU_START: { if (cp.type() != CMENU_SELECT) break; sl = cp.length(); sl -= 48; if (!simple_ci && ciMenu){ if (ciMenu->Selectable() && sl <= mrange && sl>0){ ciMenu->Select((uint8_t)(sl-1)); } else { ciMenu->Cancel(); } } else if (simple_ci){ if (sl <= mrange && sl>0){ ci_menu_select(cafd,0,(uint8_t)(sl-1)); } else { ci_cancel_menu(cafd,0); } } mtime = time(0)+MENUTIMEOUT; } break; case MENU_ENQUIRY: { if (cp.type() != CENQUIRY_REPLY) break; input = new char [EnLength+1]; memset(input,0, EnLength+1); if ( cp.length() == EnLength){ memcpy(input, cp.Payload(), EnLength); if (input[0] == 'q'){ ciEnquiry->Cancel(); } else { if (ciEnquiry) ciEnquiry->Reply(input); } menustate = MENU_START; delete [] input; } } break; } } if (simple_ci){ if(state==CAM){ char devname[80]; sprintf(devname,DEMUX_DEV,adapter,minor); int fd = open(devname, O_RDWR); set_sid = current_sid; ci_enable_pnr(fd, cafd, 0, current_sid); close(fd); state = NONE; } uint8_t buf[256]; if (ci_getmsg(cafd, 0, buf)>=0){ CamPacket cp; mtime = 0; if (strlen((char *)buf)>1) fprintf(stderr,"%s\n",(char *)buf); } } if (!simple_ci && ciHandler) { if (mtime && mtime < time(0)){ mtime = 0; menustate = MENU_NONE; } if (ciHandler->HasUserIO()) { CamPacket cp; ciMenu = NULL; ciMenu = ciHandler->GetMenu(); mtime = 0; if (ciMenu){ if (ciMenu->TitleText()){ cp.init(conn2, CMENU_TITLE, strlen(ciMenu->TitleText()), (uint8_t *)ciMenu->TitleText()); cp.psend(); cout << ciMenu->TitleText() << endl; if (ciMenu->SubTitleText()){ cp.init(conn2, CMENU_SUBTITLE, strlen(ciMenu->SubTitleText()), (uint8_t *)ciMenu->SubTitleText()); cp.psend(); cout << ciMenu->SubTitleText() << endl; } } else { cp.init(conn2, CMENU_TITLE, 0, NULL); cp.psend(); cout << "CAM MENU" << endl; } mrange = ciMenu->NumEntries(); cout << endl; cp.init(conn2, CMENU_NENTRY, mrange, NULL); cp.psend(); for (int i = 0; i < mrange; i++){ char dummy[80]; strncpy(dummy,ciMenu->Entry(i), 80); cp.init(conn2, CMENU_ENTRY, sizeof(dummy), (uint8_t *)(dummy), i); cp.psend(); cout << i+1 << ") " << dummy << endl; } cout << endl; if (ciMenu->BottomText()){ cp.init(conn2, CMENU_BOTTOMTEXT, strlen(ciMenu->BottomText()), (uint8_t *)ciMenu->BottomText()); cp.psend(); cout << ciMenu->BottomText() << endl << endl; } menustate = MENU_START; cout << "Enter 0 to exit" << endl; } else { ciEnquiry = ciHandler->GetEnquiry(); if (ciEnquiry) { EnLength = ciEnquiry->ExpectedLength(); cp.init(conn2, CENQUIRY_LENGTH, EnLength, NULL); cp.psend(); if(ciEnquiry->Text()){ cp.init(conn2, CENQUIRY_TEXT, strlen(ciEnquiry->Text()), (uint8_t *)ciEnquiry->Text()); cp.psend(); cout << "Enquiry: " << ciEnquiry->Text() << endl; } else { cp.init(conn2, CENQUIRY_TEXT, 0, NULL); cp.psend(); cout << "CAM Enquiry" << endl; } menustate = MENU_ENQUIRY; cout << "Enter key of length " << EnLength << " or q to exit" << endl; enread = 0; } } } if (ciHandler->Process()) { if (state == CAM) { for (int Slot = 0; Slot < numslot; Slot++) { if (cam_length[Slot] > 0) { cCiCaPmt CaPmt(current_sid); CaPmt.AddCaDescriptor(cam_length[Slot], cam_buf+Slot*BLEN); if (current_vpid) CaPmt.AddPid(current_vpid); if (current_apid1) CaPmt.AddPid(current_apid1); if (current_apid2) CaPmt.AddPid(current_apid2); if (current_dpid1) CaPmt.AddPid(current_dpid1); if (ciHandler->SetCaPmt( CaPmt,Slot)) { state = NONE; cerr << "state: NONE" << endl; cam_length[Slot]=0; memset(cam_buf, 0,Slot*BLEN); timeout=1000; } } } } else if(!ciHandler->connected() && time(0)-startt > TIMEOUT) { cerr << "No working CAM found within " << TIMEOUT << " seconds." << endl; if(conn1>=0) close(conn1); if(ip_sock1>=0) close(ip_sock1); if(conn2>=0) close(conn2); if(ip_sock2>=0) close(ip_sock2); exit(0); } } } } } libdvb-0.5.5.1/sample_progs/cam_test.cc0000644000175000017500000002367310220016115017632 0ustar mocmmocm00000000000000#include #include "DVB.hh" #include #include #include #include #include #include #include #include #define FILELEN 80 int handler_fd; int found_ecm (Channel *chan) { ecm_t *ecm = &chan->ecm; cerr << "found ecm" << endl; for (int i=0; i < ecm->num; i++){ cerr << " ECM: sysid 0x" << hex << ecm->sysid[i] << " pid 0x" << ecm->pid[i]; cerr << " dlength " << ecm->length[i] << " descriptor:"; if (ecm->length[i]){ for (int j=0; j< ecm->length[i]; j++){ cerr << " 0x" << int(ecm->data[j+i*MAX_ECM_DESC]); } } cerr << endl; } return 1; } void write_out(uint8_t *buf, int count,void *p) { if ((buf[3] & 0xe0) == 0xe0) buf[3] = 0xe0; write(STDOUT_FILENO, buf, count); } void help(){ cerr << "usage: cam_test [options]" << endl << "-h print this help" << endl << "-s activate string input/search for channel" << endl << "-f open name as dvbrc file" << endl << "-a use /dev/dvb/adaptorN" << endl << "-d activate dvr output" << endl << "-o output dvr to stdout" << endl << "-p output dvr as PS" << endl << "-u use socket name for io with cam_set" << endl << "-c tune to channel N at startup" << endl << "-v use name as VTX directory" << endl << "-n don't use cam" << endl << "-q frequency in Hz" << endl << "-Q ignore stdin input, allow closing stdin" << endl << "-l polarity (V/H)" << endl << "-r sample rate in Hz" << endl << "-i service pid"<< endl << "-t audio pid"<< endl << "-y inversion (0=OFF(DEFAULT),1=ON,2=AUTO)" << "-x diseqc"<< endl << "-z show switch time" << endl; } #define IN_SIZE TS_SIZE*10 #define IPACKS 2048 int main(int argc, char **argv) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int cnum=-1; int c,count ; int show_time=0; clock_t clock1, clock2; struct tms ts1,ts2; Channel *chan; char filename[FILELEN]; char *sockname=0; char *vtxdir=0; char *pol=0; int adapter=0; int dvr=0; int np=1; uint8_t str[12]; int fd_dvr=-1; char devname[80]; ipack pa, pv; ipack *p; uint16_t apid=NOPID; uint16_t vpid=NOPID; uint16_t ttpid=NOPID; int i=0; int cam=1; int ts2ps=0; int strsearch=0; int freq=0; int srate=0; int sid=NOPID; int napid=NOPID; int nvpid=NOPID; int dis=0; int inv =0; bool no_stdin=false; memset(filename, 0, FILELEN); for (;;) { if (-1 == (c = getopt(argc, argv, "hf:a:du:onc:pv:V:sq:Ql:r:i:t:x:y:z"))) break; switch (c) { case 'h': help(); exit(0); break; case 's': strsearch=1; break; case 'f': strncpy(filename, optarg, FILELEN); break; case 'd': dvr = 1; break; case 'a': adapter = strtol(optarg,(char **) NULL, 0); break; case 'u': sockname = strdup(optarg); break; case 'o': dvr = 2; break; case 'n': cam = 0; break; case 'c': cnum = strtol(optarg,(char **)NULL,0); break; case 'p': ts2ps = 1; break; case 'v': vtxdir = strdup(optarg); break; case 'q': freq = strtol(optarg,(char **)NULL,0); if(!freq) freq = -1; break; case 'Q': no_stdin=true; break; case 'l': pol = strdup(optarg); break; case 'r': srate = strtol(optarg,(char **)NULL,0); break; case 'i': sid = strtol(optarg,(char **)NULL,0); break; case 't': napid = strtol(optarg,(char **)NULL,0); break; case 'V': nvpid = strtol(optarg,(char **)NULL,0); break; case 'x': dis = strtol(optarg,(char **)NULL,0); break; case 'y': inv = strtol(optarg,(char **)NULL,0); break; case 'z': show_time=1; break; } } DVB dvb(adapter); dvb.set_showtime(show_time); if(vtxdir) { dvb.set_vtxdir(vtxdir); free(vtxdir); } sprintf(devname,DVR_DEV,adapter,0); if (!freq){ if (get_dvbrc(filename,dvb,0,FILELEN)) { cerr << "Found DVB input file " << filename << endl; } else { cerr << "Could not find DVB input file " << filename << endl; exit(1); } } else { Transponder tp; Channel nchan; dvb.AddLNB(1, 1, 9750000, 10600000, 11700000, dis, NOID, NOID); dvb.AddSat( 1, 1,"who cares", 10700000 , 12700000); if (inv==1) tp.inversion = INVERSION_ON; else if (inv==2) tp.inversion = INVERSION_AUTO; else if (inv==0) tp.inversion = INVERSION_OFF; tp.satid = 1; tp.freq = freq; tp.srate = srate; tp.type = FE_QPSK; tp.fec = FEC_AUTO; if (pol && pol[0] == 'H') tp.pol = 1; else if (pol && pol[0] == 'V') tp.pol = 0; nchan.tpid = dvb.tps[dvb.AddTP(tp)].id; nchan.satid = dvb.tps[dvb.AddTP(tp)].satid; nchan.pnr = sid; if (napid!=NOPID){ nchan.apids[0] = napid; nchan.apidnum = 1; } if (nvpid!=NOPID) nchan.vpid = nvpid; cnum = dvb.AddChannel(nchan); } if (dvr){ dvb.enable_DVR_other(); if (dvr>1) np = 2; } struct pollfd pfd[np]; pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; if(dvr>1){ pfd[1].fd = -1; pfd[1].events = 0; } while(1){ if (cnum >=0 && cnum < dvb.num[CHAN]){ if (dvr>1) close(fd_dvr); if (show_time) clock1=times(&ts1); if (dvb.SetChannel(cnum,NULL,&apid,&vpid,freq>=0)<0){ cerr << "Tuning failed for " << dvb.chans[cnum].name << endl; cnum = -1; continue; } if (show_time){ clock2=times(&ts2); cerr << "Switch time = " << (double)(clock2-clock1) /double(sysconf(_SC_CLK_TCK)) << "s" << endl; } if (dvb.chans[cnum].vpid == NOPID){ cerr << "MISSING VIDEO PID" << endl; } if (dvb.chans[cnum].apidnum ==0){ cerr << "MISSING AUDIO PID" << endl; } ttpid = dvb.chans[cnum].ttpid; cerr << "Channel: " << dvb.chans[cnum].name << " apid: 0x" << hex << apid << " vpid: 0x" << vpid << " ttpid: 0x" << ttpid<< endl; chan = &dvb.chans[cnum]; chan->ecm_callback= found_ecm; if (cam && !chan->ecm.num) dvb.check_ecm(chan); if (cam && chan->ecm.num){ if(sockname) handler_fd = udp_client_connect(sockname); else handler_fd = tcp_client_connect("localhost", 4711); ecm_t *ecm = &chan->ecm; for (int i=0; i < ecm->num; i++){ memcpy(str,&chan->pnr,2); memcpy(str+2,&chan->vpid,2); memcpy(str+4,&chan->apids[0],2); memcpy(str+6,&chan->apids[1],2); memcpy(str+8,&chan->ac3pid,2); memcpy(str+10,&ecm->length[i],2); cerr << "CAM Test: 0x" << chan->pnr << " 0x" << chan->vpid << " 0x" << chan->apids[0] << " 0x" << chan->apids[1] << " 0x" << chan->ac3pid << " 0x" << ecm->length[i] << endl; client_send_msg(handler_fd, str, 12); client_send_msg(handler_fd, ecm->data+(i*MAX_ECM_DESC), ecm->length[i]); } memset(str+2,0,10); client_send_msg(handler_fd, str, 12); memset(str, 0, 12); client_send_msg(handler_fd, str, 12); } if (dvr>1){ fd_dvr = open(devname, O_RDONLY); if (fd_dvr < 0) { cerr << "Could not open " << devname << endl; perror(devname); } else { pfd[1].fd = fd_dvr; pfd[1].events = POLLIN; if(ts2ps) { init_ipack(&pa, IPACKS,write_out, 1); init_ipack(&pv, IPACKS,write_out, 1); } if ((count = save_read(fd_dvr,mbuf,TS_SIZE))<0) perror("reading"); for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); } else { memcpy(buf,mbuf+i,TS_SIZE-i); if ((count = save_read(fd_dvr,mbuf,i))<0) perror("reading"); memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } } } cnum = -1; } if (poll(pfd,np,1000)>0){ if (dvr>1 && (pfd[1].revents & POLLIN)){ if ((count = save_read(fd_dvr,buf+i,IN_SIZE-i)+i)<0) perror("reading"); for(i = 0; i < count; i+= TS_SIZE){ uint8_t off = 0; if ( count - i < TS_SIZE) break; uint16_t pid = get_pid(buf+i+1); if (!(buf[3+i]&0x10)) // no payload? continue; if ( buf[1+i]&0x80){ fprintf(stderr,"Error in TS for PID: %d\n", pid); } if (ts2ps && pid == vpid){ p = &pv; } else if (ts2ps && pid == apid){ p = &pa; } else if (pid == ttpid){ int l, j=0; uint8_t mpag, mag, pack; for(l=0; l<4; l++) { if(buf[4+l*46+i]==2) { for(j=(8+l*46)+i; j<(50+l*46)+i; j++) buf[j] = invtab[ buf[j]]; mpag=deham(buf[0x8+l*46+i], buf[0x9+l*46+i]); mag=mpag&7; pack=(mpag>>3)&0x1f; dvb.add_vtx_line( &dvb.magazin[mag], pack, &buf[10+l*46+i], pid); } } continue; } else if(ts2ps) continue; if ( ts2ps && buf[1+i]&0x40) { if (p->plength == MMAX_PLENGTH-6){ p->plength = p->found-6; p->found = 0; send_ipack(p); reset_ipack(p); } } if ( ts2ps && buf[3+i] & 0x20) { // adaptation field? off = buf[4+i] + 1; } if(ts2ps) instant_repack(buf+4+off+i, TS_SIZE-4-off, p); else write(1, buf+i, TS_SIZE); } i = 0; } if (!no_stdin && (pfd[0].revents & POLLIN)){ if (strsearch){ char cdummy[MAXNAM+1]; memset(cdummy,0,MAXNAM+1); getname(cdummy,cin,char(0),'\n'); int nn=0; if (!strncmp(cdummy,"exit",4)) exit(0); else { while ( nn < dvb.num[CHAN] && strncmp(cdummy, dvb.chans[nn].name, strlen(cdummy))){ nn++; } cnum =nn; if (cnum == dvb.num[CHAN]) cerr << "channel not found" << endl; } } else { cin >> cnum; if (cnum < 0){ exit(0); } } } } } } libdvb-0.5.5.1/sample_progs/conv.cc0000644000175000017500000000026710220016115016772 0ustar mocmmocm00000000000000#include #include "DVB.hh" int main(int argc, char **argv) { ifstream con(argv[1]); DVB dvbd(-1); con >> dvbd; // dvbd.set_outtype(VDR_OUT); cout << dvbd; } libdvb-0.5.5.1/sample_progs/dump_TS.cc0000644000175000017500000001304710220016115017400 0ustar mocmmocm00000000000000#include #include "DVB.hh" #include #include #include #include #include #include #include #define FILELEN 80 int handler_fd; void help(){ cerr << "-h print this help" << endl << "-a use /dev/dvb/adaptorN" << endl << "-c tune to channel N at startup" << endl << "-f open name as dvbrc file" << endl << "-l polarity (V/H)" << endl << "-o only PIDS" << endl << "-p filter fpid" << endl << "-q frequency in Hz" << endl << "-r sample rate in Hz" << endl << "-s activate string input/search for channel" << endl << "-x diseqc"<< endl; } #define IN_SIZE TS_SIZE*10 #define IPACKS 2048 int main(int argc, char **argv) { uint8_t buf[IN_SIZE]; uint8_t mbuf[TS_SIZE]; int cnum=-1; int c,count ; Channel *chan; char filename[FILELEN]; char *pol=0; int adapter=0; int fd_dvr=-1; char devname[80]; int i=0; int strsearch=0; int freq=0; int srate=0; int dis=0; int fdd = -1; uint16_t fpid=NOPID; int pidonly = 0; int foundpids = 0; #define MAXP 1024 uint16_t fpids[MAXP]; memset(filename, 0, FILELEN); for (;;) { if (-1 == (c = getopt(argc, argv, "ha:c:f:l:op:q:r:sx:"))) break; switch (c) { case 'a': adapter = strtol(optarg,(char **) NULL, 0); break; case 'c': cnum = strtol(optarg,(char **)NULL,0); break; case 'f': strncpy(filename, optarg, FILELEN); break; case 'l': pol = strdup(optarg); break; case 'o': pidonly = 1; break; case 'p': fpid = strtol(optarg,(char **)NULL,0); break; case 'q': freq = strtol(optarg,(char **)NULL,0); if(!freq) freq = -1; break; case 'r': srate = strtol(optarg,(char **)NULL,0); break; case 's': strsearch=1; break; case 'x': dis = strtol(optarg,(char **)NULL,0); break; default: case 'h': help(); exit(0); break; } } DVB dvb(adapter); sprintf(devname,DVR_DEV,adapter,0); if (!freq){ if (get_dvbrc(filename,dvb,0,FILELEN)) { cerr << "Found DVB input file " << filename << endl; } else { cerr << "Could not find DVB input file " << filename << endl; exit(1); } } else { Transponder tp; Channel nchan; dvb.AddLNB(1, 1, 9750000, 10600000, 11700000, dis, NOID, NOID); dvb.AddSat( 1, 1,"who cares", 10700000 , 12700000); tp.satid = 1; tp.freq = freq; tp.srate = srate; tp.type = FE_QPSK; tp.fec = FEC_AUTO; if (pol && pol[0] == 'H') tp.pol = 1; else if (pol && pol[0] == 'V') tp.pol = 0; nchan.tpid = dvb.tps[dvb.AddTP(tp)].id; nchan.satid = dvb.tps[dvb.AddTP(tp)].satid; nchan.pnr = 0; cnum = dvb.AddChannel(nchan); } struct pollfd pfd[2]; pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; pfd[1].fd = -1; pfd[1].events = 0; while(1){ if (cnum >=0 && cnum < dvb.num[CHAN]){ close(fd_dvr); if (fdd >=0) close(fdd); chan = &dvb.chans[cnum]; dvb.get_front(); fdd = dvb.SetTP(chan->tpid, chan->satid); if ( fdd < 0 || dvb.set_front() <0){ cerr << "Tuning failed for " << chan->name << " transponder" << endl; cnum = -1; continue; } cerr << "Tuning transponder of channel " << chan->name << endl; if ((fdd = dvb.SetFullFilter(fpid))<0) cerr << "Couldn't set full filter" << endl; fd_dvr = open(devname, O_RDONLY); cerr << "Opening DVR device" << devname << endl; if (fd_dvr < 0) { cerr << "Could not open " << devname << endl; perror(devname); } else { pfd[1].fd = fd_dvr; pfd[1].events = POLLIN; if ((count = save_read(fd_dvr,mbuf,TS_SIZE))<0) perror("reading"); for ( i = 0; i < 188 ; i++){ if ( mbuf[i] == 0x47 ) break; } if ( i == 188){ fprintf(stderr,"Not a TS\n"); } else { memcpy(buf,mbuf+i,TS_SIZE-i); if ((count = save_read(fd_dvr,mbuf,i))<0) perror("reading"); memcpy(buf+TS_SIZE-i,mbuf,i); i = 188; } } cnum = -1; if (pidonly) cerr << "PIDS: "; } if (poll(pfd,2,1000)>0){ if ((pfd[1].revents & POLLIN)){ if ((count = save_read(fd_dvr,buf+i,IN_SIZE-i)+i)<0) perror("reading"); if (pidonly){ for(i = 0; i < count; i+= TS_SIZE){ if ( count - i < TS_SIZE) break; uint16_t pid = get_pid(buf+i+1); int found = 0; for (int j=0; j < foundpids && j < MAXP; j++){ if (pid == fpids[j]){ found = 1; break; } } if (!found && foundpids < MAXP){ cerr << "0x" << HEX(4) << pid << " "; fpids[foundpids] = pid; foundpids++; } if (!found && !(foundpids%16)) cerr << endl << "PIDS: "; if (!found && foundpids >= MAXP) cerr << "no more PID space left" << endl; } } else write(STDOUT_FILENO, buf+i, IN_SIZE-i); i = 0; } if (pfd[0].revents & POLLIN){ if (strsearch){ char cdummy[MAXNAM+1]; memset(cdummy,0,MAXNAM+1); getname(cdummy,cin,char(0),'\n'); int nn=0; if (!strncmp(cdummy,"exit",4)) exit(0); else { while ( nn < dvb.num[CHAN] && strncmp(cdummy, dvb.chans[nn].name, strlen(cdummy))){ nn++; } cnum =nn; if (cnum == dvb.num[CHAN]) cerr << "channel not found" << endl; } } else { cin >> cnum; if (cnum < 0){ exit(0); } } } } } } libdvb-0.5.5.1/sample_progs/merge.cc0000644000175000017500000000047510220016115017125 0ustar mocmmocm00000000000000#include #include "DVB.hh" int main(int argc, char **argv) { int i; DVB dvbd(-1); for (i = 0 ; i < argc-1 ; i++){ ifstream ifs(argv[i+1]); if (!ifs) { cerr << "Couldn't open " << argv[2] << endl; exit(1); } cerr << "Reading " << argv[i+1] << endl; ifs >> dvbd; } cout << dvbd; } libdvb-0.5.5.1/sample_progs/quickscan.cc0000644000175000017500000000115210220016115020000 0ustar mocmmocm00000000000000#include #include #include int main(int argc, char **argv) { int n=0; int adapter=0; int c; int v=1; for (;;) { if (-1 == (c = getopt(argc, argv, "a:v"))) break; switch (c) { case 'a': adapter = strtol(optarg,(char **) NULL, 0); break; case 'v': v=2; break; } } DVB dvb(-1); dvb.adapter=adapter; if ((c = dvb.scan_current(-1,v))<0) cerr << "Error in TP scan" <0){ n+=c; cerr << " found " << dec << c << " channel(s)" << endl << endl;; } } libdvb-0.5.5.1/sample_progs/satscan.cc0000644000175000017500000001137710220016115017465 0ustar mocmmocm00000000000000#include #include #include enum {Q_YESNO, Q_INTEGER, Q_FLOAT}; int ask(const char *qe, int type, void *r) { char ans[80]; cerr << qe << " ?"; switch(type){ case Q_YESNO: cerr << " (Y/N) "; cin >> ans; if ( ans[0] == 'Y' ) return 1; if ( ans[0] == 'y' ) return 1; return 0; case Q_INTEGER: { int *i = (int *)r; *i = 0; cin >> *i; } return 0; case Q_FLOAT: { float *d = (float *)r; *d = 0; cin >> *d; } return 0; } return -1; } void usage() { cerr << "usage: satscan [options] " << endl << "-h print this help" << endl << "-a use /dev/dvb/adaptorN" << endl << "-q defaultdiseqc d" << endl << "-v verbose" << endl << "-s no tuning, check current TP" << endl << "-n no interaction" << endl << "-i check other inversion settings" << endl << "-l set lof1 of LNB, e.g. 9750000" << endl << "-o set lof2 of LNB, e.g. 10600000" << endl << "-f set slof of LNB, e.g. 11700000" << endl; exit(0); } int main(int argc, char **argv) { int n=0; int adapter=0; int c; int v=1; int si=0; int dontask=0; int defaultdiseqc=0; int tryinv=0; unsigned int lof1=0; unsigned int lof2=0; unsigned int slof=0; if (argc < 2) usage(); for (;;) { if (-1 == (c = getopt(argc, argv, "l:o:f:a:q:vsnih"))) break; switch (c) { case 'l': lof1 = strtol(optarg,(char **) NULL, 0); break; case 'o': lof2 = strtol(optarg,(char **) NULL, 0); break; case 'f': slof = strtol(optarg,(char **) NULL, 0); break; case 'a': adapter = strtol(optarg,(char **) NULL, 0); break; case 'q': defaultdiseqc = strtol(optarg, (char **) NULL, 0); break; case 'v': v=2; break; case 's': si=1; break; case 'n': dontask=1; break; case 'i': tryinv = 1; break; case 'h': default: usage(); break; } } if (optind<=0){ cerr << "Enter Transponder list" << endl; exit(1); } ifstream con(argv[optind]); DVB dvb(adapter); if (si){ cerr << "Checking current transponder\n" << endl; dvb.search_in_TP(0,0,0,2); exit(0); } con >> dvb; if (dontask || ask("Clear all channels", Q_YESNO, NULL)){ cerr << "Clearing channels" << endl; for (int i=0; i=0){ diseqc << "Use different Diseqc (" << dvb.lnbs[lnb].diseqcnr << ")" << ends; if (!dontask && ask(diseqc.str().data(), Q_YESNO, NULL)){ ask("Enter diseqc Number",Q_INTEGER, &dvb.lnbs[lnb].diseqcnr); dvb.lnbs[lnb].id=dvb.lnbs[lnb].diseqcnr; dvb.sats[s].lnbid=dvb.lnbs[lnb].diseqcnr; } else if(dontask && defaultdiseqc) { dvb.lnbs[lnb].diseqcnr = defaultdiseqc; dvb.lnbs[lnb].id = defaultdiseqc; dvb.sats[s].lnbid = defaultdiseqc; } if (lof1) dvb.lnbs[lnb].lof1 = lof1; if (lof2) dvb.lnbs[lnb].lof2 = lof2; if (slof) dvb.lnbs[lnb].slof = slof; } satid = dvb.sats[s].id; for (int t=0; t < dvb.num[TRANS]; t++){ if (dvb.tps[t].satid == satid){ uint16_t tpid; int c=0; tpid = dvb.tps[t].id; if ((c = dvb.scan_TP(tpid,satid,-1,v))<0) cerr << "Error in TP scan" <0){ n+=c; cerr << " found " << dec << c << " channel(s)" << endl << endl;; } else { if (tryinv){ if (dvb.tps[t].inversion == INVERSION_OFF) dvb.tps[t].inversion = INVERSION_ON; else if (dvb.tps[t].inversion == INVERSION_ON) dvb.tps[t].inversion = INVERSION_OFF; if ((c = dvb.scan_TP(tpid,satid, -1,v))<0) cerr << "Error in TP scan" <0){ n+=c; cerr << " found " << dec << c << " channel(s)" << endl << endl;; } } } } } cerr << "Found " << dec << n << " new channels" << endl; cout << dvb; return (n > 0) ? 0 : 1; } libdvb-0.5.5.1/sample_progs/status_check.c0000644000175000017500000000711610220016115020342 0ustar mocmmocm00000000000000#include #include #include #include #include #include #include #include #include #define FRONT_DEV "/dev/dvb/adapter%d/frontend%d" void chck_frontend_state (int fefd) { fe_status_t status=0; uint16_t snr=0, strength=0; uint32_t ber=0, u_blocks=0; int err=0; struct dvb_frontend_parameters tune; fe_info_t info; int type; int freq; char *fec[]={"NONE","1/2","2/3","3/4","4/5","5/6","6/7","7/8","8/9","AUTO"}; char *mod[]={"QPSK","QAM16","QAM32","QAM64","QAM128","QAM256","QAM_AUTO"}; char *band[]={"8 MHz","7 MHz","6 MHz","AUTO"}; char *guard[]={"1/32","1/16","1/8","1/4","AUTO"}; char *hierarchy[]={"NONE","1","2","3","AUTO"}; char *trans[]={"mode2","mode8","AUTO"}; err = ioctl(fefd, FE_READ_STATUS, &status); err +=ioctl(fefd, FE_GET_INFO, &info); err +=ioctl(fefd, FE_READ_SNR, &snr); err +=ioctl(fefd, FE_READ_SIGNAL_STRENGTH, &strength); err +=ioctl(fefd, FE_READ_BER, &ber); err +=ioctl(fefd, FE_READ_UNCORRECTED_BLOCKS, &u_blocks); if (err){ printf("Error reading status %d\n", err); perror("frontend"); } else printf ("status %02x \nsignal %04x \nsnr %04x \nber %08x \nunc %08x \n\n", status, strength, snr, ber, u_blocks); type=info.type; err +=ioctl(fefd, FE_GET_FRONTEND, &tune); freq=tune.frequency; switch(type){ case FE_QPSK: printf("QPSK\n"); printf("freq %d kHz (%.3f MHz or %.3f MHz)\n",freq,freq/1000.0+9750.0, freq/1000.0+10600.0); switch (tune.inversion){ case INVERSION_OFF: printf("inv off\n"); break; case INVERSION_ON: printf("inv on\n"); break; case INVERSION_AUTO: printf("inv auto\n"); break; } printf("sr %d Sym/s\n",tune.u.qpsk.symbol_rate); printf("fec %s\n",fec[tune.u.qpsk.fec_inner]); break; case FE_QAM: printf("QAM\n"); printf("freq %d\n Hz",freq); switch (tune.inversion){ case INVERSION_OFF: printf("inv off\n"); break; case INVERSION_ON: printf("inv on\n"); break; case INVERSION_AUTO: printf("inv auto\n"); break; } printf("sr %d Sym/s\n",tune.u.qam.symbol_rate); printf("fec %s\n",fec[tune.u.qam.fec_inner]); printf("modulation %s\n",mod[tune.u.qam.modulation]); break; case FE_OFDM: printf("OFDM\n"); printf("freq %d\n Hz",freq); switch (tune.inversion){ case INVERSION_OFF: printf("inv off\n"); break; case INVERSION_ON: printf("inv on\n"); break; case INVERSION_AUTO: printf("inv auto\n"); break; } printf("bandwidth %s\n",band[tune.u.ofdm.bandwidth]); printf("fecHP %s\n",fec[tune.u.ofdm.code_rate_HP]); printf("fecLP %s\n",fec[tune.u.ofdm.code_rate_LP]); printf("constellation %s\n",mod[tune.u.ofdm.constellation]); printf("transmit %s\n",trans[tune.u.ofdm.transmission_mode]); printf("guard %s\n",guard[tune.u.ofdm.guard_interval]); printf("hierarchy %s\n",hierarchy[tune.u.ofdm.hierarchy_information]); break; } } int main(int argc, char **argv) { int adapter=0; int minor=0; char devname[80]; int fd_front; int c; memset(devname, 0, 80); for (;;) { if (-1 == (c = getopt(argc, argv, "a:"))) break; switch (c) { case 'a': adapter = strtol(optarg,(char **) NULL, 0); break; case 'm': minor = strtol(optarg,(char **) NULL, 0); break; } } sprintf(devname,FRONT_DEV,adapter,minor); if ((fd_front=open(devname, O_RDONLY))<0){ perror("frontend"); printf("Error opening %s\n",devname); exit(1); } chck_frontend_state (fd_front); return 0; } libdvb-0.5.5.1/dvb-mpegtools/0000755000175000017500000000000010220016115015600 5ustar mocmmocm00000000000000libdvb-0.5.5.1/dvb-mpegtools/.cvsignore0000644000175000017500000000011210220016115017572 0ustar mocmmocm00000000000000mpegtools mplex .depend audiofilter dvb-mpegtools_main dvb-mplex dvbaudio libdvb-0.5.5.1/dvb-mpegtools/Makefile0000644000175000017500000000437610220016115017252 0ustar mocmmocm00000000000000 include ../config.mk DCFLAGS = $(CFLAGS) -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE LIBS = -L../ -ldvbmpegtools MFLAG = -M MPLEXOBS = buffer.o inits.o interact.o systems.o domplex.o inptstrm.o \ multplex.o timecode.o mplex.o bits.o SRC = $(wildcard *.c) CPPSRC = $(wildcard *.cpp) CSRC = $(wildcard *.cc) COBJ = $(notdir $(SRC:.c=.o)) LINKS = streamtype ts2pes ps2vid pes2aud_es pes2aud pes2vid_es pes2vid \ tspids pes2ts analyze pes_demux es_demux ts_demux ts_es_demux \ pesplot pes2ts2 pes_repack split_mpg cut_mpg ts2ps ts2es\ insert_pat_pmt get_http extract_pes extract_pes_payload\ change_aspect_1_1 change_aspect_4_3 change_aspect_16_9 \ change_aspect_221_1 .PHONY: depend clean install uninstall all: dvb-mpegtools_main dvb-mplex links audiofilter dvbaudio show_dvb_image links: dvb-mpegtools_main for f in $(LINKS); do\ ln -sf dvb-mpegtools_main $$f ;\ done clean: - rm -f *.o .depend dvb-mpegtools_main dvb-mplex ctest *~ $(LINKS) ctest audiofilter show_dvb_image\ dvbaudio dvb-mpegtools_main: main.o $(CXX) main.o $(LIBS) -o $@ ctest: mainc.o $(CC) $(COBJ) -o $@ dvb-mplex: $(MPLEXOBS) $(CXX) $(MPLEXOBS) $(LIBS) -o $@ dvbaudio: dvbaudio.o $(CXX) dvbaudio.o $(LIBS) -ldvb -o $@ audiofilter: audiofilter.o $(CXX) audiofilter.o -o $@ %.o: %.cc $(CXX) -c $(DCFLAGS) $(INCLUDES) $(DEFINES) $< %.o: %.cpp $(CXX) -c $(DCFLAGS) $(INCLUDES) $(DEFINES) $< %.o: %.c $(CC) -c $(DCFLAGS) $(INCLUDES) $(DEFINES) $< install: dvb-mpegtools_main install -D -m 755 dvb-mplex $(DESTDIR)$(PREFIX)/bin/dvb-mplex install -m 755 audiofilter $(DESTDIR)$(PREFIX)/bin/ install -m 755 dvb-mpegtools_main $(DESTDIR)$(PREFIX)/bin/ install -m 755 dvbaudio $(DESTDIR)$(PREFIX)/bin/ install -m 755 show_dvb_image $(DESTDIR)$(PREFIX)/bin/ install -m 755 dia $(DESTDIR)$(PREFIX)/bin/ for f in $(LINKS); do\ (cd $(DESTDIR)$(PREFIX)/bin && ln -s -f dvb-mpegtools_main $$f) ;\ done uninstall: for f in $(LINKS); do rm -f $(DESTDIR)$(PREFIX)/bin/$$f;done rm -f $(DESTDIR)$(PREFIX)/bin/dvb-mpegtools_main rm -f $(DESTDIR)$(PREFIX)/bin/dvbaudio rm -f $(DESTDIR)$(PREFIX)/bin/audiofilter rm -f $(DESTDIR)$(PREFIX)/lib/libdvbmpegtools .depend: $(CXX) $(DEFINES) $(MFLAG) $(SRC) $(CSRC) $(CPPSRC) $(INCLUDES)> .depend include .depend libdvb-0.5.5.1/dvb-mpegtools/README0000644000175000017500000001734410220016115016471 0ustar mocmmocm00000000000000DVB-MPEGTOOLS are a variety of tools that transform between various MPEG stream formats The main program is called dvb-mpegtools. This is never called directly, but always through links. The program recognizes the link name and acts accordingly. For installation in /usr/local/bin type "make install", to delete "make uninstall" A call with -h should give you usage information. Here is a short description of the functions: get_http opens an URL and puts the stream out on STDOUT. It was created to be used with ffserver and is not really an dvb-mpegtool. You can use it to view a divx stream (or any other stream) encoded by ffmpeg on your notebook via wavelan. Just use mplayer like this: get_http http://mymachine:8090/test.avi | mplayer - usage: get_http streamtype tries to recognize the stream type and gives information about the stream. usage: streamtype or streamtype < (or pipe) ts2ps ts2pes transforms a transport stream (TS) into an MPEG2 program stream (PS) or into a stream of multiplexed PES. You have to know the audio and video PIDs. usage: ts2ps or ts2ps < (or pipe) pes2aud pes2vid pes2aud_es pes2vid_es All these programs extract audio or video streams from PES or PS streams depending on their respective names. The _es part of the name indicates that elementary streams are extracted in contrast to PES streams. Try for example pes2vid_es my.mpg | mpeg2dec. (mpeg2dec can be found on http://www.linuxvideo.org/mpeg2dec/. The optional id gives the id of the desired video or audio stream in hex, (default c0 for audio, e0 for video). usage: pes2xxx(_es) [id] or pes2xxx(_es) < [id] (or pipe) extract_pes extract_pes_payload As the generalization of the ones above these programs extract the PES or the payload of PES with a given id (in HEX). usage: extract_pes(_payload) or extract_pes(_payload) < tspids returns all the PIDs contained in a TS. usage: tspids pes2ts turns a video or audio PES (not muxed) into TS the PID is 0xa0. usage: pes2ts or pes2ts < (or pipe) pes2ts2 transforms a PES stream into a TS (muxed). You have to give the audio and video PIDs. usage: pes2ts2