📄 scan.c
字号:
buf += descriptor_len; descriptors_loop_len -= descriptor_len; }}static void parse_pat(const unsigned char *buf, int section_length, int transport_stream_id){ while (section_length > 0) { struct service *s; int service_id = (buf[0] << 8) | buf[1]; if (service_id == 0) { buf += 4; /* skip nit pid entry... */ section_length -= 4; continue; } /* SDT might have been parsed first... */ s = find_service(current_tp, service_id); if (!s) s = alloc_service(current_tp, service_id); s->pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3]; if (!s->priv && s->pmt_pid) { s->priv = malloc(sizeof(struct section_buf)); setup_filter(s->priv, demux_devname, s->pmt_pid, 0x02, 1, 0, 5); add_filter (s->priv); } buf += 4; section_length -= 4; };}static void parse_pmt (const unsigned char *buf, int section_length, int service_id){ int program_info_len; struct service *s; char msg_buf[14 * AUDIO_CHAN_MAX + 1]; char *tmp; int i; s = find_service (current_tp, service_id); if (!s) { error("PMT for serivce_id 0x%04x was not in PAT\n", service_id); return; } s->pcr_pid = ((buf[0] & 0x1f) << 8) | buf[1]; program_info_len = ((buf[2] & 0x0f) << 8) | buf[3]; buf += program_info_len + 4; section_length -= program_info_len + 4; while (section_length > 0) { int ES_info_len = ((buf[3] & 0x0f) << 8) | buf[4]; int elementary_pid = ((buf[1] & 0x1f) << 8) | buf[2]; switch (buf[0]) { case 0x01: case 0x02: moreverbose(" VIDEO : PID 0x%04x\n", elementary_pid); if (s->video_pid == 0) s->video_pid = elementary_pid; break; case 0x03: case 0x04: moreverbose(" AUDIO : PID 0x%04x\n", elementary_pid); if (s->audio_num < AUDIO_CHAN_MAX) { s->audio_pid[s->audio_num] = elementary_pid; parse_descriptors (PMT, buf + 5, ES_info_len, s); s->audio_num++; } else warning("more than %i audio channels, truncating\n", AUDIO_CHAN_MAX); break; case 0x06: if (find_descriptor(0x56, buf + 5, ES_info_len, NULL, NULL)) { moreverbose(" TELETEXT : PID 0x%04x\n", elementary_pid); s->teletext_pid = elementary_pid; break; } else if (find_descriptor(0x59, buf + 5, ES_info_len, NULL, NULL)) { /* Note: The subtitling descriptor can also signal * teletext subtitling, but then the teletext descriptor * will also be present; so we can be quite confident * that we catch DVB subtitling streams only here, w/o * parsing the descriptor. */ moreverbose(" SUBTITLING: PID 0x%04x\n", elementary_pid); s->subtitling_pid = elementary_pid; break; } else if (find_descriptor(0x6a, buf + 5, ES_info_len, NULL, NULL)) { moreverbose(" AC3 : PID 0x%04x\n", elementary_pid); s->ac3_pid = elementary_pid; break; } /* fall through */ default: moreverbose(" OTHER : PID 0x%04x TYPE 0x%02x\n", elementary_pid, buf[0]); }; buf += ES_info_len + 5; section_length -= ES_info_len + 5; }; tmp = msg_buf; tmp += sprintf(tmp, "0x%04x (%.4s)", s->audio_pid[0], s->audio_lang[0]); if (s->audio_num > AUDIO_CHAN_MAX) { warning("more than %i audio channels: %i, truncating to %i\n", AUDIO_CHAN_MAX, s->audio_num, AUDIO_CHAN_MAX); s->audio_num = AUDIO_CHAN_MAX; } for (i=1; i<s->audio_num; i++) tmp += sprintf(tmp, ", 0x%04x (%.4s)", s->audio_pid[i], s->audio_lang[i]); debug("0x%04x 0x%04x: %s -- %s, pmt_pid 0x%04x, vpid 0x%04x, apid %s\n", s->transport_stream_id, s->service_id, s->provider_name, s->service_name, s->pmt_pid, s->video_pid, msg_buf);}static void parse_nit (const unsigned char *buf, int section_length, int network_id){ int descriptors_loop_len = ((buf[0] & 0x0f) << 8) | buf[1]; if (section_length < descriptors_loop_len + 4) { warning("section too short: network_id == 0x%04x, section_length == %i, " "descriptors_loop_len == %i\n", network_id, section_length, descriptors_loop_len); return; } parse_descriptors (NIT, buf + 2, descriptors_loop_len, NULL); section_length -= descriptors_loop_len + 4; buf += descriptors_loop_len + 4; while (section_length > 6) { int transport_stream_id = (buf[0] << 8) | buf[1]; struct transponder *t, tn; descriptors_loop_len = ((buf[4] & 0x0f) << 8) | buf[5]; if (section_length < descriptors_loop_len + 4 || !transport_stream_id) { warning("section too short: transport_stream_id == 0x%04x, " "section_length == %i, descriptors_loop_len == %i\n", transport_stream_id, section_length, descriptors_loop_len); break; } debug("transport_stream_id 0x%04x\n", transport_stream_id); memset(&tn, 0, sizeof(tn)); tn.type = -1; tn.network_id = network_id; tn.transport_stream_id = transport_stream_id; parse_descriptors (NIT, buf + 6, descriptors_loop_len, &tn); if (tn.type == fe_info.type) { /* only add if develivery_descriptor matches FE type */ t = find_transponder(tn.param.frequency); if (!t) t = alloc_transponder(tn.param.frequency); copy_transponder(t, &tn); } section_length -= descriptors_loop_len + 6; buf += descriptors_loop_len + 6; };}static void parse_sdt (const unsigned char *buf, int section_length, int transport_stream_id){ buf += 3; /* skip original network id + reserved field */ while (section_length > 4) { int service_id = (buf[0] << 8) | buf[1]; int descriptors_loop_len = ((buf[3] & 0x0f) << 8) | buf[4]; struct service *s; if (section_length < descriptors_loop_len || !transport_stream_id || !descriptors_loop_len) { warning("section too short: service_id == 0x%02x, section_length == %i" "descriptors_loop_len == %i\n", service_id, section_length, descriptors_loop_len); break; } s = find_service(current_tp, service_id); if (!s) /* maybe PAT has not yet been parsed... */ s = alloc_service(current_tp, service_id); s->running = (buf[3] >> 5) & 0x7; s->scrambled = (buf[3] >> 4) & 1; parse_descriptors (SDT, buf + 5, descriptors_loop_len, s); section_length -= descriptors_loop_len + 5; buf += descriptors_loop_len + 5; };}static int get_bit (uint8_t *bitfield, int bit){ return (bitfield[bit/8] >> (bit % 8)) & 1;}static void set_bit (uint8_t *bitfield, int bit){ bitfield[bit/8] |= 1 << (bit % 8);}/** * returns 0 when more sections are expected * 1 when all sections are read on this pid * -1 on invalid table id */static int parse_section (struct section_buf *s){ const unsigned char *buf = s->buf; int table_id; int section_length; int table_id_ext; int section_version_number; int section_number; int last_section_number; int i; table_id = buf[0]; if (s->table_id != table_id) return -1; section_length = (((buf[1] & 0x0f) << 8) | buf[2]) - 11; table_id_ext = (buf[3] << 8) | buf[4]; section_version_number = (buf[5] >> 1) & 0x1f; section_number = buf[6]; last_section_number = buf[7]; if (s->segmented && s->table_id_ext != -1 && s->table_id_ext != table_id_ext) { /* find or allocate actual section_buf matching table_id_ext */ while (s->next_seg) { s = s->next_seg; if (s->table_id_ext == table_id_ext) break; } if (s->table_id_ext != table_id_ext) { assert(s->next_seg == NULL); s->next_seg = calloc(1, sizeof(struct section_buf)); s->next_seg->segmented = s->segmented; s->next_seg->run_once = s->run_once; s->next_seg->timeout = s->timeout; s = s->next_seg; s->table_id = table_id; s->table_id_ext = table_id_ext; s->section_version_number = section_version_number; } } if (s->section_version_number != section_version_number || s->table_id_ext != table_id_ext) { struct section_buf *next_seg = s->next_seg; if (s->section_version_number != -1 && s->table_id_ext != -1) debug("section version_number or table_id_ext changed " "%d -> %d / %04x -> %04x\n", s->section_version_number, section_version_number, s->table_id_ext, table_id_ext); s->table_id_ext = table_id_ext; s->section_version_number = section_version_number; s->sectionfilter_done = 0; memset (s->section_done, 0, sizeof(s->section_done)); s->next_seg = next_seg; } buf += 8; if (!get_bit(s->section_done, section_number)) { set_bit (s->section_done, section_number); debug("pid 0x%02x tid 0x%02x table_id_ext 0x%04x, " "%i/%i (version %i)\n", s->pid, table_id, table_id_ext, section_number, last_section_number, section_version_number); switch (table_id) { case 0x00: verbose("PAT\n"); parse_pat (buf, section_length, table_id_ext); break; case 0x02: verbose("PMT 0x%04x for service 0x%04x\n", s->pid, table_id_ext); parse_pmt (buf, section_length, table_id_ext); break; case 0x41: verbose("////////////////////////////////////////////// NIT other\n"); case 0x40: verbose("NIT (%s TS)\n", table_id == 0x40 ? "actual":"other"); parse_nit (buf, section_length, table_id_ext); break; case 0x42: case 0x46: verbose("SDT (%s TS)\n", table_id == 0x42 ? "actual":"other"); parse_sdt (buf, section_length, table_id_ext); break; default: ; }; for (i = 0; i <= last_section_number; i++) if (get_bit (s->section_done, i) == 0) break; if (i > last_section_number) s->sectionfilter_done = 1; } if (s->segmented) { /* always wait for timeout; this is because we don't now how * many segments there are */ return 0; } else if (s->sectionfilter_done) return 1; return 0;}static int read_sections (struct section_buf *s){ int section_length, count; if (s->sectionfilter_done && !s->segmented) return 1; /* the section filter API guarantess that we get one full section * per read(), provided that the buffer is large enough (it is) */ if (((count = read (s->fd, s->buf, sizeof(s->buf))) < 0) && errno == EOVERFLOW) count = read (s->fd, s->buf, sizeof(s->buf)); if (count < 0) { errorn("read_sections: read error"); return -1; } if (count < 4) return -1; section_length = ((s->buf[1] & 0x0f) << 8) | s->buf[2]; if (count != section_length + 3) return -1; if (parse_section(s) == 1) return 1; return 0;}static LIST_HEAD(running_filters);static LIST_HEAD(waiting_filters);static int n_running;#define MAX_RUNNING 32static struct pollfd poll_fds[MAX_RUNNING];static struct section_buf* poll_section_bufs[MAX_RUNNING];static void setup_filter (struct section_buf* s, const char *dmx_devname, int pid, int tid, int run_once, int segmented, int timeout){ memset (s, 0, sizeof(struct section_buf)); s->fd = -1; s->dmx_devname = dmx_devname; s->pid = pid; s->table_id = tid; s->run_once = run_once; s->segmented = segmented; if (long_timeout) s->timeout = 5 * timeout; else s->timeout = timeout; s->table_id_ext = -1; s->section_version_number = -1; INIT_LIST_HEAD (&s->list);}static void update_poll_fds(void){ struct list_head *p; struct section_buf* s; int i; memset(poll_section_bufs, 0, sizeof(poll_section_bufs)); for (i = 0; i < MAX_RUNNING; i++) poll_fds[i].fd = -1; i = 0; list_for_each (p, &running_filters) { if (i >= MAX_RUNNING) fatal("too many poll_fds\n"); s = list_entry (p, struct section_buf, list); if (s->fd == -1) fatal("s->fd == -1 on running_filters\n"); verbosedebug("poll fd %d\n", s->fd); poll_fds[i].fd = s->fd; poll_fds[i].events = POLLIN; poll_fds[i].revents = 0; poll_section_bufs[i] = s; i++; } if (i != n_running) fatal("n_running is hosed\n");}static int start_filter (struct section_buf* s){ struct dmx_sct_filter_params f; if (n_running >= MAX_RUNNING) goto err0; if ((s->fd = open (s->dmx_devname, O_RDWR | O_NONBLOCK)) < 0) goto err0; verbosedebug("start filter pid 0x%04x table_id 0x%02x\n", s->pid, s->table_id); memset(&f, 0, sizeof(f)); f.pid = (uint16_t) s->pid; if (s->table_id < 0x100 && s->table_id > 0) { f.filter.filter[0] = (uint8_t) s->table_id; f.filter.mask[0] = 0xff; } f.timeout = 0; f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC; if (ioctl(s->fd, DMX_SET_FILTER, &f) == -1) { errorn ("ioctl DMX_SET_FILTER failed"); goto err1; } s->sectionfilter_done = 0; time(&s->start_time); list_del_init (&s->list); /* might be in waiting filter list */ list_add (&s->list, &running_filters); n_running++; update_poll_fds(); return 0;err1: ioctl (s->fd, DMX_STOP); close (s->fd);err0: return -1;}static void stop_filter (struct section_buf *s){ verbosedebug("stop filter pid 0x%04x\n", s->pid); ioctl (s->fd, DMX_STOP); close (s->fd); s->fd = -1; list_del (&s->list); s->running_time += time(NULL) - s->start_time; n_running--; update_poll_fds();}static void add_filter (struct section_buf *s){ verbosedebug("add filter pid 0x%04x\n", s->pid); if (start_filter (s)) list_add_tail (&s->list, &waiting_filters);}static void remove_filter (struct section_buf *s){ verbosedebug("remove filter pid 0x%04x\n", s->pid); stop_filter (s); while (!list_empty(&waiting_filters)) { struct list_head *next = waiting_filters.next; s = list_entry (next, struct section_buf, list); if (start_filter (s)) break; };}static void read_filters (void){ struct section_buf *s; int i, n, done; n = poll(poll_fds, n_running, 1000); if (n == -1) errorn("poll"); for (i = 0; i < n_running; i++) { s = poll_section_bufs[i]; if (!s) fatal("poll_section_bufs[%d] is NULL\n", i); if (poll_fds[i].revents) done = read_sections (s) == 1; else done = 0; /* timeout */ if (done || time(NULL) > s->start_time + s->timeout) { if (s->run_once) { if (done) verbosedebug("filter done pid 0x%04x\n", s->pid); else warning("filter timeout pid 0x%04x\n", s->pid); remove_filter (s); } } }}static int mem_is_zero (const void *mem, int size){ const char *p = mem; while (size) { if (*p != 0x00) return 0; p++; } return 1;}#define SWITCHFREQ 11700000#define LOF_HI 10600000#define LOF_LO 9750000static int switch_pos = 0;static int __tune_to_transponder (int frontend_fd, struct transponder *t){ struct dvb_frontend_parameters p; fe_status_t s; int i; current_tp = t; if (mem_is_zero (&t->param, sizeof(struct dvb_frontend_parameters))) return -1; memcpy (&p, &t->param, sizeof(struct dvb_frontend_parameters)); if (verbosity >= 1) { dprintf(1, ">>> tune to: "); dump_dvb_parameters (stderr, t); if (t->last_tuning_failed) dprintf(1, " (tuning failed)"); dprintf(1, "\n"); } if (t->type == FE_QPSK) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -