summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrandomdan <randomdan@localhost>2011-03-21 20:26:06 +0000
committerrandomdan <randomdan@localhost>2011-03-21 20:26:06 +0000
commit24fe5eba106b6e7a36fd784323b76b350cc6b726 (patch)
tree39af1891db0657e5c3c8f792200e3de2e781a148
parentSplit into DVB SI Base reader for any SI table type (diff)
downloadp2pvr-24fe5eba106b6e7a36fd784323b76b350cc6b726.tar.bz2
p2pvr-24fe5eba106b6e7a36fd784323b76b350cc6b726.tar.xz
p2pvr-24fe5eba106b6e7a36fd784323b76b350cc6b726.zip
Tweaks to make things more generic
Add a service scanning module
-rw-r--r--p2pvr/cron/importServices.xml28
-rw-r--r--p2pvr/cron/serv.xml16
-rw-r--r--p2pvr/scanner/Jamfile.jam2
-rw-r--r--p2pvr/scanner/dvbSiReaderHelper.cpp7
-rw-r--r--p2pvr/scanner/dvbSiReaderHelper.h2
-rw-r--r--p2pvr/scanner/eitRows.cpp6
-rw-r--r--p2pvr/scanner/eitRows.h6
-rw-r--r--p2pvr/scanner/serviceRows.cpp182
-rw-r--r--p2pvr/scanner/serviceRows.h37
-rw-r--r--p2pvr/scanner/si_tables.h42
10 files changed, 317 insertions, 11 deletions
diff --git a/p2pvr/cron/importServices.xml b/p2pvr/cron/importServices.xml
new file mode 100644
index 0000000..d7b3a8b
--- /dev/null
+++ b/p2pvr/cron/importServices.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<block name="importServices" xmlns:p2="http://project2.randomdan.homeip.net">
+ <p2:library path="libp2pvr-scan-p2.so" />
+ <p2:servicerows name="services" demux="/dev/dvb/adapter0/demux0" />
+ <p2:sqlmerge name="mergeServices" datasource="postgres" targettable="services">
+ <p2:iterate name="programs" source="services">
+ <p2:sqlmergeinsert name="insertProgram">
+ <parameters>
+ <param name="serviceID"><value source="parent" attribute="serviceID" depth="1" /></param>
+ <param name="name"><value source="parent" attribute="name" depth="1" /></param>
+ <param name="providerName"><value source="parent" attribute="providerName" depth="1" /></param>
+ <param name="transportID"><value source="parent" attribute="transportID" depth="1" /></param>
+ <param name="type"><value source="parent" attribute="type" depth="1" /></param>
+ <param name="defaultAuthority"><value source="parent" attribute="defaultAuthority" depth="1" /></param>
+ </parameters>
+ </p2:sqlmergeinsert>
+ </p2:iterate>
+ <columns>
+ <column key="true">serviceID</column>
+ <column>name</column>
+ <column>providerName</column>
+ <column>transportID</column>
+ <column>type</column>
+ <column>defaultAuthority</column>
+ </columns>
+ </p2:sqlmerge>
+</block>
+
diff --git a/p2pvr/cron/serv.xml b/p2pvr/cron/serv.xml
new file mode 100644
index 0000000..1cc209e
--- /dev/null
+++ b/p2pvr/cron/serv.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<block name="showServices" xmlns:p2="http://project2.randomdan.homeip.net">
+ <p2:library path="libp2pvr-scan-p2.so" />
+ <p2:servicerows name="services" demux="/dev/dvb/adapter0/demux0" />
+ <p2:view name="showServices" source="services" rootname="services" recordname="service">
+ <columns>
+ <column name="serviceID" source="attribute">serviceID</column>
+ <column name="name">name</column>
+ <column name="providerName" source="attribute">providerName</column>
+ <column name="defaultAuthority" source="attribute">defaultAuthority</column>
+ <column name="transportID" source="attribute">transportID</column>
+ <column name="type" source="attribute">type</column>
+ </columns>
+ </p2:view>
+</block>
+
diff --git a/p2pvr/scanner/Jamfile.jam b/p2pvr/scanner/Jamfile.jam
index 7288b23..fca4615 100644
--- a/p2pvr/scanner/Jamfile.jam
+++ b/p2pvr/scanner/Jamfile.jam
@@ -7,7 +7,7 @@ project
lib p2pvr-scan-ice : icescan.cpp scanner.ice : <library>p2pvr-scan-p2 ;
# Scanner - t
-lib p2pvr-scan-p2 : eitRows.cpp dvbSiReaderHelper.cpp : <library>../../project2//p2common ;
+lib p2pvr-scan-p2 : eitRows.cpp serviceRows.cpp dvbSiReaderHelper.cpp : <library>../../project2//p2common ;
# ScannerICE - the ICE test app
#exe scanice : ice_scan.cpp : <library>p2pvr-scan ;
diff --git a/p2pvr/scanner/dvbSiReaderHelper.cpp b/p2pvr/scanner/dvbSiReaderHelper.cpp
index 015a60c..a464520 100644
--- a/p2pvr/scanner/dvbSiReaderHelper.cpp
+++ b/p2pvr/scanner/dvbSiReaderHelper.cpp
@@ -49,6 +49,9 @@ DvbSiReaderHelper::closeInput() const
VariableType
DvbSiReaderHelper::convert(const char * txt, size_t len)
{
+ if (len == 0) {
+ return boost::shared_ptr<Glib::ustring>(new Glib::ustring());
+ }
char enc[20];
switch (*txt) {
default:
@@ -114,11 +117,11 @@ DvbSiReaderHelper::readTables(const RowProcessor * rp) const
if (n < l)
throw ErrorReadingData("Smaller that section length");
if (_dvb_crc32(buf, l)) {
- if (parseSIT(buf, l, rp)) {
+ if (parseInfoTable(buf, l, rp)) {
time(&lastuseful);
}
else {
- if (lastuseful < time(NULL) - 5) {
+ if (lastuseful < time(NULL) - 15) {
break;
}
}
diff --git a/p2pvr/scanner/dvbSiReaderHelper.h b/p2pvr/scanner/dvbSiReaderHelper.h
index 325bc66..1efb461 100644
--- a/p2pvr/scanner/dvbSiReaderHelper.h
+++ b/p2pvr/scanner/dvbSiReaderHelper.h
@@ -18,7 +18,7 @@ class DvbSiReaderHelper {
void openInput() const;
virtual void filterInput(int fd) const = 0;
void readTables(const RowProcessor *) const;
- virtual bool parseSIT(const u_char *data, size_t len, const RowProcessor *) const = 0;
+ virtual bool parseInfoTable(const u_char *data, size_t len, const RowProcessor *) const = 0;
void closeInput() const;
static VariableType convert(const char * txt, size_t len);
diff --git a/p2pvr/scanner/eitRows.cpp b/p2pvr/scanner/eitRows.cpp
index aea639f..bdc46f0 100644
--- a/p2pvr/scanner/eitRows.cpp
+++ b/p2pvr/scanner/eitRows.cpp
@@ -65,7 +65,7 @@ struct EitProgram {
VariableType stopTime;
};
-Glib::ustring title("title");
+static Glib::ustring title("title");
template <class C, class M>
const M &
getMember(M C::*t, C * p) {
@@ -414,7 +414,7 @@ SeenProgram::operator<(const SeenProgram & o) const
typedef std::set<SeenProgram> SeenPrograms;
SeenPrograms seenPrograms;
bool
-EitRows::parseSIT(const u_char *data, size_t len, const RowProcessor * rp) const {
+EitRows::parseInfoTable(const u_char *data, size_t len, const RowProcessor * rp) const {
const struct eit *e = reinterpret_cast<const struct eit *>(data);
len -= 4; //remove CRC
@@ -472,7 +472,7 @@ EitRows::filterInput(int fd) const
{
struct dmx_sct_filter_params sctFilterParams;
memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params));
- sctFilterParams.pid = 18; // EIT data
+ sctFilterParams.pid = 0x12; // EIT data
sctFilterParams.timeout = 0;
sctFilterParams.flags = DMX_IMMEDIATE_START;
sctFilterParams.filter.filter[0] = chan_filter; // 4e is now/next this multiplex, 4f others
diff --git a/p2pvr/scanner/eitRows.h b/p2pvr/scanner/eitRows.h
index 9078b53..255f52b 100644
--- a/p2pvr/scanner/eitRows.h
+++ b/p2pvr/scanner/eitRows.h
@@ -1,5 +1,5 @@
-#ifndef P2SCAN_H
-#define P2SCAN_H
+#ifndef EITROWS_H
+#define EITROWS_H
#include "xmlObjectLoader.h"
#include "rowSet.h"
@@ -26,7 +26,7 @@ class EitRows : public RowSet, DvbSiReaderHelper {
private:
void filterInput(int fd) const;
- bool parseSIT(const u_char *data, size_t len, const RowProcessor *) const;
+ bool parseInfoTable(const u_char *data, size_t len, const RowProcessor *) const;
void parseEventDescription(const u_char *data) const;
void parseLongEventDescription(const u_char *data) const;
void parseComponentDescription(const u_char *data) const;
diff --git a/p2pvr/scanner/serviceRows.cpp b/p2pvr/scanner/serviceRows.cpp
new file mode 100644
index 0000000..474d1e5
--- /dev/null
+++ b/p2pvr/scanner/serviceRows.cpp
@@ -0,0 +1,182 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <stdint.h>
+#include <time.h>
+#include <boost/bind.hpp>
+#include <boost/date_time/gregorian_calendar.hpp>
+
+#include <linux/dvb/dmx.h>
+#include "si_tables.h"
+
+#include "rowProcessor.h"
+#include "serviceRows.h"
+
+class Service {
+ public:
+ VariableType serviceID;
+ VariableType name;
+ VariableType type;
+ VariableType providerName;
+ VariableType defaultAuthority;
+ VariableType transportID;
+};
+void
+ServiceRows::loadComplete(const CommonObjects *)
+{
+}
+
+void
+ServiceRows::setFilter(const Glib::ustring &)
+{
+}
+
+unsigned int
+ServiceRows::columnCount() const
+{
+ return 1;
+}
+
+static Glib::ustring name("name");
+const Glib::ustring &
+ServiceRows::getColumnName(unsigned int) const {
+ return ::name;
+}
+
+VariableType
+ServiceRows::getCurrentValue(const Glib::ustring &) const {
+ return current->name;
+}
+
+VariableType
+ServiceRows::getCurrentValue(unsigned int) const {
+ return current->name;
+}
+
+bool
+ServiceRows::isNull(unsigned int ) const {
+ return false;
+}
+
+bool
+ServiceRows::isNull(const Glib::ustring & ) const {
+ return false;
+}
+
+SimpleMessageException(NoSuchAttribute);
+template <class C, class M>
+const M &
+getMember(M C::*t, C * p) {
+ return p->*t;
+}
+#define returnAttr(name) if (attrName == #name) return boost::bind(getMember<Service, VariableType>, &Service::name, boost::ref(current))
+RowSet::RowAttribute
+ServiceRows::resolveAttr(const Glib::ustring & attrName) const {
+ returnAttr(serviceID);
+ returnAttr(name);
+ returnAttr(type);
+ returnAttr(providerName);
+ returnAttr(defaultAuthority);
+ returnAttr(transportID);
+ throw NoSuchAttribute(attrName);
+}
+
+DECLARE_LOADER("servicerows", ServiceRows);
+
+ServiceRows::ServiceRows(const xmlpp::Element * e) :
+ RowSet(e),
+ DvbSiReaderHelper(e)
+{
+}
+
+ServiceRows::~ServiceRows()
+{
+}
+
+SimpleMessageException(DemuxSetFilterFailure);
+
+void
+ServiceRows::filterInput(int fd) const
+{
+ struct dmx_sct_filter_params sctFilterParams;
+ memset(&sctFilterParams, 0, sizeof(dmx_sct_filter_params));
+ sctFilterParams.pid = 0x11; // Service data
+ sctFilterParams.timeout = 0;
+ sctFilterParams.flags = DMX_IMMEDIATE_START;
+
+ if (ioctl(fd, DMX_SET_FILTER, &sctFilterParams) < 0) {
+ throw DemuxSetFilterFailure(strerror(errno));
+ }
+}
+
+void
+ServiceRows::execute(const RowProcessor * rp) const
+{
+ openInput();
+ readTables(rp);
+ closeInput();
+}
+
+typedef std::set<int> SeenServices;
+SeenServices seenServices;
+bool
+ServiceRows::parseInfoTable(const u_char * data, size_t len, const RowProcessor * rp) const {
+ const struct sit *e = reinterpret_cast<const struct sit *>(data);
+ assert(e->tableid == 0x42 || e->tableid == 0x46);
+ len -= 4; //remove CRC
+
+ // For each event listing
+ bool found = false;
+ for (const u_char * p = e->serviceData; p < data + len; ) {
+ const struct si * sid = reinterpret_cast<const struct si *>(p);
+ int sID = be16toh(sid->serviceid);
+ bool seen = (seenServices.find(sID) != seenServices.end());
+ size_t dll = HILO(sid->desc_loop_len);
+ Service serv;
+ for (p = sid->descData; p < sid->descData + dll; p += DESCR_GEN_LEN + GetDescriptorLength(p)) {
+ if (!seen) {
+ current = &serv;
+ serv.serviceID = sID;
+ serv.transportID = be16toh(e->transport_stream_id);
+ const struct descr_gen *desc = reinterpret_cast<const struct descr_gen *>(p);
+ switch (GetDescriptorTag(desc)) {
+ case 0x48: // Service descriptor
+ parseServiceDescriptor(p, GetDescriptorLength(desc));
+ break;
+ case 0x73: // Service authority descriptor
+ parseServiceAuthDescriptor(p, GetDescriptorLength(desc));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ if (!seen) {
+ seenServices.insert(sID);
+ rp->rowReady();
+ rowNum += 1;
+ found = true;
+ }
+ }
+ return found;
+}
+
+void
+ServiceRows::parseServiceDescriptor(const u_char * p, size_t) const
+{
+ current->type = p[2];
+ if (p[3]) {
+ current->providerName = convert((const char *)(p + 4), p[3]);
+ }
+ current->name = convert((const char *)(p + 5 + p[3]), p[4 + p[3]]);
+}
+
+void
+ServiceRows::parseServiceAuthDescriptor(const u_char * p, size_t len) const
+{
+ current->defaultAuthority = convert((const char *)(p + 2), len);
+}
+
diff --git a/p2pvr/scanner/serviceRows.h b/p2pvr/scanner/serviceRows.h
new file mode 100644
index 0000000..0a048a0
--- /dev/null
+++ b/p2pvr/scanner/serviceRows.h
@@ -0,0 +1,37 @@
+#ifndef SERVICEROWS_H
+#define SERVICEROWS_H
+
+#include "xmlObjectLoader.h"
+#include "rowSet.h"
+#include "variables.h"
+#include "dvbSiReaderHelper.h"
+
+class Service;
+
+class ServiceRows : public RowSet, DvbSiReaderHelper {
+ public:
+ ServiceRows(const xmlpp::Element * p);
+ ~ServiceRows();
+
+ void execute(const RowProcessor *) const;
+ void loadComplete(const CommonObjects *);
+ void setFilter(const Glib::ustring &);
+ unsigned int columnCount() const;
+ const Glib::ustring & getColumnName(unsigned int) const;
+ VariableType getCurrentValue(const Glib::ustring &) const;
+ VariableType getCurrentValue(unsigned int) const;
+ bool isNull(unsigned int ) const;
+ bool isNull(const Glib::ustring & ) const;
+ RowAttribute resolveAttr(const Glib::ustring & attrName) const;
+
+ private:
+ void filterInput(int fd) const;
+ bool parseInfoTable(const u_char *data, size_t len, const RowProcessor *) const;
+ void parseServiceDescriptor(const u_char *data, size_t len) const;
+ void parseServiceAuthDescriptor(const u_char *data, size_t len) const;
+
+ mutable Service * current;
+};
+
+#endif
+
diff --git a/p2pvr/scanner/si_tables.h b/p2pvr/scanner/si_tables.h
index ce3b972..3721db4 100644
--- a/p2pvr/scanner/si_tables.h
+++ b/p2pvr/scanner/si_tables.h
@@ -577,7 +577,47 @@ typedef struct tot {
* streams in the partial bitstream.
*
*/
- /* TO BE DONE */
+struct sit {
+ uint8_t tableid;
+#if BYTE_ORDER == BIG_ENDIAN
+ uint8_t section_length_hi : 4;
+ bool reserved1 : 2;
+ bool reserved_fu : 1;
+ bool section_syntax : 1;
+#else
+ bool section_syntax : 1;
+ bool reserved_fu : 1;
+ bool reserved1 : 2;
+ uint8_t section_length_hi : 4;
+#endif
+ uint8_t section_length_lo;
+ uint16_t transport_stream_id ;
+ bool reserved2 : 2;
+ uint8_t version : 5;
+ bool current_next_ind : 1;
+ uint8_t section_number;
+ uint8_t last_section_number;
+ uint16_t original_network_id;
+ uint8_t reserved3;
+ u_char serviceData[];
+} __attribute__((packed));
+struct si {
+ uint16_t serviceid;
+ uint8_t reserved_fu : 6;
+ bool eit_sched : 1;
+ bool eit_now_and_next : 1;
+#if BYTE_ORDER == BIG_ENDIAN
+ uint8_t running_status : 3;
+ bool free_ca_mode : 1;
+ uint8_t desc_loop_len_hi : 4;
+#else
+ uint8_t desc_loop_len_hi : 4;
+ bool free_ca_mode : 1;
+ uint8_t running_status : 3;
+#endif
+ uint8_t desc_loop_len_lo;
+ u_char descData[];
+} __attribute__((packed));
/*
*
* 9) Discontinuity Information Table (DIT):