⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pmt.c

📁 this ebook is for GSM if any one has interest in it you can take it
💻 C
字号:
#include <sys/types.h>#include <malloc.h>#include <glib.h>#include "getstream.h"#include "psi.h"struct programcb_s {	void		(*callback)(void *data, void *arg);	void		*arg;};struct pmtes_s {	uint8_t		streamtype;	uint16_t	espid;};struct pmt_s {	uint16_t	pnr;	uint16_t	pcrpid;	GList		*es;};struct program_s {	struct adapter_s	*adapter;	unsigned int		pnr;	uint16_t		pmtpid;	void			*pmtpidcb;	/* pid callback cookie (PMT) */	struct {		GList	*cb;	} pidtable[PID_MAX];	struct psi_s		psi;	struct pmt_s		*pmtlast;	struct pmt_s		*pmtcurrent;	GList			*progcbl;};#if 0/* Callback for program pids (not pmt) from the demux */static void pmt_dvr_cb(void *data, void *arg) {	struct program_s	*prog=arg;	GList			*progcbl=g_list_first(prog->progcbl);	while(progcbl) {		struct programcb_s *pcb=progcbl->data;		/* Issue callback - typically a input callback */		pcb->callback(data, pcb->arg);		progcbl=g_list_next(progcbl);	}}#endif#define pmt_prog_gets_pid(prog, pid) \		((prog)->pidtable[(pid)].cb != NULL)/* * This program wants a specific PID - So register it with the DVR demux. As we * might habe multiple streams receiving this program we register all streams * with the dvr demux. * * As we need to leave pid in case the PMT changes we need to remember the DVR demux * call back cookies. For this we append the cookies to a GList in the programs pidtable. * */static void pmt_prog_join_pid(struct program_s *prog, uint16_t pid, unsigned int type) {	GList		*pcbl=g_list_first(prog->progcbl);	while(pcbl) {		struct programcb_s	*pcb=pcbl->data;		void			*cbc;		cbc=dvr_add_pcb(prog->adapter, pid, DVRCB_TS, type, pcb->callback, pcb->arg);		prog->pidtable[pid].cb=g_list_append(prog->pidtable[pid].cb, cbc);		pcbl=g_list_next(pcbl);	}}/* * The programs leaves a certain pid. For this we walk the DVR callback cookie * list in the programs pidtable and pass them onto the dvr_del_pcb. * If we removed all streams from the dvr callback we delete the list and * set the GList pointer in the pidtable to NULL which is the signal that * the program is not receiving that pid. */static void pmt_prog_leave_pid(struct program_s *prog, uint16_t pid) {	GList		*cbcl=g_list_first(prog->pidtable[pid].cb);	while(cbcl) {		void			*cbc=cbcl->data;		dvr_del_pcb(prog->adapter, pid, cbc);		cbcl=g_list_next(cbcl);	}	g_list_free(prog->pidtable[pid].cb);	prog->pidtable[pid].cb=NULL;}static uint16_t pmt_pnr(struct psisec_s *section) {	return (section->data[PMT_PNR_OFF1] << 8 | section->data[PMT_PNR_OFF2]);}static int pmt_mapstreamtype(uint8_t type) {	switch (type) {		case 1:		/* ISO/IEC 11172 Video		*/		case 2:		/* ITU-T Rec. H.262		*/				/* ISO/IEC 13818-2 Video	*/				/* ISO/IEC 11172-2		*/		case 27:	/* ITU-T Rec. H.264		*/				/* ISO/IEC 14496-10 Video	*/			return PID_VIDEO;			break;		case 3:		/* ISO/IEC 11172 Audio */		case 4:		/* ISO/IEC 13818-3 Audio */			return PID_AUDIO;			break;		case 5:		/* ISO/IEC 13818-1 Page 160 - Private Sections */		case 6:		/* ITU-T Rec. H.222.0 ISO/IEC 13818-1 PES - Private Data */				/* Stephen Gardner sent dvbsnoop output showing AC3 Audio				 * in here encapsulated in the private data. As we dont				 * treat different pid types differently we don't care for				 * now						*/			return PID_PRIVATE;			break;		case 7:	 /* ISO/IEC 13522 MHEG */		case 8:  /* ITU-T Rec. H.220.0 / ISO/IEC 13818-1 Annex A DSM CC */		case 9:	 /* ITU-T Rec. H.220.1 */		case 10: /* ISO/IEC 13818-6 Type A */		case 11: /* ISO/IEC 13818-6 Type B */		case 12: /* ISO/IEC 13818-6 Type C */		case 13: /* ISO/IEC 13818-6 Type D */		case 14: /* ISO/IEC 13818-1 auxiliary */			return PID_OTHER;			break;		default:			if (type & 0x80)				return PID_USER;	}	return PID_OTHER;}static uint16_t pmt_pcr(struct psisec_s *section) {	return (section->data[PMT_PCR_OFF1] << 8 | section->data[PMT_PCR_OFF2]) & PID_MASK;}static unsigned int pmt_pinfo_len(struct psisec_s *section) {	return (section->data[PMT_PILEN_OFF1] << 8 | section->data[PMT_PILEN_OFF2]) & PMT_PILEN_MASK;}#define ESINFO_LEN_OFF	3#define ESINFO_LEN_MASK	0x0fff#define ESINFO_MIN_LEN	5static int pmt_es_infolen(struct psisec_s *section, int es) {	return (section->data[es+ESINFO_LEN_OFF]<<8 |			section->data[es+ESINFO_LEN_OFF+1]) & ESINFO_LEN_MASK;}static int pmt_next_es(struct psisec_s *section, int es) {	int		nes;	nes=es+pmt_es_infolen(section, es)+ESINFO_MIN_LEN;	/* Next offset beyond PMT end ? */	if (nes >= psi_len(section)-CRC32_LEN)		return 0;	return nes;}static int pmt_first_es(struct psisec_s *section) {	return PMT_PI_OFF+pmt_pinfo_len(section);}static uint8_t pmt_es_type(struct psisec_s *section, int es) {	return section->data[es];}#define ES_PID_OFF	1static unsigned int pmt_es_pid(struct psisec_s *section, int es) {	return ((section->data[es+ES_PID_OFF]<<8 | section->data[es+ES_PID_OFF+1]) & PID_MASK);}unsigned int pmt_get_pmtpid(void *pvoid) {	struct program_s	*prog=pvoid;	return prog->pmtpid;}struct pmt_s *pmt_new(void ) {	return calloc(1, sizeof(struct pmt_s));}void pmt_free(struct pmt_s *pmt) {	GList	*es=g_list_first(pmt->es);	while(es) {		g_free(es->data);		es=g_list_next(es);	}	g_list_free(pmt->es);	free(pmt);}void pmt_add_es(struct pmt_s *pmt, uint8_t type, uint16_t pid) {	struct pmtes_s	*es=g_new(struct pmtes_s, 1);	es->streamtype=type;	es->espid=pid;	pmt->es=g_list_append(pmt->es, es);}static struct pmt_s *pmt_parse(struct program_s *prog) {	struct pmt_s		*pmt;	struct psisec_s		*s;	int			lastsecnum;	int			secnum;	int			esoff;	int			es=0;	if (!prog->psi.section[0])		return NULL;	pmt=pmt_new();	lastsecnum=psi_last_section_number(prog->psi.section[0]);	for(secnum=0;secnum<=lastsecnum;secnum++) {		s=prog->psi.section[secnum];		if (!s)			continue;		/*		 * FIXME - Multiple section PMTs might be inconsistent		 * concerning the PCR pid		 */		if (pmt_pcr(s) != PID_MAX)			pmt->pcrpid=pmt_pcr(s);		/* Walk PMT and add ES PIDS as necessary */		esoff=pmt_first_es(s);		do {			uint8_t		type=pmt_es_type(s, esoff);			uint16_t	pid=pmt_es_pid(s, esoff);			pmt_add_es(pmt, type, pid);			es++;		} while((esoff=pmt_next_es(s, esoff)) != 0);	}	logwrite(LOG_DEBUG, "pmt: parse_pmt found %d elementary streams for pnr %04x", es, prog->pnr);	return pmt;}static struct pmtes_s *pmt_find_es(struct pmt_s *pmt, uint16_t pid) {	GList		*esl;	struct pmtes_s	*es;	for(esl=g_list_first(pmt->es);esl;esl=g_list_next(esl)) {		es=esl->data;		if (es->espid == pid)			return es;	}	return NULL;}static void pmt_update(struct program_s *prog) {	struct pmt_s		*current=prog->pmtcurrent;	struct pmt_s		*last=prog->pmtlast;	GList			*esl;	struct pmtes_s		*escur, *eslast;	int			i;	logwrite(LOG_DEBUG, "pmt: pmt_update running for program %04x", prog->pnr);	for(esl=g_list_first(current->es);esl;esl=g_list_next(esl)) {		escur=esl->data;		if (last) {			eslast=pmt_find_es(last, escur->espid);			if (eslast)				continue;		}		if (!pmt_prog_gets_pid(prog, escur->espid))			pmt_prog_join_pid(prog, escur->espid, pmt_mapstreamtype(escur->streamtype));	}	/*	 * We check if we get the PCR pid already. It seems most programs	 * multiplex the PCR informations into the Audio PID instead	 * a seperate PID so there would be no need to add a seperate callback	 *	 */	if (current->pcrpid != PID_MAX) {		if (!pmt_prog_gets_pid(prog, current->pcrpid))			pmt_prog_join_pid(prog, current->pcrpid, PID_PCR);	}	/*	 * Walk all joined pids and check whether they are still active.	 * If they are not active - leave	 */	for(i=0;i<PID_MAX;i++) {		if (pmt_prog_gets_pid(prog, i)) {			if (current->pcrpid == i)				continue;			if (prog->pmtpid == i)				continue;			if (pmt_find_es(current, i))				continue;			pmt_prog_leave_pid(prog, i);		}	}}static void pmt_dvr_pmt_cb(void *data, void *arg) {	struct psisec_s		*section=data;	struct program_s	*prog=arg;	struct pmt_s		*pmt;	logwrite(LOG_XTREME, "pmt: dvr section callback");	dump_hex(LOG_XTREME, "pmt: PMT ", section->data, section->valid);	if (!psi_currentnext(section))		return;	if (psi_tableid(section) != PMT_TABLE_ID) {		logwrite(LOG_INFO, "pmt: received PMT with broken table id on pid %d", prog->pmtpid);		return;	}	if (pmt_pnr(section) != prog->pnr) {		logwrite(LOG_DEBUG, "pmt: received PMT section for pnr %04x expected %04x",				pmt_pnr(section), prog->pnr);		return;	}	if (!psi_update_table(&prog->psi, section))		return;	pmt=pmt_parse(prog);	if (prog->pmtlast)		pmt_free(prog->pmtlast);	prog->pmtlast=prog->pmtcurrent;	prog->pmtcurrent=pmt;	pmt_update(prog);}/* Find program structure for a given PNR (Program Number) */static struct program_s *pmt_prog_from_pnr(struct adapter_s *a, unsigned int pnr) {	struct program_s	*prog;	GList			*pl=g_list_first(a->pmt.pnrlist);	/* Find pnr struct for this pnr */	while(pl) {		prog=pl->data;		if (prog->pnr == pnr)			return prog;		pl=g_list_next(pl);	}	return NULL;}/* * Callback from PAT parsing - Passes in adapter, pnr and pmtpid - If * we want this PNR and we didnt already join the PMT do so - In case * of a PMT pid change - leave old pid and join new one. * * In case of a PMTPID of 0 the PAT did not contain our program anymore. * */void pmt_pidfrompat(struct adapter_s *a, unsigned int pnr, unsigned int pmtpid) {	struct program_s	*prog;	prog=pmt_prog_from_pnr(a, pnr);	if (!prog)		return;	logwrite(LOG_XTREME, "pmt: pidfrompat found pnr %04x", pnr);	if (prog->pmtpid == pmtpid)		return;	logwrite(LOG_XTREME, "pmt: pidfrompat pmt pid changed from %04x to %04x", 				prog->pmtpid, pmtpid);	/* If we have an old one - leave it */	if (prog->pmtpid) {		dvr_del_pcb(a, prog->pmtpid, prog->pmtpidcb);		pmt_prog_leave_pid(prog, prog->pmtpid);	}	if (pmtpid) {		/* Add a callback for the new pmt pid */		prog->pmtpidcb=dvr_add_pcb(a, pmtpid, DVRCB_SECTION, PID_PMT, pmt_dvr_pmt_cb, prog);		pmt_prog_join_pid(prog, pmtpid, PID_PMT);	} else {		/* FIXME - The Program disappeared - we should leave all pids */	}	prog->pmtpid=pmtpid;}static struct program_s *pmt_prog_new(struct adapter_s *a, unsigned int pnr) {	struct program_s	*prog;	prog=calloc(1, sizeof(struct program_s));	if (!prog)		return NULL;	prog->pnr=pnr;	prog->pmtpid=0;	prog->adapter=a;	a->pmt.pnrlist=g_list_append(a->pmt.pnrlist, prog);	return prog;}static void pmt_prog_add_cb(struct program_s *prog,			void (*callback)(void *data, void *arg), void *arg) {	struct programcb_s	*pcb;	pcb=malloc(sizeof(struct programcb_s));	pcb->callback=callback;	pcb->arg=arg;	prog->progcbl=g_list_append(prog->progcbl, pcb);}/* * Called from input_pnr to join a program number by supplying an * callback which will be put into the demux table by the PMT parser * */void *pmt_join_pnr(struct adapter_s *a, unsigned int pnr,			void (*callback)(void *data, void *arg), void *arg) {	struct program_s	*prog;	/*	 * Find this program - might be multiple output	 * streams for the same program	 */	prog=pmt_prog_from_pnr(a, pnr);	/* If we havent got one - create it */	if (!prog)		prog=pmt_prog_new(a, pnr);	/* Add callback to this stream to program list */	if (prog)		pmt_prog_add_cb(prog, callback, arg);	pat_init(a);	return prog;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -