diff options
author | randomdan <randomdan@localhost> | 2011-03-18 16:12:36 +0000 |
---|---|---|
committer | randomdan <randomdan@localhost> | 2011-03-18 16:12:36 +0000 |
commit | 0c6a0665bfb78989c463c80d7371b63c832b0f3c (patch) | |
tree | 89670dc7b1415b23fa51e45c38cbe152966a936b | |
parent | Work to date on p2pvr - basic EIT scanner (diff) | |
download | p2pvr-0c6a0665bfb78989c463c80d7371b63c832b0f3c.tar.bz2 p2pvr-0c6a0665bfb78989c463c80d7371b63c832b0f3c.tar.xz p2pvr-0c6a0665bfb78989c463c80d7371b63c832b0f3c.zip |
Second round of tweaks, fixes and XMLTV stripping
-rw-r--r-- | p2pvr/Jamfile.jam | 1 | ||||
-rw-r--r-- | p2pvr/cron/importSchedume.xml | 18 | ||||
-rw-r--r-- | p2pvr/cron/sched.xml | 10 | ||||
-rw-r--r-- | p2pvr/scanner/Jamfile.jam | 2 | ||||
-rw-r--r-- | p2pvr/scanner/dvb_info_tables.c | 28 | ||||
-rw-r--r-- | p2pvr/scanner/langidents.c | 211 | ||||
-rw-r--r-- | p2pvr/scanner/p2scan.cpp | 530 |
7 files changed, 224 insertions, 576 deletions
diff --git a/p2pvr/Jamfile.jam b/p2pvr/Jamfile.jam index e69de29..adbd6f6 100644 --- a/p2pvr/Jamfile.jam +++ b/p2pvr/Jamfile.jam @@ -0,0 +1 @@ +build-project scanner ; diff --git a/p2pvr/cron/importSchedume.xml b/p2pvr/cron/importSchedume.xml index 928c2bd..767b8d2 100644 --- a/p2pvr/cron/importSchedume.xml +++ b/p2pvr/cron/importSchedume.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <block name="importSchedule" xmlns:p2="http://project2.randomdan.homeip.net"> - <p2:library path="scanner/bin/gcc-4.5.2/debug/libp2pvr-scan-p2.so" /> + <p2:library path="libp2pvr-scan-p2.so" /> <p2:eitrows name="schedule" demux="/dev/dvb/adapter0/demux0" /> <p2:sqlmerge name="mergeSchedule" datasource="postgres" targettable="programs"> <p2:iterate name="programs" source="schedule"> @@ -9,20 +9,22 @@ <param name="title"><value source="parent" attribute="title" depth="1" /></param> <param name="titleLang"><value source="parent" attribute="titleLang" depth="1" /></param> <param name="subtitle"><value source="parent" attribute="subtitle" depth="1" /></param> - <param name="subtitleLang"><value source="parent" attribute="subtitleLang" depth="1" /></param> <param name="serviceID"><value source="parent" attribute="serviceID" depth="1" /></param> <param name="descLang"><value source="parent" attribute="descLang" depth="1" /></param> <param name="desc1"><value source="parent" attribute="desc1" depth="1" /></param> <param name="desc2"><value source="parent" attribute="desc2" depth="1" /></param> <param name="desc3"><value source="parent" attribute="desc3" depth="1" /></param> <param name="videoAspect"><value source="parent" attribute="videoAspect" depth="1" /></param> + <param name="videoFrameRate"><value source="parent" attribute="videoFrameRate" depth="1" /></param> + <param name="videoHD"><value source="parent" attribute="videoHD" depth="1" /></param> <param name="audioChannels"><value source="parent" attribute="audioChannels" depth="1" /></param> <param name="language"><value source="parent" attribute="language" depth="1" /></param> <param name="teletextSubtitleLang"><value source="parent" attribute="teletextSubtitleLang" depth="1" /></param> <param name="category"><value source="parent" attribute="category" depth="1" /></param> <param name="dvbRating"><value source="parent" attribute="dvbRating" depth="1" /></param> - <param name="contentIdentType"><value source="parent" attribute="contentIdentType" depth="1" /></param> - <param name="contentIdent"><value source="parent" attribute="contentIdent" depth="1" /></param> + <param name="contentItemID"><value source="parent" attribute="contentItemID" depth="1" /></param> + <param name="contentRecommendation"><value source="parent" attribute="contentRecommendation" depth="1" /></param> + <param name="contentSeriesID"><value source="parent" attribute="contentSeriesID" depth="1" /></param> <param name="startTime"><value source="parent" attribute="startTime" depth="1" /></param> <param name="stopTime"><value source="parent" attribute="stopTime" depth="1" /></param> <param name="eventID"><value source="parent" attribute="eventID" depth="1" /></param> @@ -33,7 +35,6 @@ <column>title</column> <column>titleLang</column> <column>subtitle</column> - <column>subtitleLang</column> <column key="true">serviceID</column> <column key="true">eventID</column> <column>descLang</column> @@ -41,13 +42,16 @@ <column>desc2</column> <column>desc3</column> <column>videoAspect</column> + <column>videoFrameRate</column> + <column>videoHD</column> <column>audioChannels</column> <column>language</column> <column>teletextSubtitleLang</column> <column>category</column> <column>dvbRating</column> - <column>contentIdentType</column> - <column>contentIdent</column> + <column>contentItemID</column> + <column>contentRecommendation</column> + <column>contentSeriesID</column> <column>startTime</column> <column>stopTime</column> </columns> diff --git a/p2pvr/cron/sched.xml b/p2pvr/cron/sched.xml index db438d3..25e37d2 100644 --- a/p2pvr/cron/sched.xml +++ b/p2pvr/cron/sched.xml @@ -1,26 +1,28 @@ <?xml version="1.0"?> <block name="importSchedule" xmlns:p2="http://project2.randomdan.homeip.net"> - <p2:library path="scanner/bin/gcc-4.5.2/debug/libp2pvr-scan-p2.so" /> + <p2:library path="libp2pvr-scan-p2.so" /> <p2:eitrows name="schedule" demux="/dev/dvb/adapter0/demux0" /> <p2:view name="showSchedule" source="schedule" rootname="sched" recordname="show"> <columns> <column name="title">title</column> <column name="titleLang" source="attribute">titleLang</column> <column name="subtitle" source="attribute">subtitle</column> - <column name="subtitleLang" source="attribute">subtitleLang</column> <column name="serviceID" source="attribute">serviceID</column> <column name="descLang" source="attribute">descLang</column> <column name="desc1" source="attribute">desc1</column> <column name="desc2" source="attribute">desc2</column> <column name="desc3" source="attribute">desc3</column> <column name="videoAspect" source="attribute">videoAspect</column> + <column name="videoFrameRate" source="attribute">videoFrameRate</column> + <column name="videoHD" source="attribute">videoHD</column> <column name="audioChannels" source="attribute">audioChannels</column> <column name="language" source="attribute">language</column> <column name="teletextSubtitleLang" source="attribute">teletextSubtitleLang</column> <column name="category" source="attribute">category</column> <column name="dvbRating" source="attribute">dvbRating</column> - <column name="contentIdentType" source="attribute">contentIdentType</column> - <column name="contentIdent" source="attribute">contentIdent</column> + <column name="contentItemID" source="attribute">contentItemID</column> + <column name="contentSeriesID" source="attribute">contentSeriesID</column> + <column name="contentRecommendation" source="attribute">contentRecommendation</column> <column name="startTime" source="attribute">startTime</column> <column name="stopTime" source="attribute">stopTime</column> <column name="serviceID" source="attribute">serviceID</column> diff --git a/p2pvr/scanner/Jamfile.jam b/p2pvr/scanner/Jamfile.jam index 2117886..d784eeb 100644 --- a/p2pvr/scanner/Jamfile.jam +++ b/p2pvr/scanner/Jamfile.jam @@ -4,7 +4,7 @@ project ; # Scanner base - the common part lifted from tv_grab_dvb -lib p2pvr-scan-base : langidents.c crc32.cpp dvb_info_tables.c lookup.cpp ; +lib p2pvr-scan-base : crc32.cpp dvb_info_tables.c lookup.cpp ; # Scanner - the common part implementing the ICE interface lib p2pvr-scan-ice : icescan.cpp scanner.ice : <library>p2pvr-scan-base ; diff --git a/p2pvr/scanner/dvb_info_tables.c b/p2pvr/scanner/dvb_info_tables.c index d8257be..10a687a 100644 --- a/p2pvr/scanner/dvb_info_tables.c +++ b/p2pvr/scanner/dvb_info_tables.c @@ -282,31 +282,3 @@ const struct lookup_table description_table[] = { { {-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/langidents.c b/p2pvr/scanner/langidents.c deleted file mode 100644 index 0165f67..0000000 --- a/p2pvr/scanner/langidents.c +++ /dev/null @@ -1,211 +0,0 @@ -#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/p2scan.cpp b/p2pvr/scanner/p2scan.cpp index cb3e0fc..8fe3578 100644 --- a/p2pvr/scanner/p2scan.cpp +++ b/p2pvr/scanner/p2scan.cpp @@ -23,8 +23,6 @@ * 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 <stdio.h> #include <stdlib.h> #include <unistd.h> @@ -44,6 +42,7 @@ const char *id = "@(#) $Id: tv_grab_dvb.c 86 2010-10-29 20:27:31Z pmhahn $"; #include <assert.h> #include <glibmm.h> #include <boost/bind.hpp> +#include <boost/date_time/gregorian_calendar.hpp> #include <linux/dvb/dmx.h> #include "si_tables.h" @@ -58,19 +57,21 @@ struct EitProgram { VariableType title; VariableType titleLang; VariableType subtitle; - VariableType subtitleLang; VariableType descLang; VariableType desc1; VariableType desc2; VariableType desc3; VariableType videoAspect; + VariableType videoFrameRate; + VariableType videoHD; VariableType audioChannels; VariableType language; VariableType teletextSubtitleLang; VariableType category; VariableType dvbRating; - VariableType contentIdentType; - VariableType contentIdent; + VariableType contentItemID; + VariableType contentSeriesID; + VariableType contentRecommendation; VariableType startTime; VariableType stopTime; }; @@ -118,50 +119,53 @@ class EitRows : public RowSet { returnAttr(title); returnAttr(titleLang); returnAttr(subtitle); - returnAttr(subtitleLang); returnAttr(descLang); returnAttr(desc1); returnAttr(desc2); returnAttr(desc3); returnAttr(videoAspect); + returnAttr(videoFrameRate); + returnAttr(videoHD); returnAttr(audioChannels); returnAttr(language); returnAttr(teletextSubtitleLang); returnAttr(category); returnAttr(dvbRating); - returnAttr(contentIdentType); - returnAttr(contentIdent); + returnAttr(contentItemID); + returnAttr(contentSeriesID); + returnAttr(contentRecommendation); 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 closeInput() 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 parseEventDescription(const u_char *data) const; void parseLongEventDescription(const u_char *data) const; - void parseComponentDescription(const u_char *data, enum CR round, int *seen) const; + void parseComponentDescription(const u_char *data) 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; + VariableType convert(const char * txt, size_t len) const; mutable int fd_epg; mutable EitProgram * current; + static const std::string ISO10646; static const std::string EitEncoding; static const std::string UTF8; }; DECLARE_LOADER("eitrows", EitRows); +const std::string EitRows::ISO10646("ISO-10646"); const std::string EitRows::EitEncoding("ISO6937"); const std::string EitRows::UTF8("UTF8"); @@ -176,26 +180,20 @@ EitRows::EitRows(const xmlpp::Element * p) : EitRows::~EitRows() { + closeInput(); +} +void +EitRows::closeInput() const +{ if (fd_epg) { close(fd_epg); + fd_epg = 0; } } 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) { @@ -208,153 +206,116 @@ int do_options(int arg_count, char **arg_strings) { 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); + 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; } } 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 +VariableType +EitRows::convert(const char * txt, size_t len) const { char enc[20]; - switch ((unsigned char)*txt) { - case 0x20 ... 0xFF: - return Glib::convert(txt, UTF8, EitEncoding); + switch (*txt) { + default: + EitEncoding.copy(enc, EitEncoding.length()); + enc[EitEncoding.length()] = '\0'; + break; case 0x01 ... 0x05: snprintf(enc, sizeof(enc), "ISO-8859-%d\n", txt[0] + 4); - return Glib::convert(txt + 1, UTF8, "ISO-8859-5"); + txt += 1; + len -= 1; + break; case 0x10: snprintf(enc, sizeof(enc), "ISO-8859-%02x%02x\n", txt[1], txt[2]); - return Glib::convert(txt + 3, UTF8, enc); + txt += 3; + len -= 3; + break; case 0x11: - return Glib::convert(txt, UTF8, "ISO-10646"); - case 0x06 ... 0x0F: - case 0x12 ... 0x1F: + ISO10646.copy(enc, ISO10646.length()); + enc[ISO10646.length()] = '\0'; + break; + case 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); + //fprintf(stderr, "%d: %.*s\n", txt[1], len - 2, txt + 2); + case 0x06 ... 0x0F: + case 0x12 ... 0x1E: case 0x00: // empty string - return ""; + return boost::shared_ptr<Glib::ustring>(new Glib::ustring()); + } + size_t used = 0, newlen = 0; + GError * err = NULL; + boost::shared_ptr<gchar> utf8 = boost::shared_ptr<gchar>(g_convert(txt, len, "utf-8", enc, &used, &newlen, &err), g_free); + if (err) { + throw Glib::ConvertError(err); } + return boost::shared_ptr<Glib::ustring>(new Glib::ustring(utf8.get())); } -/* Parse 0x4D Short Event Descriptor. {{{ */ void -EitRows::parseEventDescription(const u_char *data, enum ER round) const { +EitRows::parseEventDescription(const u_char *data) const { assert(GetDescriptorTag(data) == 0x4D); const struct descr_short_event *evtdesc = reinterpret_cast<const struct descr_short_event *>(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 (evtlen) { + current->titleLang = Glib::ustring((const char *)&evtdesc->lang_code1, 3); + current->title = convert((const char *)evtdesc->data, evtlen); } - 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); - } + size_t dsclen = evtdesc->data[evtlen]; + if (dsclen) { + current->subtitle = convert((const char *)evtdesc->data + evtlen + 1, dsclen); } -} /*}}}*/ +} /* 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<const struct descr_extended_event *>(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; + current->descLang = Glib::ustring((const char *)&levt->lang_code1, 3); const u_char *p = reinterpret_cast<const u_char *>(&levt->data); +#ifndef NDEBUG const void *data_end = data + DESCR_GEN_LEN + GetDescriptorLength(data); +#endif while (p < levt->data + levt->length_of_items) { const struct item_extended_event *name = reinterpret_cast<const struct item_extended_event *>(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); + current->desc1 = convert((const char *)name->data, name_len); p += ITEM_EXTENDED_EVENT_LEN + name_len; const struct item_extended_event *value = reinterpret_cast<const struct item_extended_event *>(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); + current->desc2 = convert((const char *)value->data, value_len); p += ITEM_EXTENDED_EVENT_LEN + value_len; } const struct item_extended_event *text = reinterpret_cast<const struct item_extended_event *>(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); + current->desc3 = convert((const char *)text->data, len); } } @@ -366,86 +327,47 @@ EitRows::parseLongEventDescription(const u_char *data) const { 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 { +EitRows::parseComponentDescription(const u_char *data) const { assert(GetDescriptorTag(data) == 0x50); const struct descr_component *dc = reinterpret_cast<const struct descr_component *>(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)++; - } + current->videoHD = ((dc->component_type - 1) & 0x08) ? 1 : 0; + current->videoFrameRate = ((dc->component_type - 1) & 0x04) ? 30 : 25; + current->videoAspect = ((dc->component_type - 1) & 0x03); 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)++; - } + current->audioChannels = dc->component_type; + current->language = Glib::ustring((const char *)&dc->lang_code1, 3); 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); - } + current->teletextSubtitleLang = Glib::ustring((const char *)&dc->lang_code1, 3); 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<const struct descr_content *>(data); - int once[256/8/sizeof(int)] = {0,}; - for (const u_char * p = reinterpret_cast<const u_char*>(&dc->data); p < data + dc->descriptor_length; p += NIBBLE_CONTENT_LEN) { + const struct descr_content * dc = reinterpret_cast<const struct descr_content *>(data); + for (const u_char * p = reinterpret_cast<const u_char*>(&dc->data); p < data + DESCR_GEN_LEN + dc->descriptor_length; p += NIBBLE_CONTENT_LEN) { const struct nibble_content *nc = reinterpret_cast<const nibble_content *>(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 + current->category = c1 ? c1 : (nc->user_nibble_1 << 4) + nc->user_nibble_2; } -} /*}}}*/ +} -/* Parse 0x55 Rating Descriptor. {{{ */ void EitRows::parseRatingDescription(const u_char *data) const { assert(GetDescriptorTag(data) == 0x55); - const struct descr_parental_rating *pr = reinterpret_cast<const struct descr_parental_rating *>(data); - for (const u_char * p = reinterpret_cast<const u_char *>(&pr->data); p < data + pr->descriptor_length; p += PARENTAL_RATING_ITEM_LEN) { + const struct descr_parental_rating * pr = reinterpret_cast<const struct descr_parental_rating *>(data); + for (const u_char * p = reinterpret_cast<const u_char *>(&pr->data); p < data + DESCR_GEN_LEN + pr->descriptor_length; p += PARENTAL_RATING_ITEM_LEN) { const struct parental_rating_item *pr = reinterpret_cast<const struct parental_rating_item *>(p); switch (pr->rating) { case 0x00: /*undefined*/ @@ -457,13 +379,12 @@ EitRows::parseRatingDescription(const u_char *data) const { 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 */ @@ -471,43 +392,33 @@ void EitRows::parseContentIdentifierDescription(const u_char *data) const { assert(GetDescriptorTag(data) == 0x76); const struct descr_content_identifier *ci = reinterpret_cast<const struct descr_content_identifier *>(data); - for (const u_char * p = reinterpret_cast<const u_char *>(&ci->data); p < data + ci->descriptor_length; /* at end */) { + for (const u_char * p = reinterpret_cast<const u_char *>(&ci->data); p < data + DESCR_GEN_LEN + ci->descriptor_length; p += DESCR_GEN_LEN + ci->descriptor_length) { const struct descr_content_identifier_crid *crid = reinterpret_cast<const struct descr_content_identifier_crid *>(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; + case 0x01: /* Carried in Content Identifier Table (CIT) */ + default: + break; + case 0x00: /* Carried explicitly within descriptor */ + struct descr_content_identifier_crid_local * crid_data = (descr_content_identifier_crid_local_t *)&crid->crid_ref_data; + size_t len = crid_data->crid_length; + switch (crid->crid_type) { + case 0x01: + case 0x31: + current->contentItemID = Glib::ustring((const char *)crid_data->crid_byte, len); + break; + case 0x02: + case 0x32: + current->contentSeriesID = Glib::ustring((const char *)crid_data->crid_byte, len); + break; + case 0x03: + case 0x33: + current->contentRecommendation = Glib::ustring((const char *)crid_data->crid_byte, len); + break; + } + break; } - - p += crid_length; } } /*}}}*/ @@ -521,76 +432,57 @@ EitRows::parseContentIdentifierDescription(const u_char *data) const { */ 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<const struct descr_gen *>(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: <programme @vps-start="???"> - break; - case 0x4F: // Time Shifted Event - case 0x52: // Stream Identifier Descriptor - case 0x5E: // Multi Lingual Component Descriptor - case 0x83: // Logical Channel Descriptor (some kind of news-ticker on ARD-MHP-Data?) - case 0x84: // Preferred Name List Descriptor - case 0x85: // Preferred Name Identifier Descriptor - case 0x86: // Eacem Stream Identifier Descriptor - break; - case 0x76: // Content identifier descriptor - if (round == 5) - parseContentIdentifierDescription(p); + int pds = 0; + for (const u_char * p = data; p < data + len; p += DESCR_GEN_LEN + GetDescriptorLength(p)) { + const struct descr_gen *desc = reinterpret_cast<const struct descr_gen *>(p); + switch (GetDescriptorTag(desc)) { + case 0: + break; + case 0x4D: //short evt desc, [title] [sub-title] + // there can be multiple language versions of these + parseEventDescription(p); + break; + case 0x4E: //long evt descriptor [desc] + parseLongEventDescription(p); + break; + case 0x50: //component desc [language] [video] [audio] [subtitles] + parseComponentDescription(p); + break; + case 0x53: // CA Identifier Descriptor + break; + case 0x54: // content desc [category] + parseContentDescription(p); + break; + case 0x55: // Parental Rating Descriptor [rating] + 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; - default: + case 0x82: // VPS (ARD, ZDF, ORF) + if (pds == 5) // ARD_ZDF_ORF + // TODO: <programme @vps-start="???"> break; - } + case 0x4F: // Time Shifted Event + case 0x52: // Stream Identifier Descriptor + case 0x5E: // Multi Lingual Component Descriptor + case 0x83: // Logical Channel Descriptor (some kind of news-ticker on ARD-MHP-Data?) + case 0x84: // Preferred Name List Descriptor + case 0x85: // Preferred Name Identifier Descriptor + case 0x86: // Eacem Stream Identifier Descriptor + break; + case 0x76: // Content identifier descriptor + parseContentIdentifierDescription(p); + break; + default: + break; } } } /*}}}*/ @@ -608,20 +500,26 @@ static bool validateDescription(const u_char *data, size_t len) { 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)); -} /*}}}*/ +class SeenProgram { + public: + SeenProgram(int sid, int eid); + bool operator<(const SeenProgram &) const; + const int sid; + const int eid; +}; +SeenProgram::SeenProgram(int s, int e) : + sid(s), + eid(e) +{ +} +bool +SeenProgram::operator<(const SeenProgram & o) const +{ + return ((this->sid < o.sid) || ((this->sid == o.sid) && (this->eid < o.eid))); +} +typedef std::set<SeenProgram> SeenPrograms; +SeenPrograms seenPrograms; bool EitRows::parseEIT(const u_char *data, size_t len, const RowProcessor * rp) const { const struct eit *e = reinterpret_cast<const struct eit *>(data); @@ -632,41 +530,23 @@ EitRows::parseEIT(const u_char *data, size_t len, const RowProcessor * rp) const bool found = false; for (const u_char *p = reinterpret_cast<const u_char *>(&e->data); p < data + len; p += EIT_EVENT_LEN + GetEITDescriptorsLoopLength(p)) { const struct eit_event *evt = reinterpret_cast<const struct eit_event *>(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<struct chninfo *>(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; + SeenProgram sp(HILO(e->service_id), HILO(evt->event_id)); + if (seenPrograms.find(sp) != seenPrograms.end()) { + continue; } + seenPrograms.insert(sp); // No program info at end! Just skip it - if (GetEITDescriptorsLoopLength(evt) == 0) - return false; + if (GetEITDescriptorsLoopLength(evt) == 0) { + continue; + } - 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)); + boost::gregorian::date startDate(boost::gregorian::gregorian_calendar::from_modjulian_day_number(HILO(evt->mjd))); + boost::posix_time::ptime startTime(startDate); + startTime += 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; @@ -677,24 +557,23 @@ EitRows::parseEIT(const u_char *data, size_t len, const RowProcessor * rp) const // a program must have a title that isn't empty if (!validateDescription(reinterpret_cast<const u_char *>(&evt->data), GetEITDescriptorsLoopLength(evt))) { - return false; + continue; } 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<const u_char *>(&evt->data), GetEITDescriptorsLoopLength(evt)); - rowNum += 1; rp->rowReady(); + rowNum += 1; found = true; } return found; } SimpleMessageException(ErrorReadingData); +SimpleMessageException(TimeoutReadingData); void EitRows::readEventTables(const RowProcessor * rp) const { @@ -704,8 +583,9 @@ EitRows::readEventTables(const RowProcessor * rp) const 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)))) { + int prtn = 0; + time_t lastuseful = time(NULL); + while (((prtn = poll(&ufd, 1, 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; @@ -723,6 +603,9 @@ EitRows::readEventTables(const RowProcessor * rp) const } } } + if (prtn < 1) { + throw TimeoutReadingData("Tuned to a multiplex?"); + } } SimpleMessageException(DemuxOpenFailure); @@ -753,9 +636,6 @@ EitRows::execute(const RowProcessor * rp) const { openInput(); readEventTables(rp); - if (rowNum < 10) { - } - close(fd_epg); - fd_epg = 0; + closeInput(); } |