From 51711b72590ebe30f7b4a6172b5c36ccff559d6c Mon Sep 17 00:00:00 2001 From: randomdan Date: Thu, 17 Mar 2011 10:44:20 +0000 Subject: Work to date on p2pvr - basic EIT scanner --- p2pvr/Jamfile.jam | 0 p2pvr/cron/importSchedume.xml | 55 ++ p2pvr/cron/sched.xml | 29 + p2pvr/datasources/postgres.xml | 8 + p2pvr/scanner/Jamfile.jam | 18 + p2pvr/scanner/crc32.cpp | 61 ++ p2pvr/scanner/dvb_info_tables.c | 312 ++++++++ p2pvr/scanner/ice_scan.cpp | 343 +++++++++ p2pvr/scanner/icescan.cpp | 0 p2pvr/scanner/langidents.c | 211 +++++ p2pvr/scanner/lookup.cpp | 52 ++ p2pvr/scanner/p2scan.cpp | 761 ++++++++++++++++++ p2pvr/scanner/scanner.ice | 7 + p2pvr/scanner/si_tables.h | 1625 +++++++++++++++++++++++++++++++++++++++ p2pvr/scanner/tv_grab_dvb.h | 32 + 15 files changed, 3514 insertions(+) create mode 100644 p2pvr/Jamfile.jam create mode 100644 p2pvr/cron/importSchedume.xml create mode 100644 p2pvr/cron/sched.xml create mode 100644 p2pvr/datasources/postgres.xml create mode 100644 p2pvr/scanner/Jamfile.jam create mode 100644 p2pvr/scanner/crc32.cpp create mode 100644 p2pvr/scanner/dvb_info_tables.c create mode 100644 p2pvr/scanner/ice_scan.cpp create mode 100644 p2pvr/scanner/icescan.cpp create mode 100644 p2pvr/scanner/langidents.c create mode 100644 p2pvr/scanner/lookup.cpp create mode 100644 p2pvr/scanner/p2scan.cpp create mode 100644 p2pvr/scanner/scanner.ice create mode 100644 p2pvr/scanner/si_tables.h create mode 100644 p2pvr/scanner/tv_grab_dvb.h diff --git a/p2pvr/Jamfile.jam b/p2pvr/Jamfile.jam new file mode 100644 index 0000000..e69de29 diff --git a/p2pvr/cron/importSchedume.xml b/p2pvr/cron/importSchedume.xml new file mode 100644 index 0000000..928c2bd --- /dev/null +++ b/p2pvr/cron/importSchedume.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + title + titleLang + subtitle + subtitleLang + serviceID + eventID + descLang + desc1 + desc2 + desc3 + videoAspect + audioChannels + language + teletextSubtitleLang + category + dvbRating + contentIdentType + contentIdent + startTime + stopTime + + + diff --git a/p2pvr/cron/sched.xml b/p2pvr/cron/sched.xml new file mode 100644 index 0000000..db438d3 --- /dev/null +++ b/p2pvr/cron/sched.xml @@ -0,0 +1,29 @@ + + + + + + + title + titleLang + subtitle + subtitleLang + serviceID + descLang + desc1 + desc2 + desc3 + videoAspect + audioChannels + language + teletextSubtitleLang + category + dvbRating + contentIdentType + contentIdent + startTime + stopTime + serviceID + + + diff --git a/p2pvr/datasources/postgres.xml b/p2pvr/datasources/postgres.xml new file mode 100644 index 0000000..df1ac0f --- /dev/null +++ b/p2pvr/datasources/postgres.xml @@ -0,0 +1,8 @@ + + + + host=defiant sslmode=disable user=p2tv dbname=gentoo options='-c search_path=p2tv,public' + host=firebrand sslmode=disable user=p2tv dbname=gentoo options='-c search_path=p2tv,public' + + host=defiant sslmode=disable user=p2tv dbname=gentoo options='-c search_path=p2tv,public' + diff --git a/p2pvr/scanner/Jamfile.jam b/p2pvr/scanner/Jamfile.jam new file mode 100644 index 0000000..2117886 --- /dev/null +++ b/p2pvr/scanner/Jamfile.jam @@ -0,0 +1,18 @@ +project + : requirements + debug:-Wl,-z,defs "-W -Wall -Werror -Wwrite-strings" + ; + +# Scanner base - the common part lifted from tv_grab_dvb +lib p2pvr-scan-base : langidents.c crc32.cpp dvb_info_tables.c lookup.cpp ; + +# Scanner - the common part implementing the ICE interface +lib p2pvr-scan-ice : icescan.cpp scanner.ice : p2pvr-scan-base ; + +# Scanner - t +lib p2pvr-scan-p2 : p2scan.cpp : p2pvr-scan-base ../../project2//p2common ; + +# ScannerICE - the ICE test app +#exe scanice : ice_scan.cpp : p2pvr-scan ; + +explicit p2pvr-scan-ice ; diff --git a/p2pvr/scanner/crc32.cpp b/p2pvr/scanner/crc32.cpp new file mode 100644 index 0000000..3dec763 --- /dev/null +++ b/p2pvr/scanner/crc32.cpp @@ -0,0 +1,61 @@ +/* crc32.c: CRC32 routine + */ +#include +#include + +static const uint32_t crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, + 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + +uint32_t _dvb_crc32(const uint8_t *data, size_t len) +{ + size_t i; + uint32_t crc = 0xffffffff; + + for (i = 0; i < len; i++) + crc = (crc << 8) ^ crc_table[((crc >> 24) ^ *data++) & 0xff]; + + return crc; +} diff --git a/p2pvr/scanner/dvb_info_tables.c b/p2pvr/scanner/dvb_info_tables.c new file mode 100644 index 0000000..d8257be --- /dev/null +++ b/p2pvr/scanner/dvb_info_tables.c @@ -0,0 +1,312 @@ +/* + * tv_grab_dvb - (c) Mark Bryars 2004 + * God bless vim and macros, this would have taken forever to format otherwise. + */ +#include "tv_grab_dvb.h" + +const struct lookup_table description_table[] = { + { {0x00}, "\0UNDEFINED CONTENT"}, + { {0x01}, "\0UNDEFINED CONTENT"}, + { {0x02}, "\0UNDEFINED CONTENT"}, + { {0x03}, "\0UNDEFINED CONTENT"}, + { {0x04}, "\0UNDEFINED CONTENT"}, + { {0x05}, "\0UNDEFINED CONTENT"}, + { {0x06}, "\0UNDEFINED CONTENT"}, + { {0x07}, "\0UNDEFINED CONTENT"}, + { {0x08}, "\0UNDEFINED CONTENT"}, + { {0x09}, "\0UNDEFINED CONTENT"}, + { {0x0A}, "\0UNDEFINED CONTENT"}, + { {0x0B}, "\0UNDEFINED CONTENT"}, + { {0x0C}, "\0UNDEFINED CONTENT"}, + { {0x0D}, "\0UNDEFINED CONTENT"}, + { {0x0E}, "\0UNDEFINED CONTENT"}, + { {0x0F}, "\0UNDEFINED CONTENT"}, + + { {0x10}, "Movie / Drama" }, + { {0x11}, "Movie - detective/thriller" }, + { {0x12}, "Movie - adventure/western/war" }, + { {0x13}, "Movie - science fiction/fantasy/horror" }, + { {0x14}, "Movie - comedy" }, + { {0x15}, "Movie - soap/melodrama/folkloric" }, + { {0x16}, "Movie - romance" }, + { {0x17}, "Movie - serious/classical/religious/historical movie/drama" }, + { {0x18}, "Movie - adult movie/drama" }, + { {0x19}, "\0Movie - RESERVED" }, + { {0x1A}, "\0Movie - RESERVED" }, + { {0x1B}, "\0Movie - RESERVED" }, + { {0x1C}, "\0Movie - RESERVED" }, + { {0x1D}, "\0Movie - RESERVED" }, + { {0x1E}, "\0Movie - RESERVED" }, + { {0x1F}, NULL }, + + { {0x20}, "News / Current Affairs" }, + { {0x21}, "New - news/weather report" }, + { {0x22}, "New - news magazine" }, + { {0x23}, "New - documentary" }, + { {0x24}, "New - discussion/interview/debate" }, + { {0x25}, "\0News - RESERVED" }, + { {0x26}, "\0News - RESERVED" }, + { {0x27}, "\0News - RESERVED" }, + { {0x28}, "\0News - RESERVED" }, + { {0x29}, "\0News - RESERVED" }, + { {0x2A}, "\0News - RESERVED" }, + { {0x2B}, "\0News - RESERVED" }, + { {0x2C}, "\0News - RESERVED" }, + { {0x2D}, "\0News - RESERVED" }, + { {0x2E}, "\0News - RESERVED" }, + { {0x2E}, NULL }, + + { {0x30}, "Show / Game Show" }, + { {0x31}, "Show - game show/quiz/contest" }, + { {0x32}, "Show - variety show" }, + { {0x33}, "Show - talk show" }, + { {0x34}, "\0Show - RESERVED" }, + { {0x35}, "\0Show - RESERVED" }, + { {0x36}, "\0Show - RESERVED" }, + { {0x37}, "\0Show - RESERVED" }, + { {0x38}, "\0Show - RESERVED" }, + { {0x39}, "\0Show - RESERVED" }, + { {0x3A}, "\0Show - RESERVED" }, + { {0x3B}, "\0Show - RESERVED" }, + { {0x3C}, "\0Show - RESERVED" }, + { {0x3D}, "\0Show - RESERVED" }, + { {0x3E}, "\0Show - RESERVED" }, + { {0x3F}, NULL }, + + { {0x40}, "Sports" }, + { {0x41}, "Sports - special events (Olympic Games, World Cup etc.)" }, + { {0x42}, "Sports - sports magazines" }, + { {0x43}, "Sports - football/soccer" }, + { {0x44}, "Sports - tennis/squash" }, + { {0x45}, "Sports - team sports (excluding football)" }, + { {0x46}, "Sports - athletics" }, + { {0x47}, "Sports - motor sport" }, + { {0x48}, "Sports - water sport" }, + { {0x49}, "Sports - winter sports" }, + { {0x4A}, "Sports - equestrian" }, + { {0x4B}, "Sports - martial sports" }, + { {0x4C}, "\0Sports - RESERVED" }, + { {0x4D}, "\0Sports - RESERVED" }, + { {0x4E}, "\0Sports - RESERVED" }, + { {0x4F}, NULL }, + + { {0x50}, "Childrens / Youth" }, + { {0x51}, "Children - pre-school children's programmes" }, + { {0x52}, "Children - entertainment programmes for 6 to 14" }, + { {0x53}, "Children - entertainment programmes for 10 to 16" }, + { {0x54}, "Children - informational/educational/school programmes" }, + { {0x55}, "Children - cartoons/puppets" }, + { {0x56}, "\0Children - RESERVED" }, + { {0x57}, "\0Children - RESERVED" }, + { {0x58}, "\0Children - RESERVED" }, + { {0x59}, "\0Children - RESERVED" }, + { {0x5A}, "\0Children - RESERVED" }, + { {0x5B}, "\0Children - RESERVED" }, + { {0x5C}, "\0Children - RESERVED" }, + { {0x5D}, "\0Children - RESERVED" }, + { {0x5E}, "\0Children - RESERVED" }, + { {0x5F}, NULL }, + + { {0x60}, "Music / Ballet / Dance" }, + { {0x61}, "Music - rock/pop" }, + { {0x62}, "Music - serious music/classical music" }, + { {0x63}, "Music - folk/traditional music" }, + { {0x64}, "Music - jazz" }, + { {0x65}, "Music - musical/opera" }, + { {0x66}, "Music - ballet" }, + { {0x67}, "\0Music - RESERVED" }, + { {0x68}, "\0Music - RESERVED" }, + { {0x69}, "\0Music - RESERVED" }, + { {0x6A}, "\0Music - RESERVED" }, + { {0x6B}, "\0Music - RESERVED" }, + { {0x6C}, "\0Music - RESERVED" }, + { {0x6D}, "\0Music - RESERVED" }, + { {0x6E}, "\0Music - RESERVED" }, + { {0x6F}, NULL }, + + { {0x70}, "Arts / Culture" }, + { {0x71}, "Arts - performing arts" }, + { {0x72}, "Arts - fine arts" }, + { {0x73}, "Arts - religion" }, + { {0x74}, "Arts - popular culture/traditional arts" }, + { {0x75}, "Arts - literature" }, + { {0x76}, "Arts - film/cinema" }, + { {0x77}, "Arts - experimental film/video" }, + { {0x78}, "Arts - broadcasting/press" }, + { {0x79}, "Arts - new media" }, + { {0x7A}, "Arts - arts/culture magazines" }, + { {0x7B}, "Arts - fashion" }, + { {0x7C}, "\0Arts - RESERVED" }, + { {0x7D}, "\0Arts - RESERVED" }, + { {0x7E}, "\0Arts - RESERVED" }, + { {0x7F}, NULL }, + + { {0x80}, "Social / Policical / Economics" }, + { {0x81}, "Social - magazines/reports/documentary" }, + { {0x82}, "Social - economics/social advisory" }, + { {0x83}, "Social - remarkable people" }, + { {0x84}, "\0Social - RESERVED" }, + { {0x85}, "\0Social - RESERVED" }, + { {0x86}, "\0Social - RESERVED" }, + { {0x87}, "\0Social - RESERVED" }, + { {0x88}, "\0Social - RESERVED" }, + { {0x89}, "\0Social - RESERVED" }, + { {0x8A}, "\0Social - RESERVED" }, + { {0x8b}, "\0Social - RESERVED" }, + { {0x8C}, "\0Social - RESERVED" }, + { {0x8D}, "\0Social - RESERVED" }, + { {0x8E}, "\0Social - RESERVED" }, + { {0x8F}, NULL }, + + { {0x90}, "Education / Science / Factual" }, + { {0x91}, "Education - nature/animals/environment" }, + { {0x92}, "Education - technology/natural sciences" }, + { {0x93}, "Education - medicine/physiology/psychology" }, + { {0x94}, "Education - foreign countries/expeditions" }, + { {0x95}, "Education - social/spiritual sciences" }, + { {0x96}, "Education - further education" }, + { {0x97}, "Education - languages" }, + { {0x98}, "\0Education - RESERVED" }, + { {0x99}, "\0Education - RESERVED" }, + { {0x9A}, "\0Education - RESERVED" }, + { {0x9B}, "\0Education - RESERVED" }, + { {0x9C}, "\0Education - RESERVED" }, + { {0x9D}, "\0Education - RESERVED" }, + { {0x9E}, "\0Education - RESERVED" }, + { {0x9F}, NULL }, + + { {0xA0}, "Leisure / Hobbies" }, + { {0xA1}, "Leisure - tourism/travel" }, + { {0xA2}, "Leisure - handicraft" }, + { {0xA3}, "Leisure - motoring" }, + { {0xA4}, "Leisure - fitness & health" }, + { {0xA5}, "Leisure - cooking" }, + { {0xA6}, "Leisure - advertizement/shopping" }, + { {0xA7}, "Leisure - gardening" }, + { {0xA8}, "\0Leisure - RESERVED" }, + { {0xA9}, "\0Leisure - RESERVED" }, + { {0xAA}, "\0Leisure - RESERVED" }, + { {0xAB}, "\0Leisure - RESERVED" }, + { {0xAC}, "\0Leisure - RESERVED" }, + { {0xAD}, "\0Leisure - RESERVED" }, + { {0xAE}, "\0Leisure - RESERVED" }, + { {0xAF}, NULL }, + + // Special + { {0xB0}, "Original Language" }, + { {0xB1}, "black & white" }, + { {0xB2}, "unpublished" }, + { {0xB3}, "live broadcast" }, + { {0xB4}, "\0Characteristics - RESERVED" }, + { {0xB5}, "\0Characteristics - RESERVED" }, + { {0xB6}, "\0Characteristics - RESERVED" }, + { {0xB7}, "\0Characteristics - RESERVED" }, + { {0xB8}, "\0Characteristics - RESERVED" }, + { {0xB9}, "\0Characteristics - RESERVED" }, + { {0xBA}, "\0Characteristics - RESERVED" }, + { {0xBB}, "\0Characteristics - RESERVED" }, + { {0xBC}, "\0Characteristics - RESERVED" }, + { {0xBD}, "\0Characteristics - RESERVED" }, + { {0xBE}, "\0Characteristics - RESERVED" }, + { {0xBF}, NULL }, + + { {0xC0}, "\0RESERVED" }, + { {0xC1}, "\0RESERVED" }, + { {0xC2}, "\0RESERVED" }, + { {0xC3}, "\0RESERVED" }, + { {0xC4}, "\0RESERVED" }, + { {0xC5}, "\0RESERVED" }, + { {0xC6}, "\0RESERVED" }, + { {0xC7}, "\0RESERVED" }, + { {0xC8}, "\0RESERVED" }, + { {0xC9}, "\0RESERVED" }, + { {0xCA}, "\0RESERVED" }, + { {0xCB}, "\0RESERVED" }, + { {0xCC}, "\0RESERVED" }, + { {0xCD}, "\0RESERVED" }, + { {0xCE}, "\0RESERVED" }, + { {0xCF}, "\0RESERVED" }, + + { {0xD0}, "\0RESERVED" }, + { {0xD1}, "\0RESERVED" }, + { {0xD2}, "\0RESERVED" }, + { {0xD3}, "\0RESERVED" }, + { {0xD4}, "\0RESERVED" }, + { {0xD5}, "\0RESERVED" }, + { {0xD6}, "\0RESERVED" }, + { {0xD7}, "\0RESERVED" }, + { {0xD8}, "\0RESERVED" }, + { {0xD9}, "\0RESERVED" }, + { {0xDA}, "\0RESERVED" }, + { {0xDB}, "\0RESERVED" }, + { {0xDC}, "\0RESERVED" }, + { {0xDD}, "\0RESERVED" }, + { {0xDE}, "\0RESERVED" }, + { {0xDF}, "\0RESERVED" }, + + { {0xE0}, "\0RESERVED" }, + { {0xE1}, "\0RESERVED" }, + { {0xE2}, "\0RESERVED" }, + { {0xE3}, "\0RESERVED" }, + { {0xE4}, "\0RESERVED" }, + { {0xE5}, "\0RESERVED" }, + { {0xE6}, "\0RESERVED" }, + { {0xE7}, "\0RESERVED" }, + { {0xE8}, "\0RESERVED" }, + { {0xE9}, "\0RESERVED" }, + { {0xEA}, "\0RESERVED" }, + { {0xEB}, "\0RESERVED" }, + { {0xEC}, "\0RESERVED" }, + { {0xED}, "\0RESERVED" }, + { {0xEE}, "\0RESERVED" }, + { {0xEF}, "\0RESERVED" }, + + // UK Freeview custom id + { {0xF0}, "Drama" }, + { {0xF1}, NULL }, + { {0xF2}, NULL }, + { {0xF3}, NULL }, + { {0xF4}, NULL }, + { {0xF5}, NULL }, + { {0xF6}, NULL }, + { {0xF7}, NULL }, + { {0xF8}, NULL }, + { {0xF9}, NULL }, + { {0xFA}, NULL }, + { {0xFB}, NULL }, + { {0xFC}, NULL }, + { {0xFD}, NULL }, + { {0xFE}, NULL }, + { {0xFF}, NULL }, + + { {-1}, NULL } +}; + +const struct lookup_table aspect_table[] = { + { {0}, "4:3"}, // 4/3 + { {1}, "16:9"}, // 16/9 WITH PAN VECTORS + { {2}, "16:9"}, // 16/9 WITHOUT + { {3}, "2.21:1"}, // >16/9 or 2.21/1 XMLTV no likey + {{-1}, NULL } +}; + +const struct lookup_table audio_table[] = { + {{0x01}, "mono" }, //single mono + {{0x02}, "mono" }, //dual mono - stereo?? + {{0x03}, "stereo" }, + {{0x05}, "surround" }, + {{0x04}, "x-multilingual"}, // multilingual/channel + {{0x40}, "x-visuallyimpared"}, // visual impared sound + {{0x41}, "x-hardofhearing"}, // hard hearing sound + { {-1}, NULL } +}; + +const struct lookup_table crid_type_table[] = { + {{0x00}, "none" }, + {{0x01}, "item" }, + {{0x02}, "series" }, + {{0x03}, "recommendation" }, + {{0x31}, "item" }, // UK only? -- I can't find specs that use these + {{0x32}, "series" }, // UK only? + { {-1}, NULL } +}; diff --git a/p2pvr/scanner/ice_scan.cpp b/p2pvr/scanner/ice_scan.cpp new file mode 100644 index 0000000..24ea1bc --- /dev/null +++ b/p2pvr/scanner/ice_scan.cpp @@ -0,0 +1,343 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "version.h" +#include "scan.h" +#include "dump-vdr.h" +#include "dump-xine.h" +#include "dump-dvbscan.h" +#include "dump-kaffeine.h" +#include "dump-mplayer.h" +#include "dump-vlc-m3u.h" +#include "dvbscan.h" +#include "parse-dvbscan.h" +#include "countries.h" +#include "satellites.h" +#include "atsc_psip_section.h" +#include "descriptors.h" +#include "lnb.h" +#include "diseqc.h" + +#define MOD_USE_STANDARD 0x00 +#define MOD_OVERRIDE_MIN 0x01 +#define MOD_OVERRIDE_MAX 0x02 + +static struct lnb_types_st this_lnb; // 20090320: DVB-S/S2, LNB type, initialized in main to 'UNIVERSAL' + +int main (int argc, char **argv) +{ + char frontend_devname [80]; + int adapter = 999, frontend = 0, demux = 0; + int opt; + unsigned int i = 0, j; + int frontend_fd = -1; + int fe_open_mode; + uint16_t frontend_type = FE_OFDM; + int Radio_Services = 1; + int TV_Services = 1; + int Other_Services = 0; // 20080106: don't search other services by default. + int ext = 0; + int retVersion = 0; + int discover = 0; + int a=0,c=0,s=0,t=0; + int device_preferred = -1; + int valid_initial_data = 0; + int valid_rotor_data = 0; + int modulation_flags = MOD_USE_STANDARD; + char * country = NULL; + char * satellite = NULL; + char * initdata = NULL; + char * positionfile = NULL; + char sw_type = 0; + + this_lnb = * lnb_enum(0); + this_lnb.low_val *= 1000; + this_lnb.high_val *= 1000; + this_lnb.switch_val *= 1000; + + flags.version = version; + start_time = time(NULL); + + while ((opt = getopt(argc, argv, "a:c:e:f:hi:kl:o:p:qr:s:t:vxA:D:E:FHI:LMO:PQ:R:S:T:VX")) != -1) { + switch (opt) { + case 'a': //adapter + adapter = strtoul(optarg, NULL, 0); + break; + case 'c': //country setting + country=strdup(optarg); + if (0 == strcasecmp(country, "?")) { + print_countries(); + return(0); + } + break; + case 'e': //extended scan flags + ext = strtoul(optarg, NULL, 0); + if (ext & 0x01) + dvbc_symbolrate_max = 16; + if (ext & 0x02) { + modulation_max = 2; + modulation_flags |= MOD_OVERRIDE_MAX; + } + break; + case 'f': //frontend type + if (strcmp(optarg, "t") == 0) frontend_type = FE_OFDM; + if (strcmp(optarg, "c") == 0) frontend_type = FE_QAM; + if (strcmp(optarg, "a") == 0) frontend_type = FE_ATSC; + if (strcmp(optarg, "s") == 0) frontend_type = FE_QPSK; + if (strcmp(optarg, "?") == 0) discover++; + if (frontend_type == FE_ATSC) + this_channellist = ATSC_VSB; + break; + case 'h': //basic help + bad_usage("w_scan"); + return 0; + break; + case 'i': //specify inversion + caps_inversion = strtoul(optarg, NULL, 0); + break; + case 'k': //kaffeine output + output_format = OUTPUT_KAFFEINE; + break; + case 'l': //satellite lnb type + if (strcmp(optarg, "?") == 0) { + struct lnb_types_st * p; + char ** cp; + + while((p = lnb_enum(i++))) { + info("%s\n", p->name); + for (cp = p->desc; *cp;) + info("\t%s\n", *cp++); + } + return 0; + } + if (lnb_decode(optarg, &this_lnb) < 0) + fatal("LNB decoding failed. Use \"-l ?\" for list.\n"); + /* MHz -> kHz */ + this_lnb.low_val *= 1000; + this_lnb.high_val *= 1000; + this_lnb.switch_val *= 1000; + break; + case 'o': //vdr Version + flags.vdr_version = strtoul(optarg, NULL, 0); + if (flags.vdr_version > 2) flags.dump_provider = 1; + break; + case 'p': //satellite *p*osition file + positionfile=strdup(optarg); + break; + case 'q': //quite + if (--verbosity < 0) + verbosity = 0; + break; + case 'r': //satellite rotor position + flags.rotor_position = strtoul(optarg, NULL, 0); + break; + case 's': //satellite setting + satellite=strdup(optarg); + if (0 == strcasecmp(satellite, "?")) { + print_satellites(); + return(0); + } + break; + case 't': //tuning speed + flags.tuning_timeout = strtoul(optarg, NULL, 0); + if ((flags.tuning_timeout < 1)) bad_usage(argv[0]); + if ((flags.tuning_timeout > 3)) bad_usage(argv[0]); + break; + case 'v': //verbose + verbosity++; + break; + case 'x': //dvbscan output + output_format = OUTPUT_DVBSCAN_TUNING_DATA; + break; + case 'A': //ATSC type + ATSC_type = strtoul(optarg,NULL,0); + switch (ATSC_type) { + case 1: ATSC_type = ATSC_VSB; break; + case 2: ATSC_type = ATSC_QAM; break; + case 3: ATSC_type = (ATSC_VSB + ATSC_QAM); break; + default: + bad_usage(argv[0]); + return -1; + } + /* if -A is specified, it implies -f a */ + frontend_type = FE_ATSC; + break; + case 'D': //DiSEqC committed/uncommitted switch + sscanf(optarg,"%d%c", &i, &sw_type); + switch(sw_type) { + case 'u': + uncommitted_switch = i; + if (uncommitted_switch > 15) + fatal("uncommitted switch position needs to be < 16!\n"); + flags.sw_pos = (flags.sw_pos & 0xF) | uncommitted_switch; + break; + case 'c': + committed_switch = i; + if (committed_switch > 3) + fatal("committed switch position needs to be < 4!\n"); + flags.sw_pos = (flags.sw_pos & 0xF0) | committed_switch; + break; + default: + fatal("Could not parse Argument \"-D\"\n" + "Should be number followed \"u\" or \"c\"\n"); + } + break; + case 'E': //include encrypted channels + flags.ca_select = strtoul(optarg, NULL, 0); + break; + case 'F': //filter timeout + flags.filter_timeout = 1; + break; + case 'H': //expert help + ext_help(); + return 0; + break; + case 'I': //expert providing initial_tuning_data + initdata=strdup(optarg); + break; + case 'L': //vlc output + output_format = OUTPUT_VLC_M3U; + break; + case 'M': //mplayer output + output_format = OUTPUT_MPLAYER; + break; + case 'O': //other services + Other_Services = strtoul(optarg, NULL, 0); + if ((Other_Services < 0)) bad_usage(argv[0]); + if ((Other_Services > 1)) bad_usage(argv[0]); + break; + case 'P': //ATSC PSIP scan + no_ATSC_PSIP = 1; + break; + case 'Q': //specify DVB-C QAM + modulation_min=modulation_max=strtoul(optarg, NULL, 0); + modulation_flags |= MOD_OVERRIDE_MIN; + modulation_flags |= MOD_OVERRIDE_MAX; + break; + case 'R': //include Radio + Radio_Services = strtoul(optarg, NULL, 0); + if ((Radio_Services < 0)) bad_usage(argv[0]); + if ((Radio_Services > 1)) bad_usage(argv[0]); + break; + case 'S': //DVB-C symbolrate index + dvbc_symbolrate_min=dvbc_symbolrate_max=strtoul(optarg, NULL, 0); + break; + case 'T': //include TV + TV_Services = strtoul(optarg, NULL, 0); + if ((TV_Services < 0)) bad_usage(argv[0]); + if ((TV_Services > 1)) bad_usage(argv[0]); + break; + case 'V': //Version + retVersion++; + break; + case 'X': //xine output + output_format = OUTPUT_XINE; + break; + default: //undefined + bad_usage(argv[0]); + return -1; + } + } + info("w_scan version %d (compiled for DVB API %d.%d)\n", version, DVB_API_VERSION, DVB_API_VERSION_MINOR); + if ((flags.vdr_version < 7) && (frontend_type == FE_ATSC)) + fatal("VDR up to version 1.7.13 doesn't support ATSC.\n" + "\tPlease add option '-o 7' enabling vdr-1.7 support or" + "\tchoose other output format, current: 'VDR channels.conf'.\n"); + if (NULL == initdata) { + if ((NULL == country) && (frontend_type != FE_QPSK)) + fatal("Missing argument \"-c\" (country setting)\n"); + if ((NULL == satellite) && (frontend_type == FE_QPSK)) + fatal("Missing argument \"-s\" (satellite setting)\n"); + } + serv_select = 1 * TV_Services + 2 * Radio_Services + 4 * Other_Services; + if (caps_inversion > INVERSION_AUTO) { + info("Inversion out of range!\n"); + bad_usage(argv[0]); + return -1; + } + if (((adapter > 7) && (adapter != 999)) || (adapter < 0)) { + info("Invalid adapter: out of range (0..7)\n"); + bad_usage(argv[0]); + return -1; + } + switch(frontend_type) { + case FE_ATSC: + case FE_QAM: + case FE_OFDM: + if (country != NULL) { + int atsc = ATSC_type; + int dvb = frontend_type; + flags.atsc_type = ATSC_type; + choose_country(country, &atsc, &dvb, &frontend_type, &this_channellist); + //dvbc: setting qam loop + if ((modulation_flags & MOD_OVERRIDE_MAX) == MOD_USE_STANDARD) + modulation_max = dvbc_qam_max(2, this_channellist); + if ((modulation_flags & MOD_OVERRIDE_MIN) == MOD_USE_STANDARD) + modulation_min = dvbc_qam_min(2, this_channellist); + flags.list_id = txt_to_country(country); + free(country); + } + break; + case FE_QPSK: + if (satellite != NULL) { + choose_satellite(satellite, &this_channellist); + flags.list_id = txt_to_satellite(satellite); + free(satellite); + sat_list[this_channellist].rotor_position = flags.rotor_position; + } + else if (flags.rotor_position > -1) + fatal("Using rotor position needs option \"-s\"\n"); + if (positionfile != NULL) { + valid_rotor_data = dvbscan_parse_rotor_positions(positionfile); + free(positionfile); + if (! valid_rotor_data) + fatal("could not parse rotor position file\n" + "CHECK IDENTIFIERS AND FILE FORMAT.\n"); + } + break; + default: + fatal("Unknown frontend type %d\n", frontend_type); + } + + if (initdata != NULL) { + valid_initial_data = dvbscan_parse_tuningdata(initdata, &flags); + free(initdata); + if (valid_initial_data == 0) + fatal("Could not read initial tuning data. EXITING.\n"); + if (flags.fe_type != frontend_type) { + warning("\n" + "========================================================================\n" + "INITIAL TUNING DATA NEEDS FRONTEND TYPE %s, YOU SELECTED TYPE %s.\n" + "I WILL OVERRIDE YOUR DEFAULTS TO %s\n" + "========================================================================\n", + frontend_type_to_text(flags.fe_type), + frontend_type_to_text(frontend_type), + frontend_type_to_text(flags.fe_type)); + frontend_type = flags.fe_type; + sleep(10); // enshure that user reads warning. + } + } + info("frontend_type %s, channellist %d\n", frontend_type_to_text(frontend_type), this_channellist); + + for (i = 0; i < MAX_RUNNING; i++) + poll_fds[i].fd = -1; + + fe_open_mode = O_RDWR; + if (adapter == 999) + fatal("***** NO USEABLE DVB CARD FOUND. *****\n" + "Please check wether dvb driver is loaded and\n" + "verify that no dvb application (i.e. vdr) is running.\n"); + + + return 0; +} + diff --git a/p2pvr/scanner/icescan.cpp b/p2pvr/scanner/icescan.cpp new file mode 100644 index 0000000..e69de29 diff --git a/p2pvr/scanner/langidents.c b/p2pvr/scanner/langidents.c new file mode 100644 index 0000000..0165f67 --- /dev/null +++ b/p2pvr/scanner/langidents.c @@ -0,0 +1,211 @@ +#include "tv_grab_dvb.h" +const struct lookup_table languageid_table[] = { + {{.c="aar"}, "aa"}, + {{.c="abk"}, "ab"}, + {{.c="afr"}, "af"}, + {{.c="aka"}, "ak"}, + {{.c="amh"}, "am"}, + {{.c="ara"}, "ar"}, + {{.c="arg"}, "an"}, + {{.c="asm"}, "as"}, + {{.c="ava"}, "av"}, + {{.c="ave"}, "ae"}, + {{.c="aym"}, "ay"}, + {{.c="aze"}, "az"}, + {{.c="bak"}, "ba"}, + {{.c="bam"}, "bm"}, + {{.c="bel"}, "be"}, + {{.c="ben"}, "bn"}, + {{.c="bih"}, "bh"}, + {{.c="bis"}, "bi"}, + {{.c="bod"}, "bo"}, + {{.c="tib"}, "bo"}, + {{.c="bos"}, "bs"}, + {{.c="bre"}, "br"}, + {{.c="bul"}, "bg"}, + {{.c="cat"}, "ca"}, + {{.c="ces"}, "cs"}, + {{.c="cze"}, "cs"}, + {{.c="cha"}, "ch"}, + {{.c="che"}, "ce"}, + {{.c="chu"}, "cu"}, + {{.c="chv"}, "cv"}, + {{.c="cor"}, "kw"}, + {{.c="cos"}, "co"}, + {{.c="cre"}, "cr"}, + {{.c="cym"}, "cy"}, + {{.c="wel"}, "cy"}, + {{.c="dan"}, "da"}, + {{.c="deu"}, "de"}, + {{.c="ger"}, "de"}, + {{.c="div"}, "dv"}, + {{.c="dzo"}, "dz"}, + {{.c="ell"}, "el"}, + {{.c="gre"}, "el"}, + {{.c="eng"}, "en"}, + {{.c="epo"}, "eo"}, + {{.c="est"}, "et"}, + {{.c="eus"}, "eu"}, + {{.c="baq"}, "eu"}, + {{.c="ewe"}, "ee"}, + {{.c="fao"}, "fo"}, + {{.c="fas"}, "fa"}, + {{.c="per"}, "fa"}, + {{.c="fij"}, "fj"}, + {{.c="fin"}, "fi"}, + {{.c="fra"}, "fr"}, + {{.c="fre"}, "fr"}, + {{.c="fry"}, "fy"}, + {{.c="ful"}, "ff"}, + {{.c="gla"}, "gd"}, + {{.c="gle"}, "ga"}, + {{.c="glg"}, "gl"}, + {{.c="glv"}, "gv"}, + {{.c="grn"}, "gn"}, + {{.c="guj"}, "gu"}, + {{.c="hat"}, "ht"}, + {{.c="hau"}, "ha"}, + {{.c="heb"}, "he"}, + {{.c="her"}, "hz"}, + {{.c="hin"}, "hi"}, + {{.c="hmo"}, "ho"}, + {{.c="hrv"}, "hr"}, + {{.c="scr"}, "hr"}, + {{.c="hun"}, "hu"}, + {{.c="hye"}, "hy"}, + {{.c="arm"}, "hy"}, + {{.c="ibo"}, "ig"}, + {{.c="ido"}, "io"}, + {{.c="iii"}, "ii"}, + {{.c="iku"}, "iu"}, + {{.c="ile"}, "ie"}, + {{.c="ina"}, "ia"}, + {{.c="ind"}, "id"}, + {{.c="ipk"}, "ik"}, + {{.c="isl"}, "is"}, + {{.c="ice"}, "is"}, + {{.c="ita"}, "it"}, + {{.c="jav"}, "jv"}, + {{.c="jpn"}, "ja"}, + {{.c="kal"}, "kl"}, + {{.c="kan"}, "kn"}, + {{.c="kas"}, "ks"}, + {{.c="kat"}, "ka"}, + {{.c="geo"}, "ka"}, + {{.c="kau"}, "kr"}, + {{.c="kaz"}, "kk"}, + {{.c="khm"}, "km"}, + {{.c="kik"}, "ki"}, + {{.c="kin"}, "rw"}, + {{.c="kir"}, "ky"}, + {{.c="kom"}, "kv"}, + {{.c="kon"}, "kg"}, + {{.c="kor"}, "ko"}, + {{.c="kua"}, "kj"}, + {{.c="kur"}, "ku"}, + {{.c="lao"}, "lo"}, + {{.c="lat"}, "la"}, + {{.c="lav"}, "lv"}, + {{.c="lim"}, "li"}, + {{.c="lin"}, "ln"}, + {{.c="lit"}, "lt"}, + {{.c="ltz"}, "lb"}, + {{.c="lub"}, "lu"}, + {{.c="lug"}, "lg"}, + {{.c="mah"}, "mh"}, + {{.c="mal"}, "ml"}, + {{.c="mar"}, "mr"}, + {{.c="mkd"}, "mk"}, + {{.c="mac"}, "mk"}, + {{.c="mlg"}, "mg"}, + {{.c="mlt"}, "mt"}, + {{.c="mol"}, "mo"}, + {{.c="mon"}, "mn"}, + {{.c="mri"}, "mi"}, + {{.c="mao"}, "mi"}, + {{.c="msa"}, "ms"}, + {{.c="may"}, "ms"}, + {{.c="mya"}, "my"}, + {{.c="bur"}, "my"}, + {{.c="nau"}, "na"}, + {{.c="nav"}, "nv"}, + {{.c="nbl"}, "nr"}, + {{.c="nde"}, "nd"}, + {{.c="ndo"}, "ng"}, + {{.c="nep"}, "ne"}, + {{.c="nld"}, "nl"}, + {{.c="dut"}, "nl"}, + {{.c="nno"}, "nn"}, + {{.c="nob"}, "nb"}, + {{.c="nor"}, "no"}, + {{.c="nya"}, "ny"}, + {{.c="oci"}, "oc"}, + {{.c="oji"}, "oj"}, + {{.c="ori"}, "or"}, + {{.c="orm"}, "om"}, + {{.c="oss"}, "os"}, + {{.c="pan"}, "pa"}, + {{.c="pli"}, "pi"}, + {{.c="pol"}, "pl"}, + {{.c="por"}, "pt"}, + {{.c="pus"}, "ps"}, + {{.c="que"}, "qu"}, + {{.c="roh"}, "rm"}, + {{.c="ron"}, "ro"}, + {{.c="rum"}, "ro"}, + {{.c="run"}, "rn"}, + {{.c="rus"}, "ru"}, + {{.c="sag"}, "sg"}, + {{.c="san"}, "sa"}, + {{.c="sin"}, "si"}, + {{.c="slk"}, "sk"}, + {{.c="slo"}, "sk"}, + {{.c="slv"}, "sl"}, + {{.c="sme"}, "se"}, + {{.c="smo"}, "sm"}, + {{.c="sna"}, "sn"}, + {{.c="snd"}, "sd"}, + {{.c="som"}, "so"}, + {{.c="sot"}, "st"}, + {{.c="spa"}, "es"}, + {{.c="sqi"}, "sq"}, + {{.c="alb"}, "sq"}, + {{.c="srd"}, "sc"}, + {{.c="srp"}, "sr"}, + {{.c="scc"}, "sr"}, + {{.c="ssw"}, "ss"}, + {{.c="sun"}, "su"}, + {{.c="swa"}, "sw"}, + {{.c="swe"}, "sv"}, + {{.c="tah"}, "ty"}, + {{.c="tam"}, "ta"}, + {{.c="tat"}, "tt"}, + {{.c="tel"}, "te"}, + {{.c="tgk"}, "tg"}, + {{.c="tgl"}, "tl"}, + {{.c="tha"}, "th"}, + {{.c="tir"}, "ti"}, + {{.c="ton"}, "to"}, + {{.c="tsn"}, "tn"}, + {{.c="tso"}, "ts"}, + {{.c="tuk"}, "tk"}, + {{.c="tur"}, "tr"}, + {{.c="twi"}, "tw"}, + {{.c="uig"}, "ug"}, + {{.c="ukr"}, "uk"}, + {{.c="urd"}, "ur"}, + {{.c="uzb"}, "uz"}, + {{.c="ven"}, "ve"}, + {{.c="vie"}, "vi"}, + {{.c="vol"}, "vo"}, + {{.c="wln"}, "wa"}, + {{.c="wol"}, "wo"}, + {{.c="xho"}, "xh"}, + {{.c="yid"}, "yi"}, + {{.c="yor"}, "yo"}, + {{.c="zha"}, "za"}, + {{.c="zho"}, "zh"}, + {{.c="chi"}, "zh"}, + {{.c="zul"}, "zu"}, + {{-1}, NULL}, +}; diff --git a/p2pvr/scanner/lookup.cpp b/p2pvr/scanner/lookup.cpp new file mode 100644 index 0000000..6d2a0b6 --- /dev/null +++ b/p2pvr/scanner/lookup.cpp @@ -0,0 +1,52 @@ +#include +#include + +#include "tv_grab_dvb.h" + +const char *lookup(const struct lookup_table *l, int id) { +// printf("Looked up %x", id); + while ((l->u.i != id) && (l->u.i != -1)) + l++; + return l->desc; +} + +/* Read lookup_table from file into newly allocated table. + * The table is a single allocation consisting of two parts: + * first the array of structs, followed by a char-array of strings. */ +int load_lookup(struct lookup_table **l, const char *file) { + int name; + char value[256]; + int n = 1, size = sizeof(struct lookup_table); + + if (file == NULL) + return -1; + + FILE *fd = fopen(file, "r"); + if (!fd) + return -1; + + // 1st: determine size needed + while (fscanf(fd, "%d %255s", &name, value) == 2) { + n++; + size += sizeof(struct lookup_table); + size += strlen(value) + 1; + } + struct lookup_table *p = *l = static_cast(malloc(size)); + if (p == NULL) + return -1; + + // 2nd: read data + rewind(fd); + char *c = (char *)(p + n); + while (fscanf(fd, "%d %255s", &p->u.i, c) == 2) { + p->desc = c; + c += strlen(c) + 1; + p++; + } + p->u.i = -1; + p->desc = NULL; + + fclose(fd); + return 0; +} + diff --git a/p2pvr/scanner/p2scan.cpp b/p2pvr/scanner/p2scan.cpp new file mode 100644 index 0000000..cb3e0fc --- /dev/null +++ b/p2pvr/scanner/p2scan.cpp @@ -0,0 +1,761 @@ +/* + * tv_grab_dvb - dump dvb epg info in xmltv + * Version 0.2 - 20/04/2004 - First Public Release + * + * Copyright (C) 2004 Mark Bryars + * + * DVB code Mercilessly ripped off from dvddate + * dvbdate Copyright (C) Laurence Culhane 2002 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +const char *id = "@(#) $Id: tv_grab_dvb.c 86 2010-10-29 20:27:31Z pmhahn $"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "si_tables.h" +#include "tv_grab_dvb.h" + +#include "variables.h" +#include "rowProcessor.h" + +struct EitProgram { + VariableType serviceID; + VariableType eventID; + VariableType title; + VariableType titleLang; + VariableType subtitle; + VariableType subtitleLang; + VariableType descLang; + VariableType desc1; + VariableType desc2; + VariableType desc3; + VariableType videoAspect; + VariableType audioChannels; + VariableType language; + VariableType teletextSubtitleLang; + VariableType category; + VariableType dvbRating; + VariableType contentIdentType; + VariableType contentIdent; + VariableType startTime; + VariableType stopTime; +}; + +Glib::ustring title("title"); +#include "xmlObjectLoader.h" +#include "rowSet.h" +template +const M & +getMember(M C::*t, C * p) { + return p->*t; +} +SimpleMessageException(NoSuchAttribute); +class EitRows : public RowSet { + public: + EitRows(const xmlpp::Element * p); + ~EitRows(); + void execute(const RowProcessor *) const; + void loadComplete(const CommonObjects *) { + } + void setFilter(const Glib::ustring &) { + } + unsigned int columnCount() const { + return 1; + } + const Glib::ustring & getColumnName(unsigned int) const { + return title; + } + VariableType getCurrentValue(const Glib::ustring &) const { + return current->title; + } + VariableType getCurrentValue(unsigned int) const { + return current->title; + } + bool isNull(unsigned int ) const { + return false; + } + bool isNull(const Glib::ustring & ) const { + return false; + } +#define returnAttr(name) if (attrName == #name) return boost::bind(getMember, &EitProgram::name, boost::ref(current)) + RowAttribute resolveAttr(const Glib::ustring & attrName) const { + returnAttr(serviceID); + returnAttr(eventID); + returnAttr(title); + returnAttr(titleLang); + returnAttr(subtitle); + returnAttr(subtitleLang); + returnAttr(descLang); + returnAttr(desc1); + returnAttr(desc2); + returnAttr(desc3); + returnAttr(videoAspect); + returnAttr(audioChannels); + returnAttr(language); + returnAttr(teletextSubtitleLang); + returnAttr(category); + returnAttr(dvbRating); + returnAttr(contentIdentType); + returnAttr(contentIdent); + returnAttr(startTime); + returnAttr(stopTime); + throw NoSuchAttribute(attrName); + } + private: + enum ER { TITLE, SUB_TITLE }; + enum CR { LANGUAGE, VIDEO, AUDIO, SUBTITLES }; + Variable demux; + Variable timeout; + void openInput() const; + void readEventTables(const RowProcessor *) const; + bool parseEIT(const u_char *data, size_t len, const RowProcessor *) const; + void parseEventDescription(const u_char *data, enum ER round) const; + void parseLongEventDescription(const u_char *data) const; + void parseComponentDescription(const u_char *data, enum CR round, int *seen) const; + void parseContentDescription(const u_char *data) const; + void parseRatingDescription(const u_char *data) const; + void parseContentIdentifierDescription(const u_char *data) const; + void parseDescription(const u_char * data, size_t len) const; + + Glib::ustring convert(const char * txt) const; + + mutable int fd_epg; + mutable EitProgram * current; + + static const std::string EitEncoding; + static const std::string UTF8; +}; + +DECLARE_LOADER("eitrows", EitRows); + +const std::string EitRows::EitEncoding("ISO6937"); +const std::string EitRows::UTF8("UTF8"); + +EitRows::EitRows(const xmlpp::Element * p) : + RowSet(p), + demux(p, "demux", false, "/dev/dvb/adapter0/demux0"), + timeout(p, "timeout", false, 10000), + fd_epg(0), + current(NULL) +{ +} + +EitRows::~EitRows() +{ + if (fd_epg) { + close(fd_epg); + } +} + +static int time_offset = 0; +static int chan_filter = 0; +static int chan_filter_mask = 0; +static bool ignore_bad_dates = true; +static bool ignore_updates = true; +static bool silent = false; + +typedef struct chninfo { + struct chninfo *next; + int sid; + int eid; + int ver; +} chninfo_t; + +static struct chninfo *channels; + +/* Parse command line arguments. {{{ */ +int do_options(int arg_count, char **arg_strings) { + static const struct option Long_Options[] = { + {"help", 0, 0, 'h'}, + {"chanidents", 1, 0, 'c'}, + {0, 0, 0, 0} + }; + int Option_Index = 0; + + while (1) { + int c = getopt_long(arg_count, arg_strings, "udscmpnht:o:f:i:e:", Long_Options, &Option_Index); + if (c == EOF) + break; + switch (c) { + case 'u': + ignore_updates = false; + break; + case 'd': + ignore_bad_dates = false; + break; + case 'n': + chan_filter = 0x4e; + chan_filter_mask = 0xfe; + break; + case 'm': + chan_filter = 0x4e; + chan_filter_mask = 0xff; + break; + case 'p': + chan_filter = 0x4f; + chan_filter_mask = 0xff; + break; + case 's': + silent = true; + break; + case 'h': + case '?': + break; + case 0: + default: + _exit(1); + } + } + return 0; +} /*}}}*/ + + +/* Parse language-id translation file. {{{ */ +static const char *xmllang(const u_char *l) { + static union lookup_key lang; + lang.c[0] = (char)l[0]; + lang.c[1] = (char)l[1]; + lang.c[2] = (char)l[2]; + lang.c[3] = '\0'; + + const char *c = lookup(languageid_table, lang.i); + return c ? c : lang.c; +} /*}}}*/ + +Glib::ustring +EitRows::convert(const char * txt) const +{ + char enc[20]; + switch ((unsigned char)*txt) { + case 0x20 ... 0xFF: + return Glib::convert(txt, UTF8, EitEncoding); + case 0x01 ... 0x05: + snprintf(enc, sizeof(enc), "ISO-8859-%d\n", txt[0] + 4); + return Glib::convert(txt + 1, UTF8, "ISO-8859-5"); + case 0x10: + snprintf(enc, sizeof(enc), "ISO-8859-%02x%02x\n", txt[1], txt[2]); + return Glib::convert(txt + 3, UTF8, enc); + case 0x11: + return Glib::convert(txt, UTF8, "ISO-10646"); + case 0x06 ... 0x0F: + case 0x12 ... 0x1F: + // Values for the first byte of "0x00", "0x06" to "0x0F", and "0x12" to "0x1F" are reserved for future use. + //fprintf(stderr, "Reserved encoding: %02x\n", txt[0]); + //fprintf(stderr, "%s\n", txt); + case 0x00: // empty string + return ""; + } +} + +/* Parse 0x4D Short Event Descriptor. {{{ */ +void +EitRows::parseEventDescription(const u_char *data, enum ER round) const { + assert(GetDescriptorTag(data) == 0x4D); + const struct descr_short_event *evtdesc = reinterpret_cast(data); + char evt[256]; + char dsc[256]; + + size_t evtlen = evtdesc->event_name_length; + if (round == TITLE) { + if (!evtlen) + return; + assert(evtlen < sizeof(evt)); + memcpy(evt, &evtdesc->data, evtlen); + evt[evtlen] = '\0'; + current->titleLang = xmllang(&evtdesc->lang_code1); + current->title = convert(evt); + return; + } + + if (round == SUB_TITLE) { + size_t dsclen = evtdesc->data[evtlen]; + assert(dsclen < sizeof(dsc)); + memcpy(dsc, &evtdesc->data[evtlen+1], dsclen); + dsc[dsclen] = '\0'; + + if (*dsc) { + current->subtitleLang = xmllang(&evtdesc->lang_code1); + current->subtitle = convert(dsc); + } + } +} /*}}}*/ + +/* Parse 0x4E Extended Event Descriptor. {{{ */ +void +EitRows::parseLongEventDescription(const u_char *data) const { + assert(GetDescriptorTag(data) == 0x4E); + const struct descr_extended_event *levt = reinterpret_cast(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) { + current->descLang = levt->lang_code1; + + const u_char *p = reinterpret_cast(&levt->data); + const void *data_end = data + DESCR_GEN_LEN + GetDescriptorLength(data); + while (p < levt->data + levt->length_of_items) { + const struct item_extended_event *name = reinterpret_cast(p); + size_t name_len = name->item_description_length; + assert(p + ITEM_EXTENDED_EVENT_LEN + name_len < data_end); + assert(name_len < sizeof(dsc)); + memcpy(dsc, &name->data, name_len); + dsc[name_len] = '\0'; + current->desc1 = convert(dsc); + + p += ITEM_EXTENDED_EVENT_LEN + name_len; + + const struct item_extended_event *value = reinterpret_cast(p); + size_t value_len = value->item_description_length; + assert(p + ITEM_EXTENDED_EVENT_LEN + value_len < data_end); + assert(value_len < sizeof(dsc)); + memcpy(dsc, &value->data, value_len); + dsc[value_len] = '\0'; + current->desc2 = convert(dsc); + + p += ITEM_EXTENDED_EVENT_LEN + value_len; + } + const struct item_extended_event *text = reinterpret_cast(p); + size_t len = text->item_description_length; + if (non_empty && len) { + assert(len < sizeof(dsc)); + memcpy(dsc, &text->data, len); + dsc[len] = '\0'; + current->desc3 = convert(dsc); + } + + } +} /*}}}*/ + +/* 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) */ +void +EitRows::parseComponentDescription(const u_char *data, enum CR round, int *seen) const { + assert(GetDescriptorTag(data) == 0x50); + const struct descr_component *dc = reinterpret_cast(data); + char buf[256]; + + size_t len = dc->descriptor_length; + assert(len < sizeof(buf)); + memcpy(buf, &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 + current->videoAspect = lookup(aspect_table, (dc->component_type-1) & 0x03); + (*seen)++; + } + break; + case 0x02: // Audio Info + if (round == AUDIO && !*seen) { + current->audioChannels = lookup(audio_table, (dc->component_type)); + (*seen)++; + } + if (round == LANGUAGE) { + if (!*seen) + current->language = 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 + current->teletextSubtitleLang = xmllang(&dc->lang_code1); + } + break; + // case 0x04: // AC3 info + } +} /*}}}*/ + +static inline void set_bit(int *bf, int b) { + int i = b / 8 / sizeof(int); + int s = b % (8 * sizeof(int)); + bf[i] |= (1 << s); +} + +static inline bool get_bit(int *bf, int b) { + int i = b / 8 / sizeof(int); + int s = b % (8 * sizeof(int)); + return bf[i] & (1 << s); +} + +/* Parse 0x54 Content Descriptor. {{{ */ +void +EitRows::parseContentDescription(const u_char *data) const { + assert(GetDescriptorTag(data) == 0x54); + const struct descr_content *dc = reinterpret_cast(data); + int once[256/8/sizeof(int)] = {0,}; + for (const u_char * p = reinterpret_cast(&dc->data); p < data + dc->descriptor_length; p += NIBBLE_CONTENT_LEN) { + const struct nibble_content *nc = reinterpret_cast(p); + int c1 = (nc->content_nibble_level_1 << 4) + nc->content_nibble_level_2; + if (c1 > 0 && !get_bit(once, c1)) { + set_bit(once, c1); + const char *c = lookup(description_table, c1); + if (c) + if (c[0]) + current->category = c; + } + // This is weird in the uk, they use user but not content, and almost the same values + } +} /*}}}*/ + +/* Parse 0x55 Rating Descriptor. {{{ */ +void +EitRows::parseRatingDescription(const u_char *data) const { + assert(GetDescriptorTag(data) == 0x55); + const struct descr_parental_rating *pr = reinterpret_cast(data); + for (const u_char * p = reinterpret_cast(&pr->data); p < data + pr->descriptor_length; p += PARENTAL_RATING_ITEM_LEN) { + const struct parental_rating_item *pr = reinterpret_cast(p); + switch (pr->rating) { + case 0x00: /*undefined*/ + break; + case 0x01 ... 0x0F: + current->dvbRating = pr->rating + 3; + break; + case 0x10 ... 0xFF: /*broadcaster defined*/ + break; + } + } +} /*}}}*/ + +/* Parse 0x5F Private Data Specifier. {{{ */ +int parsePrivateDataSpecifier(const u_char *data) { + assert(GetDescriptorTag(data) == 0x5F); + return GetPrivateDataSpecifier(data); +} /*}}}*/ + +/* Parse 0x76 Content Identifier Descriptor. {{{ */ +/* See ETSI TS 102 323, section 12 */ +void +EitRows::parseContentIdentifierDescription(const u_char *data) const { + assert(GetDescriptorTag(data) == 0x76); + const struct descr_content_identifier *ci = reinterpret_cast(data); + for (const u_char * p = reinterpret_cast(&ci->data); p < data + ci->descriptor_length; /* at end */) { + const struct descr_content_identifier_crid *crid = reinterpret_cast(p); + struct descr_content_identifier_crid_local *crid_data; + + int crid_length = 3; + + char type_buf[32]; + const 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 0x01: /* Carried in Content Identifier Table (CIT) */ + break; + default: + break; + case 0x00: /* Carried explicitly within descriptor */ + crid_data = (descr_content_identifier_crid_local_t *)&crid->crid_ref_data; + size_t cridlen = crid_data->crid_length; + assert(cridlen < sizeof(buf)); + memcpy(buf, &crid_data->crid_byte, cridlen); + buf[cridlen] = '\0'; + + current->contentIdentType = type; + current->contentIdent = buf; + crid_length = 2 + crid_data->crid_length; + 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' +*/ +void +EitRows::parseDescription(const u_char * data, size_t len) const { + int round, pds = 0; + + for (round = 0; round < 8; round++) { + int seen = 0; // no title/language/video/audio/subtitles seen in this round + for (const u_char * p = data; p < data + len; p += DESCR_GEN_LEN + GetDescriptorLength(p)) { + const struct descr_gen *desc = reinterpret_cast(p); + switch (GetDescriptorTag(desc)) { + case 0: + break; + case 0x4D: //short evt desc, [title] [sub-title] + // there can be multiple language versions of these + if (round == 0) { + parseEventDescription(p, TITLE); + } + else if (round == 1) + parseEventDescription(p, SUB_TITLE); + break; + case 0x4E: //long evt descriptor [desc] + if (round == 2) + parseLongEventDescription(p); + break; + case 0x50: //component desc [language] [video] [audio] [subtitles] + if (round == 4) + parseComponentDescription(p, LANGUAGE, &seen); + else if (round == 5) + parseComponentDescription(p, VIDEO, &seen); + else if (round == 6) + parseComponentDescription(p, AUDIO, &seen); + else if (round == 7) + parseComponentDescription(p, SUBTITLES, &seen); + break; + case 0x53: // CA Identifier Descriptor + break; + case 0x54: // content desc [category] + if (round == 3) + parseContentDescription(p); + break; + case 0x55: // Parental Rating Descriptor [rating] + if (round == 7) + parseRatingDescription(p); + break; + case 0x5f: // Private Data Specifier + pds = parsePrivateDataSpecifier(p); + 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: + 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 + break; + case 0x76: // Content identifier descriptor + if (round == 5) + parseContentIdentifierDescription(p); + break; + default: + break; + } + } + } +} /*}}}*/ + +/* Check that program has at least a title as is required by xmltv.dtd. {{{ */ +static bool validateDescription(const u_char *data, size_t len) { + for (const u_char * p = data; p < data + len; p += DESCR_GEN_LEN + GetDescriptorLength(p)) { + const struct descr_gen *desc = reinterpret_cast(p); + if (GetDescriptorTag(desc) == 0x4D) { + const struct descr_short_event *evtdesc = reinterpret_cast(p); + // make sure that title isn't empty + if (evtdesc->event_name_length) return true; + } + } + return false; +} /*}}}*/ + +/* Use the routine specified in ETSI EN 300 468 V1.4.1, {{{ + * "Specification for Service Information in Digital Video Broadcasting" + * to convert from Modified Julian Date to Year, Month, Day. */ +static boost::posix_time::ptime parseMJD(long int mjd) { + int year = (int) ((mjd - 15078.2) / 365.25); + int month = (int) ((mjd - 14956.1 - (int) (year * 365.25)) / 30.6001); + int day = mjd - 14956 - (int) (year * 365.25) - (int) (month * 30.6001); + int i = (month == 14 || month == 15) ? 1 : 0; + year += i ; + month = month - 1 - i * 12; + + return boost::posix_time::ptime(boost::gregorian::date(1900 + year, month, day)); +} /*}}}*/ + +bool +EitRows::parseEIT(const u_char *data, size_t len, const RowProcessor * rp) const { + const struct eit *e = reinterpret_cast(data); + + len -= 4; //remove CRC + + // For each event listing + bool found = false; + for (const u_char *p = reinterpret_cast(&e->data); p < data + len; p += EIT_EVENT_LEN + GetEITDescriptorsLoopLength(p)) { + const struct eit_event *evt = reinterpret_cast(p); + struct chninfo *c; + // find existing information? + for (c = channels; c != NULL; c = c->next) { + // found it + if (c->sid == HILO(e->service_id) && (c->eid == HILO(evt->event_id))) { + if (c->ver <= e->version_number) // seen it before or its older FIXME: wrap-around to 0 + return false; + else { + c->ver = e->version_number; // update outputted version + if (ignore_updates) { + return false; + } + break; + } + } + } + + // its a new program + if (c == NULL) { + chninfo_t *nc = static_cast(malloc(sizeof(struct chninfo))); + nc->sid = HILO(e->service_id); + nc->eid = HILO(evt->event_id); + nc->ver = e->version_number; + nc->next = channels; + channels = nc; + } + + // No program info at end! Just skip it + if (GetEITDescriptorsLoopLength(evt) == 0) + return false; + + boost::posix_time::ptime startTime = parseMJD(HILO(evt->mjd)) + boost::posix_time::time_duration( + BcdCharToInt(evt->start_time_h) + time_offset, + BcdCharToInt(evt->start_time_m), + BcdCharToInt(evt->start_time_s)); + EitProgram results; + current = &results; + results.startTime = startTime; + results.stopTime = startTime + boost::posix_time::time_duration( + BcdCharToInt(evt->duration_h), + BcdCharToInt(evt->duration_m), + BcdCharToInt(evt->duration_s)); + + // a program must have a title that isn't empty + if (!validateDescription(reinterpret_cast(&evt->data), GetEITDescriptorsLoopLength(evt))) { + return false; + } + + + results.serviceID = HILO(e->service_id); + results.eventID = HILO(evt->event_id); + + //1 Airing, 2 Starts in a few seconds, 3 Pausing, 4 About to air + + parseDescription(reinterpret_cast(&evt->data), GetEITDescriptorsLoopLength(evt)); + rowNum += 1; + rp->rowReady(); + found = true; + } + return found; +} + +SimpleMessageException(ErrorReadingData); +void +EitRows::readEventTables(const RowProcessor * rp) const +{ + u_char buf[1<<12]; + struct pollfd ufd; + memset(&ufd, 0, sizeof(pollfd)); + ufd.fd = fd_epg; + ufd.events = POLLIN; + size_t n; + time_t lastuseful = 0; + while ((poll(&ufd, 1, (int64_t)timeout()) == 1) && (n = read(fd_epg, buf, sizeof(buf)))) { + if (n < sizeof(struct si_tab)) + throw ErrorReadingData("Smaller that si_tab"); + struct si_tab *tab = (struct si_tab *)buf; + size_t l = sizeof(struct si_tab) + GetSectionLength(tab); + if (n < l) + throw ErrorReadingData("Smaller that section length"); + if (_dvb_crc32(buf, l) == 0) { + if (parseEIT(buf, l, rp)) { + time(&lastuseful); + } + else { + if (lastuseful < time(NULL) - 5) { + break; + } + } + } + } +} + +SimpleMessageException(DemuxOpenFailure); +SimpleMessageException(DemuxSetFilterFailure); + +void +EitRows::openInput() const +{ + if ((fd_epg = open(demux(), O_RDWR)) < 0) { + throw DemuxOpenFailure(strerror(errno)); + } + + struct dmx_sct_filter_params sctFilterParams; + memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params)); + sctFilterParams.pid = 18; // EIT data + sctFilterParams.timeout = 0; + sctFilterParams.flags = DMX_IMMEDIATE_START; + sctFilterParams.filter.filter[0] = chan_filter; // 4e is now/next this multiplex, 4f others + sctFilterParams.filter.mask[0] = chan_filter_mask; + + if (ioctl(fd_epg, DMX_SET_FILTER, &sctFilterParams) < 0) { + throw DemuxSetFilterFailure(strerror(errno)); + } +} + +void +EitRows::execute(const RowProcessor * rp) const +{ + openInput(); + readEventTables(rp); + if (rowNum < 10) { + } + close(fd_epg); + fd_epg = 0; +} + diff --git a/p2pvr/scanner/scanner.ice b/p2pvr/scanner/scanner.ice new file mode 100644 index 0000000..7730a1c --- /dev/null +++ b/p2pvr/scanner/scanner.ice @@ -0,0 +1,7 @@ +module P2TV { + interface Scanner { + void updatePrograms(bool zap, int adapter, int frontend); + void updateNowAndNext(bool zap, int adapter, int frontend); + }; +}; + diff --git a/p2pvr/scanner/si_tables.h b/p2pvr/scanner/si_tables.h new file mode 100644 index 0000000..ce3b972 --- /dev/null +++ b/p2pvr/scanner/si_tables.h @@ -0,0 +1,1625 @@ +////////////////////////////////////////////////////////////// +/// /// +/// si_tables.h: definitions for data structures of the /// +/// incoming SI data stream /// +/// /// +////////////////////////////////////////////////////////////// + +// $Revision: 84 $ +// $Date: 2010-03-05 17:46:16 +0000 (Fri, 05 Mar 2010) $ +// $Author: cpaton $ +// +// (C) 2001-03 Rolf Hakenes , under the +// GNU GPL with contribution of Oleg Assovski, +// www.satmania.com +// +// libsi is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// libsi is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You may have received a copy of the GNU General Public License +// along with libsi; see the file COPYING. If not, write to the +// Free Software Foundation, Inc., 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +#define HILO(x) (x##_hi << 8 | x##_lo) +#define HILO2(x) (x##1 << 8 | x##2) +#define HILO3(x) (x##1 << 16 | x##2 << 8 | x##3) +#define HILO4(x) (x##4 << 24 | x##2 << 16 | x##3 << 8 | x##4) + +#define MjdToEpochTime(x) ((HILO(x)-40587)*86400) +#define BcdTimeToSeconds(x) ((3600 * ((10*((x##_h & 0xF0)>>4)) + (x##_h & 0xF))) + \ + (60 * ((10*((x##_m & 0xF0)>>4)) + (x##_m & 0xF))) + \ + ((10*((x##_s & 0xF0)>>4)) + (x##_s & 0xF))) +#define BcdTimeToMinutes(x) ((60 * ((10*((x##_h & 0xF0)>>4)) + (x##_h & 0xF))) + \ + (((10*((x##_m & 0xF0)>>4)) + (x##_m & 0xF)))) +#define BcdCharToInt(x) (10*((x & 0xF0)>>4) + (x & 0xF)) +#define CheckBcdChar(x) ((((x & 0xF0)>>4) <= 9) && \ + ((x & 0x0F) <= 9)) +#define CheckBcdSignedChar(x) ((((x & 0xF0)>>4) >= 0) && (((x & 0xF0)>>4) <= 9) && \ + ((x & 0x0F) >= 0) && ((x & 0x0F) <= 9)) + +#define GetTableId(x) (((si_tab_t *)(x))->table_id) +#define GetSectionLength(x) HILO(((si_tab_t *)(x))->section_length) +typedef struct si_tab { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; +} si_tab_t; + +/* + * + * ETSI ISO/IEC 13818-1 specifies SI which is referred to as PSI. The PSI + * data provides information to enable automatic configuration of the + * receiver to demultiplex and decode the various streams of programs + * within the multiplex. The PSI data is structured as four types of table. + * The tables are transmitted in sections. + * + * 1) Program Association Table (PAT): + * + * - for each service in the multiplex, the PAT indicates the location + * (the Packet Identifier (PID) values of the Transport Stream (TS) + * packets) of the corresponding Program Map Table (PMT). + * It also gives the location of the Network Information Table (NIT). + * + */ +#define TableHasMoreSections(x) (((pat_t *)(x))->last_section_number > ((pat_t *)(x))->section_number) +#define GetSectionNumber(x) ((pat_t *)(x))->section_number +#define GetLastSectionNumber(x) ((pat_t *)(x))->last_section_number +#define GetServiceId(x) HILO(((eit_t *)(x))->service_id) +#define GetLastTableId(x) ((eit_t *)(x))->segment_last_table_id +#define GetSegmentLastSectionNumber(x) ((eit_t *)(x))->segment_last_section_number +typedef struct pat { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number /*:8*/; + u_char last_section_number /*:8*/; +} pat_t; +#define PAT_LEN sizeof (pat_t) + +typedef struct pat_prog { + u_char program_number_hi /*:8*/; + u_char program_number_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char network_pid_hi :5; +#else + u_char network_pid_hi :5; + u_char :3; +#endif + u_char network_pid_lo /*:8*/; + /* or program_map_pid (if prog_num=0)*/ +} pat_prog_t; +#define PAT_PROG_LEN sizeof (pat_prog_t) + +/* + * + * 2) Conditional Access Table (CAT): + * + * - the CAT provides information on the CA systems used in the + * multiplex; the information is private and dependent on the CA + * system, but includes the location of the EMM stream, when + * applicable. + * + */ +typedef struct cat { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char :8; + u_char :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number /*:8*/; + u_char last_section_number /*:8*/; +} cat_t; +#define CAT_LEN sizeof (cat_t) + +/* + * + * 3) Program Map Table (PMT): + * + * - the PMT identifies and indicates the locations of the streams that + * make up each service, and the location of the Program Clock + * Reference fields for a service. + * + */ +typedef struct pmt { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char dummy :1; // has to be 0 + u_char :2; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :2; + u_char dummy :1; // has to be 0 + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char program_number_hi /*:8*/; + u_char program_number_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number /*:8*/; + u_char last_section_number /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char PCR_PID_hi :5; +#else + u_char PCR_PID_hi :5; + u_char :3; +#endif + u_char PCR_PID_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char program_info_length_hi :4; +#else + u_char program_info_length_hi :4; + u_char :4; +#endif + u_char program_info_length_lo /*:8*/; + //descriptors +} pmt_t; +#define PMT_LEN sizeof (pmt_t) + +typedef struct pmt_info { + u_char stream_type /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char elementary_PID_hi :5; +#else + u_char elementary_PID_hi :5; + u_char :3; +#endif + u_char elementary_PID_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char ES_info_length_hi :4; +#else + u_char ES_info_length_hi :4; + u_char :4; +#endif + u_char ES_info_length_lo /*:8*/; + // descriptors +} pmt_info_t; +#define PMT_INFO_LEN sizeof (pmt_info_t) + +/* + * + * 4) Network Information Table (NIT): + * + * - the NIT is intended to provide information about the physical + * network. The syntax and semantics of the NIT are defined in + * ETSI EN 300 468. + * + */ +typedef struct nit { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char network_id_hi /*:8*/; + u_char network_id_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number /*:8*/; + u_char last_section_number /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char network_descriptor_length_hi :4; +#else + u_char network_descriptor_length_hi :4; + u_char :4; +#endif + u_char network_descriptor_length_lo /*:8*/; + /* descriptors */ +} nit_t; +#define NIT_LEN sizeof (nit_t) + +typedef struct nit_mid { // after descriptors +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char transport_stream_loop_length_hi :4; +#else + u_char transport_stream_loop_length_hi :4; + u_char :4; +#endif + u_char transport_stream_loop_length_lo /*:8*/; +} nit_mid_t; +#define SIZE_NIT_MID sizeof (nit_mid_t) + +typedef struct nit_end { + long CRC; +} nit_end_t; +#define SIZE_NIT_END sizeof (nit_end_t) + +typedef struct nit_ts { + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char transport_descriptors_length_hi :4; +#else + u_char transport_descriptors_length_hi :4; + u_char :4; +#endif + u_char transport_descriptors_length_lo /*:8*/; + /* descriptors */ +} nit_ts_t; +#define NIT_TS_LEN sizeof (nit_ts_t) + +/* + * + * In addition to the PSI, data is needed to provide identification of + * services and events for the user. In contrast with the PAT, CAT, and + * PMT of the PSI, which give information only for the multiplex in which + * they are contained (the actual multiplex), the additional information + * defined within the present document can also provide information on + * services and events carried by different multiplexes, and even on other + * networks. This data is structured as nine tables: + * + * 1) Bouquet Association Table (BAT): + * + * - the BAT provides information regarding bouquets. As well as giving + * the name of the bouquet, it provides a list of services for each + * bouquet. + * + */ +/* SEE NIT (It has the same structure but has different allowed descriptors) */ +/* + * + * 2) Service Description Table (SDT): + * + * - the SDT contains data describing the services in the system e.g. + * names of services, the service provider, etc. + * + */ +typedef struct sdt { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number /*:8*/; + u_char last_section_number /*:8*/; + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; + u_char :8; +} sdt_t; +#define SDT_LEN sizeof (sdt_t) +#define GetSDTTransportStreamId(x) HILO(((sdt_t *)x)->transport_stream_id) +#define GetSDTOriginalNetworkId(x) HILO(((sdt_t *)x)->original_network_id) + +typedef struct sdt_descr { + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :6; + u_char eit_schedule_flag :1; + u_char eit_present_following_flag :1; + u_char running_status :3; + u_char free_ca_mode :1; + u_char descriptors_loop_length_hi :4; +#else + u_char eit_present_following_flag :1; + u_char eit_schedule_flag :1; + u_char :6; + u_char descriptors_loop_length_hi :4; + u_char free_ca_mode :1; + u_char running_status :3; +#endif + u_char descriptors_loop_length_lo /*:8*/; + u_char data[]; +} sdt_descr_t; +#define SDT_DESCR_LEN sizeof (sdt_descr_t) +#define GetSDTDescriptorsLoopLength(x) HILO(((sdt_descr_t *)x)->descriptors_loop_length) + +/* + * + * 3) Event Information Table (EIT): + * + * - the EIT contains data concerning events or programmes such as event + * name, start time, duration, etc.; - the use of different descriptors + * allows the transmission of different kinds of event information e.g. + * for different service types. + * + */ +typedef struct eit { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char version_number :5; + u_char current_next_indicator :1; +#else + u_char current_next_indicator :1; + u_char version_number :5; + u_char :2; +#endif + u_char section_number /*:8*/; + u_char last_section_number /*:8*/; + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; + u_char segment_last_section_number /*:8*/; + u_char segment_last_table_id /*:8*/; + u_char data[]; /* struct eit_event */ +} eit_t; +#define EIT_LEN sizeof (eit_t) + +typedef struct eit_event { + u_char event_id_hi /*:8*/; + u_char event_id_lo /*:8*/; + u_char mjd_hi /*:8*/; + u_char mjd_lo /*:8*/; + u_char start_time_h /*:8*/; + u_char start_time_m /*:8*/; + u_char start_time_s /*:8*/; + u_char duration_h /*:8*/; + u_char duration_m /*:8*/; + u_char duration_s /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char running_status :3; + u_char free_ca_mode :1; + u_char descriptors_loop_length_hi :4; +#else + u_char descriptors_loop_length_hi :4; + u_char free_ca_mode :1; + u_char running_status :3; +#endif + u_char descriptors_loop_length_lo /*:8*/; + u_char data[]; /* struct descr_gen */ +} eit_event_t; +#define EIT_EVENT_LEN sizeof (eit_event_t) +#define GetEITDescriptorsLoopLength(x) HILO(((eit_event_t *)x)->descriptors_loop_length) + +/* + * + * 4) Running Status Table (RST): + * + * - the RST gives the status of an event (running/not running). The RST + * updates this information and allows timely automatic switching to + * events. + * + */ + /* TO BE DONE */ +/* + * + * 5) Time and Date Table (TDT): + * + * - the TDT gives information relating to the present time and date. + * This information is given in a separate table due to the frequent + * updating of this information. + * + */ + +typedef struct tdt { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char utc_mjd_hi /*:8*/; + u_char utc_mjd_lo /*:8*/; + u_char utc_time_h /*:8*/; + u_char utc_time_m /*:8*/; + u_char utc_time_s /*:8*/; +} tdt_t; +#define TDT_LEN sizeof (tdt_t) + +/* + * + * 6) Time Offset Table (TOT): + * + * - the TOT gives information relating to the present time and date and + * local time offset. This information is given in a separate table due + * to the frequent updating of the time information. + * + */ +typedef struct tot { + u_char table_id /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char section_syntax_indicator :1; + u_char :3; + u_char section_length_hi :4; +#else + u_char section_length_hi :4; + u_char :3; + u_char section_syntax_indicator :1; +#endif + u_char section_length_lo /*:8*/; + u_char utc_mjd_hi /*:8*/; + u_char utc_mjd_lo /*:8*/; + u_char utc_time_h /*:8*/; + u_char utc_time_m /*:8*/; + u_char utc_time_s /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char descriptors_loop_length_hi :4; +#else + u_char descriptors_loop_length_hi :4; + u_char :4; +#endif + u_char descriptors_loop_length_lo /*:8*/; +} tot_t; +#define TOT_LEN sizeof (tot_t) + +/* + * + * 7) Stuffing Table (ST): + * + * - the ST is used to invalidate existing sections, for example at + * delivery system boundaries. + * + */ + /* TO BE DONE */ +/* + * + * 8) Selection Information Table (SIT): + * + * - the SIT is used only in "partial" (i.e. recorded) bitstreams. It + * carries a summary of the SI information required to describe the + * streams in the partial bitstream. + * + */ + /* TO BE DONE */ +/* + * + * 9) Discontinuity Information Table (DIT): + * + * - the DIT is used only in "partial" (i.e. recorded) bitstreams. + * It is inserted where the SI information in the partial bitstream may + * be discontinuous. Where applicable the use of descriptors allows a + * flexible approach to the organization of the tables and allows for + * future compatible extensions. + * + */ + /* TO BE DONE */ +/* + * + * The following describes the different descriptors that can be used within + * the SI. + * + * The following semantics apply to all the descriptors defined in this + * subclause: + * + * descriptor_tag: The descriptor tag is an 8-bit field which identifies + * each descriptor. Those values with MPEG-2 normative + * meaning are described in ISO/IEC 13818-1. The values of + * descriptor_tag are defined in 'libsi.h' + * descriptor_length: The descriptor length is an 8-bit field specifying the + * total number of bytes of the data portion of the + * descriptor following the byte defining the value of + * this field. + * + */ + +typedef struct descr_gen { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +} descr_gen_t; +#define DESCR_GEN_LEN sizeof (descr_gen_t) +#define CastGenericDescriptor(x) ((descr_gen_t *)(x)) + +#define GetDescriptorTag(x) (((descr_gen_t *)x)->descriptor_tag) +#define GetDescriptorLength(x) (((descr_gen_t *)x)->descriptor_length) + +/* 0x09 ca_descriptor */ +typedef struct descr_ca { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char CA_type_hi /*:8*/; + u_char CA_type_lo /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :3; + u_char CA_PID_hi :5; +#else + u_char CA_PID_hi :5; + u_char :3; +#endif + u_char CA_PID_lo /*:8*/; +} descr_ca_t; +#define DESCR_CA_LEN sizeof (descr_ca_t) +#define CastCaDescriptor(x) ((descr_ca_t *)(x)) + +/* 0x0A iso_639_language_descriptor */ +typedef struct descr_iso_639_language { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; +} descr_iso_639_language_t; +#define DESCR_ISO_639_LANGUAGE_LEN sizeof (descr_iso_639_language_t) +#define CastIso639LanguageDescriptor(x) ((descr_iso_639_language_t *)(x)) + +/* 0x40 network_name_descriptor */ +typedef struct descr_network_name { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +} descr_network_name_t; +#define DESCR_NETWORK_NAME_LEN sizeof (descr_network_name_t) +#define CastNetworkNameDescriptor(x) ((descr_network_name_t *)(x)) + +/* 0x41 service_list_descriptor */ +typedef struct descr_service_list { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +} descr_service_list_t; +#define DESCR_SERVICE_LIST_LEN sizeof (descr_service_list_t) +#define CastServiceListDescriptor(x) ((descr_service_list_t *)(x)) + +typedef struct descr_service_list_loop { + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; + u_char service_type /*:8*/; +} descr_service_list_loop_t; +#define DESCR_SERVICE_LIST_LOOP_LEN sizeof (descr_service_list_loop_t) +#define CastServiceListDescriptorLoop(x) ((descr_service_list_loop_t *)(x)) + +/* 0x42 stuffing_descriptor */ +typedef struct descr_stuffing { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; +} descr_stuffing_t; +#define DESCR_STUFFING_LEN sizeof (descr_stuffing_t) +#define CastStuffingDescriptor(x) ((descr_stuffing_t *)(x)) + +/* 0x43 satellite_delivery_system_descriptor */ +typedef struct descr_satellite_delivery_system { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char frequency1 /*:8*/; + u_char frequency2 /*:8*/; + u_char frequency3 /*:8*/; + u_char frequency4 /*:8*/; + u_char orbital_position1 /*:8*/; + u_char orbital_position2 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char west_east_flag :1; + u_char polarization :2; + u_char modulation :5; +#else + u_char modulation :5; + u_char polarization :2; + u_char west_east_flag :1; +#endif + u_char symbol_rate1 /*:8*/; + u_char symbol_rate2 /*:8*/; + u_char symbol_rate3 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char symbol_rate4 :4; + u_char fec_inner :4; +#else + u_char fec_inner :4; + u_char symbol_rate4 :4; +#endif +} descr_satellite_delivery_system_t; +#define DESCR_SATELLITE_DELIVERY_SYSTEM_LEN sizeof (descr_satellite_delivery_system_t) +#define CastSatelliteDeliverySystemDescriptor(x) ((descr_satellite_delivery_system_t *)(x)) +#define GetSatelliteDeliverySystemFrequency(x) HILO4(((descr_satellite_delivert_system_t *)x)->frequency) +#define GetSatelliteDeliverySystemSymbolRate(x) HILO4(((descr_satellite_delivert_system_t *)x)->symbol_rate) + + +/* 0x44 cable_delivery_system_descriptor */ +typedef struct descr_cable_delivery_system { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char frequency1 /*:8*/; + u_char frequency2 /*:8*/; + u_char frequency3 /*:8*/; + u_char frequency4 /*:8*/; + u_char :8; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char fec_outer :4; +#else + u_char fec_outer :4; + u_char :4; +#endif + u_char modulation /*:8*/; + u_char symbol_rate1 /*:8*/; + u_char symbol_rate2 /*:8*/; + u_char symbol_rate3 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char symbol_rate4 :4; + u_char fec_inner :4; +#else + u_char fec_inner :4; + u_char symbol_rate4 :4; +#endif +} descr_cable_delivery_system_t; +#define DESCR_CABLE_DELIVERY_SYSTEM_LEN sizeof (descr_cable_delivery_system_t) +#define CastCableDeliverySystemDescriptor(x) ((descr_cable_delivery_system_t *)(x)) +#define GetCableDeliverySystemFrequency(x) HILO4(((descr_cable_delivert_system_t *)x)->frequency) +#define GetCableDeliverySystemSymbolRate(x) HILO4(((descr_cable_delivert_system_t *)x)->symbol_rate) + +/* 0x45 vbi_data_descriptor */ +typedef struct descr_vbi_data { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + /* TBD */ +} descr_vbi_data_t; +#define DESCR_VBI_DATA_LEN sizeof (descr_vbi_data_t) +#define CastVbiDataDescriptor(x) ((descr_vbi_data_t *)(x)) + +/* 0x46 vbi_teletext_descriptor */ +typedef struct descr_vbi_teletext { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + /* TBD */ +} descr_vbi_teletext_t; +#define DESCR_VBI_TELETEXT_LEN sizeof (descr_vbi_teletext_t) +#define CastVbiDescriptor(x) ((descr_vbi_teletext_t *)(x)) + +/* 0x47 bouquet_name_descriptor */ +typedef struct descr_bouquet_name { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +} descr_bouquet_name_t; +#define DESCR_BOUQUET_NAME_LEN sizeof (descr_bouquet_name_t) + +#define CastBouquetNameDescriptor(x) ((descr_bouquet_name_t *)(x)) + +/* 0x48 service_descriptor */ +typedef struct descr_service { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char service_type /*:8*/; + u_char provider_name_length /*:8*/; +} descr_service_t; +#define DESCR_SERVICE_LEN sizeof (descr_service_t) +#define CastServiceDescriptor(x) ((descr_service_t *)(x)) + +/* 0x49 country_availability_descriptor */ +typedef struct descr_country_availability { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char country_availability_flag :1; + u_char :7; +#else + u_char :7; + u_char country_availability_flag :1; +#endif +} descr_country_availability_t; +#define DESCR_COUNTRY_AVAILABILITY_LEN sizeof (descr_country_availability_t) +#define CastCountryAvailabilityDescriptor(x) ((descr_country_availability_t *)(x)) + +/* 0x4A linkage_descriptor */ +typedef struct descr_linkage { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; + u_char linkage_type /*:8*/; +} descr_linkage_t; +#define DESCR_LINKAGE_LEN sizeof (descr_linkage_t) +#define CastLinkageDescriptor(x) ((descr_linkage_t *)(x)) + +/* 0x4B nvod_reference_descriptor */ +typedef struct descr_nvod_reference { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* struct item_nvod_reference */ +} descr_nvod_reference_t; +#define DESCR_NVOD_REFERENCE_LEN sizeof (descr_nvod_reference_t) +#define CastNvodReferenceDescriptor(x) ((descr_nvod_reference_t *)(x)) + +typedef struct item_nvod_reference { + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; +} item_nvod_reference_t; +#define ITEM_NVOD_REFERENCE_LEN sizeof (item_nvod_reference_t) +#define CastNvodReferenceItem(x) ((item_nvod_reference_t *)(x)) + +/* 0x4C time_shifted_service_descriptor */ +typedef struct descr_time_shifted_service { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char reference_service_id_hi /*:8*/; + u_char reference_service_id_lo /*:8*/; +} descr_time_shifted_service_t; +#define DESCR_TIME_SHIFTED_SERVICE_LEN sizeof (descr_time_shifted_service_t) +#define CastTimeShiftedServiceDescriptor(x) ((descr_time_shifted_service_t *)(x)) + +/* 0x4D short_event_descriptor */ +typedef struct descr_short_event { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char event_name_length /*:8*/; + u_char data[]; +} descr_short_event_t; +#define DESCR_SHORT_EVENT_LEN sizeof (descr_short_event_t) +#define CastShortEventDescriptor(x) ((descr_short_event_t *)(x)) + +/* 0x4E extended_event_descriptor */ +typedef struct descr_extended_event { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char descriptor_number :4; + u_char last_descriptor_number :4; +#else + u_char last_descriptor_number :4; + u_char descriptor_number :4; +#endif + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char length_of_items /*:8*/; + u_char data[]; /* struct item_extended_event */ +} descr_extended_event_t; +#define DESCR_EXTENDED_EVENT_LEN sizeof (descr_extended_event_t) +#define CastExtendedEventDescriptor(x) ((descr_extended_event_t *)(x)) + +typedef struct item_extended_event { + u_char item_description_length /*:8*/; + u_char data[]; +} item_extended_event_t; +#define ITEM_EXTENDED_EVENT_LEN sizeof (item_extended_event_t) +#define CastExtendedEventItem(x) ((item_extended_event_t *)(x)) + +/* 0x4F time_shifted_event_descriptor */ +typedef struct descr_time_shifted_event { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char reference_service_id_hi /*:8*/; + u_char reference_service_id_lo /*:8*/; + u_char reference_event_id_hi /*:8*/; + u_char reference_event_id_lo /*:8*/; +} descr_time_shifted_event_t; +#define DESCR_TIME_SHIFTED_EVENT_LEN sizeof (descr_time_shifted_event_t) +#define CastTimeShiftedEventDescriptor(x) ((descr_time_shifted_event_t *)(x)) + +/* 0x50 component_descriptor */ +typedef struct descr_component { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char stream_content :4; +#else + u_char stream_content :4; + u_char :4; +#endif + u_char component_type /*:8*/; + u_char component_tag /*:8*/; + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char data[]; +} descr_component_t; +#define DESCR_COMPONENT_LEN sizeof (descr_component_t) +#define CastComponentDescriptor(x) ((descr_component_t *)(x)) + +/* 0x51 mosaic_descriptor */ +typedef struct descr_mosaic { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char mosaic_entry_point :1; + u_char number_of_horizontal_elementary_cells :3; + u_char :1; + u_char number_of_vertical_elementary_cells :3; +#else + u_char number_of_vertical_elementary_cells :3; + u_char :1; + u_char number_of_horizontal_elementary_cells :3; + u_char mosaic_entry_point :1; +#endif + u_char data[]; /* struct item_mosaic */ +} descr_mosaic_t; +#define DESCR_MOSAIC_LEN sizeof (descr_mosaic_t) +#define CastMosaicDescriptor(x) ((descr_mosaic_t *)(x)) + +typedef struct item_mosaic { +#if BYTE_ORDER == BIG_ENDIAN + u_char logical_cell_id :6; + u_char :7; + u_char logical_cell_presentation_info :3; +#else + u_char :2; + u_char logical_cell_id :6; + u_char logical_cell_presentation_info :3; /*0=undefined, 1=video, 2=still picture, 3=graphical text, 4--7=reserved*/ + u_char :5; +#endif + u_char elementary_cell_field_length /*:8*/; + u_char data[]; /* struct item_mosaic_cell; struct item_mosaic_end */ +} item_mosaic_t; +typedef struct item_mosaic_end { + u_char cell_linkage_info /*:8*/; /*0=undefined, 1=bouquet, 2=service, 3=other mosaic, 4=event, 5--255=reserved*/ + u_char data[]; /* union item_cell_linkage */ +} item_mosaic_end_t; + +typedef struct item_mosaic_cell { +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char elementary_cell_id :6; +#else + u_char elementary_cell_id :6; + u_char :2; +#endif +} item_mosaic_cell_t; +typedef union item_mosaic_cell_linkage { + struct item_mosaic_cell_bouquet { + u_char bouquet_id_hi /*:8*/; + u_char bouquet_id_lo /*:8*/; + } bouquet; + struct item_mosaic_cell_service { + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; + } service; + struct item_mosaic_cell_other { + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; + } other; + struct item_mosaic_cell_event { + u_char original_network_id_hi /*:8*/; + u_char original_network_id_lo /*:8*/; + u_char transport_stream_id_hi /*:8*/; + u_char transport_stream_id_lo /*:8*/; + u_char service_id_hi /*:8*/; + u_char service_id_lo /*:8*/; + u_char event_id_hi /*:8*/; + u_char event_id_lo /*:8*/; + } event; +} item_mosaic_cell_linkage_t; + +/* 0x52 stream_identifier_descriptor */ +typedef struct descr_stream_identifier { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char component_tag /*:8*/; +} descr_stream_identifier_t; +#define DESCR_STREAM_IDENTIFIER_LEN sizeof (descr_stream_identifier_t) +#define CastStreamIdentifierDescriptor(x) ((descr_stream_identifier_t *)(x)) + +/* 0x53 ca_identifier_descriptor */ +typedef struct descr_ca_identifier { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +} descr_ca_identifier_t; +#define DESCR_CA_IDENTIFIER_LEN sizeof (descr_ca_identifier_t) +#define CastCaIdentifierDescriptor(x) ((descr_ca_identifier_t *)(x)) + +/* 0x54 content_descriptor */ +typedef struct descr_content { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* struct nibble_content */ +} descr_content_t; +#define DESCR_CONTENT_LEN sizeof (descr_content_t) +#define CastContentDescriptor(x) ((descr_content_t *)(x)) + +typedef struct nibble_content { +#if BYTE_ORDER == BIG_ENDIAN + u_char content_nibble_level_1 :4; + u_char content_nibble_level_2 :4; + u_char user_nibble_1 :4; + u_char user_nibble_2 :4; +#else + u_char user_nibble_2 :4; + u_char user_nibble_1 :4; + u_char content_nibble_level_2 :4; + u_char content_nibble_level_1 :4; +#endif +} nibble_content_t; +#define NIBBLE_CONTENT_LEN sizeof (nibble_content_t) +#define CastContentNibble(x) ((nibble_content_t *)(x)) + +/* 0x55 parental_rating_descriptor */ +typedef struct descr_parental_rating { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* struct parental_rating_item */ +} descr_parental_rating_t; +#define DESCR_PARENTAL_RATING_LEN sizeof (descr_parental_rating_t) +#define CastParentalRatingDescriptor(x) ((descr_parental_rating_t *)(x)) + +typedef struct parental_rating_item { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char rating /*:8*/; +} parental_rating_item_t; +#define PARENTAL_RATING_ITEM_LEN sizeof (parental_rating_item_t) +#define CastParentalRatingItem(x) ((parental_rating_item_t *)(x)) + +/* 0x56 teletext_descriptor */ +typedef struct descr_teletext { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* struct item_teletext */ +} descr_teletext_t; +#define DESCR_TELETEXT_LEN sizeof (descr_teletext_t) +#define CastTeletextDescriptor(x) ((descr_teletext_t *)(x)) + +typedef struct item_teletext { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char type :5; + u_char magazine_number :3; +#else + u_char magazine_number :3; + u_char type :5; +#endif + u_char page_number /*:8*/; +} item_teletext_t; +#define ITEM_TELETEXT_LEN sizeof (item_teletext_t) +#define CastTeletextItem(x) ((item_teletext_t *)(x)) + +/* 0x57 telephone_descriptor */ +typedef struct descr_telephone { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char foreign_availability :1; + u_char connection_type :5; +#else + u_char connection_type :5; + u_char foreign_availability :1; + u_char :2; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char :1; + u_char country_prefix_length :2; + u_char international_area_code_length :3; + u_char operator_code_length :2; +#else + u_char operator_code_length :2; + u_char international_area_code_length :3; + u_char country_prefix_length :2; + u_char :1; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char :1; + u_char national_area_code_length :3; + u_char core_number_length :4; +#else + u_char core_number_length :4; + u_char national_area_code_length :3; + u_char :1; +#endif + u_char data[]; /* coutry area operator national core */ +} descr_telephone_t; +#define DESCR_TELEPHONE_LEN sizeof (descr_telephone_t) +#define CastTelephoneDescriptor(x) ((descr_telephone_t *)(x)) + +/* 0x58 local_time_offset_descriptor */ +typedef struct descr_local_time_offset { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +} descr_local_time_offset_t; +#define DESCR_LOCAL_TIME_OFFSET_LEN sizeof (descr_local_time_offset_t) +#define CastLocalTimeOffsetDescriptor(x) ((descr_local_time_offset_t *)(x)) + +typedef struct local_time_offset_entry { + u_char country_code1 /*:8*/; + u_char country_code2 /*:8*/; + u_char country_code3 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char country_region_id :6; + u_char :1; + u_char local_time_offset_polarity :1; +#else + u_char local_time_offset_polarity :1; + u_char :1; + u_char country_region_id :6; +#endif + u_char local_time_offset_h /*:8*/; + u_char local_time_offset_m /*:8*/; + u_char time_of_change_mjd_hi /*:8*/; + u_char time_of_change_mjd_lo /*:8*/; + u_char time_of_change_time_h /*:8*/; + u_char time_of_change_time_m /*:8*/; + u_char time_of_change_time_s /*:8*/; + u_char next_time_offset_h /*:8*/; + u_char next_time_offset_m /*:8*/; +} local_time_offset_entry_t ; +#define LOCAL_TIME_OFFSET_ENTRY_LEN sizeof (local_time_offset_entry_t) +#define CastLocalTimeOffsetEntry(x) ((local_time_offset_entry_t *)(x)) + +/* 0x59 subtitling_descriptor */ +typedef struct descr_subtitling { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* item_subtitling */ +} descr_subtitling_t; +#define DESCR_SUBTITLING_LEN sizeof (descr_subtitling_t) +#define CastSubtitlingDescriptor(x) ((descr_subtitling_t *)(x)) + +typedef struct item_subtitling { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char subtitling_type /*:8*/; + u_char composition_page_id_hi /*:8*/; + u_char composition_page_id_lo /*:8*/; + u_char ancillary_page_id_hi /*:8*/; + u_char ancillary_page_id_lo /*:8*/; +} item_subtitling_t; +#define ITEM_SUBTITLING_LEN sizeof (item_subtitling_t) +#define CastSubtitlingItem(x) ((item_subtitling_t *)(x)) + +/* 0x5A terrestrial_delivery_system_descriptor */ +typedef struct descr_terrestrial_delivery { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char frequency1 /*:8*/; + u_char frequency2 /*:8*/; + u_char frequency3 /*:8*/; + u_char frequency4 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char bandwidth :3; + u_char :5; +#else + u_char :5; + u_char bandwidth :3; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char constellation :2; + u_char hierarchy :3; + u_char code_rate_HP :3; +#else + u_char code_rate_HP :3; + u_char hierarchy :3; + u_char constellation :2; +#endif +#if BYTE_ORDER == BIG_ENDIAN + u_char code_rate_LP :3; + u_char guard_interval :2; + u_char transmission_mode :2; + u_char other_frequency_flag :1; +#else + u_char other_frequency_flag :1; + u_char transmission_mode :2; + u_char guard_interval :2; + u_char code_rate_LP :3; +#endif + u_char reserver2 /*:8*/; + u_char reserver3 /*:8*/; + u_char reserver4 /*:8*/; + u_char reserver5 /*:8*/; +} descr_terrestrial_delivery_system_t; +#define DESCR_TERRESTRIAL_DELIVERY_SYSTEM_LEN sizeof (descr_terrestrial_delivery_system_t) +#define CastTerrestrialDeliverySystemDescriptor(x) ((descr_terrestrial_delivery_system_t *)(x)) +#define GetTerrestrialDeliverySystemFrequency(x) HILO4(((descr_terrestrial_delivert_system_t *)x)->frequency) + +/* 0x5B multilingual_network_name_descriptor */ +typedef struct descr_multilingual_network_name { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* struct item_multilingual_network_name */ +} descr_multilingual_network_name_t; +#define DESCR_MULTILINGUAL_NETWORK_NAME_LEN sizeof (descr_multilingual_network_name_t) +#define CastMultilingualNetworkNameDescriptor(x) ((descr_multilingual_network_name_t *)(x)) + +typedef struct item_multilingual_network_name { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char network_name_length /*:8*/; + u_char network_name[]; +} item_multilingual_network_name_t; + +/* 0x5C multilingual_bouquet_name_descriptor */ +typedef struct descr_multilingual_bouquet_name { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char names[]; /* struct item_multilingual_bouquet_name */ +} descr_multilingual_bouquet_name_t; +#define DESCR_MULTILINGUAL_BOUQUET_NAME_LEN sizeof (descr_multilingual_bouquet_name_t) +#define CastMultilingualBouquetNameDescriptor(x) ((descr_multilingual_bouquet_name_t *)(x)) + +typedef struct item_multilingual_bouquet_name { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char bouquet_name_length /*:8*/; + u_char bouquet_name[]; +} item_multilingual_bouquet_name_t; + +/* 0x5D multilingual_service_name_descriptor */ +typedef struct descr_multilingual_service_name { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* struct multilingual_service_name_item */ +} descr_multilingual_service_name_t; +#define DESCR_MULTILINGUAL_SERVICE_NAME_LEN sizeof (descr_multilingual_service_name_t) +#define CastMultilingualServiceNameDescriptor(x) ((descr_multilingual_service_name_t *)(x)) + +typedef struct multilingual_service_name_item { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char data[]; /* struct multilingual_service_name_item_(mid|end) */ +} multilingual_service_name_item_t; +typedef struct multilingual_service_name_item_mid { + u_char service_provider_name_length /*:8*/; + u_char service_provider_name[]; +} multilingual_service_name_item_mid_t; +typedef struct multilingual_service_name_item_end { + u_char service_name_length /*:8*/; + u_char service_name[]; +} multilingual_service_name_item_end_t; + +/* 0x5E multilingual_component_descriptor */ +typedef struct descr_multilingual_component { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char component_tag /*:8*/; + u_char data[]; /* struct multilingual_component_item */ +} descr_multilingual_component_t; +#define DESCR_MULTILINGUAL_COMPONENT_LEN sizeof (descr_multilingual_component_t) +#define CastMultilingualComponentDescriptor(x) ((descr_multilingual_component_t *)(x)) + +typedef struct item_multilingual_component { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char text_description_length /*:8*/; + u_char text_description[]; +} item_multilingual_component_t; + +/* 0x5F private_data_specifier_descriptor */ +typedef struct descr_private_data_specifier { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char private_data_specifier1 /*:8*/; + u_char private_data_specifier2 /*:8*/; + u_char private_data_specifier3 /*:8*/; + u_char private_data_specifier4 /*:8*/; +} descr_private_data_specifier_t; +#define DESCR_PRIVATE_DATA_SPECIFIER_LEN sizeof (descr_private_data_specifier_t) +#define CastPrivateDataSpecifierDescriptor(x) ((descr_private_data_specifier_t *)(x)) +#define GetPrivateDataSpecifier(x) HILO4(((descr_private_data_specifier_t *)x)->private_data_specifier) + +/* 0x60 service_move_descriptor */ +typedef struct descr_service_move { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char new_original_network_id_hi /*:8*/; + u_char new_original_network_id_lo /*:8*/; + u_char new_transport_stream_id_hi /*:8*/; + u_char new_transport_stream_id_lo /*:8*/; + u_char new_service_id_hi /*:8*/; + u_char new_service_id_lo /*:8*/; +} descr_service_move_t; +#define DESCR_SERVICE_MOVE_LEN sizeof (descr_service_move_t) +#define CastServiceMoveDescriptor(x) ((descr_service_move_t *)(x)) + +/* 0x61 short_smoothing_buffer_descriptor */ +typedef struct descr_short_smoothing_buffer { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char sb_size :2; + u_char sb_leak_rate :6; +#else + u_char sb_leak_rate :6; + u_char sb_size :2; +#endif + u_char data[]; +} descr_short_smoothing_buffer_t; +#define DESCR_SHORT_SMOOTHING_BUFFER_LEN sizeof (descr_short_smoothing_buffer_t) +#define CastShortSmoothingBufferDescriptor(x) ((descr_short_smoothing_buffer_t *)(x)) + +/* 0x62 frequency_list_descriptor */ +typedef struct descr_frequency_list { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :6; + u_char coding_type :2; /* 00=not def 01=satelite 10=cable 11=terrestrial */ +#else + u_char coding_type :2; /* 00=not def 01=satelite 10=cable 11=terrestrial */ + u_char :6; +#endif + u_char centre_frequency1 /*:8*/; + u_char centre_frequency2 /*:8*/; + u_char centre_frequency3 /*:8*/; + u_char centre_frequency4 /*:8*/; +} descr_frequency_list_t; +#define DESCR_FREQUENCY_LIST_LEN sizeof (descr_frequency_list_t) +#define CastFrequencyListDescriptor(x) ((descr_frequency_list_t *)(x)) + +/* 0x63 partial_transport_stream_descriptor */ +typedef struct descr_partial_transport_stream { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char peak_rate1 :6; +#else + u_char peak_rate1 :6; + u_char :2; +#endif + u_char peak_rate2 /*:8*/; + u_char peak_rate3 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char minimum_overall_smoothing_rate1 :6; +#else + u_char minimum_overall_smoothing_rate1 :6; + u_char :2; +#endif + u_char minimum_overall_smoothing_rate2 /*:8*/; + u_char minimum_overall_smoothing_rate3 /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :2; + u_char maximum_overall_smoothing_rate1 :6; +#else + u_char maximum_overall_smoothing_rate1 :6; + u_char :2; +#endif + u_char maximum_overall_smoothing_rate2 /*:8*/; +} descr_partial_transport_stream_t; +#define DESCR_PARTIAL_TRANSPORT_STREAM_LEN sizeof (descr_partial_transport_stream_t) +#define CastPartialDescriptor(x) ((descr_partial_transport_stream_t *)(x)) +#define GetPartialTransportStreamCentreFrequency(x) HILO4(((descr_partial_transport_stream_t *)x)->centre_frequency) +#define GetPTSPeakRate(x) HILO2(((descr_partial_transport_stream *)x)->peak_rate) +#define GetPTSMinOSRate(x) HILO3(((descr_partial_transport_stream *)x)->minimum_overall_smoothing_rate) +#define GetPTSMaxOSRate(x) HILO2(((descr_partial_transport_stream *)x)->minimum_overall_smoothing_rate) + +/* 0x64 data_broadcast_descriptor */ +typedef struct descr_data_broadcast { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data_broadcast_id_hi /*:8*/; + u_char data_broadcast_id_lo /*:8*/; + u_char component_tag /*:8*/; + u_char selector_length /*:8*/; + u_char data[]; /* char[]; struct descr_data_broadcast_end */ +} descr_data_broadcast_t; +typedef struct descr_data_broadcast_end { + u_char lang_code1 /*:8*/; + u_char lang_code2 /*:8*/; + u_char lang_code3 /*:8*/; + u_char text_length /*:8*/; + u_char text[]; +} descr_data_broadcast_end_t; + +/* 0x65 ca_system_descriptor */ +typedef struct descr_ca_system { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; /* struct item_ca_system */ +} descr_ca_system_t; +#define DESCR_CA_SYSTEM_LEN sizeof (descr_ca_system_t) +#define CastCaSystemDescriptor(x) ((descr_ca_system_t *)(x)) + +typedef struct item_ca_system { + u_char CA_system_id_hi /*:8*/; + u_char CA_system_id_lo /*:8*/; +} item_ca_system_t; + +/* 0x66 data_broadcast_id_descriptor */ +typedef struct descr_data_broadcast_id { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data_broadcast_id_hi /*:8*/; + u_char data_broadcast_id_lo /*:8*/; +} descr_data_broadcast_id_t; +#define DESCR_DATA_BROADCAST_ID_LEN sizeof (descr_data_broadcast_id_t) +#define CastDataBroadcastIdDescriptor(x) ((descr_data_broadcast_id_t *)(x)) + +/* 0x67 transport_stream_descriptor */ +typedef struct descr_transport_stream { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + /* TBD */ +} descr_transport_stream_t; +#define DESCR_TRANSPORT_STREAM_LEN sizeof (descr_transport_stream_t) +#define CastTransportStreamDescriptor(x) ((descr_transport_stream_t *)(x)) + +/* 0x68 dsng_descriptor */ +typedef struct descr_dsng { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + /* TBD */ +} descr_dsng_t; +#define DESCR_DSNG_LEN sizeof (descr_dsng_t) +#define CastDsngDescriptor(x) ((descr_dsng_t *)(x)) + +/* 0x69 programme_identificaion_label_descriptor */ +typedef struct descr_pdc { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char :4; + u_char day :5; + u_char month :4; + u_char hour :5; + u_char minute :6; +#else + u_char minute :6; + u_char hour :5; + u_char month :4; + u_char day :5; + u_char :4; +#endif +} descr_pdc_t; +#define DESCR_PDC_LEN sizeof (descr_pdc_t) +#define CastPdcDescriptor(x) ((descr_pdc_t *)(x)) + +/* 0x6A ac3_descriptor */ +typedef struct descr_ac3 { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; +#if BYTE_ORDER == BIG_ENDIAN + u_char ac3_type_flag :1; + u_char bsid_flag :1; + u_char mainid_flag :1; + u_char asvc_flag :1; + u_char :4; +#else + u_char :4; + u_char asvc_flag :1; + u_char mainid_flag :1; + u_char bsid_flag :1; + u_char ac3_type_flag :1; +#endif + u_char ac3_type /*:8*/; + u_char bsid /*:8*/; + u_char mainid /*:8*/; + u_char asvc /*:8*/; +} descr_ac3_t; +#define DESCR_AC3_LEN sizeof (descr_ac3_t) +#define CastAc3Descriptor(x) ((descr_ac3_t *)(x)) + +/* 0x6B ancillary_data_descriptor */ +typedef struct descr_ancillary_data { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char ancillary_data_identifier /*:8*/; +} descr_ancillary_data_t; +#define DESCR_ANCILLARY_DATA_LEN sizeof (descr_ancillary_data_t) +#define CastAncillaryDataDescriptor(x) ((descr_ancillary_data_t *)(x)) + +/* 0x6C cell_list_descriptor */ +typedef struct descr_cell_list { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + /* TBD */ +} descr_cell_list_t; +#define DESCR_CELL_LIST_LEN sizeof (descr_cell_list_t) +#define CastCellListDescriptor(x) ((descr_cell_list_t *)(x)) + +/* 0x6D cell_frequency_link_descriptor */ +typedef struct descr_cell_frequency_link { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + /* TBD */ +} descr_cell_frequency_link_t; +#define DESCR_CELL_FREQUENCY_LINK_LEN sizeof (descr_cell_frequency_link_t) +#define CastCellFrequencyLinkDescriptor(x) ((descr_cell_frequency_link_t *)(x)) + +/* 0x6E announcement_support_descriptor */ +typedef struct descr_announcement_support { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + /* TBD */ +} descr_announcement_support_t; +#define DESCR_ANNOUNCEMENT_SUPPORT_LEN sizeof (descr_announcement_support_t) +#define CastAnnouncementSupportDescriptor(x) ((descr_announcement_support_t *)(x)) + +/* 0x76 content_identifier_descriptor */ +typedef struct descr_content_identifier { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char data[]; +} descr_content_identifier_t; + +typedef struct descr_content_identifier_crid { +#if BYTE_ORDER == BIG_ENDIAN + u_char crid_type :6; + u_char crid_location :2; +#else + u_char crid_location :2; + u_char crid_type :6; +#endif + u_char crid_ref_data[]; +} descr_content_identifier_crid_t; + +typedef struct descr_content_identifier_crid_local { + u_char crid_length /*:8*/; + u_char crid_byte[]; +} descr_content_identifier_crid_local_t; + + +/* 0x80 custom_category_descriptor TODO */ +typedef struct descr_custom_category { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char dummy /*:8*/; // 7F + u_char data_length /*:8*/; + u_char data[]; /* struct custom_category_item(1|2) */ +} descr_custom_category_t; +struct custom_category_item1 { + u_char dummy /*:8*/; // 10 40 +}; +struct custom_category_item2 { + u_char length /*:8*/; + u_char data[]; /* struct custom_category_item3 */ +}; +struct custom_category_item3 { + u_char dummy0 /*:8*/; // FF +#if BYTE_ORDER == BIG_ENDIAN + u_char content_nibble_level_1 :4; + u_char content_nibble_level_2 :4; + u_char user_nibble_1 :4; + u_char user_nibble_2 :4; +#else + u_char user_nibble_2 :4; + u_char user_nibble_1 :4; + u_char content_nibble_level_2 :4; + u_char content_nibble_level_1 :4; +#endif + u_char dummy1[2] /*:8*/; // CF E2 | D4 48 + u_char text_length /*:8*/; + u_char text[]; +}; + +/* 0x81 xxx_descriptor TODO */ +typedef struct descr_xxx { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char dummy /*:8 FF*/; +} descr_xxx_t; +#define DESCR_XXX_LEN sizeof (descr_xxx_t) +#define CastXxxDescriptor(x) ((descr_xxx_t *)(x)) + +/* 0x82 vps_descriptor TODO */ +typedef struct descr_vps { + u_char descriptor_tag /*:8*/; + u_char descriptor_length /*:8*/; + u_char hour[2] /*:8*/; + u_char delimiter_time /*:8 ':'*/; + u_char minute[2] /*:8*/; + u_char day[2] /*:8*/; + u_char delimiter_date /*:8 '.'*/; + u_char month[2] /*:8*/; + u_char delimiter /*:8 '#'*/; + u_char number[2] /*:8*/; +} descr_vps_t; +#define DESCR_VPS_LEN sizeof (descr_vps_t) +#define CastVpsDescriptor(x) ((descr_vps_t *)(x)) diff --git a/p2pvr/scanner/tv_grab_dvb.h b/p2pvr/scanner/tv_grab_dvb.h new file mode 100644 index 0000000..460b7f6 --- /dev/null +++ b/p2pvr/scanner/tv_grab_dvb.h @@ -0,0 +1,32 @@ +#ifndef __tv_grab_dvd +#define __tv_grab_dvd + +#include +#include + +/* lookup.c */ +union lookup_key { + int i; + char c[4]; +}; +struct lookup_table { + union lookup_key u; + const char *desc; +}; + +extern const char *lookup(const struct lookup_table *l, int id); +extern int load_lookup(struct lookup_table **l, const char *file); + +/* dvb_info_tables.c */ +extern const struct lookup_table description_table[]; +extern const struct lookup_table aspect_table[]; +extern const struct lookup_table audio_table[]; +extern const struct lookup_table crid_type_table[]; + +/* langidents.c */ +extern const struct lookup_table languageid_table[]; + +/* crc32.c */ +extern uint32_t _dvb_crc32(const uint8_t *data, size_t len); + +#endif -- cgit v1.2.3