📄 scan.c
字号:
int test_bit (uint8_t *bitfield, int bit){ return (bitfield[bit/8] >> (bit % 8)) & 1;}staticvoid 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 */staticint parse_section (struct section_buf *s){ const unsigned char *buf = s->buf; int table_id; int section_length; int id; int section_version_number; int section_number; int last_section_number; int i, j; table_id = buf[0]; for (i=0; i<3; i++) if (s->table_id[i] == table_id) break; if (i > 2) return -1; section_length = (((buf[1] & 0x0f) << 8) | buf[2]) - 11; id = (buf[3] << 8) | buf[4]; section_version_number = (buf[5] >> 1) & 0x1f; section_number = buf[6]; last_section_number = buf[7]; if (s->section_version_number[i] != section_version_number || s->id[i] != id) { s->id[i] = id; s->section_version_number[i] = section_version_number; s->start_section_number[i] = section_number; s->sectionfilter_done[i] = 0; memset (s->section_done[i], 0, sizeof(s->section_done[i])); } buf += 8;// if (!test_bit(s->section_done[i], section_number)) { { set_bit (s->section_done[i], section_number); MSG("pid 0x%02x tid 0x%02x id 0x%04x, " "%i/%i (version %i, start %i)", s->pid, table_id, id, section_number, last_section_number, section_version_number, s->start_section_number[i]); switch (table_id) { case 0x00: parse_pat (buf, section_length, id); break; case 0x02: parse_pmt (buf, section_length, id); break; case 0x40: case 0x41: MSG("NIT (%s TS)\n", table_id == 0x40 ? "actual":"other"); parse_nit (buf, section_length, id); break; case 0x42: case 0x46: MSG("SDT (%s TS)\n", table_id == 0x42 ? "actual":"other"); parse_sdt (buf, section_length, id); break; default: ; }; for (j=0; j<=last_section_number; j++) if (test_bit (s->section_done[i], section_number) == 0) break; if (j > last_section_number) s->sectionfilter_done[i] = 1; } if (s->sectionfilter_done[0] && s->sectionfilter_done[1] && s->sectionfilter_done[2]) return 1; return 0;}staticint read_sections (struct section_buf *s){ int section_length, count; if (s->sectionfilter_done[0] && s->sectionfilter_done[1] && s->sectionfilter_done[2]) return 1; if ((count = read (s->fd, s->buf, 1024 - s->bytes_in_buf)) < 0) if ((count = read (s->fd, s->buf, 1024 - s->bytes_in_buf)) < 0) return -1; s->bytes_in_buf += count; if (s->bytes_in_buf >= 1024) s->bytes_in_buf = 0; if (s->bytes_in_buf < 4) return -1; section_length = ((s->buf[1] & 0x0f) << 8) | s->buf[2]; if (s->bytes_in_buf > section_length + 3) s->bytes_in_buf = 0; if (section_length == s->bytes_in_buf - 3) if (parse_section (s) == 1) return 1; return 0;}static LIST_HEAD(running_filters);static LIST_HEAD(waiting_filters);staticvoid setup_filter (struct section_buf* s, const char *dmx_devname, int pid, int tid0, int tid1, int tid2, int run_once, int timeout){ int i; memset (s, 0, sizeof(struct section_buf)); s->dmx_devname = dmx_devname; s->pid = pid; s->table_id[0] = tid0; s->table_id[1] = tid1; s->table_id[2] = tid2; s->run_once = run_once; s->timeout = timeout; for (i=0; i<3; i++) { s->id[i] = -1; s->section_version_number[i] = -1; s->start_section_number[i] = -1; } memset (s->section_done, 0, sizeof(s->section_done)); INIT_LIST_HEAD (&s->list_head);}staticint start_filter (struct section_buf* s){ struct dmx_sct_filter_params f; int i; s->bytes_in_buf = 0; if ((s->fd = open (s->dmx_devname, O_RDWR | O_NONBLOCK)) < 0) goto err0; MSG("start filter pid 0x%04x\n", s->pid); memset(&f, 0, sizeof(struct dmx_sct_filter_params)); f.pid = (uint16_t) s->pid; if (s->table_id[1] == -1 && s->table_id[2] == -1 && s->table_id[0] < 0x100 && s->table_id[0] > 0) { f.filter.filter[0] = (uint8_t) s->table_id[0]; f.filter.mask[0] = 0xff; } for (i=0; i<3; i++) if (s->table_id[i] == -1) s->sectionfilter_done[i] = 1; else s->sectionfilter_done[i] = 0; f.timeout = 0; f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC; if (ioctl(s->fd, DMX_SET_FILTER, &f) == -1) { PERROR ("ioctl DMX_SET_FILTER failed"); goto err1; } time (&s->start_time); list_del_init (&s->list_head); /* might be in waiting filter list */ list_add (&s->list_head, &running_filters); return 0;err1: ioctl (s->fd, DMX_STOP); close (s->fd);err0: return -1;}staticvoid stop_filter (struct section_buf *s){ ioctl (s->fd, DMX_STOP); close (s->fd); list_del (&s->list_head); s->running_time += time(NULL) - s->start_time;}void add_filter (struct section_buf *s){ MSG("add filter pid 0x%04x\n", s->pid); if (start_filter (s)) list_add_tail (&s->list_head, &waiting_filters);}void remove_filter (struct section_buf *s){ stop_filter (s); while (!list_empty(&waiting_filters)) { struct list_head *next = waiting_filters.next; s = list_entry (next, struct section_buf, list_head); if (start_filter (s)) break; };}void reschedule_filter (struct section_buf *s){ remove_filter (s); add_filter (s);}void read_filters (void){ struct list_head *p, *n; list_for_each_safe (p, n, &running_filters) { struct section_buf *s; int done; s = list_entry (p, struct section_buf, list_head); done = read_sections (s) == 1; if (done || time(NULL) > s->start_time + s->timeout) { if (s->run_once) { if (done) MSG("filter done pid 0x%04x\n", s->pid); else MSG("filter timeout pid 0x%04x\n", s->pid); remove_filter (s); } else reschedule_filter(s); } }}staticint 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;staticint __tune_to_transponder (int frontend_fd, struct transponder *t){ struct dvb_frontend_parameters p; int i; if (mem_is_zero (&t->param, sizeof(struct dvb_frontend_parameters))) return -1; memcpy (&p, &t->param, sizeof(struct dvb_frontend_parameters)); MSG(">>> tune to: "); dump_dvb_parameters (stderr, t->type, &p); if (t->scan_done) fprintf (stderr, " (done)"); if (t->last_tuning_failed) fprintf (stderr, " (tuning failed)"); MSG("\n"); if (t->type == FE_QPSK) { int hiband = (p.frequency >= SWITCHFREQ); setup_switch (frontend_fd, switch_pos, t->polarisation == POLARISATION_VERTICAL ? 0 : 1, hiband); if (hiband) p.frequency -= LOF_HI; else p.frequency -= LOF_LO; } ioctl(frontend_fd, FE_SET_FRONTEND, &p); for (i=0; i<3; i++) { fe_status_t s; ioctl(frontend_fd, FE_READ_STATUS, &s); MSG(">>> tuning status == 0x%02x!!!", s); if (s & FE_HAS_LOCK) { t->last_tuning_failed = 0; return 0; } usleep (500000); } MSG(">>> tuning failed!!!\n"); t->last_tuning_failed = 1; return -1;}staticint tune_to_transponder (int frontend_fd, struct transponder *t){ if (__tune_to_transponder (frontend_fd, t) == 0) return 0; return __tune_to_transponder (frontend_fd, t);}#include "initial.h"staticint tune_initial (int frontend_fd){ struct dvb_frontend_info fe_info; struct transponder *initial_list; int list_size; static int index = 0; ioctl(frontend_fd, FE_GET_INFO, &fe_info); switch (fe_info.type) { case FE_QPSK: initial_list = qpsk_probes; list_size = sizeof(qpsk_probes)/sizeof(struct transponder); break; case FE_QAM: initial_list = qam_probes; list_size = sizeof(qam_probes)/sizeof(struct transponder); break; case FE_OFDM: initial_list = ofdm_probes; list_size = sizeof(ofdm_probes)/sizeof(struct transponder); break; default: WARN("FE_GET_INFO returned unknown frontend type!"); return -1; }; while (index < list_size) { struct transponder *t = &initial_list[index]; if (tune_to_transponder (frontend_fd, t) == 0) return 0; index++; } index = 0; return -1;}staticint tune_to_next_transponder (int frontend_fd){ struct transponder *t; int ret; int i=0; while (1) { if (!(t = find_nth_entry (&transponder_list, i))) return -1; if (!(t->scan_done || t->last_tuning_failed)) break; i++; }; t->scan_done = 1; ret = tune_to_transponder (frontend_fd, t); if (ret == 0) return 0; return tune_to_next_transponder (frontend_fd);}staticvoid scan_tp (const char *demux_devname){ struct section_buf s0; struct section_buf s1; struct section_buf s2; int i; /** * filter timeouts > min repetition rates specified in ETR211 */ setup_filter (&s0, demux_devname, 0x00, 0x00, -1, -1, 1, 5); setup_filter (&s1, demux_devname, 0x10, 0x40, -1, -1, 1, 15); setup_filter (&s2, demux_devname, 0x11, 0x42, -1, -1, 1, 5); add_filter (&s0); add_filter (&s1); add_filter (&s2); do { read_filters (); for (i=0; i<service_list.count; i++) { struct service *s; s = find_nth_entry (&service_list, i); if (!s->priv && s->pmt_pid) { s->priv = malloc(sizeof(struct section_buf)); setup_filter(s->priv, "/dev/dvb/adapter0/demux0", s->pmt_pid, 0x02, -1, -1, 1, 5); add_filter (s->priv); } } } while (!(list_empty(&running_filters) && list_empty(&waiting_filters)));}staticvoid scan_network (const char *frontend_devname, const char *demux_devname){ int frontend_fd; MSG ("using '%s' and '%s'\n", frontend_devname, demux_devname); if ((frontend_fd = open (frontend_devname, O_RDWR)) < 0) PERROR("failed opening '%s'", frontend_devname); if (tune_initial (frontend_fd) < 0) { MSG("initial tuning failed!"); return; } do { scan_tp(demux_devname); } while (tune_to_next_transponder(frontend_fd) == 0); close (frontend_fd);}staticvoid dump_lists (void){ int i; for (i=0; i<service_list.count; i++) { struct service *s = find_nth_entry (&service_list, i); struct transponder *t; struct network *n; t = find_entry_by_id (&transponder_list, -1, s->transport_stream_id); if (t) { n = find_entry_by_id (&network_list, -1, t->network_id); dump_service_parameter_set (stdout, s->service_name, t->type, &t->param, s->video_pid, s->audio_pid); } }}static const char *usage = "\nusage: %s [-c] [-a adapter_num] [-f frontend_id] [-d demux_id] [-s switch_pos]\n\t-c\tscan on currently tuned transponder only\n\n";int main (int argc, char **argv){ char frontend_devname [80]; char demux_devname [80]; int adapter = 0, frontend = 0, demux = 0; int opt, current_tp_only = 0; while ((opt = getopt(argc, argv, "ca:f:d:s:")) != -1) { switch (opt) { case 'a': adapter = strtoul(optarg, NULL, 0); break; case 'f': frontend = strtoul(optarg, NULL, 0); break; case 'd': demux = strtoul(optarg, NULL, 0); break; case 's': switch_pos = strtoul(optarg, NULL, 0); break; case 'c': current_tp_only = 1; break; default: fprintf (stderr, usage, argv[0]); return -1; }; } if (switch_pos >= 4) { fprintf (stderr, "switch position needs to be < 4!\n"); return -1; } snprintf (frontend_devname, sizeof(frontend_devname), "/dev/dvb/adapter%i/frontend%i", adapter, frontend); snprintf (demux_devname, sizeof(demux_devname), "/dev/dvb/adapter%i/demux%i", adapter, demux); if (current_tp_only) scan_tp (demux_devname); else scan_network (frontend_devname, demux_devname); dump_lists (); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -