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): | 
