diff options
-rw-r--r-- | p2pvr/cron/importServices.xml | 28 | ||||
-rw-r--r-- | p2pvr/cron/serv.xml | 16 | ||||
-rw-r--r-- | p2pvr/scanner/Jamfile.jam | 2 | ||||
-rw-r--r-- | p2pvr/scanner/dvbSiReaderHelper.cpp | 7 | ||||
-rw-r--r-- | p2pvr/scanner/dvbSiReaderHelper.h | 2 | ||||
-rw-r--r-- | p2pvr/scanner/eitRows.cpp | 6 | ||||
-rw-r--r-- | p2pvr/scanner/eitRows.h | 6 | ||||
-rw-r--r-- | p2pvr/scanner/serviceRows.cpp | 182 | ||||
-rw-r--r-- | p2pvr/scanner/serviceRows.h | 37 | ||||
-rw-r--r-- | p2pvr/scanner/si_tables.h | 42 |
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): |