#include <string>
#include <lib/service/servicedvb.h>
#include <lib/service/service.h>
+#include <lib/base/estring.h>
#include <lib/base/init_num.h>
#include <lib/base/init.h>
-#include <lib/base/nconfig.h> // access to python config
#include <lib/dvb/dvb.h>
#include <lib/dvb/db.h>
#include <lib/dvb/decoder.h>
#include <lib/dvb/metaparser.h>
#include <lib/dvb/tstools.h>
#include <lib/python/python.h>
+#include <lib/base/nconfig.h> // access to python config
/* for subtitles */
#include <lib/gui/esubtitle.h>
#include <sys/vfs.h>
+#include <sys/stat.h>
#include <byteswap.h>
#include <netinet/in.h>
-#define INTERNAL_TELETEXT
-
#ifndef BYTE_ORDER
#error no byte order defined!
#endif
-#define TSPATH "/media/hdd"
-
class eStaticServiceDVBInformation: public iStaticServiceInformation
{
DECLARE_REF(eStaticServiceDVBInformation);
public:
RESULT getName(const eServiceReference &ref, std::string &name);
int getLength(const eServiceReference &ref);
+ int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
+ PyObject *getInfoObject(const eServiceReference &ref, int);
};
DEFINE_REF(eStaticServiceDVBInformation);
if (!service_center->info(parent, service_info))
{
if (!service_info->getName(parent, name))
- {
- // just show short name
- unsigned int pos = name.find("\xc2\x86");
- if ( pos != std::string::npos )
- name.erase(0, pos+2);
- pos = name.find("\xc2\x87");
- if ( pos != std::string::npos )
- name.erase(pos);
- name+=" - ";
- }
+ name=buildShortName(name) + " - ";
}
}
}
return -1;
}
-class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
+int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
{
- DECLARE_REF(eStaticServiceDVBBouquetInformation);
-public:
- RESULT getName(const eServiceReference &ref, std::string &name);
- int getLength(const eServiceReference &ref);
-};
+ ePtr<eDVBResourceManager> res_mgr;
+ if ( eDVBResourceManager::getInstance( res_mgr ) )
+ eDebug("isPlayable... no res manager!!");
+ else
+ {
+ eDVBChannelID chid, chid_ignore;
+ ((const eServiceReferenceDVB&)ref).getChannelID(chid);
+ ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
+ return res_mgr->canAllocateChannel(chid, chid_ignore);
+ }
+ return false;
+}
+
+extern void PutToDict(ePyObject &dict, const char*key, long value); // defined in dvb/frontend.cpp
+extern void PutToDict(ePyObject &dict, const char*key, ePyObject item); // defined in dvb/frontend.cpp
+extern void PutToDict(ePyObject &dict, const char*key, const char *value); // defined in dvb/frontend.cpp
+
+void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm)
+{
+ PutToDict(dict, "tuner_type", "DVB-S");
+ PutToDict(dict, "frequency", feparm.frequency);
+ PutToDict(dict, "symbol_rate", feparm.symbol_rate);
+ PutToDict(dict, "orbital_position", feparm.orbital_position);
+ PutToDict(dict, "inversion", feparm.inversion);
+ PutToDict(dict, "fec_inner", feparm.fec);
+ PutToDict(dict, "modulation", feparm.modulation);
+ PutToDict(dict, "polarization", feparm.polarisation);
+ if (feparm.system == eDVBFrontendParametersSatellite::System_DVB_S2)
+ {
+ PutToDict(dict, "rolloff", feparm.rolloff);
+ PutToDict(dict, "pilot", feparm.pilot);
+ }
+ PutToDict(dict, "system", feparm.system);
+}
+
+void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm)
+{
+ PutToDict(dict, "tuner_type", "DVB-T");
+ PutToDict(dict, "frequency", feparm.frequency);
+ PutToDict(dict, "bandwidth", feparm.bandwidth);
+ PutToDict(dict, "code_rate_lp", feparm.code_rate_LP);
+ PutToDict(dict, "code_rate_hp", feparm.code_rate_HP);
+ PutToDict(dict, "constellation", feparm.modulation);
+ PutToDict(dict, "transmission_mode", feparm.transmission_mode);
+ PutToDict(dict, "guard_interval", feparm.guard_interval);
+ PutToDict(dict, "hierarchy_information", feparm.hierarchy);
+ PutToDict(dict, "inversion", feparm.inversion);
+}
+
+void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm)
+{
+ PutToDict(dict, "tuner_type", "DVB-C");
+ PutToDict(dict, "frequency", feparm.frequency);
+ PutToDict(dict, "symbol_rate", feparm.symbol_rate);
+ PutToDict(dict, "modulation", feparm.modulation);
+ PutToDict(dict, "inversion", feparm.inversion);
+ PutToDict(dict, "fec_inner", feparm.fec_inner);
+}
+
+PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
+{
+ if (r.type == eServiceReference::idDVB)
+ {
+ const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)r;
+ switch(what)
+ {
+ case iServiceInformation::sTransponderData:
+ {
+ ePtr<eDVBResourceManager> res;
+ if (!eDVBResourceManager::getInstance(res))
+ {
+ ePtr<iDVBChannelList> db;
+ if (!res->getChannelList(db))
+ {
+ eDVBChannelID chid;
+ ref.getChannelID(chid);
+ ePtr<iDVBFrontendParameters> feparm;
+ if (!db->getChannelFrontendData(chid, feparm))
+ {
+ int system;
+ if (!feparm->getSystem(system))
+ {
+ ePyObject dict = PyDict_New();
+ switch(system)
+ {
+ case iDVBFrontend::feSatellite:
+ {
+ eDVBFrontendParametersSatellite s;
+ feparm->getDVBS(s);
+ PutSatelliteDataToDict(dict, s);
+ break;
+ }
+ case iDVBFrontend::feTerrestrial:
+ {
+ eDVBFrontendParametersTerrestrial t;
+ feparm->getDVBT(t);
+ PutTerrestrialDataToDict(dict, t);
+ break;
+ }
+ case iDVBFrontend::feCable:
+ {
+ eDVBFrontendParametersCable c;
+ feparm->getDVBC(c);
+ PutCableDataToDict(dict, c);
+ break;
+ }
+ default:
+ eDebug("unknown frontend type %d", system);
+ Py_DECREF(dict);
+ break;
+ }
+ return dict;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Py_RETURN_NONE;
+}
DEFINE_REF(eStaticServiceDVBBouquetInformation);
return -1;
}
+int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate)
+{
+ if (ref.flags & eServiceReference::isGroup)
+ {
+ ePtr<iDVBChannelList> db;
+ ePtr<eDVBResourceManager> res;
+
+ if (eDVBResourceManager::getInstance(res))
+ {
+ eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no resource manager!");
+ return 0;
+ }
+
+ if (res->getChannelList(db))
+ {
+ eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no channel list!");
+ return 0;
+ }
+
+ eBouquet *bouquet=0;
+ if (db->getBouquet(ref, bouquet))
+ {
+ eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. getBouquet failed!");
+ return 0;
+ }
+
+ int prio_order = eDVBFrontend::getTypePriorityOrder();
+ int cur=0;
+ eDVBChannelID chid, chid_ignore;
+ ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
+ for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
+ {
+ static unsigned char prio_map[6][3] = {
+ { 3, 2, 1 }, // -S -C -T
+ { 3, 1, 2 }, // -S -T -C
+ { 2, 3, 1 }, // -C -S -T
+ { 1, 3, 2 }, // -C -T -S
+ { 1, 2, 3 }, // -T -C -S
+ { 2, 1, 3 } // -T -S -C
+ };
+ ((const eServiceReferenceDVB&)*it).getChannelID(chid);
+ int tmp=res->canAllocateChannel(chid, chid_ignore, simulate);
+ switch(tmp)
+ {
+ case 0:
+ break;
+ case 30000: // cached DVB-T channel
+ case 1: // DVB-T frontend
+ tmp = prio_map[prio_order][2];
+ break;
+ case 40000: // cached DVB-C channel
+ case 2:
+ tmp = prio_map[prio_order][1];
+ break;
+ default: // DVB-S
+ tmp = prio_map[prio_order][0];
+ break;
+ }
+ if (tmp > cur)
+ {
+ m_playable_service = *it;
+ cur = tmp;
+ }
+ }
+ if (cur)
+ return cur;
+ }
+ m_playable_service = eServiceReference();
+ return 0;
+}
+
int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
{
return -1;
}
+#include <lib/dvb/epgcache.h>
+
+RESULT eStaticServiceDVBBouquetInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
+{
+ return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
+}
+
class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
{
DECLARE_REF(eStaticServiceDVBPVRInformation);
RESULT getName(const eServiceReference &ref, std::string &name);
int getLength(const eServiceReference &ref);
RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
-
+ int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
int getInfo(const eServiceReference &ref, int w);
std::string getInfoString(const eServiceReference &ref,int w);
+ PyObject *getInfoObject(const eServiceReference &r, int what);
};
DEFINE_REF(eStaticServiceDVBPVRInformation);
RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
{
ASSERT(ref == m_ref);
- name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
+ if (m_parser.m_name.size())
+ name = m_parser.m_name;
+ else
+ {
+ name = ref.path;
+ size_t n = name.rfind('/');
+ if (n != std::string::npos)
+ name = name.substr(n + 1);
+ }
return 0;
}
eDVBTSTools tstools;
+ struct stat s;
+ stat(ref.path.c_str(), &s);
+
+ if (tstools.openFile(ref.path.c_str(), 1))
+ return 0;
+
+ /* check if cached data is still valid */
+ if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
+ return m_parser.m_length / 90000;
+
+ /* open again, this time with stream info */
if (tstools.openFile(ref.path.c_str()))
return 0;
+ /* otherwise, re-calc length and update meta file */
pts_t len;
if (tstools.calcLen(len))
return 0;
- return len / 90000;
+ m_parser.m_length = len;
+ m_parser.m_filesize = s.st_size;
+ m_parser.updateMeta(ref.path);
+ return m_parser.m_length / 90000;
}
int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
return iServiceInformation::resIsString;
case iServiceInformation::sServiceref:
return iServiceInformation::resIsString;
+ case iServiceInformation::sFileSize:
+ return m_parser.m_filesize;
case iServiceInformation::sTimeCreate:
if (m_parser.m_time_create)
return m_parser.m_time_create;
return m_parser.m_description;
case iServiceInformation::sServiceref:
return m_parser.m_ref.toString();
+ case iServiceInformation::sTags:
+ return m_parser.m_tags;
default:
return "";
}
}
+PyObject *eStaticServiceDVBPVRInformation::getInfoObject(const eServiceReference &r, int what)
+{
+ switch (what)
+ {
+ case iServiceInformation::sFileSize:
+ return PyLong_FromLongLong(m_parser.m_filesize);
+ default:
+ Py_RETURN_NONE;
+ }
+}
+
RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
{
if (!ref.path.empty())
res.push_back(m_ref.path + ".meta");
res.push_back(m_ref.path + ".ap");
+ res.push_back(m_ref.path + ".sc");
res.push_back(m_ref.path + ".cuts");
std::string tmp = m_ref.path;
tmp.erase(m_ref.path.length()-3);
eServiceCenter::getPrivInstance(sc);
if (sc)
- sc->addServiceFactory(eServiceFactoryDVB::id, this);
+ {
+ std::list<std::string> extensions;
+ extensions.push_back("ts");
+ extensions.push_back("trp");
+ sc->addServiceFactory(eServiceFactoryDVB::id, this, extensions);
+ }
+
+ m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
+ m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
}
eServiceFactoryDVB::~eServiceFactoryDVB()
if (!m_query)
return -1;
-
+
while (!m_query->getNextResult(ref))
list.push_back(ref);
// useable format options are
// R = Service Reference (as swig object .. this is very slow)
// S = Service Reference (as python string object .. same as ref.toString())
+// C = Service Reference (as python string object .. same as ref.toCompareString())
// N = Service Name (as python string object)
+// n = Short Service Name (short name brakets used) (as python string object)
// when exactly one return value per service is selected in the format string,
// then each value is directly a list entry
// when more than one value is returned per service, then the list is a list of
// unknown format string chars are returned as python None values !
PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
{
- PyObject *ret=0;
+ ePyObject ret;
std::list<eServiceReference> tmplist;
int retcount=1;
ePtr<iStaticServiceInformation> sptr;
eServiceCenterPtr service_center;
- if (strchr(format, 'N'))
+ if (strchr(format, 'N') || strchr(format, 'n'))
eServiceCenter::getPrivInstance(service_center);
ret = PyList_New(services);
for (int cnt=0; cnt < services; ++cnt)
{
eServiceReference &ref=*it++;
- PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
+ ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
for (int i=0; i < retcount; ++i)
{
- PyObject *tmp=0;
+ ePyObject tmp;
switch(format[i])
{
case 'R': // service reference (swig)object
- tmp = New_eServiceReference(ref);
+ tmp = NEW_eServiceReference(ref);
+ break;
+ case 'C': // service reference compare string
+ tmp = PyString_FromString(ref.toCompareString().c_str());
break;
case 'S': // service reference string
tmp = PyString_FromString(ref.toString().c_str());
{
std::string name;
sptr->getName(ref, name);
+
+ // filter short name brakets
+ size_t pos;
+ while((pos = name.find("\xc2\x86")) != std::string::npos)
+ name.erase(pos,2);
+ while((pos = name.find("\xc2\x87")) != std::string::npos)
+ name.erase(pos,2);
+
+ if (name.length())
+ tmp = PyString_FromString(name.c_str());
+ }
+ }
+ if (!tmp)
+ tmp = PyString_FromString("<n/a>");
+ break;
+ case 'n': // short service name
+ if (service_center)
+ {
+ service_center->info(ref, sptr);
+ if (sptr)
+ {
+ std::string name;
+ sptr->getName(ref, name);
+ name = buildShortName(name);
if (name.length())
tmp = PyString_FromString(name.c_str());
}
PyList_SET_ITEM(ret, cnt, tuple);
}
}
- return ret ? ret : PyList_New(0);
+ return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
}
RESULT eDVBServiceList::getNext(eServiceReference &ref)
return m_query->getNextResult((eServiceReferenceDVB&)ref);
}
-int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
-{
- return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
-}
-
RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
{
- if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
+ if (m_parent.flags & eServiceReference::canDescent) // bouquet
{
ePtr<iDVBChannelList> db;
ePtr<eDVBResourceManager> resm;
RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
{
/* is a listable service? */
- if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
+ if (ref.flags & eServiceReference::canDescent) // bouquet
{
if ( !ref.name.empty() ) // satellites or providers list
- ptr = new eStaticServiceDVBInformation;
+ ptr = m_StaticServiceDVBInfo;
else // a dvb bouquet
- ptr = new eStaticServiceDVBBouquetInformation;
+ ptr = m_StaticServiceDVBBouquetInfo;
}
else if (!ref.path.empty()) /* do we have a PVR service? */
ptr = new eStaticServiceDVBPVRInformation(ref);
{
ePtr<eDVBService> service;
if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
- ptr = new eStaticServiceDVBInformation;
+ ptr = m_StaticServiceDVBInfo;
else
/* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
ptr = service;
RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
{
- // TODO: handle the listing itself
- // if (ref.... == -1) .. return "... bouquets ...";
- // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
- // TODO: cache
- ePtr<iDVBChannelList> db;
- ePtr<eDVBResourceManager> res;
-
- int err;
- if ((err = eDVBResourceManager::getInstance(res)) != 0)
+ if (!ref.path.empty()) // playback
{
- eDebug("no resource manager");
- return err;
+ eDVBMetaParser parser;
+ int ret=parser.parseFile(ref.path);
+ service = new eDVBService;
+ if (!ret)
+ eDVBDB::getInstance()->parseServiceData(service, parser.m_service_data);
}
- if ((err = res->getChannelList(db)) != 0)
+ else
{
- eDebug("no channel list");
- return err;
- }
+ // TODO: handle the listing itself
+ // if (ref.... == -1) .. return "... bouquets ...";
+ // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
+ // TODO: cache
+ ePtr<iDVBChannelList> db;
+ ePtr<eDVBResourceManager> res;
+
+ int err;
+ if ((err = eDVBResourceManager::getInstance(res)) != 0)
+ {
+ eDebug("no resource manager");
+ return err;
+ }
+ if ((err = res->getChannelList(db)) != 0)
+ {
+ eDebug("no channel list");
+ return err;
+ }
/* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
- if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
- {
- eDebug("getService failed!");
- return err;
+ if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
+ {
+ eDebug("getService failed!");
+ return err;
+ }
}
return 0;
m_is_primary = 1;
m_is_pvr = !m_reference.path.empty();
- m_timeshift_enabled = m_timeshift_active = 0;
+ m_timeshift_enabled = m_timeshift_active = 0, m_timeshift_changed = 0;
m_skipmode = 0;
CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
m_subtitle_widget = 0;
- CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
+ m_tune_state = -1;
+
+ m_subtitle_sync_timer = eTimer::create(eApp);
+
+ CONNECT(m_subtitle_sync_timer->timeout, eDVBServicePlay::checkSubtitleTiming);
}
eDVBServicePlay::~eDVBServicePlay()
{
+ if (m_is_pvr)
+ {
+ eDVBMetaParser meta;
+ int ret=meta.parseFile(m_reference.path);
+ if (!ret)
+ {
+ char tmp[255];
+ meta.m_service_data="";
+ sprintf(tmp, "f:%x", m_dvb_service->m_flags);
+ meta.m_service_data += tmp;
+ // cached pids
+ for (int x=0; x < eDVBService::cacheMax; ++x)
+ {
+ int entry = m_dvb_service->getCacheEntry((eDVBService::cacheID)x);
+ if (entry != -1)
+ {
+ sprintf(tmp, ",c:%02d%04x", x, entry);
+ meta.m_service_data += tmp;
+ }
+ }
+ meta.updateMeta(m_reference.path);
+ }
+ }
delete m_subtitle_widget;
}
void eDVBServicePlay::serviceEvent(int event)
{
+ m_tune_state = event;
+
switch (event)
{
case eDVBServicePMTHandler::eventTuned:
else
m_event_handler.start(m_demux, sid);
}
+ m_event((iPlayableService*)this, evTunedIn);
break;
}
+ case eDVBServicePMTHandler::eventNoResources:
+ case eDVBServicePMTHandler::eventNoPAT:
+ case eDVBServicePMTHandler::eventNoPATEntry:
+ case eDVBServicePMTHandler::eventNoPMT:
case eDVBServicePMTHandler::eventTuneFailed:
+ case eDVBServicePMTHandler::eventMisconfiguration:
{
- eDebug("DVB service failed to tune");
+ eDebug("DVB service failed to tune - error %d", event);
m_event((iPlayableService*)this, evTuneFailed);
break;
}
m_event((iPlayableService*)this, evSOF);
break;
case eDVBServicePMTHandler::eventEOF:
- switchToLive();
+ if ((!m_is_paused) && (m_skipmode >= 0))
+ {
+ eDebug("timeshift EOF, so let's go live");
+ switchToLive();
+ }
break;
}
}
to start recording from the data demux. */
if (m_is_pvr)
m_cue = new eCueSheet();
+ else
+ m_event(this, evStart);
m_first_program_info = 1;
eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
- r = m_service_handler.tune(service, m_is_pvr, m_cue);
+ r = m_service_handler.tune(service, m_is_pvr, m_cue, false, m_dvb_service);
/* inject EIT if there is a stored one */
if (m_is_pvr)
}
if (m_is_pvr)
+ {
loadCuesheet();
-
- m_event(this, evStart);
- m_event((iPlayableService*)this, evSeekableStatusChanged);
+ m_event(this, evStart);
+ }
return 0;
}
/* add bookmark for last play position */
if (m_is_pvr)
{
- pts_t play_position;
+ pts_t play_position, length;
if (!getPlayPosition(play_position))
{
/* remove last position */
++i;
}
- m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+ if (getLength(length))
+ length = 0;
+
+ if (length)
+ {
+ int perc = play_position * 100LL / length;
+
+ /* only store last play position when between 1% and 99% */
+ if ((1 < perc) && (perc < 99))
+ m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
+ }
m_cuesheet_changed = 1;
}
}
m_service_handler.free();
if (m_is_pvr && m_cuesheet_changed)
- saveCuesheet();
-
+ {
+ struct stat s;
+ /* save cuesheet only when main file is accessible. */
+ if (!::stat(m_reference.path.c_str(), &s))
+ saveCuesheet();
+ }
+ m_event((iPlayableService*)this, evStopped);
return 0;
}
RESULT eDVBServicePlay::setSlowMotion(int ratio)
{
+ ASSERT(ratio); /* The API changed: instead of calling setSlowMotion(0), call play! */
+ eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
+ setFastForward_internal(0);
if (m_decoder)
return m_decoder->setSlowMotion(ratio);
else
}
RESULT eDVBServicePlay::setFastForward(int ratio)
+{
+ eDebug("eDVBServicePlay::setFastForward(%d)", ratio);
+ ASSERT(ratio);
+ return setFastForward_internal(ratio);
+}
+
+RESULT eDVBServicePlay::setFastForward_internal(int ratio)
{
int skipmode, ffratio;
if (!m_decoder)
return -1;
-
- return m_decoder->setFastForward(ffratio);
+
+ if (ffratio == 0)
+ ; /* return m_decoder->play(); is done in caller*/
+ else if (ffratio != 1)
+ return m_decoder->setFastForward(ffratio);
+ else
+ return m_decoder->setTrickmode();
+ return 0;
}
-
+
RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
{
if (m_is_pvr || m_timeshift_enabled)
RESULT eDVBServicePlay::pause()
{
- if (!m_is_paused && m_decoder)
+ eDebug("eDVBServicePlay::pause");
+ setFastForward_internal(0);
+ if (m_decoder)
{
m_is_paused = 1;
- return m_decoder->freeze(0);
+ return m_decoder->pause();
} else
return -1;
}
RESULT eDVBServicePlay::unpause()
{
- if (m_is_paused && m_decoder)
+ eDebug("eDVBServicePlay::unpause");
+ setFastForward_internal(0);
+ if (m_decoder)
{
m_is_paused = 0;
- return m_decoder->unfreeze();
+ return m_decoder->play();
} else
return -1;
}
return -1;
m_cue->seekTo(0, to);
+ m_dvb_subtitle_pages.clear();
+ m_subtitle_pages.clear();
+
return 0;
}
return 0;
m_cue->seekTo(mode, to);
+ m_dvb_subtitle_pages.clear();
+ m_subtitle_pages.clear();
return 0;
}
RESULT eDVBServicePlay::setTrickmode(int trick)
{
- if (m_decoder)
- m_decoder->setTrickmode(trick);
- return 0;
+ /* currently unimplemented */
+ return -1;
}
RESULT eDVBServicePlay::isCurrentlySeekable()
{
if (!m_timeshift_enabled)
{
- /* we need enough diskspace */
+ /* query config path */
+ std::string tspath;
+ if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){
+ eDebug("could not query ts path from config");
+ return -4;
+ }
+ tspath.append("/");
+ /* we need enough diskspace */
struct statfs fs;
- if (statfs(TSPATH "/.", &fs) < 0)
+ if (statfs(tspath.c_str(), &fs) < 0)
{
eDebug("statfs failed!");
return -2;
return 0;
}
+RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr)
+{
+ ptr = this;
+ return 0;
+}
+
RESULT eDVBServicePlay::getName(std::string &name)
{
if (m_is_pvr)
ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
return i->getName(m_reference, name);
}
- if (m_dvb_service)
+ else if (m_dvb_service)
{
m_dvb_service->getName(m_reference, name);
if (name.empty())
if (w == sCAIDs)
return resIsPyObject;
- if (m_service_handler.getProgramInfo(program))
- return -1;
-
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+
+ int no_program_info = 0;
+
+ if (h.getProgramInfo(program))
+ no_program_info = 1;
+
switch (w)
{
+ case sVideoHeight:
+ if (m_decoder)
+ return m_decoder->getVideoHeight();
+ break;
+ case sVideoWidth:
+ if (m_decoder)
+ return m_decoder->getVideoWidth();
+ break;
+ case sFrameRate:
+ if (m_decoder)
+ return m_decoder->getVideoFrameRate();
+ break;
+ case sProgressive:
+ if (m_decoder)
+ return m_decoder->getVideoProgressive();
+ break;
case sAspect:
- if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
+ {
+ int aspect = -1;
+ if (m_decoder)
+ aspect = m_decoder->getVideoAspect();
+ if (aspect == -1 && no_program_info)
+ break;
+ else if (aspect == -1 && !program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
{
ePtr<eServiceEvent> evt;
if (!m_event_handler.getEvent(evt, 0))
}
}
}
- return -1;
- case sIsCrypted: return program.isCrypted();
- case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
- case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
- case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
- case sPCRPID: return program.pcrPid;
- case sPMTPID: return program.pmtPid;
- case sTXTPID: return program.textPid;
+ else
+ return aspect;
+ break;
+ }
+ case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
+ case sVideoPID:
+ if (m_dvb_service)
+ {
+ int vpid = m_dvb_service->getCacheEntry(eDVBService::cVPID);
+ if (vpid != -1)
+ return vpid;
+ }
+ if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
+ case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
+ case sAudioPID:
+ if (m_dvb_service)
+ {
+ int apid = m_dvb_service->getCacheEntry(eDVBService::cAPID);
+ if (apid != -1)
+ return apid;
+ apid = m_dvb_service->getCacheEntry(eDVBService::cAC3PID);
+ if (apid != -1)
+ return apid;
+ }
+ if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
+ case sPCRPID:
+ if (m_dvb_service)
+ {
+ int pcrpid = m_dvb_service->getCacheEntry(eDVBService::cPCRPID);
+ if (pcrpid != -1)
+ return pcrpid;
+ }
+ if (no_program_info) return -1; return program.pcrPid;
+ case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
+ case sTXTPID: if (no_program_info) return -1; return program.textPid;
case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
case sProvider: if (!m_dvb_service) return -1; return -2;
+ case sServiceref: return resIsString;
+ case sDVBState: return m_tune_state;
default:
- return -1;
+ break;
}
+ return -1;
}
std::string eDVBServicePlay::getInfoString(int w)
case sProvider:
if (!m_dvb_service) return "";
return m_dvb_service->m_provider_name;
+ case sServiceref:
+ return m_reference.toString();
default:
break;
}
{
case sCAIDs:
return m_service_handler.getCaIds();
+ case sTransponderData:
+ return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
default:
break;
}
int eDVBServicePlay::getNumberOfTracks()
{
eDVBServicePMTHandler::program program;
- if (m_service_handler.getProgramInfo(program))
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ if (h.getProgramInfo(program))
return 0;
return program.audioStreams.size();
}
+int eDVBServicePlay::getCurrentTrack()
+{
+ eDVBServicePMTHandler::program program;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ if (h.getProgramInfo(program))
+ return 0;
+
+ int max = program.audioStreams.size();
+ int i;
+
+ for (i = 0; i < max; ++i)
+ if (program.audioStreams[i].pid == m_current_audio_pid)
+ return i;
+
+ return 0;
+}
+
RESULT eDVBServicePlay::selectTrack(unsigned int i)
{
int ret = selectAudioStream(i);
- if (m_decoder->start())
+ if (m_decoder->set())
return -5;
return ret;
RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
{
eDVBServicePMTHandler::program program;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
- if (m_service_handler.getProgramInfo(program))
+ if (h.getProgramInfo(program))
return -1;
if (i >= program.audioStreams.size())
return -2;
+ info.m_pid = program.audioStreams[i].pid;
+
if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
info.m_description = "MPEG";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
info.m_description = "AC3";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
info.m_description = "AAC";
+ else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
+ info.m_description = "AAC-HE";
else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
info.m_description = "DTS";
else
int eDVBServicePlay::selectAudioStream(int i)
{
eDVBServicePMTHandler::program program;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
- if (m_service_handler.getProgramInfo(program))
+ if (h.getProgramInfo(program))
return -1;
-
- if ((unsigned int)i >= program.audioStreams.size())
+
+ if ((i != -1) && ((unsigned int)i >= program.audioStreams.size()))
return -2;
-
+
if (!m_decoder)
return -3;
-
- if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
- return -4;
- if (m_dvb_service && !m_is_pvr)
- {
- if (program.audioStreams[i].type == eDVBAudio::aMPEG)
+ int stream = i;
+ if (stream == -1)
+ stream = program.defaultAudioStream;
+
+ int apid = -1, apidtype = -1;
+
+ if (((unsigned int)stream) < program.audioStreams.size())
+ {
+ apid = program.audioStreams[stream].pid;
+ apidtype = program.audioStreams[stream].type;
+ }
+
+ m_current_audio_pid = apid;
+
+ if (m_is_primary && m_decoder->setAudioPID(apid, apidtype))
+ {
+ eDebug("set audio pid failed");
+ return -4;
+ }
+
+ int rdsPid = apid;
+
+ /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */
+ if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
+ {
+ int different_pid = program.videoStreams.empty() && program.audioStreams.size() == 1 && program.audioStreams[stream].rdsPid != -1;
+ if (different_pid)
+ rdsPid = program.audioStreams[stream].rdsPid;
+ if (!m_rds_decoder || m_rds_decoder->getPid() != rdsPid)
+ {
+ m_rds_decoder = 0;
+ ePtr<iDVBDemux> data_demux;
+ if (!h.getDataDemux(data_demux))
+ {
+ m_rds_decoder = new eDVBRdsDecoder(data_demux, different_pid);
+ m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
+ m_rds_decoder->start(rdsPid);
+ }
+ }
+ }
+
+ /* store new pid as default only when:
+ a.) we have an entry in the service db for the current service,
+ b.) we are not playing back something,
+ c.) we are not selecting the default entry. (we wouldn't change
+ anything in the best case, or destroy the default setting in
+ case the real default is not yet available.)
+ */
+ if (m_dvb_service && ((i != -1)
+ || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
+ {
+ if (apidtype == eDVBAudio::aMPEG)
{
- m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
+ m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
- } else
+ }
+ else if (apidtype == eDVBAudio::aAC3)
{
m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
- m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
+ m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
+ }
+ else
+ {
+ m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
+ m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
}
}
- m_current_audio_stream = i;
+ h.resetCachedProgram();
return 0;
}
return 0;
}
+std::string eDVBServicePlay::getText(int x)
+{
+ if (m_rds_decoder)
+ switch(x)
+ {
+ case RadioText:
+ return convertLatin1UTF8(m_rds_decoder->getRadioText());
+ case RtpText:
+ return convertLatin1UTF8(m_rds_decoder->getRtpText());
+ }
+ return "";
+}
+
+void eDVBServicePlay::rdsDecoderEvent(int what)
+{
+ switch(what)
+ {
+ case eDVBRdsDecoder::RadioTextChanged:
+ m_event((iPlayableService*)this, evUpdatedRadioText);
+ break;
+ case eDVBRdsDecoder::RtpTextChanged:
+ m_event((iPlayableService*)this, evUpdatedRtpText);
+ break;
+ case eDVBRdsDecoder::RassInteractivePicMaskChanged:
+ m_event((iPlayableService*)this, evUpdatedRassInteractivePicMask);
+ break;
+ case eDVBRdsDecoder::RecvRassSlidePic:
+ m_event((iPlayableService*)this, evUpdatedRassSlidePic);
+ break;
+ }
+}
+
+void eDVBServicePlay::showRassSlidePicture()
+{
+ if (m_rds_decoder)
+ {
+ if (m_decoder)
+ {
+ std::string rass_slide_pic = m_rds_decoder->getRassSlideshowPicture();
+ if (rass_slide_pic.length())
+ m_decoder->showSinglePic(rass_slide_pic.c_str());
+ else
+ eDebug("empty filename for rass slide picture received!!");
+ }
+ else
+ eDebug("no MPEG Decoder to show iframes avail");
+ }
+ else
+ eDebug("showRassSlidePicture called.. but not decoder");
+}
+
+void eDVBServicePlay::showRassInteractivePic(int page, int subpage)
+{
+ if (m_rds_decoder)
+ {
+ if (m_decoder)
+ {
+ std::string rass_interactive_pic = m_rds_decoder->getRassPicture(page, subpage);
+ if (rass_interactive_pic.length())
+ m_decoder->showSinglePic(rass_interactive_pic.c_str());
+ else
+ eDebug("empty filename for rass interactive picture %d/%d received!!", page, subpage);
+ }
+ else
+ eDebug("no MPEG Decoder to show iframes avail");
+ }
+ else
+ eDebug("showRassInteractivePic called.. but not decoder");
+}
+
+ePyObject eDVBServicePlay::getRassInteractiveMask()
+{
+ if (m_rds_decoder)
+ return m_rds_decoder->getRassPictureMask();
+ Py_RETURN_NONE;
+}
+
int eDVBServiceBase::getFrontendInfo(int w)
{
eUsePtr<iDVBChannel> channel;
return fe->readFrontendData(w);
}
-PyObject *eDVBServiceBase::getFrontendData(bool original)
+PyObject *eDVBServiceBase::getFrontendData()
{
- PyObject *ret=0;
+ ePyObject ret = PyDict_New();
+ if (ret)
+ {
+ eUsePtr<iDVBChannel> channel;
+ if(!m_service_handler.getChannel(channel))
+ {
+ ePtr<iDVBFrontend> fe;
+ if(!channel->getFrontend(fe))
+ fe->getFrontendData(ret);
+ }
+ }
+ else
+ Py_RETURN_NONE;
+ return ret;
+}
- eUsePtr<iDVBChannel> channel;
- if(!m_service_handler.getChannel(channel))
+PyObject *eDVBServiceBase::getFrontendStatus()
+{
+ ePyObject ret = PyDict_New();
+ if (ret)
{
- ePtr<iDVBFrontend> fe;
- if(!channel->getFrontend(fe))
+ eUsePtr<iDVBChannel> channel;
+ if(!m_service_handler.getChannel(channel))
{
- ret = fe->readTransponderData(original);
- if (ret)
- {
- ePtr<iDVBFrontendParameters> feparm;
- channel->getCurrentFrontendParameters(feparm);
- if (feparm)
- {
- eDVBFrontendParametersSatellite osat;
- if (!feparm->getDVBS(osat))
- {
- void PutToDict(PyObject *, const char*, long);
- void PutToDict(PyObject *, const char*, const char*);
- PutToDict(ret, "orbital_position", osat.orbital_position);
- const char *tmp = "UNKNOWN";
- switch(osat.polarisation)
- {
- case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
- case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
- case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
- case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
- default:break;
- }
- PutToDict(ret, "polarization", tmp);
- }
- }
- }
+ ePtr<iDVBFrontend> fe;
+ if(!channel->getFrontend(fe))
+ fe->getFrontendStatus(ret);
+ }
+ }
+ else
+ Py_RETURN_NONE;
+ return ret;
+}
+
+PyObject *eDVBServiceBase::getTransponderData(bool original)
+{
+ ePyObject ret = PyDict_New();
+ if (ret)
+ {
+ eUsePtr<iDVBChannel> channel;
+ if(!m_service_handler.getChannel(channel))
+ {
+ ePtr<iDVBFrontend> fe;
+ if(!channel->getFrontend(fe))
+ fe->getTransponderData(ret, original);
}
}
- if (!ret)
+ else
+ Py_RETURN_NONE;
+ return ret;
+}
+
+PyObject *eDVBServiceBase::getAll(bool original)
+{
+ ePyObject ret = getTransponderData(original);
+ if (ret != Py_None)
{
- ret = Py_None;
- Py_INCREF(ret);
+ eUsePtr<iDVBChannel> channel;
+ if(!m_service_handler.getChannel(channel))
+ {
+ ePtr<iDVBFrontend> fe;
+ if(!channel->getFrontend(fe))
+ {
+ fe->getFrontendData(ret);
+ fe->getFrontendStatus(ret);
+ }
+ }
}
return ret;
}
if (!m_record)
return -3;
- char templ[]=TSPATH "/timeshift.XXXXXX";
+ std::string tspath;
+ if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){
+ eDebug("could not query ts path");
+ return -5;
+ }
+ tspath.append("/timeshift.XXXXXX");
+ char* templ;
+ templ = new char[tspath.length() + 1];
+ strcpy(templ, tspath.c_str());
+
m_timeshift_fd = mkstemp(templ);
- m_timeshift_file = templ;
-
+ m_timeshift_file = std::string(templ);
+
eDebug("recording to %s", templ);
-
+
+ delete [] templ;
+
if (m_timeshift_fd < 0)
{
m_record = 0;
close(m_timeshift_fd);
eDebug("remove timeshift file");
- remove(m_timeshift_file.c_str());
+ eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
return 0;
}
PyObject *eDVBServicePlay::getCutList()
{
- PyObject *list = PyList_New(0);
+ ePyObject list = PyList_New(0);
for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
{
- PyObject *tuple = PyTuple_New(2);
- PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
- PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
+ ePyObject tuple = PyTuple_New(2);
+ PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
PyList_Append(list, tuple);
Py_DECREF(tuple);
}
return list;
}
-void eDVBServicePlay::setCutList(PyObject *list)
+void eDVBServicePlay::setCutList(ePyObject list)
{
if (!PyList_Check(list))
return;
for (i=0; i<size; ++i)
{
- PyObject *tuple = PyList_GetItem(list, i);
+ ePyObject tuple = PyList_GET_ITEM(list, i);
if (!PyTuple_Check(tuple))
{
eDebug("non-tuple in cutlist");
eDebug("cutlist entries need to be a 2-tuple");
continue;
}
- PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
+ ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
{
eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
return;
eDVBServicePMTHandler::program program;
- if (m_service_handler.getProgramInfo(program))
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+
+ if (h.getProgramInfo(program))
return;
else
{
i != program.audioStreams.end(); ++i)
pids_to_record.insert(i->pid);
+ for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
+ i(program.subtitleStreams.begin());
+ i != program.subtitleStreams.end(); ++i)
+ pids_to_record.insert(i->pid);
+
std::set<int> new_pids, obsolete_pids;
std::set_difference(pids_to_record.begin(), pids_to_record.end(),
if (!m_timeshift_active)
return;
+ eDebug("SwitchToLive");
+
m_cue = 0;
m_decoder = 0;
m_decode_demux = 0;
m_teletext_parser = 0;
+ m_rds_decoder = 0;
+ m_subtitle_parser = 0;
+ m_new_dvb_subtitle_page_connection = 0;
m_new_subtitle_page_connection = 0;
-
+ m_rds_decoder_event_connection = 0;
+ m_video_event_connection = 0;
+ m_is_paused = m_skipmode = 0; /* not supported in live mode */
+
/* free the timeshift service handler, we need the resources */
m_service_handler_timeshift.free();
m_timeshift_active = 0;
-
+ m_timeshift_changed = 1;
+
m_event((iPlayableService*)this, evSeekableStatusChanged);
-
+
updateDecoder();
}
{
if (m_timeshift_active)
return;
-
+
m_decode_demux = 0;
m_decoder = 0;
m_teletext_parser = 0;
+ m_rds_decoder = 0;
+ m_subtitle_parser = 0;
m_new_subtitle_page_connection = 0;
-
+ m_new_dvb_subtitle_page_connection = 0;
+ m_rds_decoder_event_connection = 0;
+ m_video_event_connection = 0;
+
m_timeshift_active = 1;
+ m_timeshift_changed = 1;
- m_event((iPlayableService*)this, evSeekableStatusChanged);
-
eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
r.path = m_timeshift_file;
-
+
m_cue = new eCueSheet();
- m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
- updateDecoder(); /* mainly to switch off PCR */
+ m_service_handler_timeshift.tune(r, 1, m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
+
+ eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
+ pause();
+ updateDecoder(); /* mainly to switch off PCR, and to set pause */
+
+ m_event((iPlayableService*)this, evSeekableStatusChanged);
}
void eDVBServicePlay::updateDecoder()
{
- int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
+ int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
- bool defaultac3=false;
- std::string default_ac3;
-
- if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
- defaultac3 = default_ac3 == "enable";
-
eDVBServicePMTHandler::program program;
if (h.getProgramInfo(program))
eDebug("getting program info failed.");
{
eDebugNoNewLine(" (");
for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
- i(program.videoStreams.begin());
+ i(program.videoStreams.begin());
i != program.videoStreams.end(); ++i)
{
if (vpid == -1)
{
eDebugNoNewLine(" (");
for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
- i(program.audioStreams.begin());
+ i(program.audioStreams.begin());
i != program.audioStreams.end(); ++i)
{
- if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
- {
- if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
- {
- apid = i->pid;
- apidtype = i->type;
- }
- }
if (i != program.audioStreams.begin())
eDebugNoNewLine(", ");
eDebugNoNewLine("%04x", i->pid);
if (!m_decoder)
{
h.getDecodeDemux(m_decode_demux);
+ if (m_timeshift_changed)
+ m_decoder = 0;
if (m_decode_demux)
+ {
m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
+ if (m_decoder)
+ m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
+ if (m_is_primary)
+ {
+ m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
+ m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
+ m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
+ m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
+ if (m_timeshift_changed)
+ {
+ ePyObject subs = getCachedSubtitle();
+ if (subs != Py_None)
+ {
+ int type = PyInt_AsLong(PyTuple_GET_ITEM(subs, 0)),
+ pid = PyInt_AsLong(PyTuple_GET_ITEM(subs, 1)),
+ comp_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 2)), // ttx page
+ anc_page = PyInt_AsLong(PyTuple_GET_ITEM(subs, 3)); // ttx magazine
+ if (type == 0) // dvb
+ m_subtitle_parser->start(pid, comp_page, anc_page);
+ else if (type == 1) // ttx
+ m_teletext_parser->setPageAndMagazine(comp_page, anc_page);
+ }
+ Py_DECREF(subs);
+ }
+ }
+ m_decoder->play(); /* pids will be set later */
+ }
if (m_cue)
m_cue->setDecodingDemux(m_decode_demux, m_decoder);
-#ifdef INTERNAL_TELETEXT
- m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
- m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
-#endif
}
+ m_timeshift_changed = 0;
+
if (m_decoder)
{
if (m_dvb_service)
ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
}
- else // subservice or recording
+ else // subservice
{
eServiceReferenceDVB ref;
m_service_handler.getServiceReference(ref);
}
}
}
- m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
- m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
+
+ std::string config_delay;
+ int config_delay_int = 0;
+ if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
+ config_delay_int = atoi(config_delay.c_str());
+ m_decoder->setAC3Delay(ac3_delay == -1 ? config_delay_int : ac3_delay + config_delay_int);
+
+ if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
+ config_delay_int = atoi(config_delay.c_str());
+ else
+ config_delay_int = 0;
+ m_decoder->setPCMDelay(pcm_delay == -1 ? config_delay_int : pcm_delay + config_delay_int);
m_decoder->setVideoPID(vpid, vpidtype);
- m_current_audio_stream = 0;
- m_decoder->setAudioPID(apid, apidtype);
+ selectAudioStream();
+
if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
m_decoder->setSyncPCR(pcrpid);
else
m_decoder->setSyncPCR(-1);
- m_decoder->setTextPID(tpid);
-
- if (m_teletext_parser)
- m_teletext_parser->start(tpid);
-
- if (!m_is_primary)
- m_decoder->setTrickmode(1);
-
- m_decoder->start();
+ if (m_is_primary)
+ {
+ m_decoder->setTextPID(tpid);
+ m_teletext_parser->start(program.textPid);
+ }
if (vpid > 0 && vpid < 0x2000)
;
m_decoder->setRadioPic(radio_pic);
}
+ m_decoder->set();
m_decoder->setAudioChannel(achannel);
-// how we can do this better?
-// update cache pid when the user changed the audio track or video track
-// TODO handling of difference audio types.. default audio types..
-
/* don't worry about non-existing services, nor pvr services */
- if (m_dvb_service && !m_is_pvr)
+ if (m_dvb_service)
{
- if (apidtype == eDVBAudio::aMPEG)
- {
- m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
- m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
- }
- else
- {
- m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
- m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
- }
+ /* (audio pid will be set in selectAudioTrack */
m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
+ int have_any_span = 0;
+
while (1)
{
if (i == m_cue_entries.end())
+ {
+ if (!have_any_span)
+ break;
out = length;
- else {
+ } else {
if (i->what == 0) /* in */
{
in = i++->where;
}
}
- if (in != out)
+ if (in < 0)
+ in = 0;
+ if (out < 0)
+ out = 0;
+ if (in > length)
+ in = length;
+ if (out > length)
+ out = length;
+
+ if (in < out)
+ {
+ have_any_span = 1;
m_cue->addSourceSpan(in, out);
+ }
in = length;
m_cue->commitSpans();
}
-RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
+RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
{
if (m_subtitle_widget)
disableSubtitles(parent);
-
- if (!m_teletext_parser)
- return -1;
-
+
+ ePyObject entry;
+ int tuplesize = PyTuple_Size(tuple);
+ int type = 0;
+
+ if (!PyTuple_Check(tuple))
+ goto error_out;
+
+ if (tuplesize < 1)
+ goto error_out;
+
+ entry = PyTuple_GET_ITEM(tuple, 0);
+
if (!PyInt_Check(entry))
- return -1;
-
- m_subtitle_widget = new eSubtitleWidget(parent);
- m_subtitle_widget->resize(parent->size()); /* full size */
-
- int page = PyInt_AsLong(entry);
-
- m_teletext_parser->setPage(page);
+ goto error_out;
+
+ type = PyInt_AsLong(entry);
+ if (type == 1) // teletext subtitles
+ {
+ int page, magazine, pid;
+ if (tuplesize < 4)
+ goto error_out;
+
+ if (!m_teletext_parser)
+ {
+ eDebug("enable teletext subtitles.. no parser !!!");
+ return -1;
+ }
+
+ entry = PyTuple_GET_ITEM(tuple, 1);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ pid = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 2);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ page = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 3);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ magazine = PyInt_AsLong(entry);
+
+ m_subtitle_widget = new eSubtitleWidget(parent);
+ m_subtitle_widget->resize(parent->size()); /* full size */
+ m_teletext_parser->setPageAndMagazine(page, magazine);
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
+ }
+ else if (type == 0)
+ {
+ int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
+ if (!m_subtitle_parser)
+ {
+ eDebug("enable dvb subtitles.. no parser !!!");
+ return -1;
+ }
+ if (tuplesize < 4)
+ goto error_out;
+
+ entry = PyTuple_GET_ITEM(tuple, 1);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ pid = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 2);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ composition_page_id = PyInt_AsLong(entry);
+
+ entry = PyTuple_GET_ITEM(tuple, 3);
+ if (!PyInt_Check(entry))
+ goto error_out;
+ ancillary_page_id = PyInt_AsLong(entry);
+
+ m_subtitle_widget = new eSubtitleWidget(parent);
+ m_subtitle_widget->resize(parent->size()); /* full size */
+ m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
+ }
+ else
+ goto error_out;
return 0;
+error_out:
+ eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
+ "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
+ "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
+ return -1;
}
RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
{
delete m_subtitle_widget;
m_subtitle_widget = 0;
+ if (m_subtitle_parser)
+ {
+ m_subtitle_parser->stop();
+ m_dvb_subtitle_pages.clear();
+ }
+ if (m_teletext_parser)
+ {
+ m_teletext_parser->setPageAndMagazine(-1, -1);
+ m_subtitle_pages.clear();
+ }
+ if (m_dvb_service)
+ m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
return 0;
}
+PyObject *eDVBServicePlay::getCachedSubtitle()
+{
+ if (m_dvb_service)
+ {
+ int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
+ if (tmp != -1)
+ {
+ unsigned int data = (unsigned int)tmp;
+ int pid = (data&0xFFFF0000)>>16;
+ ePyObject tuple = PyTuple_New(4);
+ eDVBServicePMTHandler::program program;
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ if (!h.getProgramInfo(program))
+ {
+ if (program.textPid==pid) // teletext
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
+ else
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(pid)); // pid
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
+ return tuple;
+ }
+ }
+ }
+ Py_RETURN_NONE;
+}
+
PyObject *eDVBServicePlay::getSubtitleList()
{
if (!m_teletext_parser)
+ Py_RETURN_NONE;
+
+ ePyObject l = PyList_New(0);
+ std::set<int> added_ttx_pages;
+
+ std::set<eDVBServicePMTHandler::subtitleStream> &subs =
+ m_teletext_parser->m_found_subtitle_pages;
+
+ eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
+ eDVBServicePMTHandler::program program;
+ if (h.getProgramInfo(program))
+ eDebug("getting program info failed.");
+ else
{
- Py_INCREF(Py_None);
- return Py_None;
+ for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
+ it != program.subtitleStreams.end(); ++it)
+ {
+ switch(it->subtitling_type)
+ {
+ case 0x01: // ebu teletext subtitles
+ {
+ int page_number = it->teletext_page_number & 0xFF;
+ int magazine_number = it->teletext_magazine_number & 7;
+ int hash = magazine_number << 8 | page_number;
+ if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+ {
+ ePyObject tuple = PyTuple_New(5);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+ PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+ PyList_Append(l, tuple);
+ Py_DECREF(tuple);
+ added_ttx_pages.insert(hash);
+ }
+ break;
+ }
+ case 0x10 ... 0x13:
+ case 0x20 ... 0x23: // dvb subtitles
+ {
+ ePyObject tuple = PyTuple_New(5);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
+ PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
+ PyList_Insert(l, 0, tuple);
+ Py_DECREF(tuple);
+ break;
+ }
+ }
+ }
}
-
- PyObject *l = PyList_New(0);
-
- for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
+
+ for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
+ it != subs.end(); ++it)
{
- PyObject *tuple = PyTuple_New(2);
- char desc[20];
- sprintf(desc, "Page %x", *i);
- PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
- PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
- PyList_Append(l, tuple);
+ int page_number = it->teletext_page_number & 0xFF;
+ int magazine_number = it->teletext_magazine_number & 7;
+ int hash = magazine_number << 8 | page_number;
+ if (added_ttx_pages.find(hash) == added_ttx_pages.end())
+ {
+ ePyObject tuple = PyTuple_New(5);
+ PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
+ PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
+ PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
+ PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
+ PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und")); // undetermined
+ PyList_Append(l, tuple);
+ Py_DECREF(tuple);
+ }
}
-
+
return l;
}
{
if (m_subtitle_widget)
{
+ pts_t pos = 0;
+ if (m_decoder)
+ m_decoder->getPTS(0, pos);
+ eDebug("got new subtitle page %lld %lld %d", pos, page.m_pts, page.m_have_pts);
m_subtitle_pages.push_back(page);
-
checkSubtitleTiming();
}
}
void eDVBServicePlay::checkSubtitleTiming()
{
+ eDebug("checkSubtitleTiming");
+ if (!m_subtitle_widget)
+ return;
while (1)
{
- if (m_subtitle_pages.empty())
+ enum { TELETEXT, DVB } type;
+ eDVBTeletextSubtitlePage page;
+ eDVBSubtitlePage dvb_page;
+ pts_t show_time;
+ if (!m_subtitle_pages.empty())
+ {
+ page = m_subtitle_pages.front();
+ type = TELETEXT;
+ show_time = page.m_pts;
+ }
+ else if (!m_dvb_subtitle_pages.empty())
+ {
+ dvb_page = m_dvb_subtitle_pages.front();
+ type = DVB;
+ show_time = dvb_page.m_show_time;
+ }
+ else
return;
- eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
-
pts_t pos = 0;
if (m_decoder)
m_decoder->getPTS(0, pos);
-
- int diff = p.m_pts - pos;
+
+ eDebug("%lld %lld", pos, show_time);
+ int diff = show_time - pos;
+ if (type == TELETEXT && !page.m_have_pts)
+ {
+ eDebug("ttx subtitle page without pts... immediate show");
+ diff = 0;
+ }
if (diff < 0)
{
eDebug("[late (%d ms)]", -diff / 90);
diff = 0;
}
- if (diff > 900000)
+ if (abs(diff) > 1800000)
{
- eDebug("[invalid]");
+ eDebug("[invalid]... immediate show!");
diff = 0;
}
-
- if (!diff)
+ if ((diff/90)<20)
{
- m_subtitle_widget->setPage(p);
- m_subtitle_pages.pop_front();
+ if (type == TELETEXT)
+ {
+ eDebug("display teletext subtitle page %lld", show_time);
+ m_subtitle_widget->setPage(page);
+ m_subtitle_pages.pop_front();
+ }
+ else
+ {
+ eDebug("display dvb subtitle Page %lld", show_time);
+ m_subtitle_widget->setPage(dvb_page);
+ m_dvb_subtitle_pages.pop_front();
+ }
} else
{
- m_subtitle_sync_timer.start(diff / 90, 1);
+ eDebug("start subtitle delay %d", diff / 90);
+ m_subtitle_sync_timer->start(diff / 90, 1);
break;
}
}
}
+void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
+{
+ if (m_subtitle_widget)
+ {
+ pts_t pos = 0;
+ if (m_decoder)
+ m_decoder->getPTS(0, pos);
+ eDebug("got new subtitle page %lld %lld", pos, p.m_show_time);
+ m_dvb_subtitle_pages.push_back(p);
+ checkSubtitleTiming();
+ }
+}
+
int eDVBServicePlay::getAC3Delay()
{
if (m_dvb_service)
m_decoder->setPCMDelay(delay);
}
+void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
+{
+ switch(event.type) {
+ case iTSMPEGDecoder::videoEvent::eventSizeChanged:
+ m_event((iPlayableService*)this, evVideoSizeChanged);
+ break;
+ case iTSMPEGDecoder::videoEvent::eventFrameRateChanged:
+ m_event((iPlayableService*)this, evVideoFramerateChanged);
+ break;
+ case iTSMPEGDecoder::videoEvent::eventProgressiveChanged:
+ m_event((iPlayableService*)this, evVideoProgressiveChanged);
+ break;
+ default:
+ break;
+ }
+}
+
+RESULT eDVBServicePlay::stream(ePtr<iStreamableService> &ptr)
+{
+ ptr = this;
+ return 0;
+}
+
+PyObject *eDVBServicePlay::getStreamingData()
+{
+ eDVBServicePMTHandler::program program;
+ if (m_service_handler.getProgramInfo(program))
+ {
+ Py_RETURN_NONE;
+ }
+
+ ePyObject r = program.createPythonObject();
+ ePtr<iDVBDemux> demux;
+ if (!m_service_handler.getDataDemux(demux))
+ {
+ uint8_t demux_id;
+ if (!demux->getCADemuxID(demux_id))
+ PutToDict(r, "demux", demux_id);
+ }
+
+ return r;
+}
+
+
DEFINE_REF(eDVBServicePlay)
+PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
+{
+ switch (w)
+ {
+ case iServiceInformation::sTransponderData:
+ return eStaticServiceDVBInformation().getInfoObject(ref, w);
+ default:
+ break;
+ }
+ return iStaticServiceInformation::getInfoObject(ref, w);
+}
+
eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");