📄 scan.c
字号:
/* remove control characters (FIXME: handle short/long name) */ /* FIXME: handle character set correctly (e.g. via iconv) * c.f. EN 300 468 annex A */ for (src = dest = (unsigned char *) s->service_name; *src; src++) if (*src >= 0x20 && (*src < 0x80 || *src > 0x9f)) *dest++ = *src; *dest = '\0'; if (!s->service_name[0]) { /* zap zero length names */ free (s->service_name); s->service_name = 0; } info("0x%04x 0x%04x: pmt_pid 0x%04x %s -- %s (%s%s)\n", 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 ? ", scrambled" : "");}static int find_descriptor(uint8_t tag, const unsigned char *buf, int descriptors_loop_len, const unsigned char **desc, int *desc_len){ while (descriptors_loop_len > 0) { unsigned char descriptor_tag = buf[0]; unsigned char descriptor_len = buf[1] + 2; if (!descriptor_len) { warning("descriptor_tag == 0x%02x, len is 0\n", descriptor_tag); break; } if (tag == descriptor_tag) { if (desc) *desc = buf; if (desc_len) *desc_len = descriptor_len; return 1; } buf += descriptor_len; descriptors_loop_len -= descriptor_len; } return 0;}static void parse_descriptors(enum table_type t, 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) { warning("descriptor_tag == 0x%02x, len is 0\n", descriptor_tag); break; } switch (descriptor_tag) { case 0x0a: if (t == PMT) parse_iso639_language_descriptor (buf, data); break; case 0x40: if (t == NIT) parse_network_name_descriptor (buf, data); break; case 0x43: if (t == NIT) parse_satellite_delivery_system_descriptor (buf, data); break; case 0x44: if (t == NIT) parse_cable_delivery_system_descriptor (buf, data); break; case 0x48: if (t == SDT) parse_service_descriptor (buf, data); break; case 0x53: if (t == SDT) parse_ca_identifier_descriptor (buf, data); break; case 0x5a: if (t == NIT) parse_terrestrial_delivery_system_descriptor (buf, data); break; case 0x62: if (t == NIT) parse_frequency_list_descriptor (buf, data); break; case 0x83: /* 0x83 is in the privately defined range of descriptor tags, * so we parse this only if the user says so to avoid * problems when 0x83 is something entirely different... */ if (t == NIT && vdr_dump_channum) parse_terrestrial_uk_channel_number (buf, data); break; default: verbosedebug("skip descriptor 0x%02x\n", descriptor_tag); }; buf += descriptor_len; descriptors_loop_len -= descriptor_len; }}static void parse_pat(const unsigned char *buf, int section_length, int transport_stream_id){ (void)transport_stream_id; while (section_length > 0) { struct service *s; int service_id = (buf[0] << 8) | buf[1]; if (service_id == 0) goto skip; /* nit pid entry */ /* 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, s->service_id, 1, 0, 5); add_filter (s->priv); }skip: 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 >= 5) { 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 0x81: /* Audio per ATSC A/53B [2] Annex B */ 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) { 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){ (void)transport_stream_id; buf += 3; /* skip original network id + reserved field */ while (section_length >= 5) { 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 || !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; };}/* ATSC PSIP VCT */static void parse_atsc_service_loc_desc(struct service *s,const unsigned char *buf){ struct ATSC_service_location_descriptor d = read_ATSC_service_location_descriptor(buf); int i; unsigned char *b = (unsigned char *) buf+5; s->pcr_pid = d.PCR_PID; for (i=0; i < d.number_elements; i++) { struct ATSC_service_location_element e = read_ATSC_service_location_element(b); switch (e.stream_type) { case 0x02: /* video */ s->video_pid = e.elementary_PID; moreverbose(" VIDEO : PID 0x%04x\n", e.elementary_PID); break; case 0x81: /* ATSC audio */ if (s->audio_num < AUDIO_CHAN_MAX) { s->audio_pid[s->audio_num] = e.elementary_PID; s->audio_lang[s->audio_num][0] = (e.ISO_639_language_code >> 16) & 0xff; s->audio_lang[s->audio_num][1] = (e.ISO_639_language_code >> 8) & 0xff; s->audio_lang[s->audio_num][2] = e.ISO_639_language_code & 0xff; s->audio_num++; } moreverbose(" AUDIO : PID 0x%04x lang: %s\n",e.elementary_PID,s->audio_lang[s->audio_num-1]); break; default: warning("unhandled stream_type: %x\n",e.stream_type); break; }; b += 6; }}static void parse_atsc_ext_chan_name_desc(struct service *s,const unsigned char *buf){ unsigned char *b = (unsigned char *) buf+2; int i,j; int num_str = b[0]; b++; for (i = 0; i < num_str; i++) { int num_seg = b[3]; b += 4; /* skip lang code */ for (j = 0; j < num_seg; j++) { int comp_type = b[0],/* mode = b[1],*/ num_bytes = b[2]; switch (comp_type) { case 0x00: if (s->service_name) free(s->service_name); s->service_name = malloc(num_bytes * sizeof(char) + 1); memcpy(s->service_name,&b[3],num_bytes); s->service_name[num_bytes] = '\0'; break; default: warning("compressed strings are not supported yet\n"); break; } b += 3 + num_bytes; } }}static void parse_psip_descriptors(struct service *s,const unsigned char *buf,int len){ unsigned char *b = (unsigned char *) buf; int desc_len; while (len > 0) { desc_len = b[1]; switch (b[0]) { case ATSC_SERVICE_LOCATION_DESCRIPTOR_ID: parse_atsc_service_loc_desc(s,b); break; case ATSC_EXTENDED_CHANNEL_NAME_DESCRIPTOR_ID: parse_atsc_ext_chan_name_desc(s,b); break; default: warning("unhandled psip descriptor: %02x\n",b[0]); break; } b += 2 + desc_len; len -= 2 + desc_len; }}static void parse_psip_vct (const unsigned char *buf, int section_length, int table_id, int transport_stream_id){ (void)section_length; (void)table_id; (void)transport_stream_id;/* int protocol_version = buf[0];*/ int num_channels_in_section = buf[1]; int i; int pseudo_id = 0xffff; unsigned char *b = (unsigned char *) buf + 2; for (i = 0; i < num_channels_in_section; i++) { struct service *s; struct tvct_channel ch = read_tvct_channel(b); switch (ch.service_type) { case 0x01: info("analog channels won't be put info channels.conf\n"); break; case 0x02: /* ATSC TV */ case 0x03: /* ATSC Radio */ break; case 0x04: /* ATSC Data */ default: continue; } if (ch.program_number == 0) ch.program_number = --pseudo_id; s = find_service(current_tp, ch.program_number); if (!s) s = alloc_service(current_tp, ch.program_number); if (s->service_name) free(s->service_name); s->service_name = malloc(7*sizeof(unsigned char)); /* TODO find a better solution to convert UTF-16 */ s->service_name[0] = ch.short_name0; s->service_name[1] = ch.short_name1; s->service_name[2] = ch.short_name2; s->service_name[3] = ch.short_name3; s->service_name[4] = ch.short_name4; s->service_name[5] = ch.short_name5; s->service_name[6] = ch.short_name6; parse_psip_descriptors(s,&b[32],ch.descriptors_length); s->channel_num = ch.major_channel_number << 10 | ch.minor_channel_number; if (ch.hidden) { s->running = RM_NOT_RUNNING; info("service is not running, pseudo program_number."); } else { s->running = RM_RUNNING; info("service is running."); } info(" Channel number: %d:%d. Name: '%s'\n", ch.major_channel_number, ch.minor_channel_number,s->service_name); b += 32 + ch.descriptors_length; }}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]; 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; /* past generic table header */ section_length -= 5 + 4; /* header + crc */ if (section_length < 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -