static void parseEventDescription(void *data, enum ER round) { assert(GetDescriptorTag(data) == 0x4D); struct descr_short_event *evtdesc = data; char evt[256]; char dsc[256]; int evtlen = evtdesc->event_name_length; if (round == TITLE) { if (!evtlen) return; assert(evtlen < sizeof(evt)); memcpy(evt, (char *)&evtdesc->data, evtlen); evt[evtlen] = '\0'; printf("\t<title lang=\"%s\">%s</title>\n", xmllang(&evtdesc->lang_code1), xmlify(evt)); return; } if (round == SUB_TITLE) { int dsclen = evtdesc->data[evtlen]; assert(dsclen < sizeof(dsc)); memcpy(dsc, (char *)&evtdesc->data[evtlen+1], dsclen); dsc[dsclen] = '\0'; if (*dsc) { char *d = xmlify(dsc); if (d && *d) printf("\t<sub-title lang=\"%s\">%s</sub-title>\n", xmllang(&evtdesc->lang_code1), d); } } } /*}}}*/
/* * Parse 0x4D Short Event Descriptor */ static void parseEventDescription(void *data, enum ER round) { assert(GetDescriptorTag(data) == 0x4D); struct descr_short_event *evtdesc = CastShortEventDescriptor(data); char evt[256]; char dsc[256]; int evtlen = evtdesc->event_name_length; if (round == TITLE) { if (!evtlen) return; strncpy(evt, (char *) &evtdesc->data, evtlen); evt[evtlen] = '\0'; printf("\t<title lang=\"%s\">%s</title>\n", lookup_language( &evtdesc->lang_code1), convert_text(evt)); return; } if (round == SUB_TITLE) { int dsclen = evtdesc->data[evtlen]; strncpy(dsc, (char *) &evtdesc->data[evtlen + 1], dsclen); dsc[dsclen] = '\0'; if (*dsc) { const char *d = convert_text(dsc); if (d && *d) printf("\t<sub-title lang=\"%s\">%s</sub-title>\n", lookup_language(&evtdesc->lang_code1), d); } } }
/* * Parse 0x54 Content Descriptor */ static void parseContentDescription(u_char *data) { assert(GetDescriptorTag(data) == 0x54); struct descr_content *dc = CastContentDescriptor(data); int once[256 / 8 / sizeof(int)] = { 0, }; u_char *p; for (p = (u_char *) (&dc->data); p < (u_char *) (data + dc->descriptor_length); p += NIBBLE_CONTENT_LEN) { struct nibble_content *nc = (struct nibble_content *) p; int c1 = (nc->content_nibble_level_1 << 4) + nc->content_nibble_level_2; #ifdef CATEGORY_UNKNOWN int c2 = (nc->user_nibble_1 << 4) + nc->user_nibble_2; #endif if (c1 > 0 && !get_bit(once, c1)) { set_bit(once, c1); const char *c = lookup_description(c1); if (c) if (c[0]) printf("\t<category>%s</category>\n", c); #ifdef CATEGORY_UNKNOWN else printf("\t<!--category>%s %02X %02X</category-->\n", c + 1, c1, c2); else printf("\t<!--category>%02X %02X</category-->\n", c1, c2); #endif } // This is weird in the uk, they use user but not content, and almost the same values } }
static void parseComponentDescription(void *data, enum CR round, int *seen) { assert(GetDescriptorTag(data) == 0x50); struct descr_component *dc = data; char buf[256]; int len = dc->descriptor_length; assert(len < sizeof(buf)); memcpy(buf, (char *)&dc->data, len); buf[len] = '\0'; switch (dc->stream_content) { case 0x01: // Video Info if (round == VIDEO && !*seen) { //if ((dc->component_type-1)&0x08) //HD TV //if ((dc->component_type-1)&0x04) //30Hz else 25 printf("\t<video>\n"); printf("\t\t<aspect>%s</aspect>\n", lookup(aspect_table, (dc->component_type-1) & 0x03)); printf("\t</video>\n"); (*seen)++; } break; case 0x02: // Audio Info if (round == AUDIO && !*seen) { printf("\t<audio>\n"); printf("\t\t<stereo>%s</stereo>\n", lookup(audio_table, (dc->component_type))); printf("\t</audio>\n"); (*seen)++; } if (round == LANGUAGE) { if (!*seen) printf("\t<language>%s</language>\n", xmllang(&dc->lang_code1)); else printf("\t<!--language>%s</language-->\n", xmllang(&dc->lang_code1)); (*seen)++; } break; case 0x03: // Teletext Info if (round == SUBTITLES) { // FIXME: is there a suitable XMLTV output for this? // if ((dc->component_type)&0x10) //subtitles // if ((dc->component_type)&0x20) //subtitles for hard of hearing printf("\t<subtitles type=\"teletext\">\n"); printf("\t\t<language>%s</language>\n", xmllang(&dc->lang_code1)); printf("\t</subtitles>\n"); } break; // case 0x04: // AC3 info } #if 0 printf("\t<StreamComponent>\n"); printf("\t\t<StreamContent>%d</StreamContent>\n", dc->stream_content); printf("\t\t<ComponentType>%x</ComponentType>\n", dc->component_type); printf("\t\t<ComponentTag>%x</ComponentTag>\n", dc->component_tag); printf("\t\t<Length>%d</Length>\n", dc->component_tag, dc->descriptor_length-6); printf("\t\t<Language>%s</Language>\n", lang); printf("\t\t<Data>%s</Data>\n", buf); printf("\t</StreamComponent>\n"); #endif } /*}}}*/
/* Check that program has at least a title as is required by xmltv.dtd. {{{ */ static bool validateDescription(void *data, size_t len) { void *p; for (p = data; p < data + len; p += DESCR_GEN_LEN + GetDescriptorLength(p)) { struct descr_gen *desc = p; if (GetDescriptorTag(desc) == 0x4D) { struct descr_short_event *evtdesc = p; // make sure that title isn't empty if (evtdesc->event_name_length) return true; } } return false; } /*}}}*/
/* Parse 0x4E Extended Event Descriptor. {{{ */ void parseLongEventDescription(void *data) { assert(GetDescriptorTag(data) == 0x4E); struct descr_extended_event *levt = data; char dsc[256]; bool non_empty = (levt->descriptor_number || levt->last_descriptor_number || levt->length_of_items || levt->data[0]); if (non_empty && levt->descriptor_number == 0) printf("\t<desc lang=\"%s\">", xmllang(&levt->lang_code1)); void *p = &levt->data; void *data_end = data + DESCR_GEN_LEN + GetDescriptorLength(data); while (p < (void *)levt->data + levt->length_of_items) { struct item_extended_event *name = p; int name_len = name->item_description_length; assert(p + ITEM_EXTENDED_EVENT_LEN + name_len < data_end); assert(name_len < sizeof(dsc)); memcpy(dsc, (char *)&name->data, name_len); dsc[name_len] = '\0'; printf("%s: ", xmlify(dsc)); p += ITEM_EXTENDED_EVENT_LEN + name_len; struct item_extended_event *value = p; int value_len = value->item_description_length; assert(p + ITEM_EXTENDED_EVENT_LEN + value_len < data_end); assert(value_len < sizeof(dsc)); memcpy(dsc, (char *)&value->data, value_len); dsc[value_len] = '\0'; printf("%s; ", xmlify(dsc)); p += ITEM_EXTENDED_EVENT_LEN + value_len; } struct item_extended_event *text = p; int len = text->item_description_length; if (non_empty && len) { assert(len < sizeof(dsc)); memcpy(dsc, (char *)&text->data, len); dsc[len] = '\0'; printf("%s", xmlify(dsc)); } //printf("/%d/%d/%s", levt->descriptor_number, levt->last_descriptor_number, xmlify(dsc)); if (non_empty && levt->descriptor_number == levt->last_descriptor_number) printf("</desc>\n"); } /*}}}*/
/* * Parse 0x4E Extended Event Descriptor */ static void parseLongEventDescription(void *data) { assert(GetDescriptorTag(data) == 0x4E); struct descr_extended_event *levt = CastExtendedEventDescriptor(data); char dsc[256]; bool non_empty = (levt->descriptor_number || levt->last_descriptor_number || levt->length_of_items || levt->data[0]); if (non_empty && levt->descriptor_number == 0) printf("\t<desc lang=\"%s\">", lookup_language(&levt->lang_code1)); u_char *p = (u_char *) &levt->data; u_char *data_end = (u_char *) (CastExtendedEventDescriptor(data) + DESCR_GEN_LEN + GetDescriptorLength(data)); while (p < (u_char *) levt->data + levt->length_of_items) { struct item_extended_event *name = (struct item_extended_event *) p; int name_len = name->item_description_length; assert(p + ITEM_EXTENDED_EVENT_LEN + name_len < data_end); strncpy(dsc, (char *) &name->data, name_len); dsc[name_len] = '\0'; printf("%s: ", convert_text(dsc)); p += ITEM_EXTENDED_EVENT_LEN + name_len; struct item_extended_event *value = (struct item_extended_event *) p; int value_len = value->item_description_length; assert(p + ITEM_EXTENDED_EVENT_LEN + value_len < data_end); strncpy(dsc, (char *) &value->data, value_len); dsc[value_len] = '\0'; printf("%s; ", convert_text(dsc)); p += ITEM_EXTENDED_EVENT_LEN + value_len; } struct item_extended_event *text = (struct item_extended_event *) p; int len = text->item_description_length; if (non_empty && len) { strncpy(dsc, (char *) &text->data, len); dsc[len] = '\0'; printf("%s", convert_text(dsc)); } //printf("/%d/%d/%s", levt->descriptor_number, levt->last_descriptor_number, convert_text(dsc)); if (non_empty && levt->descriptor_number == levt->last_descriptor_number) printf("</desc>\n"); }
/* Parse 0x55 Rating Descriptor. {{{ */ void parseRatingDescription(void *data) { assert(GetDescriptorTag(data) == 0x55); struct descr_parental_rating *pr = data; void *p; for (p = &pr->data; p < data + pr->descriptor_length; p += PARENTAL_RATING_ITEM_LEN) { struct parental_rating_item *pr = p; switch (pr->rating) { case 0x00: /*undefined*/ break; case 0x01 ... 0x0F: printf("\t<rating system=\"dvb\">\n"); printf("\t\t<value>%d</value>\n", pr->rating + 3); printf("\t</rating>\n"); break; case 0x10 ... 0xFF: /*broadcaster defined*/ break; } } } /*}}}*/
/* See ETSI TS 102 323, section 12 */ void parseContentIdentifierDescription(void *data) { assert(GetDescriptorTag(data) == 0x76); struct descr_content_identifier *ci = data; void *p; for (p = &ci->data; p < data + ci->descriptor_length; /* at end */) { struct descr_content_identifier_crid *crid = p; struct descr_content_identifier_crid_local *crid_data; int crid_length = 3; char type_buf[32]; char *type; char buf[256]; type = lookup(crid_type_table, crid->crid_type); if (type == NULL) { type = type_buf; sprintf(type_buf, "0x%2x", crid->crid_type); } switch (crid->crid_location) { case 0x00: /* Carried explicitly within descriptor */ crid_data = (descr_content_identifier_crid_local_t *)&crid->crid_ref_data; int cridlen = crid_data->crid_length; assert(cridlen < sizeof(buf)); memcpy(buf, (char *)&crid_data->crid_byte, cridlen); buf[cridlen] = '\0'; printf("\t<crid type='%s'>%s</crid>\n", type, xmlify(buf)); crid_length = 2 + crid_data->crid_length; break; case 0x01: /* Carried in Content Identifier Table (CIT) */ break; default: break; } p += crid_length; } } /*}}}*/
/* * Parse Descriptor * Tags should be output in this order: * * 'title', 'sub-title', 'desc', 'credits', 'date', 'category', 'language', * 'orig-language', 'length', 'icon', 'url', 'country', 'episode-num', * 'video', 'audio', 'previously-shown', 'premiere', 'last-chance', * 'new', 'subtitles', 'rating', 'star-rating' */ static void parseDescription(u_char *data, size_t len) { int round, pds = 0; bool notupscaled = true; bool audiosubtitle = false; for (round = 0; round < 8; round++) { int seen = 0; // no title/language/video/audio/subtitles seen in this round u_char *p; for (p = data; p < (u_char *) (data + len); p += DESCR_GEN_LEN + GetDescriptorLength(p)) { struct descr_gen *desc = (struct descr_gen *) p; switch (GetDescriptorTag(desc)) { case 0: break; case 0x48: //service_description parseServiceDescription(desc); break; case 0x4D: //short evt desc, [title] [sub-title] // there can be multiple language versions of these if (round == 0) { parseEventDescription(desc, TITLE); } else if (round == 1) parseEventDescription(desc, SUB_TITLE); break; case 0x4E: //long evt descriptor [desc] if (round == 2) parseLongEventDescription(desc); break; case 0x50: //component desc [language] [video] [audio] [subtitles] if (round == 4) parseComponentDescription(desc, LANGUAGE, &seen, ¬upscaled); else if (round == 5) parseComponentDescription(desc, VIDEO, &seen, ¬upscaled); else if (round == 6) parseComponentDescription(desc, AUDIO, &seen, &audiosubtitle); else if (round == 7) parseComponentDescription(desc, SUBTITLES, &seen, &audiosubtitle); break; case 0x53: // CA Identifier Descriptor break; case 0x54: // content desc [category] if (round == 3) parseContentDescription((u_char *) desc); break; case 0x55: // Parental Rating Descriptor [rating] if (round == 7) parseRatingDescription((u_char *) desc); break; case 0x5f: // Private Data Specifier pds = parsePrivateDataSpecifier(desc); break; case 0x64: // Data broadcast desc - Text Desc for Data components break; case 0x69: // Programm Identification Label break; case 0x81: // TODO ??? if (pds == 5) // ARD_ZDF_ORF break; case 0x82: // VPS (ARD, ZDF, ORF) if (pds == 5) // ARD_ZDF_ORF // TODO: <programme @vps-start="???"> break; case 0x4F: // Time Shifted Event case 0x52: // Stream Identifier Descriptor case 0x5E: // Multi Lingual Component Descriptor case 0x83: // Logical Channel Descriptor (some kind of news-ticker on ARD-MHP-Data?) case 0x84: // Preferred Name List Descriptor case 0x85: // Preferred Name Identifier Descriptor case 0x86: // Eacem Stream Identifier Descriptor default: if (round == 0) { parseUnknown((u_char *) desc); } } } } }
static void parseServiceDescription(void *data) { assert(GetDescriptorTag(data) == 0x48); struct descr_service *pr = CastServiceDescriptor(data); log_message(DEBUG, "got a service descriptor %d", pr->provider_name_length); }
/* * Parse 0x5F Private Data Specifier */ static int parsePrivateDataSpecifier(void *data) { assert(GetDescriptorTag(data) == 0x5F); return GetPrivateDataSpecifier(data); }
/* * Parse 0x50 Component Descriptor. * video is a flag, 1=> output the video information, 0=> output the * audio information. seen is a pointer to a counter to ensure we * only output the first one of each (XMLTV can't cope with more than * one) */ static void parseComponentDescription(void *data, enum CR round, int *seen, bool *testfield) { assert(GetDescriptorTag(data) == 0x50); struct descr_component *dc = CastComponentDescriptor(data); char buf[256]; int len = dc->descriptor_length; strncpy(buf, (char *) &dc->data, len); buf[len] = '\0'; switch (dc->stream_content) { case 0x01: // Video Info case 0x05: // AVC Video Info if (round == VIDEO && !*seen) { //if ((dc->component_type-1)&0x08) //HD TV //if ((dc->component_type-1)&0x04) //30Hz else 25 printf("\t<video>\n"); printf("\t\t<aspect>%s</aspect>\n", lookup_aspect( (dc->component_type - 1) & 0x03)); if ((dc->component_type-1)>0x07 && *testfield) { //HD TV printf("\t\t<quality>HDTV</quality>\n"); } printf("\t</video>\n"); (*seen)++; } break; case 0x02: // Audio Info case 0x06: { // AVC Audio Info std::string audioinfo = lookup_audio(dc->component_type); if (round == SUBTITLES && audioinfo.compare("audio-subtitle") == 0 && *seen < 4 ) { if (testfield && *seen != 2) { printf("\t<subtitles type=\"audio-described\">\n"); printf("\t\t<language>%s</language>\n", lookup_language(&dc->lang_code1)); printf("\t</subtitles>\n"); (*seen)+=4; } } if (round == AUDIO && !*seen && audioinfo.compare("audio-subtitle") !=0) { printf("\t<audio>\n"); printf("\t\t<stereo>%s</stereo>\n", lookup_audio(dc->component_type)); printf("\t</audio>\n"); (*seen)++; } if (round == LANGUAGE) { if (!*seen) { printf("\t<language>%s</language>\n", lookup_language( &dc->lang_code1)); } else { //printf("\t<!--language>%s</language-->\n", lookup_language(&dc->lang_code1)); } (*seen)++; } } break; case 0x03: // Teletext Info if (round == LANGUAGE){ // need this BEFORE VIDEO runs if ((dc->component_type)&0x40) { *testfield=false; } } if (round == SUBTITLES) { switch (dc->component_type) { case 0x01: case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: if (testfield && *seen != 2 && *seen != 3 && *seen != 6 && *seen != 7) { printf("\t<subtitles type=\"teletext\">\n"); printf("\t\t<language>%s</language>\n", lookup_language(&dc->lang_code1)); printf("\t</subtitles>\n"); (*seen)+=2; } break; case 0x30: case 0x31: if (testfield && *seen != 1 && *seen != 3 && *seen != 5 && *seen != 7) { printf("\t<subtitles type=\"deaf-signed\">\n"); printf("\t\t<language>%s</language>\n", lookup_language(&dc->lang_code1)); printf("\t</subtitles>\n"); (*seen)++; } } // FIXME: is there a suitable XMLTV output for this? // if ((dc->component_type)&0x10) //subtitles // if ((dc->component_type)&0x20) //subtitles for hard of hearing //printf("\t<subtitles type=\"teletext\">\n"); //printf("\t\t<language>%s</language>\n", lookup_language(&dc->lang_code1)); //printf("\t</subtitles>\n"); } //break; // case 0x04: // AC3 info break; } }