?? scan.c
字號:
/** * Simple MPEG parser to achieve network/service information. * * refered standards: * * ETSI EN 300 468 * ETSI TR 101 211 * ETSI ETR 211 * ITU-T H.222.0 */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ioctl.h>#include <unistd.h>#include <fcntl.h>#include <time.h>#include <errno.h>#include <linux/dvb/frontend.h>#include <linux/dvb/dmx.h>#include "list.h"#include "diseqc.h"#include "dump.h"#include "scan.h"struct list_entry { int id1; int id2;};struct list { char *name; struct list_entry *entry; int count; int entry_size;};struct network { int dummy; int network_id; char *network_name;};enum polarisation { POLARISATION_HORIZONTAL = 0x00, POLARISATION_VERTICAL = 0x01, POLARISATION_CIRCULAR_LEFT = 0x02, POLARISATION_CIRCULAR_RIGHT = 0x03};struct transponder { int network_id; int transport_stream_id; fe_type_t type; struct dvb_frontend_parameters param; enum polarisation polarisation : 2; /* only for DVB-S */ int scan_done : 1; int last_tuning_failed : 1;};enum service_type { ST_TV = 0x01, ST_RADIO = 0x02, ST_TELETEXT = 0x03, ST_MHP = 0x10};enum running_mode { RM_NOT_RUNNING = 0x01, RM_STARTS_SOON = 0x02, RM_PAUSING = 0x03, RM_RUNNING = 0x04};struct service { int transport_stream_id; int service_id; char *provider_name; char *service_name; uint16_t pmt_pid; uint16_t pcr_pid; uint16_t video_pid; uint16_t audio_pid; int private_pid_count : 8; enum service_type type : 8; enum running_mode running : 3; int scrambled : 1; void *priv;};staticstruct list network_list = { "network_list", NULL, 0, sizeof(struct network)};staticstruct list transponder_list = { "transponder_list", NULL, 0, sizeof(struct transponder)};static struct list service_list = { "service_list", NULL, 0, sizeof(struct service)};static void* find_entry_by_id (struct list *list, int id1, int id2){ int i; long entry = (long) list->entry; for (i=0; i<list->count; i++, entry += list->entry_size) { struct list_entry *e = (struct list_entry*) entry; if (e->id1 == id1 && (e->id2 == id2 || id2 == -1)) return e; if (e->id2 == id2 && id1 == -1) return e; if (e->id1 == id1 && e->id2 == -1) { e->id2 = id2; return e; } if (e->id1 == -1 && e->id2 == id2) { e->id1 = id1; return e; } } return NULL;}static void* find_or_alloc_entry_by_id (struct list *list, int id1, int id2){ struct list_entry *e = find_entry_by_id (list, id1, id2); long addr; if (!e) { list->entry = realloc (list->entry, (list->count+1) * list->entry_size); addr = (long) list->entry + list->count * list->entry_size; e = (struct list_entry*) addr; memset (e, 0, list->entry_size); e->id1 = id1; e->id2 = id2; list->count++; } return e;}staticvoid* find_nth_entry (struct list *list, unsigned int n){ if (n >= list->count) return NULL; return (void*) ((long) list->entry + n * list->entry_size);}staticvoid parse_network_name_descriptor (const unsigned char *buf, struct network *n){ unsigned char len = buf [1]; n->network_name = malloc (len + 1); memcpy (n->network_name, buf + 2, len); n->network_name[len] = '\0'; MSG("(%s)", n->network_name);}staticlong bcd32_to_cpu (const int b0, const int b1, const int b2, const int b3){ return ((b0 >> 4) & 0x0f) * 10000000 + (b0 & 0x0f) * 1000000 + ((b1 >> 4) & 0x0f) * 100000 + (b1 & 0x0f) * 10000 + ((b2 >> 4) & 0x0f) * 1000 + (b2 & 0x0f) * 100 + ((b3 >> 4) & 0x0f) * 10 + (b3 & 0x0f);}static const fe_code_rate_t fec_tab [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 qam_tab [6] = { QAM_AUTO, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256};staticvoid parse_cable_delivery_system_descriptor (const unsigned char *buf, struct transponder *t){ t->type = FE_QAM; t->param.frequency = bcd32_to_cpu (buf[2], buf[3], buf[4], buf[5]); t->param.frequency *= 100; t->param.u.qam.fec_inner = fec_tab[buf[12] & 0x07]; t->param.u.qam.symbol_rate = 10 * bcd32_to_cpu (buf[9], buf[10], buf[11], buf[12] & 0xf0); if ((buf[8] & 0x0f) > 5) t->param.u.qam.modulation = QAM_AUTO; else t->param.u.qam.modulation = qam_tab[buf[8] & 0x0f]; fprintf (stderr, "%#06x/%#06x ", t->network_id, t->transport_stream_id); dump_dvb_parameters (stderr, t->type, &t->param); if (t->scan_done) fprintf (stderr, " (done)"); if (t->last_tuning_failed) fprintf (stderr, " (tuning failed)"); fprintf (stderr, "\n");}staticvoid parse_satellite_delivery_system_descriptor (const unsigned char *buf, struct transponder *t){ t->type = FE_QPSK; t->param.frequency = 10 * bcd32_to_cpu (buf[2], buf[3], buf[4], buf[5]); t->param.u.qpsk.fec_inner = fec_tab[buf[12] & 0x07]; t->param.u.qpsk.symbol_rate = 10 * bcd32_to_cpu (buf[9], buf[10], buf[11], buf[12] & 0xf0); t->polarisation = (buf[8] >> 5) & 0x03; dump_dvb_parameters (stderr, t->type, &t->param); if (t->scan_done) fprintf (stderr, " (done)"); if (t->last_tuning_failed) fprintf (stderr, " (tuning failed)"); fprintf (stderr, "\n");}staticvoid parse_terrestrial_delivery_system_descriptor (const unsigned char *buf, struct transponder *t){ static const fe_modulation_t m_tab [] = { QPSK, QAM_16, QAM_64, QAM_AUTO }; static const fe_code_rate_t ofec_tab [8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8 }; struct dvb_ofdm_parameters *o = &t->param.u.ofdm; t->type = FE_OFDM; t->param.frequency = (buf[2] << 24) | (buf[3] << 16); t->param.frequency |= (buf[4] << 8) | buf[5]; t->param.frequency *= 10; o->bandwidth = BANDWIDTH_8_MHZ + ((buf[6] >> 5) & 0x3); o->constellation = m_tab[(buf[7] >> 6) & 0x3]; o->hierarchy_information = HIERARCHY_NONE + ((buf[7] >> 3) & 0x3); if ((buf[7] & 0x7) > 4) o->code_rate_HP = FEC_AUTO; else o->code_rate_HP = ofec_tab [buf[7] & 0x7]; if (((buf[8] >> 5) & 0x7) > 4) o->code_rate_HP = FEC_AUTO; else o->code_rate_HP = ofec_tab [(buf[8] >> 5) & 0x7]; o->guard_interval = GUARD_INTERVAL_1_32 + ((buf[8] >> 3) & 0x3); o->transmission_mode = (buf[8] & 0x2) ? TRANSMISSION_MODE_8K : TRANSMISSION_MODE_2K; dump_dvb_parameters (stderr, t->type, &t->param); if (t->scan_done) fprintf (stderr, " (done)"); if (t->last_tuning_failed) fprintf (stderr, " (tuning failed)"); fprintf (stderr, "\n");}staticvoid parse_service_descriptor (const unsigned char *buf, struct service *s){ unsigned char len; unsigned char *src, *dest; s->type = buf[2]; buf += 3; len = *buf; buf++; if (s->provider_name) free (s->provider_name); s->provider_name = malloc (len + 1); memcpy (s->provider_name, buf, len); s->provider_name[len] = '\0'; if (s->service_name) free (s->service_name); buf += len; len = *buf; buf++; /* FIXME: handle character set correctly (e.g. via iconv) * c.f. EN 300 468 annex A */ if (len && *buf < 0x20) { buf++; len--; } s->service_name = malloc (len + 1); memcpy (s->service_name, buf, len); s->service_name[len] = '\0'; /* remove control characters (FIXME: handle short/long name) */ for (src = dest = s->service_name; *src; src++) if (*src >= 0x20 && (*src < 0x80 || *src > 0x9f)) *dest++ = *src; *dest = '\0'; MSG("0x%04x 0x%04x: pmt_pid 0x%04x %s -- %s (%s, %sscrambled)", s->transport_stream_id, s->service_id, s->pmt_pid, s->provider_name, s->service_name, s->running == RM_NOT_RUNNING ? "not running" : s->running == RM_STARTS_SOON ? "starts soon" : s->running == RM_PAUSING ? "pausing" : s->running == RM_RUNNING ? "running" : "???", s->scrambled ? "" : "not ");}staticvoid parse_descriptors (const unsigned char *buf, int descriptors_loop_len, void *data){ while (descriptors_loop_len > 0) { unsigned char descriptor_tag = buf[0]; unsigned char descriptor_len = buf[1] + 2; if (!descriptor_len) { WARN("descriptor_tag == 0x%02x, descriptor_len == %i", descriptor_tag, descriptor_len); break; } switch (descriptor_tag) { case 0x40: parse_network_name_descriptor (buf, data); break; case 0x43: parse_satellite_delivery_system_descriptor (buf, data); break; case 0x44: parse_cable_delivery_system_descriptor (buf, data); break; case 0x48: parse_service_descriptor (buf, data); break; case 0x5a: parse_terrestrial_delivery_system_descriptor (buf, data); break; default: /*WARN("skip descriptor 0x%02x", descriptor_tag)*/; }; buf += descriptor_len; descriptors_loop_len -= descriptor_len; }}staticvoid 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; } s = find_or_alloc_entry_by_id (&service_list, transport_stream_id, service_id); s->pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3]; buf += 4; section_length -= 4; };}staticvoid parse_pmt (const unsigned char *buf, int section_length, int service_id){ int program_info_len; struct service *s; s = find_or_alloc_entry_by_id (&service_list, -1, service_id); 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: s->video_pid = elementary_pid; break; case 0x03: case 0x04: s->audio_pid = elementary_pid; break; default: s->private_pid_count++; }; buf += ES_info_len + 5; section_length -= ES_info_len + 5; }; MSG("0x%04x 0x%04x: %s -- %s, pmt_pid 0x%04x, vpid 0x%04x, apid 0x%04x", s->transport_stream_id, s->service_id, s->provider_name, s->service_name, s->pmt_pid, s->video_pid, s->audio_pid);}staticvoid parse_nit (const unsigned char *buf, int section_length, int network_id){ int descriptors_loop_len = ((buf[0] & 0x0f) << 8) | buf[1]; struct network *n; if (section_length < descriptors_loop_len + 4 || !descriptors_loop_len) { WARN("network_id == 0x%02x, section_length == %i" "descriptors_loop_len == %i", network_id, section_length, descriptors_loop_len); return; } n = find_or_alloc_entry_by_id (&network_list, 0, network_id); parse_descriptors (buf + 2, descriptors_loop_len, n); section_length -= descriptors_loop_len + 4; buf += descriptors_loop_len + 4; while (section_length > 4) { int transport_stream_id = (buf[0] << 8) | buf[1]; struct transponder *t; descriptors_loop_len = ((buf[4] & 0x0f) << 8) | buf[5]; if (section_length < descriptors_loop_len + 4 || !transport_stream_id || !descriptors_loop_len) { WARN("transport_stream_id == 0x%02x, " "section_length == %i, descriptors_loop_len == %i", transport_stream_id, section_length, descriptors_loop_len); break; } t = find_or_alloc_entry_by_id (&transponder_list, network_id, transport_stream_id); parse_descriptors (buf + 6, descriptors_loop_len, t); section_length -= descriptors_loop_len + 6; buf += descriptors_loop_len + 6; };}staticvoid 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) { WARN("service_id == 0x%02x, section_length == %i" "descriptors_loop_len == %i", service_id, section_length, descriptors_loop_len); break; } s = find_or_alloc_entry_by_id (&service_list, transport_stream_id, service_id); s->running = (buf[3] >> 5) & 0x7; s->scrambled = (buf[3] >> 4) & 1; parse_descriptors (buf + 5, descriptors_loop_len, s); section_length -= descriptors_loop_len + 5; buf += descriptors_loop_len + 5; };}struct section_buf { struct list_head list_head; const char *dmx_devname; int run_once; int fd; int pid; int table_id [3]; int id [3]; int section_version_number [3]; int start_section_number [3]; uint8_t section_done [3][32]; int sectionfilter_done [3]; unsigned char buf [1024]; int bytes_in_buf; time_t timeout; time_t start_time; time_t running_time;};static
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -