summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2011-03-18 16:12:36 +0000
committerrandomdan <randomdan@localhost>2011-03-18 16:12:36 +0000
commit0c6a0665bfb78989c463c80d7371b63c832b0f3c (patch)
tree89670dc7b1415b23fa51e45c38cbe152966a936b
parentWork to date on p2pvr - basic EIT scanner (diff)
downloadp2pvr-0c6a0665bfb78989c463c80d7371b63c832b0f3c.tar.bz2
p2pvr-0c6a0665bfb78989c463c80d7371b63c832b0f3c.tar.xz
p2pvr-0c6a0665bfb78989c463c80d7371b63c832b0f3c.zip
Second round of tweaks, fixes and XMLTV stripping
-rw-r--r--p2pvr/Jamfile.jam1
-rw-r--r--p2pvr/cron/importSchedume.xml18
-rw-r--r--p2pvr/cron/sched.xml10
-rw-r--r--p2pvr/scanner/Jamfile.jam2
-rw-r--r--p2pvr/scanner/dvb_info_tables.c28
-rw-r--r--p2pvr/scanner/langidents.c211
-rw-r--r--p2pvr/scanner/p2scan.cpp530
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();
}