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);
316 m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
317 m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
320 eServiceFactoryDVB::~eServiceFactoryDVB()
322 ePtr<eServiceCenter> sc;
324 eServiceCenter::getPrivInstance(sc);
326 sc->removeServiceFactory(eServiceFactoryDVB::id);
329 DEFINE_REF(eDVBServiceList);
331 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
335 eDVBServiceList::~eDVBServiceList()
339 RESULT eDVBServiceList::startQuery()
341 ePtr<iDVBChannelList> db;
342 ePtr<eDVBResourceManager> res;
345 if ((err = eDVBResourceManager::getInstance(res)) != 0)
347 eDebug("no resource manager");
350 if ((err = res->getChannelList(db)) != 0)
352 eDebug("no channel list");
356 ePtr<eDVBChannelQuery> q;
358 if (!m_parent.path.empty())
360 eDVBChannelQuery::compile(q, m_parent.path);
363 eDebug("compile query failed");
368 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
370 eDebug("startQuery failed");
377 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
379 eServiceReferenceDVB ref;
384 while (!m_query->getNextResult(ref))
388 list.sort(iListableServiceCompare(this));
393 // The first argument of this function is a format string to specify the order and
394 // the content of the returned list
395 // useable format options are
396 // R = Service Reference (as swig object .. this is very slow)
397 // S = Service Reference (as python string object .. same as ref.toString())
398 // N = Service Name (as python string object)
399 // when exactly one return value per service is selected in the format string,
400 // then each value is directly a list entry
401 // when more than one value is returned per service, then the list is a list of
403 // unknown format string chars are returned as python None values !
404 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
407 std::list<eServiceReference> tmplist;
410 if (!format || !(retcount=strlen(format)))
411 format = "R"; // just return service reference swig object ...
413 if (!getContent(tmplist, sorted))
415 int services=tmplist.size();
416 ePtr<iStaticServiceInformation> sptr;
417 eServiceCenterPtr service_center;
419 if (strchr(format, 'N'))
420 eServiceCenter::getPrivInstance(service_center);
422 ret = PyList_New(services);
423 std::list<eServiceReference>::iterator it(tmplist.begin());
425 for (int cnt=0; cnt < services; ++cnt)
427 eServiceReference &ref=*it++;
428 PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
429 for (int i=0; i < retcount; ++i)
434 case 'R': // service reference (swig)object
435 tmp = New_eServiceReference(ref);
437 case 'S': // service reference string
438 tmp = PyString_FromString(ref.toString().c_str());
440 case 'N': // service name
443 service_center->info(ref, sptr);
447 sptr->getName(ref, name);
449 tmp = PyString_FromString(name.c_str());
453 tmp = PyString_FromString("<n/a>");
466 PyTuple_SET_ITEM(tuple, i, tmp);
468 PyList_SET_ITEM(ret, cnt, tmp);
472 PyList_SET_ITEM(ret, cnt, tuple);
475 return ret ? ret : PyList_New(0);
478 RESULT eDVBServiceList::getNext(eServiceReference &ref)
483 return m_query->getNextResult((eServiceReferenceDVB&)ref);
486 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
488 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
491 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
493 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
495 ePtr<iDVBChannelList> db;
496 ePtr<eDVBResourceManager> resm;
498 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
501 if (db->getBouquet(m_parent, m_bouquet) != 0)
512 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
516 return m_bouquet->addService(ref, before);
519 RESULT eDVBServiceList::removeService(eServiceReference &ref)
523 return m_bouquet->removeService(ref);
526 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
530 return m_bouquet->moveService(ref, pos);
533 RESULT eDVBServiceList::flushChanges()
537 return m_bouquet->flushChanges();
540 RESULT eDVBServiceList::setListName(const std::string &name)
544 return m_bouquet->setListName(name);
547 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
549 ePtr<eDVBService> service;
550 int r = lookupService(service, ref);
553 // check resources...
554 ptr = new eDVBServicePlay(ref, service);
558 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
560 if (ref.path.empty())
562 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
571 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
573 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
574 if (list->startQuery())
584 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
586 /* is a listable service? */
587 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
589 if ( !ref.name.empty() ) // satellites or providers list
590 ptr = m_StaticServiceDVBInfo;
591 else // a dvb bouquet
592 ptr = m_StaticServiceDVBBouquetInfo;
594 else if (!ref.path.empty()) /* do we have a PVR service? */
595 ptr = new eStaticServiceDVBPVRInformation(ref);
596 else // normal dvb service
598 ePtr<eDVBService> service;
599 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
600 ptr = m_StaticServiceDVBInfo;
602 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
608 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
610 if (ref.path.empty())
616 ptr = new eDVBPVRServiceOfflineOperations(ref);
621 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
623 // TODO: handle the listing itself
624 // if (ref.... == -1) .. return "... bouquets ...";
625 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
627 ePtr<iDVBChannelList> db;
628 ePtr<eDVBResourceManager> res;
631 if ((err = eDVBResourceManager::getInstance(res)) != 0)
633 eDebug("no resource manager");
636 if ((err = res->getChannelList(db)) != 0)
638 eDebug("no channel list");
642 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
643 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
645 eDebug("getService failed!");
652 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
653 m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
656 m_is_pvr = !m_reference.path.empty();
658 m_timeshift_enabled = m_timeshift_active = 0;
661 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
662 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
663 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
665 m_cuesheet_changed = 0;
666 m_cutlist_enabled = 1;
668 m_subtitle_widget = 0;
670 CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
673 eDVBServicePlay::~eDVBServicePlay()
675 delete m_subtitle_widget;
678 void eDVBServicePlay::gotNewEvent()
682 ePtr<eServiceEvent> m_event_now, m_event_next;
683 getEvent(m_event_now, 0);
684 getEvent(m_event_next, 1);
687 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
689 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
691 m_event((iPlayableService*)this, evUpdatedEventInfo);
694 void eDVBServicePlay::serviceEvent(int event)
698 case eDVBServicePMTHandler::eventTuned:
700 ePtr<iDVBDemux> m_demux;
701 if (!m_service_handler.getDataDemux(m_demux))
703 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
704 int sid = ref.getParentServiceID().get();
706 sid = ref.getServiceID().get();
707 if ( ref.getParentTransportStreamID().get() &&
708 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
709 m_event_handler.startOther(m_demux, sid);
711 m_event_handler.start(m_demux, sid);
715 case eDVBServicePMTHandler::eventTuneFailed:
717 eDebug("DVB service failed to tune");
718 m_event((iPlayableService*)this, evTuneFailed);
721 case eDVBServicePMTHandler::eventNewProgramInfo:
723 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
724 if (m_timeshift_enabled)
725 updateTimeshiftPids();
726 if (!m_timeshift_active)
728 if (m_first_program_info && m_is_pvr)
730 m_first_program_info = 0;
733 m_event((iPlayableService*)this, evUpdatedInfo);
736 case eDVBServicePMTHandler::eventEOF:
737 m_event((iPlayableService*)this, evEOF);
739 case eDVBServicePMTHandler::eventSOF:
740 m_event((iPlayableService*)this, evSOF);
745 void eDVBServicePlay::serviceEventTimeshift(int event)
749 case eDVBServicePMTHandler::eventNewProgramInfo:
750 if (m_timeshift_active)
753 case eDVBServicePMTHandler::eventSOF:
754 m_event((iPlayableService*)this, evSOF);
756 case eDVBServicePMTHandler::eventEOF:
762 RESULT eDVBServicePlay::start()
765 /* in pvr mode, we only want to use one demux. in tv mode, we're using
766 two (one for decoding, one for data source), as we must be prepared
767 to start recording from the data demux. */
769 m_cue = new eCueSheet();
771 m_first_program_info = 1;
772 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
773 r = m_service_handler.tune(service, m_is_pvr, m_cue);
775 /* inject EIT if there is a stored one */
778 std::string filename = service.path;
779 filename.erase(filename.length()-2, 2);
781 ePtr<eServiceEvent> event = new eServiceEvent;
782 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
784 ePtr<eServiceEvent> empty;
785 m_event_handler.inject(event, 0);
786 m_event_handler.inject(empty, 1);
793 m_event(this, evStart);
794 m_event((iPlayableService*)this, evSeekableStatusChanged);
798 RESULT eDVBServicePlay::stop()
800 /* add bookmark for last play position */
804 if (!getPlayPosition(play_position))
806 /* remove last position */
807 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
809 if (i->what == 3) /* current play position */
811 m_cue_entries.erase(i);
812 i = m_cue_entries.begin();
818 m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
819 m_cuesheet_changed = 1;
823 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
825 m_service_handler_timeshift.free();
826 m_service_handler.free();
828 if (m_is_pvr && m_cuesheet_changed)
834 RESULT eDVBServicePlay::setTarget(int target)
836 m_is_primary = !target;
840 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
842 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
846 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
848 /* note: we check for timeshift to be enabled,
849 not neccessary active. if you pause when timeshift
850 is not active, you should activate it when unpausing */
851 if ((!m_is_pvr) && (!m_timeshift_enabled))
861 RESULT eDVBServicePlay::setSlowMotion(int ratio)
864 return m_decoder->setSlowMotion(ratio);
869 RESULT eDVBServicePlay::setFastForward(int ratio)
871 int skipmode, ffratio;
877 } else if (ratio > 0)
885 } else // if (ratio < 0)
891 if (m_skipmode != skipmode)
893 eDebug("setting cue skipmode to %d", skipmode);
895 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
898 m_skipmode = skipmode;
903 return m_decoder->setFastForward(ffratio);
906 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
908 if (m_is_pvr || m_timeshift_enabled)
918 /* TODO: when timeshift is enabled but not active, this doesn't work. */
919 RESULT eDVBServicePlay::getLength(pts_t &len)
921 ePtr<iDVBPVRChannel> pvr_channel;
923 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
926 return pvr_channel->getLength(len);
929 RESULT eDVBServicePlay::pause()
931 if (!m_is_paused && m_decoder)
934 return m_decoder->freeze(0);
939 RESULT eDVBServicePlay::unpause()
941 if (m_is_paused && m_decoder)
944 return m_decoder->unfreeze();
949 RESULT eDVBServicePlay::seekTo(pts_t to)
951 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
956 ePtr<iDVBPVRChannel> pvr_channel;
958 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
964 m_cue->seekTo(0, to);
968 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
970 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
975 ePtr<iDVBPVRChannel> pvr_channel;
977 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
982 /* HACK until we have skip-AP api */
983 if ((to > 0) && (to < 100))
991 m_cue->seekTo(mode, to);
995 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
997 ePtr<iDVBPVRChannel> pvr_channel;
1002 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1007 /* if there is a decoder, use audio or video PTS */
1010 r = m_decoder->getPTS(0, pos);
1016 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1019 RESULT eDVBServicePlay::setTrickmode(int trick)
1022 m_decoder->setTrickmode(trick);
1026 RESULT eDVBServicePlay::isCurrentlySeekable()
1028 return m_is_pvr || m_timeshift_active;
1031 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1037 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1043 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1049 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1055 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1061 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1064 if (m_have_video_pid && // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1065 (m_timeshift_enabled || !m_is_pvr))
1067 if (!m_timeshift_enabled)
1069 /* we need enough diskspace */
1071 if (statfs(TSPATH "/.", &fs) < 0)
1073 eDebug("statfs failed!");
1077 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1079 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1089 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1100 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1106 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1112 RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
1118 RESULT eDVBServicePlay::getName(std::string &name)
1122 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1123 return i->getName(m_reference, name);
1127 m_dvb_service->getName(m_reference, name);
1131 else if (!m_reference.name.empty())
1132 eStaticServiceDVBInformation().getName(m_reference, name);
1134 name = "DVB service";
1138 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1140 return m_event_handler.getEvent(evt, nownext);
1143 int eDVBServicePlay::getInfo(int w)
1145 eDVBServicePMTHandler::program program;
1148 return resIsPyObject;
1150 if (m_service_handler.getProgramInfo(program))
1156 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1158 ePtr<eServiceEvent> evt;
1159 if (!m_event_handler.getEvent(evt, 0))
1161 ePtr<eComponentData> data;
1162 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1164 if ( data->getStreamContent() == 1 )
1166 switch(data->getComponentType())
1169 case 1: // 4:3 SD PAL
1171 case 3: // 16:9 SD PAL
1172 case 4: // > 16:9 PAL
1173 case 5: // 4:3 SD NTSC
1175 case 7: // 16:9 SD NTSC
1176 case 8: // > 16:9 NTSC
1179 case 9: // 4:3 HD PAL
1181 case 0xB: // 16:9 HD PAL
1182 case 0xC: // > 16:9 HD PAL
1183 case 0xD: // 4:3 HD NTSC
1185 case 0xF: // 16:9 HD NTSC
1186 case 0x10: // > 16:9 HD PAL
1187 return data->getComponentType();
1194 case sIsCrypted: return program.isCrypted();
1195 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1196 case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1197 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1198 case sPCRPID: return program.pcrPid;
1199 case sPMTPID: return program.pmtPid;
1200 case sTXTPID: return program.textPid;
1201 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1202 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1203 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1204 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1205 case sProvider: if (!m_dvb_service) return -1; return -2;
1211 std::string eDVBServicePlay::getInfoString(int w)
1216 if (!m_dvb_service) return "";
1217 return m_dvb_service->m_provider_name;
1221 return iServiceInformation::getInfoString(w);
1224 PyObject *eDVBServicePlay::getInfoObject(int w)
1229 return m_service_handler.getCaIds();
1233 return iServiceInformation::getInfoObject(w);
1236 int eDVBServicePlay::getNumberOfTracks()
1238 eDVBServicePMTHandler::program program;
1239 if (m_service_handler.getProgramInfo(program))
1241 return program.audioStreams.size();
1244 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1246 int ret = selectAudioStream(i);
1248 if (m_decoder->start())
1254 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1256 eDVBServicePMTHandler::program program;
1258 if (m_service_handler.getProgramInfo(program))
1261 if (i >= program.audioStreams.size())
1264 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1265 info.m_description = "MPEG";
1266 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1267 info.m_description = "AC3";
1268 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1269 info.m_description = "AAC";
1270 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1271 info.m_description = "DTS";
1273 info.m_description = "???";
1275 if (program.audioStreams[i].component_tag != -1)
1277 ePtr<eServiceEvent> evt;
1278 if (!m_event_handler.getEvent(evt, 0))
1280 ePtr<eComponentData> data;
1281 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1282 info.m_language = data->getText();
1286 if (info.m_language.empty())
1287 info.m_language = program.audioStreams[i].language_code;
1292 int eDVBServicePlay::selectAudioStream(int i)
1294 eDVBServicePMTHandler::program program;
1296 if (m_service_handler.getProgramInfo(program))
1299 if ((unsigned int)i >= program.audioStreams.size())
1305 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1308 if (m_radiotext_parser)
1309 m_radiotext_parser->start(program.audioStreams[i].pid);
1311 if (m_dvb_service && !m_is_pvr)
1313 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1315 m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
1316 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1320 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1321 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
1325 m_current_audio_stream = i;
1330 int eDVBServicePlay::getCurrentChannel()
1332 return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1335 RESULT eDVBServicePlay::selectChannel(int i)
1337 if (i < LEFT || i > RIGHT || i == STEREO)
1340 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1342 m_decoder->setAudioChannel(i);
1346 std::string eDVBServicePlay::getRadioText(int x)
1348 if (m_radiotext_parser)
1352 return m_radiotext_parser->getCurrentText();
1357 void eDVBServicePlay::radioTextUpdated()
1359 m_event((iPlayableService*)this, evUpdatedRadioText);
1362 int eDVBServiceBase::getFrontendInfo(int w)
1364 eUsePtr<iDVBChannel> channel;
1365 if(m_service_handler.getChannel(channel))
1367 ePtr<iDVBFrontend> fe;
1368 if(channel->getFrontend(fe))
1370 return fe->readFrontendData(w);
1373 PyObject *eDVBServiceBase::getFrontendData(bool original)
1377 eUsePtr<iDVBChannel> channel;
1378 if(!m_service_handler.getChannel(channel))
1380 ePtr<iDVBFrontend> fe;
1381 if(!channel->getFrontend(fe))
1383 ret = fe->readTransponderData(original);
1386 ePtr<iDVBFrontendParameters> feparm;
1387 channel->getCurrentFrontendParameters(feparm);
1390 eDVBFrontendParametersSatellite osat;
1391 if (!feparm->getDVBS(osat))
1393 void PutToDict(PyObject *, const char*, long);
1394 void PutToDict(PyObject *, const char*, const char*);
1395 PutToDict(ret, "orbital_position", osat.orbital_position);
1396 const char *tmp = "UNKNOWN";
1397 switch(osat.polarisation)
1399 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1400 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1401 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1402 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1405 PutToDict(ret, "polarization", tmp);
1419 int eDVBServicePlay::getNumberOfSubservices()
1421 ePtr<eServiceEvent> evt;
1422 if (!m_event_handler.getEvent(evt, 0))
1423 return evt->getNumOfLinkageServices();
1427 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1429 ePtr<eServiceEvent> evt;
1430 if (!m_event_handler.getEvent(evt, 0))
1432 if (!evt->getLinkageService(sub, m_reference, n))
1435 sub.type=eServiceReference::idInvalid;
1439 RESULT eDVBServicePlay::startTimeshift()
1441 ePtr<iDVBDemux> demux;
1443 eDebug("Start timeshift!");
1445 if (m_timeshift_enabled)
1448 /* start recording with the data demux. */
1449 if (m_service_handler.getDataDemux(demux))
1452 demux->createTSRecorder(m_record);
1456 char templ[]=TSPATH "/timeshift.XXXXXX";
1457 m_timeshift_fd = mkstemp(templ);
1458 m_timeshift_file = templ;
1460 eDebug("recording to %s", templ);
1462 if (m_timeshift_fd < 0)
1468 m_record->setTargetFD(m_timeshift_fd);
1470 m_timeshift_enabled = 1;
1472 updateTimeshiftPids();
1478 RESULT eDVBServicePlay::stopTimeshift()
1480 if (!m_timeshift_enabled)
1485 m_timeshift_enabled = 0;
1490 close(m_timeshift_fd);
1491 eDebug("remove timeshift file");
1492 remove(m_timeshift_file.c_str());
1497 int eDVBServicePlay::isTimeshiftActive()
1499 return m_timeshift_enabled && m_timeshift_active;
1502 RESULT eDVBServicePlay::activateTimeshift()
1504 if (!m_timeshift_enabled)
1507 if (!m_timeshift_active)
1509 switchToTimeshift();
1516 PyObject *eDVBServicePlay::getCutList()
1518 PyObject *list = PyList_New(0);
1520 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1522 PyObject *tuple = PyTuple_New(2);
1523 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1524 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1525 PyList_Append(list, tuple);
1532 void eDVBServicePlay::setCutList(PyObject *list)
1534 if (!PyList_Check(list))
1536 int size = PyList_Size(list);
1539 m_cue_entries.clear();
1541 for (i=0; i<size; ++i)
1543 PyObject *tuple = PyList_GetItem(list, i);
1544 if (!PyTuple_Check(tuple))
1546 eDebug("non-tuple in cutlist");
1549 if (PyTuple_Size(tuple) != 2)
1551 eDebug("cutlist entries need to be a 2-tuple");
1554 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1555 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1557 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1560 pts_t pts = PyLong_AsLongLong(ppts);
1561 int type = PyInt_AsLong(ptype);
1562 m_cue_entries.insert(cueEntry(pts, type));
1563 eDebug("adding %08llx, %d", pts, type);
1565 m_cuesheet_changed = 1;
1567 cutlistToCuesheet();
1568 m_event((iPlayableService*)this, evCuesheetChanged);
1571 void eDVBServicePlay::setCutListEnable(int enable)
1573 m_cutlist_enabled = enable;
1574 cutlistToCuesheet();
1577 void eDVBServicePlay::updateTimeshiftPids()
1582 eDVBServicePMTHandler::program program;
1583 if (m_service_handler.getProgramInfo(program))
1587 std::set<int> pids_to_record;
1588 pids_to_record.insert(0); // PAT
1589 if (program.pmtPid != -1)
1590 pids_to_record.insert(program.pmtPid); // PMT
1592 if (program.textPid != -1)
1593 pids_to_record.insert(program.textPid); // Videotext
1595 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1596 i(program.videoStreams.begin());
1597 i != program.videoStreams.end(); ++i)
1598 pids_to_record.insert(i->pid);
1600 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1601 i(program.audioStreams.begin());
1602 i != program.audioStreams.end(); ++i)
1603 pids_to_record.insert(i->pid);
1605 std::set<int> new_pids, obsolete_pids;
1607 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1608 m_pids_active.begin(), m_pids_active.end(),
1609 std::inserter(new_pids, new_pids.begin()));
1611 std::set_difference(
1612 m_pids_active.begin(), m_pids_active.end(),
1613 pids_to_record.begin(), pids_to_record.end(),
1614 std::inserter(new_pids, new_pids.begin())
1617 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1618 m_record->addPID(*i);
1620 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1621 m_record->removePID(*i);
1625 void eDVBServicePlay::switchToLive()
1627 if (!m_timeshift_active)
1633 m_teletext_parser = 0;
1634 m_radiotext_parser = 0;
1635 m_new_subtitle_page_connection = 0;
1636 m_radiotext_updated_connection = 0;
1638 /* free the timeshift service handler, we need the resources */
1639 m_service_handler_timeshift.free();
1640 m_timeshift_active = 0;
1642 m_event((iPlayableService*)this, evSeekableStatusChanged);
1647 void eDVBServicePlay::switchToTimeshift()
1649 if (m_timeshift_active)
1654 m_teletext_parser = 0;
1655 m_radiotext_parser = 0;
1656 m_new_subtitle_page_connection = 0;
1657 m_radiotext_updated_connection = 0;
1659 m_timeshift_active = 1;
1661 m_event((iPlayableService*)this, evSeekableStatusChanged);
1663 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1664 r.path = m_timeshift_file;
1666 m_cue = new eCueSheet();
1667 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1668 updateDecoder(); /* mainly to switch off PCR */
1671 void eDVBServicePlay::updateDecoder()
1673 int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
1675 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1677 bool defaultac3=false;
1678 std::string default_ac3;
1680 if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1681 defaultac3 = default_ac3 == "enable";
1683 eDVBServicePMTHandler::program program;
1684 if (h.getProgramInfo(program))
1685 eDebug("getting program info failed.");
1688 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1689 if (!program.videoStreams.empty())
1691 eDebugNoNewLine(" (");
1692 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1693 i(program.videoStreams.begin());
1694 i != program.videoStreams.end(); ++i)
1701 if (i != program.videoStreams.begin())
1702 eDebugNoNewLine(", ");
1703 eDebugNoNewLine("%04x", i->pid);
1705 eDebugNoNewLine(")");
1707 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1708 if (!program.audioStreams.empty())
1710 eDebugNoNewLine(" (");
1711 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1712 i(program.audioStreams.begin());
1713 i != program.audioStreams.end(); ++i)
1715 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1717 if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1723 if (i != program.audioStreams.begin())
1724 eDebugNoNewLine(", ");
1725 eDebugNoNewLine("%04x", i->pid);
1727 eDebugNoNewLine(")");
1729 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1730 pcrpid = program.pcrPid;
1731 eDebug(", and the text pid is %04x", program.textPid);
1732 tpid = program.textPid;
1737 h.getDecodeDemux(m_decode_demux);
1739 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1741 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1742 #ifdef INTERNAL_TELETEXT
1743 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1744 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
1752 achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1753 ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
1754 pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
1756 else // subservice or recording
1758 eServiceReferenceDVB ref;
1759 m_service_handler.getServiceReference(ref);
1760 eServiceReferenceDVB parent = ref.getParentServiceReference();
1765 ePtr<eDVBResourceManager> res_mgr;
1766 if (!eDVBResourceManager::getInstance(res_mgr))
1768 ePtr<iDVBChannelList> db;
1769 if (!res_mgr->getChannelList(db))
1771 ePtr<eDVBService> origService;
1772 if (!db->getService(parent, origService))
1774 ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
1775 pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
1781 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
1782 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
1784 m_decoder->setVideoPID(vpid, vpidtype);
1785 m_current_audio_stream = 0;
1786 m_decoder->setAudioPID(apid, apidtype);
1787 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1789 m_decoder->setSyncPCR(pcrpid);
1792 ePtr<iDVBDemux> data_demux;
1793 if (!h.getDataDemux(data_demux))
1795 m_radiotext_parser = new eDVBRadioTextParser(data_demux);
1796 m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
1797 m_radiotext_parser->start(apid);
1802 m_decoder->setSyncPCR(-1);
1804 m_decoder->setTextPID(tpid);
1806 if (m_teletext_parser)
1807 m_teletext_parser->start(tpid);
1810 m_decoder->setTrickmode(1);
1814 if (vpid > 0 && vpid < 0x2000)
1818 std::string radio_pic;
1819 if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1820 m_decoder->setRadioPic(radio_pic);
1823 m_decoder->setAudioChannel(achannel);
1825 // how we can do this better?
1826 // update cache pid when the user changed the audio track or video track
1827 // TODO handling of difference audio types.. default audio types..
1829 /* don't worry about non-existing services, nor pvr services */
1830 if (m_dvb_service && !m_is_pvr)
1832 if (apidtype == eDVBAudio::aMPEG)
1834 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1835 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1839 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1840 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1842 m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1843 m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1844 m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1845 m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1848 m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1851 void eDVBServicePlay::loadCuesheet()
1853 std::string filename = m_reference.path + ".cuts";
1855 m_cue_entries.clear();
1857 FILE *f = fopen(filename.c_str(), "rb");
1861 eDebug("loading cuts..");
1864 unsigned long long where;
1867 if (!fread(&where, sizeof(where), 1, f))
1869 if (!fread(&what, sizeof(what), 1, f))
1872 #if BYTE_ORDER == LITTLE_ENDIAN
1873 where = bswap_64(where);
1880 m_cue_entries.insert(cueEntry(where, what));
1883 eDebug("%d entries", m_cue_entries.size());
1885 eDebug("cutfile not found!");
1887 m_cuesheet_changed = 0;
1888 cutlistToCuesheet();
1889 m_event((iPlayableService*)this, evCuesheetChanged);
1892 void eDVBServicePlay::saveCuesheet()
1894 std::string filename = m_reference.path + ".cuts";
1896 FILE *f = fopen(filename.c_str(), "wb");
1900 unsigned long long where;
1903 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1905 #if BYTE_ORDER == BIG_ENDIAN
1908 where = bswap_64(i->where);
1910 what = htonl(i->what);
1911 fwrite(&where, sizeof(where), 1, f);
1912 fwrite(&what, sizeof(what), 1, f);
1918 m_cuesheet_changed = 0;
1921 void eDVBServicePlay::cutlistToCuesheet()
1925 eDebug("no cue sheet");
1930 if (!m_cutlist_enabled)
1932 m_cue->commitSpans();
1933 eDebug("cutlists were disabled");
1937 pts_t in = 0, out = 0, length = 0;
1941 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1945 if (i == m_cue_entries.end())
1948 if (i->what == 0) /* in */
1952 } else if (i->what == 1) /* out */
1954 else /* mark (2) or last play position (3) */
1962 m_cue->addSourceSpan(in, out);
1966 if (i == m_cue_entries.end())
1969 m_cue->commitSpans();
1972 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1974 if (m_subtitle_widget)
1975 disableSubtitles(parent);
1977 if (!m_teletext_parser)
1980 if (!PyInt_Check(entry))
1983 m_subtitle_widget = new eSubtitleWidget(parent);
1984 m_subtitle_widget->resize(parent->size()); /* full size */
1986 int page = PyInt_AsLong(entry);
1988 m_teletext_parser->setPage(page);
1993 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
1995 delete m_subtitle_widget;
1996 m_subtitle_widget = 0;
2000 PyObject *eDVBServicePlay::getSubtitleList()
2002 if (!m_teletext_parser)
2008 PyObject *l = PyList_New(0);
2010 for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
2012 PyObject *tuple = PyTuple_New(2);
2014 sprintf(desc, "Page %x", *i);
2015 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2016 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
2017 PyList_Append(l, tuple);
2023 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2025 if (m_subtitle_widget)
2027 m_subtitle_pages.push_back(page);
2029 checkSubtitleTiming();
2033 void eDVBServicePlay::checkSubtitleTiming()
2037 if (m_subtitle_pages.empty())
2040 eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
2045 m_decoder->getPTS(0, pos);
2047 int diff = p.m_pts - pos;
2050 eDebug("[late (%d ms)]", -diff / 90);
2055 eDebug("[invalid]");
2061 m_subtitle_widget->setPage(p);
2062 m_subtitle_pages.pop_front();
2065 m_subtitle_sync_timer.start(diff / 90, 1);
2071 int eDVBServicePlay::getAC3Delay()
2074 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2076 return m_decoder->getAC3Delay();
2081 int eDVBServicePlay::getPCMDelay()
2084 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2086 return m_decoder->getPCMDelay();
2091 void eDVBServicePlay::setAC3Delay(int delay)
2094 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2096 m_decoder->setAC3Delay(delay);
2099 void eDVBServicePlay::setPCMDelay(int delay)
2102 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2104 m_decoder->setPCMDelay(delay);
2107 DEFINE_REF(eDVBServicePlay)
2109 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");