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[0].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);
1328 int eDVBServicePlay::getCurrentChannel()
1330 return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1333 RESULT eDVBServicePlay::selectChannel(int i)
1335 if (i < LEFT || i > RIGHT || i == STEREO)
1338 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1340 m_decoder->setAudioChannel(i);
1344 std::string eDVBServicePlay::getRadioText(int x)
1346 if (m_radiotext_parser)
1350 return m_radiotext_parser->getCurrentText();
1355 void eDVBServicePlay::radioTextUpdated()
1357 m_event((iPlayableService*)this, evUpdatedRadioText);
1360 int eDVBServiceBase::getFrontendInfo(int w)
1362 eUsePtr<iDVBChannel> channel;
1363 if(m_service_handler.getChannel(channel))
1365 ePtr<iDVBFrontend> fe;
1366 if(channel->getFrontend(fe))
1368 return fe->readFrontendData(w);
1371 PyObject *eDVBServiceBase::getFrontendData(bool original)
1375 eUsePtr<iDVBChannel> channel;
1376 if(!m_service_handler.getChannel(channel))
1378 ePtr<iDVBFrontend> fe;
1379 if(!channel->getFrontend(fe))
1381 ret = fe->readTransponderData(original);
1384 ePtr<iDVBFrontendParameters> feparm;
1385 channel->getCurrentFrontendParameters(feparm);
1388 eDVBFrontendParametersSatellite osat;
1389 if (!feparm->getDVBS(osat))
1391 void PutToDict(PyObject *, const char*, long);
1392 void PutToDict(PyObject *, const char*, const char*);
1393 PutToDict(ret, "orbital_position", osat.orbital_position);
1394 const char *tmp = "UNKNOWN";
1395 switch(osat.polarisation)
1397 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1398 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1399 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1400 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1403 PutToDict(ret, "polarization", tmp);
1417 int eDVBServicePlay::getNumberOfSubservices()
1419 ePtr<eServiceEvent> evt;
1420 if (!m_event_handler.getEvent(evt, 0))
1421 return evt->getNumOfLinkageServices();
1425 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1427 ePtr<eServiceEvent> evt;
1428 if (!m_event_handler.getEvent(evt, 0))
1430 if (!evt->getLinkageService(sub, m_reference, n))
1433 sub.type=eServiceReference::idInvalid;
1437 RESULT eDVBServicePlay::startTimeshift()
1439 ePtr<iDVBDemux> demux;
1441 eDebug("Start timeshift!");
1443 if (m_timeshift_enabled)
1446 /* start recording with the data demux. */
1447 if (m_service_handler.getDataDemux(demux))
1450 demux->createTSRecorder(m_record);
1454 char templ[]=TSPATH "/timeshift.XXXXXX";
1455 m_timeshift_fd = mkstemp(templ);
1456 m_timeshift_file = templ;
1458 eDebug("recording to %s", templ);
1460 if (m_timeshift_fd < 0)
1466 m_record->setTargetFD(m_timeshift_fd);
1468 m_timeshift_enabled = 1;
1470 updateTimeshiftPids();
1476 RESULT eDVBServicePlay::stopTimeshift()
1478 if (!m_timeshift_enabled)
1483 m_timeshift_enabled = 0;
1488 close(m_timeshift_fd);
1489 eDebug("remove timeshift file");
1490 remove(m_timeshift_file.c_str());
1495 int eDVBServicePlay::isTimeshiftActive()
1497 return m_timeshift_enabled && m_timeshift_active;
1500 RESULT eDVBServicePlay::activateTimeshift()
1502 if (!m_timeshift_enabled)
1505 if (!m_timeshift_active)
1507 switchToTimeshift();
1514 PyObject *eDVBServicePlay::getCutList()
1516 PyObject *list = PyList_New(0);
1518 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1520 PyObject *tuple = PyTuple_New(2);
1521 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1522 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1523 PyList_Append(list, tuple);
1530 void eDVBServicePlay::setCutList(PyObject *list)
1532 if (!PyList_Check(list))
1534 int size = PyList_Size(list);
1537 m_cue_entries.clear();
1539 for (i=0; i<size; ++i)
1541 PyObject *tuple = PyList_GetItem(list, i);
1542 if (!PyTuple_Check(tuple))
1544 eDebug("non-tuple in cutlist");
1547 if (PyTuple_Size(tuple) != 2)
1549 eDebug("cutlist entries need to be a 2-tuple");
1552 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1553 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1555 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1558 pts_t pts = PyLong_AsLongLong(ppts);
1559 int type = PyInt_AsLong(ptype);
1560 m_cue_entries.insert(cueEntry(pts, type));
1561 eDebug("adding %08llx, %d", pts, type);
1563 m_cuesheet_changed = 1;
1565 cutlistToCuesheet();
1566 m_event((iPlayableService*)this, evCuesheetChanged);
1569 void eDVBServicePlay::setCutListEnable(int enable)
1571 m_cutlist_enabled = enable;
1572 cutlistToCuesheet();
1575 void eDVBServicePlay::updateTimeshiftPids()
1580 eDVBServicePMTHandler::program program;
1581 if (m_service_handler.getProgramInfo(program))
1585 std::set<int> pids_to_record;
1586 pids_to_record.insert(0); // PAT
1587 if (program.pmtPid != -1)
1588 pids_to_record.insert(program.pmtPid); // PMT
1590 if (program.textPid != -1)
1591 pids_to_record.insert(program.textPid); // Videotext
1593 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1594 i(program.videoStreams.begin());
1595 i != program.videoStreams.end(); ++i)
1596 pids_to_record.insert(i->pid);
1598 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1599 i(program.audioStreams.begin());
1600 i != program.audioStreams.end(); ++i)
1601 pids_to_record.insert(i->pid);
1603 std::set<int> new_pids, obsolete_pids;
1605 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1606 m_pids_active.begin(), m_pids_active.end(),
1607 std::inserter(new_pids, new_pids.begin()));
1609 std::set_difference(
1610 m_pids_active.begin(), m_pids_active.end(),
1611 pids_to_record.begin(), pids_to_record.end(),
1612 std::inserter(new_pids, new_pids.begin())
1615 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1616 m_record->addPID(*i);
1618 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1619 m_record->removePID(*i);
1623 void eDVBServicePlay::switchToLive()
1625 if (!m_timeshift_active)
1631 m_teletext_parser = 0;
1632 m_radiotext_parser = 0;
1633 m_new_subtitle_page_connection = 0;
1634 m_radiotext_updated_connection = 0;
1636 /* free the timeshift service handler, we need the resources */
1637 m_service_handler_timeshift.free();
1638 m_timeshift_active = 0;
1640 m_event((iPlayableService*)this, evSeekableStatusChanged);
1645 void eDVBServicePlay::switchToTimeshift()
1647 if (m_timeshift_active)
1652 m_teletext_parser = 0;
1653 m_radiotext_parser = 0;
1654 m_new_subtitle_page_connection = 0;
1655 m_radiotext_updated_connection = 0;
1657 m_timeshift_active = 1;
1659 m_event((iPlayableService*)this, evSeekableStatusChanged);
1661 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1662 r.path = m_timeshift_file;
1664 m_cue = new eCueSheet();
1665 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1666 updateDecoder(); /* mainly to switch off PCR */
1669 void eDVBServicePlay::updateDecoder()
1671 int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
1673 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1675 bool defaultac3=false;
1676 std::string default_ac3;
1678 if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1679 defaultac3 = default_ac3 == "enable";
1681 eDVBServicePMTHandler::program program;
1682 if (h.getProgramInfo(program))
1683 eDebug("getting program info failed.");
1686 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1687 if (!program.videoStreams.empty())
1689 eDebugNoNewLine(" (");
1690 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1691 i(program.videoStreams.begin());
1692 i != program.videoStreams.end(); ++i)
1699 if (i != program.videoStreams.begin())
1700 eDebugNoNewLine(", ");
1701 eDebugNoNewLine("%04x", i->pid);
1703 eDebugNoNewLine(")");
1705 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1706 if (!program.audioStreams.empty())
1708 eDebugNoNewLine(" (");
1709 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1710 i(program.audioStreams.begin());
1711 i != program.audioStreams.end(); ++i)
1713 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1715 if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1721 if (i != program.audioStreams.begin())
1722 eDebugNoNewLine(", ");
1723 eDebugNoNewLine("%04x", i->pid);
1725 eDebugNoNewLine(")");
1727 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1728 pcrpid = program.pcrPid;
1729 eDebug(", and the text pid is %04x", program.textPid);
1730 tpid = program.textPid;
1735 h.getDecodeDemux(m_decode_demux);
1737 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1739 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1740 #ifdef INTERNAL_TELETEXT
1741 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1742 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
1750 achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1751 ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
1752 pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
1754 else // subservice or recording
1756 eServiceReferenceDVB ref;
1757 m_service_handler.getServiceReference(ref);
1758 eServiceReferenceDVB parent = ref.getParentServiceReference();
1763 ePtr<eDVBResourceManager> res_mgr;
1764 if (!eDVBResourceManager::getInstance(res_mgr))
1766 ePtr<iDVBChannelList> db;
1767 if (!res_mgr->getChannelList(db))
1769 ePtr<eDVBService> origService;
1770 if (!db->getService(parent, origService))
1772 ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
1773 pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
1779 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
1780 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
1782 m_decoder->setVideoPID(vpid, vpidtype);
1783 m_decoder->setAudioPID(apid, apidtype);
1784 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1786 m_decoder->setSyncPCR(pcrpid);
1789 ePtr<iDVBDemux> data_demux;
1790 if (!h.getDataDemux(data_demux))
1792 m_radiotext_parser = new eDVBRadioTextParser(data_demux);
1793 m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
1794 m_radiotext_parser->start(apid);
1799 m_decoder->setSyncPCR(-1);
1801 m_decoder->setTextPID(tpid);
1803 if (m_teletext_parser)
1804 m_teletext_parser->start(tpid);
1807 m_decoder->setTrickmode(1);
1811 if (vpid > 0 && vpid < 0x2000)
1815 std::string radio_pic;
1816 if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1817 m_decoder->setRadioPic(radio_pic);
1820 m_decoder->setAudioChannel(achannel);
1822 // how we can do this better?
1823 // update cache pid when the user changed the audio track or video track
1824 // TODO handling of difference audio types.. default audio types..
1826 /* don't worry about non-existing services, nor pvr services */
1827 if (m_dvb_service && !m_is_pvr)
1829 if (apidtype == eDVBAudio::aMPEG)
1831 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1832 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1836 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1837 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1839 m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1840 m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1841 m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1842 m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1845 m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1848 void eDVBServicePlay::loadCuesheet()
1850 std::string filename = m_reference.path + ".cuts";
1852 m_cue_entries.clear();
1854 FILE *f = fopen(filename.c_str(), "rb");
1858 eDebug("loading cuts..");
1861 unsigned long long where;
1864 if (!fread(&where, sizeof(where), 1, f))
1866 if (!fread(&what, sizeof(what), 1, f))
1869 #if BYTE_ORDER == LITTLE_ENDIAN
1870 where = bswap_64(where);
1877 m_cue_entries.insert(cueEntry(where, what));
1880 eDebug("%d entries", m_cue_entries.size());
1882 eDebug("cutfile not found!");
1884 m_cuesheet_changed = 0;
1885 cutlistToCuesheet();
1886 m_event((iPlayableService*)this, evCuesheetChanged);
1889 void eDVBServicePlay::saveCuesheet()
1891 std::string filename = m_reference.path + ".cuts";
1893 FILE *f = fopen(filename.c_str(), "wb");
1897 unsigned long long where;
1900 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1902 #if BYTE_ORDER == BIG_ENDIAN
1905 where = bswap_64(i->where);
1907 what = htonl(i->what);
1908 fwrite(&where, sizeof(where), 1, f);
1909 fwrite(&what, sizeof(what), 1, f);
1915 m_cuesheet_changed = 0;
1918 void eDVBServicePlay::cutlistToCuesheet()
1922 eDebug("no cue sheet");
1927 if (!m_cutlist_enabled)
1929 m_cue->commitSpans();
1930 eDebug("cutlists were disabled");
1934 pts_t in = 0, out = 0, length = 0;
1938 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1942 if (i == m_cue_entries.end())
1945 if (i->what == 0) /* in */
1949 } else if (i->what == 1) /* out */
1951 else /* mark (2) or last play position (3) */
1959 m_cue->addSourceSpan(in, out);
1963 if (i == m_cue_entries.end())
1966 m_cue->commitSpans();
1969 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1971 if (m_subtitle_widget)
1972 disableSubtitles(parent);
1974 if (!m_teletext_parser)
1977 if (!PyInt_Check(entry))
1980 m_subtitle_widget = new eSubtitleWidget(parent);
1981 m_subtitle_widget->resize(parent->size()); /* full size */
1983 int page = PyInt_AsLong(entry);
1985 m_teletext_parser->setPage(page);
1990 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
1992 delete m_subtitle_widget;
1993 m_subtitle_widget = 0;
1997 PyObject *eDVBServicePlay::getSubtitleList()
1999 if (!m_teletext_parser)
2005 PyObject *l = PyList_New(0);
2007 for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
2009 PyObject *tuple = PyTuple_New(2);
2011 sprintf(desc, "Page %x", *i);
2012 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2013 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
2014 PyList_Append(l, tuple);
2020 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2022 if (m_subtitle_widget)
2024 m_subtitle_pages.push_back(page);
2026 checkSubtitleTiming();
2030 void eDVBServicePlay::checkSubtitleTiming()
2034 if (m_subtitle_pages.empty())
2037 eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
2042 m_decoder->getPTS(0, pos);
2044 int diff = p.m_pts - pos;
2047 eDebug("[late (%d ms)]", -diff / 90);
2052 eDebug("[invalid]");
2058 m_subtitle_widget->setPage(p);
2059 m_subtitle_pages.pop_front();
2062 m_subtitle_sync_timer.start(diff / 90, 1);
2068 int eDVBServicePlay::getAC3Delay()
2071 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2073 return m_decoder->getAC3Delay();
2078 int eDVBServicePlay::getPCMDelay()
2081 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2083 return m_decoder->getPCMDelay();
2088 void eDVBServicePlay::setAC3Delay(int delay)
2091 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2093 m_decoder->setAC3Delay(delay);
2096 void eDVBServicePlay::setPCMDelay(int delay)
2099 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2101 m_decoder->setPCMDelay(delay);
2104 DEFINE_REF(eDVBServicePlay)
2106 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");