1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
4 #include <lib/service/servicedvb.h>
5 #include <lib/service/service.h>
6 #include <lib/base/init_num.h>
7 #include <lib/base/init.h>
8 #include <lib/base/nconfig.h> // access to python config
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
13 #include <lib/components/file_eraser.h>
14 #include <lib/service/servicedvbrecord.h>
15 #include <lib/service/event.h>
16 #include <lib/dvb/metaparser.h>
17 #include <lib/dvb/tstools.h>
18 #include <lib/python/python.h>
21 #include <lib/gui/esubtitle.h>
26 #include <netinet/in.h>
28 #define INTERNAL_TELETEXT
31 #error no byte order defined!
34 #define TSPATH "/media/hdd"
36 class eStaticServiceDVBInformation: public iStaticServiceInformation
38 DECLARE_REF(eStaticServiceDVBInformation);
40 RESULT getName(const eServiceReference &ref, std::string &name);
41 int getLength(const eServiceReference &ref);
44 DEFINE_REF(eStaticServiceDVBInformation);
46 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
48 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
49 if ( !ref.name.empty() )
51 if (service.getParentTransportStreamID().get()) // linkage subservice
53 ePtr<iServiceHandler> service_center;
54 if (!eServiceCenter::getInstance(service_center))
56 eServiceReferenceDVB parent = service;
57 parent.setTransportStreamID( service.getParentTransportStreamID() );
58 parent.setServiceID( service.getParentServiceID() );
59 parent.setParentTransportStreamID(eTransportStreamID(0));
60 parent.setParentServiceID(eServiceID(0));
62 ePtr<iStaticServiceInformation> service_info;
63 if (!service_center->info(parent, service_info))
65 if (!service_info->getName(parent, name))
67 // just show short name
68 unsigned int pos = name.find("\xc2\x86");
69 if ( pos != std::string::npos )
71 pos = name.find("\xc2\x87");
72 if ( pos != std::string::npos )
88 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
93 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
95 DECLARE_REF(eStaticServiceDVBBouquetInformation);
97 RESULT getName(const eServiceReference &ref, std::string &name);
98 int getLength(const eServiceReference &ref);
101 DEFINE_REF(eStaticServiceDVBBouquetInformation);
103 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
105 ePtr<iDVBChannelList> db;
106 ePtr<eDVBResourceManager> res;
109 if ((err = eDVBResourceManager::getInstance(res)) != 0)
111 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
114 if ((err = res->getChannelList(db)) != 0)
116 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
121 if ((err = db->getBouquet(ref, bouquet)) != 0)
123 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
127 if ( bouquet && bouquet->m_bouquet_name.length() )
129 name = bouquet->m_bouquet_name;
136 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
141 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
143 DECLARE_REF(eStaticServiceDVBPVRInformation);
144 eServiceReference m_ref;
145 eDVBMetaParser m_parser;
147 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
148 RESULT getName(const eServiceReference &ref, std::string &name);
149 int getLength(const eServiceReference &ref);
150 RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
152 int getInfo(const eServiceReference &ref, int w);
153 std::string getInfoString(const eServiceReference &ref,int w);
156 DEFINE_REF(eStaticServiceDVBPVRInformation);
158 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
161 m_parser.parseFile(ref.path);
164 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
166 ASSERT(ref == m_ref);
167 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
171 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
173 ASSERT(ref == m_ref);
177 if (tstools.openFile(ref.path.c_str()))
181 if (tstools.calcLen(len))
187 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
191 case iServiceInformation::sDescription:
192 return iServiceInformation::resIsString;
193 case iServiceInformation::sServiceref:
194 return iServiceInformation::resIsString;
195 case iServiceInformation::sTimeCreate:
196 if (m_parser.m_time_create)
197 return m_parser.m_time_create;
199 return iServiceInformation::resNA;
201 return iServiceInformation::resNA;
205 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
209 case iServiceInformation::sDescription:
210 return m_parser.m_description;
211 case iServiceInformation::sServiceref:
212 return m_parser.m_ref.toString();
218 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
220 if (!ref.path.empty())
222 ePtr<eServiceEvent> event = new eServiceEvent;
223 std::string filename = ref.path;
224 filename.erase(filename.length()-2, 2);
226 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
236 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
238 DECLARE_REF(eDVBPVRServiceOfflineOperations);
239 eServiceReferenceDVB m_ref;
241 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
243 RESULT deleteFromDisk(int simulate);
244 RESULT getListOfFilenames(std::list<std::string> &);
247 DEFINE_REF(eDVBPVRServiceOfflineOperations);
249 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
253 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
259 std::list<std::string> res;
260 if (getListOfFilenames(res))
263 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
265 eDebug("FATAL !! can't get background file eraser");
267 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
269 eDebug("Removing %s...", i->c_str());
271 eraser->erase(i->c_str());
273 ::unlink(i->c_str());
280 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
283 res.push_back(m_ref.path);
285 // handling for old splitted recordings (enigma 1)
290 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
292 if (stat(buf, &s) < 0)
297 res.push_back(m_ref.path + ".meta");
298 res.push_back(m_ref.path + ".ap");
299 res.push_back(m_ref.path + ".cuts");
300 std::string tmp = m_ref.path;
301 tmp.erase(m_ref.path.length()-3);
302 res.push_back(tmp + ".eit");
306 DEFINE_REF(eServiceFactoryDVB)
308 eServiceFactoryDVB::eServiceFactoryDVB()
310 ePtr<eServiceCenter> sc;
312 eServiceCenter::getPrivInstance(sc);
314 sc->addServiceFactory(eServiceFactoryDVB::id, this);
317 eServiceFactoryDVB::~eServiceFactoryDVB()
319 ePtr<eServiceCenter> sc;
321 eServiceCenter::getPrivInstance(sc);
323 sc->removeServiceFactory(eServiceFactoryDVB::id);
326 DEFINE_REF(eDVBServiceList);
328 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
332 eDVBServiceList::~eDVBServiceList()
336 RESULT eDVBServiceList::startQuery()
338 ePtr<iDVBChannelList> db;
339 ePtr<eDVBResourceManager> res;
342 if ((err = eDVBResourceManager::getInstance(res)) != 0)
344 eDebug("no resource manager");
347 if ((err = res->getChannelList(db)) != 0)
349 eDebug("no channel list");
353 ePtr<eDVBChannelQuery> q;
355 if (!m_parent.path.empty())
357 eDVBChannelQuery::compile(q, m_parent.path);
360 eDebug("compile query failed");
365 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
367 eDebug("startQuery failed");
374 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
376 eServiceReferenceDVB ref;
381 while (!m_query->getNextResult(ref))
385 list.sort(iListableServiceCompare(this));
390 // The first argument of this function is a format string to specify the order and
391 // the content of the returned list
392 // useable format options are
393 // R = Service Reference (as swig object .. this is very slow)
394 // S = Service Reference (as python string object .. same as ref.toString())
395 // N = Service Name (as python string object)
396 // when exactly one return value per service is selected in the format string,
397 // then each value is directly a list entry
398 // when more than one value is returned per service, then the list is a list of
400 // unknown format string chars are returned as python None values !
401 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
404 std::list<eServiceReference> tmplist;
407 if (!format || !(retcount=strlen(format)))
408 format = "R"; // just return service reference swig object ...
410 if (!getContent(tmplist, sorted))
412 int services=tmplist.size();
413 ePtr<iStaticServiceInformation> sptr;
414 eServiceCenterPtr service_center;
416 if (strchr(format, 'N'))
417 eServiceCenter::getPrivInstance(service_center);
419 ret = PyList_New(services);
420 std::list<eServiceReference>::iterator it(tmplist.begin());
422 for (int cnt=0; cnt < services; ++cnt)
424 eServiceReference &ref=*it++;
425 PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
426 for (int i=0; i < retcount; ++i)
431 case 'R': // service reference (swig)object
432 tmp = New_eServiceReference(ref);
434 case 'S': // service reference string
435 tmp = PyString_FromString(ref.toString().c_str());
437 case 'N': // service name
440 service_center->info(ref, sptr);
444 sptr->getName(ref, name);
446 tmp = PyString_FromString(name.c_str());
450 tmp = PyString_FromString("<n/a>");
463 PyTuple_SET_ITEM(tuple, i, tmp);
465 PyList_SET_ITEM(ret, cnt, tmp);
469 PyList_SET_ITEM(ret, cnt, tuple);
472 return ret ? ret : PyList_New(0);
475 RESULT eDVBServiceList::getNext(eServiceReference &ref)
480 return m_query->getNextResult((eServiceReferenceDVB&)ref);
483 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
485 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
488 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
490 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
492 ePtr<iDVBChannelList> db;
493 ePtr<eDVBResourceManager> resm;
495 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
498 if (db->getBouquet(m_parent, m_bouquet) != 0)
509 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
513 return m_bouquet->addService(ref, before);
516 RESULT eDVBServiceList::removeService(eServiceReference &ref)
520 return m_bouquet->removeService(ref);
523 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
527 return m_bouquet->moveService(ref, pos);
530 RESULT eDVBServiceList::flushChanges()
534 return m_bouquet->flushChanges();
537 RESULT eDVBServiceList::setListName(const std::string &name)
541 return m_bouquet->setListName(name);
544 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
546 ePtr<eDVBService> service;
547 int r = lookupService(service, ref);
550 // check resources...
551 ptr = new eDVBServicePlay(ref, service);
555 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
557 if (ref.path.empty())
559 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
568 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
570 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
571 if (list->startQuery())
581 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
583 /* is a listable service? */
584 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
586 if ( !ref.name.empty() ) // satellites or providers list
587 ptr = new eStaticServiceDVBInformation;
588 else // a dvb bouquet
589 ptr = new eStaticServiceDVBBouquetInformation;
591 else if (!ref.path.empty()) /* do we have a PVR service? */
592 ptr = new eStaticServiceDVBPVRInformation(ref);
593 else // normal dvb service
595 ePtr<eDVBService> service;
596 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
597 ptr = new eStaticServiceDVBInformation;
599 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
605 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
607 if (ref.path.empty())
613 ptr = new eDVBPVRServiceOfflineOperations(ref);
618 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
620 // TODO: handle the listing itself
621 // if (ref.... == -1) .. return "... bouquets ...";
622 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
624 ePtr<iDVBChannelList> db;
625 ePtr<eDVBResourceManager> res;
628 if ((err = eDVBResourceManager::getInstance(res)) != 0)
630 eDebug("no resource manager");
633 if ((err = res->getChannelList(db)) != 0)
635 eDebug("no channel list");
639 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
640 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
642 eDebug("getService failed!");
649 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
650 m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
653 m_is_pvr = !m_reference.path.empty();
655 m_timeshift_enabled = m_timeshift_active = 0;
658 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
659 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
660 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
662 m_cuesheet_changed = 0;
663 m_cutlist_enabled = 1;
665 m_subtitle_widget = 0;
667 CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
670 eDVBServicePlay::~eDVBServicePlay()
672 delete m_subtitle_widget;
675 void eDVBServicePlay::gotNewEvent()
679 ePtr<eServiceEvent> m_event_now, m_event_next;
680 getEvent(m_event_now, 0);
681 getEvent(m_event_next, 1);
684 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
686 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
688 m_event((iPlayableService*)this, evUpdatedEventInfo);
691 void eDVBServicePlay::serviceEvent(int event)
695 case eDVBServicePMTHandler::eventTuned:
697 ePtr<iDVBDemux> m_demux;
698 if (!m_service_handler.getDataDemux(m_demux))
700 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
701 int sid = ref.getParentServiceID().get();
703 sid = ref.getServiceID().get();
704 if ( ref.getParentTransportStreamID().get() &&
705 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
706 m_event_handler.startOther(m_demux, sid);
708 m_event_handler.start(m_demux, sid);
712 case eDVBServicePMTHandler::eventTuneFailed:
714 eDebug("DVB service failed to tune");
715 m_event((iPlayableService*)this, evTuneFailed);
718 case eDVBServicePMTHandler::eventNewProgramInfo:
720 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
721 if (m_timeshift_enabled)
722 updateTimeshiftPids();
723 if (!m_timeshift_active)
725 if (m_first_program_info && m_is_pvr)
727 m_first_program_info = 0;
730 m_event((iPlayableService*)this, evUpdatedInfo);
733 case eDVBServicePMTHandler::eventEOF:
734 m_event((iPlayableService*)this, evEOF);
736 case eDVBServicePMTHandler::eventSOF:
737 m_event((iPlayableService*)this, evSOF);
742 void eDVBServicePlay::serviceEventTimeshift(int event)
746 case eDVBServicePMTHandler::eventNewProgramInfo:
747 if (m_timeshift_active)
750 case eDVBServicePMTHandler::eventSOF:
751 m_event((iPlayableService*)this, evSOF);
753 case eDVBServicePMTHandler::eventEOF:
759 RESULT eDVBServicePlay::start()
762 /* in pvr mode, we only want to use one demux. in tv mode, we're using
763 two (one for decoding, one for data source), as we must be prepared
764 to start recording from the data demux. */
766 m_cue = new eCueSheet();
768 m_first_program_info = 1;
769 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
770 r = m_service_handler.tune(service, m_is_pvr, m_cue);
772 /* inject EIT if there is a stored one */
775 std::string filename = service.path;
776 filename.erase(filename.length()-2, 2);
778 ePtr<eServiceEvent> event = new eServiceEvent;
779 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
781 ePtr<eServiceEvent> empty;
782 m_event_handler.inject(event, 0);
783 m_event_handler.inject(empty, 1);
790 m_event(this, evStart);
791 m_event((iPlayableService*)this, evSeekableStatusChanged);
795 RESULT eDVBServicePlay::stop()
797 /* add bookmark for last play position */
801 if (!getPlayPosition(play_position))
803 /* remove last position */
804 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
806 if (i->what == 3) /* current play position */
808 m_cue_entries.erase(i);
809 i = m_cue_entries.begin();
815 m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
816 m_cuesheet_changed = 1;
820 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
822 m_service_handler_timeshift.free();
823 m_service_handler.free();
825 if (m_is_pvr && m_cuesheet_changed)
831 RESULT eDVBServicePlay::setTarget(int target)
833 m_is_primary = !target;
837 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
839 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
843 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
845 /* note: we check for timeshift to be enabled,
846 not neccessary active. if you pause when timeshift
847 is not active, you should activate it when unpausing */
848 if ((!m_is_pvr) && (!m_timeshift_enabled))
858 RESULT eDVBServicePlay::setSlowMotion(int ratio)
861 return m_decoder->setSlowMotion(ratio);
866 RESULT eDVBServicePlay::setFastForward(int ratio)
868 int skipmode, ffratio;
874 } else if (ratio > 0)
882 } else // if (ratio < 0)
888 if (m_skipmode != skipmode)
890 eDebug("setting cue skipmode to %d", skipmode);
892 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
895 m_skipmode = skipmode;
900 return m_decoder->setFastForward(ffratio);
903 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
905 if (m_is_pvr || m_timeshift_enabled)
915 /* TODO: when timeshift is enabled but not active, this doesn't work. */
916 RESULT eDVBServicePlay::getLength(pts_t &len)
918 ePtr<iDVBPVRChannel> pvr_channel;
920 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
923 return pvr_channel->getLength(len);
926 RESULT eDVBServicePlay::pause()
928 if (!m_is_paused && m_decoder)
931 return m_decoder->freeze(0);
936 RESULT eDVBServicePlay::unpause()
938 if (m_is_paused && m_decoder)
941 return m_decoder->unfreeze();
946 RESULT eDVBServicePlay::seekTo(pts_t to)
948 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
953 ePtr<iDVBPVRChannel> pvr_channel;
955 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
961 m_cue->seekTo(0, to);
965 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
967 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
972 ePtr<iDVBPVRChannel> pvr_channel;
974 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
979 /* HACK until we have skip-AP api */
980 if ((to > 0) && (to < 100))
988 m_cue->seekTo(mode, to);
992 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
994 ePtr<iDVBPVRChannel> pvr_channel;
999 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1004 /* if there is a decoder, use audio or video PTS */
1007 r = m_decoder->getPTS(0, pos);
1013 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1016 RESULT eDVBServicePlay::setTrickmode(int trick)
1019 m_decoder->setTrickmode(trick);
1023 RESULT eDVBServicePlay::isCurrentlySeekable()
1025 return m_is_pvr || m_timeshift_active;
1028 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1034 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1040 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1046 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1052 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1058 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1061 if (m_have_video_pid && // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1062 (m_timeshift_enabled || !m_is_pvr))
1064 if (!m_timeshift_enabled)
1066 /* we need enough diskspace */
1068 if (statfs(TSPATH "/.", &fs) < 0)
1070 eDebug("statfs failed!");
1074 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1076 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1086 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1097 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1103 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1109 RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
1115 RESULT eDVBServicePlay::getName(std::string &name)
1119 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1120 return i->getName(m_reference, name);
1124 m_dvb_service->getName(m_reference, name);
1128 else if (!m_reference.name.empty())
1129 eStaticServiceDVBInformation().getName(m_reference, name);
1131 name = "DVB service";
1135 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1137 return m_event_handler.getEvent(evt, nownext);
1140 int eDVBServicePlay::getInfo(int w)
1142 eDVBServicePMTHandler::program program;
1145 return resIsPyObject;
1147 if (m_service_handler.getProgramInfo(program))
1153 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1155 ePtr<eServiceEvent> evt;
1156 if (!m_event_handler.getEvent(evt, 0))
1158 ePtr<eComponentData> data;
1159 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1161 if ( data->getStreamContent() == 1 )
1163 switch(data->getComponentType())
1166 case 1: // 4:3 SD PAL
1168 case 3: // 16:9 SD PAL
1169 case 4: // > 16:9 PAL
1170 case 5: // 4:3 SD NTSC
1172 case 7: // 16:9 SD NTSC
1173 case 8: // > 16:9 NTSC
1176 case 9: // 4:3 HD PAL
1178 case 0xB: // 16:9 HD PAL
1179 case 0xC: // > 16:9 HD PAL
1180 case 0xD: // 4:3 HD NTSC
1182 case 0xF: // 16:9 HD NTSC
1183 case 0x10: // > 16:9 HD PAL
1184 return data->getComponentType();
1191 case sIsCrypted: return program.isCrypted();
1192 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1193 case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1194 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1195 case sPCRPID: return program.pcrPid;
1196 case sPMTPID: return program.pmtPid;
1197 case sTXTPID: return program.textPid;
1198 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1199 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1200 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1201 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1202 case sProvider: if (!m_dvb_service) return -1; return -2;
1208 std::string eDVBServicePlay::getInfoString(int w)
1213 if (!m_dvb_service) return "";
1214 return m_dvb_service->m_provider_name;
1218 return iServiceInformation::getInfoString(w);
1221 PyObject *eDVBServicePlay::getInfoObject(int w)
1226 return m_service_handler.getCaIds();
1230 return iServiceInformation::getInfoObject(w);
1233 int eDVBServicePlay::getNumberOfTracks()
1235 eDVBServicePMTHandler::program program;
1236 if (m_service_handler.getProgramInfo(program))
1238 return program.audioStreams.size();
1241 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1243 int ret = selectAudioStream(i);
1245 if (m_decoder->start())
1251 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1253 eDVBServicePMTHandler::program program;
1255 if (m_service_handler.getProgramInfo(program))
1258 if (i >= program.audioStreams.size())
1261 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1262 info.m_description = "MPEG";
1263 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1264 info.m_description = "AC3";
1265 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1266 info.m_description = "AAC";
1267 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1268 info.m_description = "DTS";
1270 info.m_description = "???";
1272 if (program.audioStreams[i].component_tag != -1)
1274 ePtr<eServiceEvent> evt;
1275 if (!m_event_handler.getEvent(evt, 0))
1277 ePtr<eComponentData> data;
1278 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1279 info.m_language = data->getText();
1283 if (info.m_language.empty())
1284 info.m_language = program.audioStreams[i].language_code;
1289 int eDVBServicePlay::selectAudioStream(int i)
1291 eDVBServicePMTHandler::program program;
1293 if (m_service_handler.getProgramInfo(program))
1296 if ((unsigned int)i >= program.audioStreams.size())
1302 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1305 if (m_radiotext_parser)
1306 m_radiotext_parser->start(program.audioStreams[i].pid);
1308 if (m_dvb_service && !m_is_pvr)
1310 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1312 m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
1313 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1317 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1318 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
1322 m_current_audio_stream = i;
1327 int eDVBServicePlay::getCurrentChannel()
1329 return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1332 RESULT eDVBServicePlay::selectChannel(int i)
1334 if (i < LEFT || i > RIGHT || i == STEREO)
1337 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1339 m_decoder->setAudioChannel(i);
1343 std::string eDVBServicePlay::getRadioText(int x)
1345 if (m_radiotext_parser)
1349 return m_radiotext_parser->getCurrentText();
1354 void eDVBServicePlay::radioTextUpdated()
1356 m_event((iPlayableService*)this, evUpdatedRadioText);
1359 int eDVBServiceBase::getFrontendInfo(int w)
1361 eUsePtr<iDVBChannel> channel;
1362 if(m_service_handler.getChannel(channel))
1364 ePtr<iDVBFrontend> fe;
1365 if(channel->getFrontend(fe))
1367 return fe->readFrontendData(w);
1370 PyObject *eDVBServiceBase::getFrontendData(bool original)
1374 eUsePtr<iDVBChannel> channel;
1375 if(!m_service_handler.getChannel(channel))
1377 ePtr<iDVBFrontend> fe;
1378 if(!channel->getFrontend(fe))
1380 ret = fe->readTransponderData(original);
1383 ePtr<iDVBFrontendParameters> feparm;
1384 channel->getCurrentFrontendParameters(feparm);
1387 eDVBFrontendParametersSatellite osat;
1388 if (!feparm->getDVBS(osat))
1390 void PutToDict(PyObject *, const char*, long);
1391 void PutToDict(PyObject *, const char*, const char*);
1392 PutToDict(ret, "orbital_position", osat.orbital_position);
1393 const char *tmp = "UNKNOWN";
1394 switch(osat.polarisation)
1396 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1397 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1398 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1399 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1402 PutToDict(ret, "polarization", tmp);
1416 int eDVBServicePlay::getNumberOfSubservices()
1418 ePtr<eServiceEvent> evt;
1419 if (!m_event_handler.getEvent(evt, 0))
1420 return evt->getNumOfLinkageServices();
1424 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1426 ePtr<eServiceEvent> evt;
1427 if (!m_event_handler.getEvent(evt, 0))
1429 if (!evt->getLinkageService(sub, m_reference, n))
1432 sub.type=eServiceReference::idInvalid;
1436 RESULT eDVBServicePlay::startTimeshift()
1438 ePtr<iDVBDemux> demux;
1440 eDebug("Start timeshift!");
1442 if (m_timeshift_enabled)
1445 /* start recording with the data demux. */
1446 if (m_service_handler.getDataDemux(demux))
1449 demux->createTSRecorder(m_record);
1453 char templ[]=TSPATH "/timeshift.XXXXXX";
1454 m_timeshift_fd = mkstemp(templ);
1455 m_timeshift_file = templ;
1457 eDebug("recording to %s", templ);
1459 if (m_timeshift_fd < 0)
1465 m_record->setTargetFD(m_timeshift_fd);
1467 m_timeshift_enabled = 1;
1469 updateTimeshiftPids();
1475 RESULT eDVBServicePlay::stopTimeshift()
1477 if (!m_timeshift_enabled)
1482 m_timeshift_enabled = 0;
1487 close(m_timeshift_fd);
1488 eDebug("remove timeshift file");
1489 remove(m_timeshift_file.c_str());
1494 int eDVBServicePlay::isTimeshiftActive()
1496 return m_timeshift_enabled && m_timeshift_active;
1499 RESULT eDVBServicePlay::activateTimeshift()
1501 if (!m_timeshift_enabled)
1504 if (!m_timeshift_active)
1506 switchToTimeshift();
1513 PyObject *eDVBServicePlay::getCutList()
1515 PyObject *list = PyList_New(0);
1517 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1519 PyObject *tuple = PyTuple_New(2);
1520 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1521 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1522 PyList_Append(list, tuple);
1529 void eDVBServicePlay::setCutList(PyObject *list)
1531 if (!PyList_Check(list))
1533 int size = PyList_Size(list);
1536 m_cue_entries.clear();
1538 for (i=0; i<size; ++i)
1540 PyObject *tuple = PyList_GetItem(list, i);
1541 if (!PyTuple_Check(tuple))
1543 eDebug("non-tuple in cutlist");
1546 if (PyTuple_Size(tuple) != 2)
1548 eDebug("cutlist entries need to be a 2-tuple");
1551 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1552 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1554 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1557 pts_t pts = PyLong_AsLongLong(ppts);
1558 int type = PyInt_AsLong(ptype);
1559 m_cue_entries.insert(cueEntry(pts, type));
1560 eDebug("adding %08llx, %d", pts, type);
1562 m_cuesheet_changed = 1;
1564 cutlistToCuesheet();
1565 m_event((iPlayableService*)this, evCuesheetChanged);
1568 void eDVBServicePlay::setCutListEnable(int enable)
1570 m_cutlist_enabled = enable;
1571 cutlistToCuesheet();
1574 void eDVBServicePlay::updateTimeshiftPids()
1579 eDVBServicePMTHandler::program program;
1580 if (m_service_handler.getProgramInfo(program))
1584 std::set<int> pids_to_record;
1585 pids_to_record.insert(0); // PAT
1586 if (program.pmtPid != -1)
1587 pids_to_record.insert(program.pmtPid); // PMT
1589 if (program.textPid != -1)
1590 pids_to_record.insert(program.textPid); // Videotext
1592 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1593 i(program.videoStreams.begin());
1594 i != program.videoStreams.end(); ++i)
1595 pids_to_record.insert(i->pid);
1597 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1598 i(program.audioStreams.begin());
1599 i != program.audioStreams.end(); ++i)
1600 pids_to_record.insert(i->pid);
1602 std::set<int> new_pids, obsolete_pids;
1604 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1605 m_pids_active.begin(), m_pids_active.end(),
1606 std::inserter(new_pids, new_pids.begin()));
1608 std::set_difference(
1609 m_pids_active.begin(), m_pids_active.end(),
1610 pids_to_record.begin(), pids_to_record.end(),
1611 std::inserter(new_pids, new_pids.begin())
1614 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1615 m_record->addPID(*i);
1617 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1618 m_record->removePID(*i);
1622 void eDVBServicePlay::switchToLive()
1624 if (!m_timeshift_active)
1630 m_teletext_parser = 0;
1631 m_radiotext_parser = 0;
1632 m_new_subtitle_page_connection = 0;
1633 m_radiotext_updated_connection = 0;
1635 /* free the timeshift service handler, we need the resources */
1636 m_service_handler_timeshift.free();
1637 m_timeshift_active = 0;
1639 m_event((iPlayableService*)this, evSeekableStatusChanged);
1644 void eDVBServicePlay::switchToTimeshift()
1646 if (m_timeshift_active)
1651 m_teletext_parser = 0;
1652 m_radiotext_parser = 0;
1653 m_new_subtitle_page_connection = 0;
1654 m_radiotext_updated_connection = 0;
1656 m_timeshift_active = 1;
1658 m_event((iPlayableService*)this, evSeekableStatusChanged);
1660 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1661 r.path = m_timeshift_file;
1663 m_cue = new eCueSheet();
1664 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1665 updateDecoder(); /* mainly to switch off PCR */
1668 void eDVBServicePlay::updateDecoder()
1670 int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
1672 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1674 bool defaultac3=false;
1675 std::string default_ac3;
1677 if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1678 defaultac3 = default_ac3 == "enable";
1680 eDVBServicePMTHandler::program program;
1681 if (h.getProgramInfo(program))
1682 eDebug("getting program info failed.");
1685 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1686 if (!program.videoStreams.empty())
1688 eDebugNoNewLine(" (");
1689 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1690 i(program.videoStreams.begin());
1691 i != program.videoStreams.end(); ++i)
1698 if (i != program.videoStreams.begin())
1699 eDebugNoNewLine(", ");
1700 eDebugNoNewLine("%04x", i->pid);
1702 eDebugNoNewLine(")");
1704 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1705 if (!program.audioStreams.empty())
1707 eDebugNoNewLine(" (");
1708 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1709 i(program.audioStreams.begin());
1710 i != program.audioStreams.end(); ++i)
1712 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1714 if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1720 if (i != program.audioStreams.begin())
1721 eDebugNoNewLine(", ");
1722 eDebugNoNewLine("%04x", i->pid);
1724 eDebugNoNewLine(")");
1726 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1727 pcrpid = program.pcrPid;
1728 eDebug(", and the text pid is %04x", program.textPid);
1729 tpid = program.textPid;
1734 h.getDecodeDemux(m_decode_demux);
1736 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1738 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1739 #ifdef INTERNAL_TELETEXT
1740 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1741 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
1745 ePtr<iDVBDemux> data_demux;
1746 if ( (m_timeshift_active && !m_service_handler_timeshift.getDataDemux(data_demux))
1747 || (!m_timeshift_active && !m_service_handler.getDataDemux(data_demux)))
1749 m_radiotext_parser = new eDVBRadioTextParser(data_demux);
1750 m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
1759 achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1760 ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
1761 pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
1763 else // subservice or recording
1765 eServiceReferenceDVB ref;
1766 m_service_handler.getServiceReference(ref);
1767 eServiceReferenceDVB parent = ref.getParentServiceReference();
1772 ePtr<eDVBResourceManager> res_mgr;
1773 if (!eDVBResourceManager::getInstance(res_mgr))
1775 ePtr<iDVBChannelList> db;
1776 if (!res_mgr->getChannelList(db))
1778 ePtr<eDVBService> origService;
1779 if (!db->getService(parent, origService))
1781 ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
1782 pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
1788 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
1789 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
1791 m_decoder->setVideoPID(vpid, vpidtype);
1792 m_current_audio_stream = 0;
1793 m_decoder->setAudioPID(apid, apidtype);
1794 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1795 m_decoder->setSyncPCR(pcrpid);
1797 m_decoder->setSyncPCR(-1);
1799 m_decoder->setTextPID(tpid);
1801 if (m_teletext_parser)
1802 m_teletext_parser->start(tpid);
1804 if (m_radiotext_parser)
1805 m_radiotext_parser->start(apid);
1808 m_decoder->setTrickmode(1);
1812 if (vpid > 0 && vpid < 0x2000)
1816 std::string radio_pic;
1817 if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1818 m_decoder->setRadioPic(radio_pic);
1821 m_decoder->setAudioChannel(achannel);
1823 // how we can do this better?
1824 // update cache pid when the user changed the audio track or video track
1825 // TODO handling of difference audio types.. default audio types..
1827 /* don't worry about non-existing services, nor pvr services */
1828 if (m_dvb_service && !m_is_pvr)
1830 if (apidtype == eDVBAudio::aMPEG)
1832 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1833 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1837 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1838 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1840 m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1841 m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1842 m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1843 m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1846 m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1849 void eDVBServicePlay::loadCuesheet()
1851 std::string filename = m_reference.path + ".cuts";
1853 m_cue_entries.clear();
1855 FILE *f = fopen(filename.c_str(), "rb");
1859 eDebug("loading cuts..");
1862 unsigned long long where;
1865 if (!fread(&where, sizeof(where), 1, f))
1867 if (!fread(&what, sizeof(what), 1, f))
1870 #if BYTE_ORDER == LITTLE_ENDIAN
1871 where = bswap_64(where);
1878 m_cue_entries.insert(cueEntry(where, what));
1881 eDebug("%d entries", m_cue_entries.size());
1883 eDebug("cutfile not found!");
1885 m_cuesheet_changed = 0;
1886 cutlistToCuesheet();
1887 m_event((iPlayableService*)this, evCuesheetChanged);
1890 void eDVBServicePlay::saveCuesheet()
1892 std::string filename = m_reference.path + ".cuts";
1894 FILE *f = fopen(filename.c_str(), "wb");
1898 unsigned long long where;
1901 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1903 #if BYTE_ORDER == BIG_ENDIAN
1906 where = bswap_64(i->where);
1908 what = htonl(i->what);
1909 fwrite(&where, sizeof(where), 1, f);
1910 fwrite(&what, sizeof(what), 1, f);
1916 m_cuesheet_changed = 0;
1919 void eDVBServicePlay::cutlistToCuesheet()
1923 eDebug("no cue sheet");
1928 if (!m_cutlist_enabled)
1930 m_cue->commitSpans();
1931 eDebug("cutlists were disabled");
1935 pts_t in = 0, out = 0, length = 0;
1939 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1943 if (i == m_cue_entries.end())
1946 if (i->what == 0) /* in */
1950 } else if (i->what == 1) /* out */
1952 else /* mark (2) or last play position (3) */
1960 m_cue->addSourceSpan(in, out);
1964 if (i == m_cue_entries.end())
1967 m_cue->commitSpans();
1970 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1972 if (m_subtitle_widget)
1973 disableSubtitles(parent);
1975 if (!m_teletext_parser)
1978 if (!PyInt_Check(entry))
1981 m_subtitle_widget = new eSubtitleWidget(parent);
1982 m_subtitle_widget->resize(parent->size()); /* full size */
1984 int page = PyInt_AsLong(entry);
1986 m_teletext_parser->setPage(page);
1991 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
1993 delete m_subtitle_widget;
1994 m_subtitle_widget = 0;
1998 PyObject *eDVBServicePlay::getSubtitleList()
2000 if (!m_teletext_parser)
2006 PyObject *l = PyList_New(0);
2008 for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
2010 PyObject *tuple = PyTuple_New(2);
2012 sprintf(desc, "Page %x", *i);
2013 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2014 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
2015 PyList_Append(l, tuple);
2021 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2023 if (m_subtitle_widget)
2025 m_subtitle_pages.push_back(page);
2027 checkSubtitleTiming();
2031 void eDVBServicePlay::checkSubtitleTiming()
2035 if (m_subtitle_pages.empty())
2038 eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
2043 m_decoder->getPTS(0, pos);
2045 int diff = p.m_pts - pos;
2048 eDebug("[late (%d ms)]", -diff / 90);
2053 eDebug("[invalid]");
2059 m_subtitle_widget->setPage(p);
2060 m_subtitle_pages.pop_front();
2063 m_subtitle_sync_timer.start(diff / 90, 1);
2069 int eDVBServicePlay::getAC3Delay()
2072 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2074 return m_decoder->getAC3Delay();
2079 int eDVBServicePlay::getPCMDelay()
2082 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2084 return m_decoder->getPCMDelay();
2089 void eDVBServicePlay::setAC3Delay(int delay)
2092 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2094 m_decoder->setAC3Delay(delay);
2097 void eDVBServicePlay::setPCMDelay(int delay)
2100 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2102 m_decoder->setPCMDelay(delay);
2105 DEFINE_REF(eDVBServicePlay)
2107 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");