📄 pat.c
字号:
#include <time.h>#include <stdlib.h>#include <string.h>#include <glib.h>#include "getstream.h"#include "psi.h"/* * PAT Programm Association Table * * The PAT is multiplexed into the TS (Transport Stream) * at PID 0x0. It contains the table of all PMT (Program Map Table) * pids within the TS. * * Name Bits Offset * * table_id 8 0 * section_syntax_indicator 1 1 * pad (0) 1 1 * reserved 2 1 * section_length 12 1/2 * transport_stream_id 16 3/4 * reserved 2 5 * version_number 5 5 * current_next_indicator 1 5 * section_number 8 6 * last_section_number 8 7 * * 1..N * program_number 16 * reserved 3 * pid 13 * (if pnum==0 network_pid else program_map_pid) * * crc32 32 * */struct patprog_s { uint16_t pnr; uint16_t pid;};static int pat_pnrno(struct psisec_s *section) { return psi_payload_len(section)/PAT_PNR_LEN;}static int pat_pnrfrompat(struct psisec_s *section, int i) { uint8_t *pat=section->data; return pat[PAT_HDR_LEN+i*4+0] << 8 | pat[PAT_HDR_LEN+i*4+1];}static int pat_pidfrompat(struct psisec_s *section, int i) { uint8_t *pat=section->data; return (pat[PAT_HDR_LEN+i*4+2] << 8 | pat[PAT_HDR_LEN+i*4+3]) & PID_MASK;}/* * Send out a pat created from a struct pat_s. Things like the CC (Continuity Counter) * version and transport id are passed from the caller. * pat_send assembles the sections and passes them onto psi_segment_and_send which * will create TS packets and feed them into the callback. * * FIXME This is completely untested with multisegment PATs so beware of the dogs. * * */unsigned int pat_send(struct pat_s *pat, uint8_t cc, uint8_t version, uint16_t tid, void (*callback)(void *data, void *arg), void *arg) { struct psisec_s *section=psi_section_new(); uint8_t *p; uint32_t ccrc; GList *pl=g_list_first(pat->program); int i, seclen, patlen; int pkts=0; /* FIXME - Need to calculate number of sections */ p=section->data; while(1) { memset(p, 0xff, PSI_SECTION_MAX); p[PSI_TABLE_ID_OFF]=PAT_TABLE_ID; p[PAT_TID_OFF1]=(tid>>8); p[PAT_TID_OFF2]=(tid&0xff); /* Version and set lowest bit to 1 (current next) */ p[PSI_VERSION_OFF]=(version&0x1f)<<1|1; p[PSI_SECNO_OFF]=0x0; p[PSI_LASTSECNO_OFF]=0x0; i=0; for(;pl;pl=g_list_next(pl)) { struct patprog_s *pp=pl->data; p[PAT_HDR_LEN+i*4+0]=pp->pnr >> 8; p[PAT_HDR_LEN+i*4+1]=pp->pnr & 0xff; p[PAT_HDR_LEN+i*4+2]=pp->pid >> 8; p[PAT_HDR_LEN+i*4+3]=pp->pid & 0xff; /* FIXME - Should check for PSI Section overflow (multi section PAT) */ i++; } patlen=PAT_HDR_LEN+i*4+CRC32_LEN; seclen=(patlen-PSI_SECLEN_ADD)&PSI_SECLEN_MASK; p[PSI_SECLEN_OFF+0]=0x80|(seclen>>8); p[PSI_SECLEN_OFF+1]=(seclen&0xff); ccrc=crc32_be(0xffffffff, p, patlen-CRC32_LEN); p[patlen-CRC32_LEN+0]=(ccrc>>24)&0xff; p[patlen-CRC32_LEN+1]=(ccrc>>16)&0xff; p[patlen-CRC32_LEN+2]=(ccrc>>8)&0xff; p[patlen-CRC32_LEN+3]=(ccrc&0xff); pkts=psi_segment_and_send(section, 0, cc+pkts, callback, arg); /* If we have all programs in this section */ if (!pl) break; } psi_section_free(section); return pkts;}struct pat_s *pat_new() { return calloc(1, sizeof(struct pat_s));}void pat_free(struct pat_s *pat) { GList *pl=g_list_first(pat->program); while(pl) { g_free(pl->data); pl=g_list_next(pl); } g_list_free(pat->program); free(pat);}void pat_add_program(struct pat_s *pat, uint16_t pnr, uint16_t pid) { struct patprog_s *prog=g_new(struct patprog_s, 1); prog->pnr=pnr; prog->pid=pid; pat->program=g_list_append(pat->program, prog);}struct pat_s *pat_parse(struct adapter_s *a) { struct psisec_s *s; struct pat_s *next; unsigned int secnum; unsigned int lastsecnum; unsigned int pnr; if (!a->pat.psi.section[0]) return NULL; next=pat_new(); lastsecnum=psi_last_section_number(a->pat.psi.section[0]); for(secnum=0;secnum<=lastsecnum;secnum++) { s=a->pat.psi.section[secnum]; if (!s) continue; for(pnr=0;pnr<=pat_pnrno(s);pnr++) { pat_add_program(next, pat_pnrfrompat(s, pnr), pat_pidfrompat(s, pnr)); next->progcount++; } } logwrite(LOG_DEBUG, "pat: pat parse found %d programs", next->progcount); return next;}static struct patprog_s *pat_findpnr(struct pat_s *pat, uint16_t pnr) { GList *ppl=g_list_first(pat->program); while(ppl) { struct patprog_s *prog=ppl->data; if (prog->pnr == pnr) return prog; ppl=g_list_next(ppl); } return NULL;}/* * The PAT did change e.g. we added or changed a section * Parse it into our pat_s structure and check which PMTs * changed or were added and service the PMT callback * */static void pat_update(struct adapter_s *a) { struct pat_s *current=a->pat.current; struct pat_s *last=a->pat.last; GList *pl; struct patprog_s *plast, *pcur; /* Check whether new programs appeared or the programs PMTPIDs changed */ for(pl=g_list_first(current->program);pl;pl=g_list_next(pl)) { pcur=pl->data; /* Do we have a current PAT ? */ if (!last) { pmt_pidfrompat(a, pcur->pnr, pcur->pid); } else { /* Do we have the program and if so did the PMT pid change ? */ plast=pat_findpnr(last, pcur->pnr); if (plast && plast->pid != pcur->pid) pmt_pidfrompat(a, pcur->pnr, pcur->pid); } } if (!last) return; /* Did programs disappear e.g. we dont have their PNR anymore */ for(pl=g_list_first(last->program);pl;pl=g_list_next(pl)) { plast=pl->data; pcur=pat_findpnr(current, plast->pnr); if (!pcur) pmt_pidfrompat(a, plast->pnr, 0); }}/* Add/Update a section in our PAT. * * - Check whether this is a current section * - Check whether its really a PAT * - Add/Update the section in our PSI table * - If we had an update/change parse the PAT and call pat_update * * Input: * - pointer to our adapter * - a static section (need to clone before usage) * */static void pat_section_cb(void *data, void *arg) { struct psisec_s *section=data; struct adapter_s *adapter=arg; if (!psi_currentnext(section)) return; if (psi_tableid(section) != PAT_TABLE_ID) return; if (!psi_update_table(&adapter->pat.psi, section)) return; if (adapter->pat.last) pat_free(adapter->pat.last); adapter->pat.last=adapter->pat.current; adapter->pat.current=pat_parse(adapter); pat_update(adapter); return;}void pat_init(struct adapter_s *adapter) { /* Did we already add a callback? */ if (adapter->pat.cbc != NULL) return; adapter->pat.cbc=dvr_add_pcb(adapter, 0, DVRCB_SECTION, PID_PAT, pat_section_cb, adapter);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -