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>
27 #include <netinet/in.h>
29 #define INTERNAL_TELETEXT
32 #error no byte order defined!
35 #define TSPATH "/media/hdd"
37 class eStaticServiceDVBInformation: public iStaticServiceInformation
39 DECLARE_REF(eStaticServiceDVBInformation);
41 RESULT getName(const eServiceReference &ref, std::string &name);
42 int getLength(const eServiceReference &ref);
45 DEFINE_REF(eStaticServiceDVBInformation);
47 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
49 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
50 if ( !ref.name.empty() )
52 if (service.getParentTransportStreamID().get()) // linkage subservice
54 ePtr<iServiceHandler> service_center;
55 if (!eServiceCenter::getInstance(service_center))
57 eServiceReferenceDVB parent = service;
58 parent.setTransportStreamID( service.getParentTransportStreamID() );
59 parent.setServiceID( service.getParentServiceID() );
60 parent.setParentTransportStreamID(eTransportStreamID(0));
61 parent.setParentServiceID(eServiceID(0));
63 ePtr<iStaticServiceInformation> service_info;
64 if (!service_center->info(parent, service_info))
66 if (!service_info->getName(parent, name))
68 // just show short name
69 unsigned int pos = name.find("\xc2\x86");
70 if ( pos != std::string::npos )
72 pos = name.find("\xc2\x87");
73 if ( pos != std::string::npos )
89 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
94 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
96 DECLARE_REF(eStaticServiceDVBBouquetInformation);
98 RESULT getName(const eServiceReference &ref, std::string &name);
99 int getLength(const eServiceReference &ref);
102 DEFINE_REF(eStaticServiceDVBBouquetInformation);
104 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
106 ePtr<iDVBChannelList> db;
107 ePtr<eDVBResourceManager> res;
110 if ((err = eDVBResourceManager::getInstance(res)) != 0)
112 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
115 if ((err = res->getChannelList(db)) != 0)
117 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
122 if ((err = db->getBouquet(ref, bouquet)) != 0)
124 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
128 if ( bouquet && bouquet->m_bouquet_name.length() )
130 name = bouquet->m_bouquet_name;
137 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
142 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
144 DECLARE_REF(eStaticServiceDVBPVRInformation);
145 eServiceReference m_ref;
146 eDVBMetaParser m_parser;
148 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
149 RESULT getName(const eServiceReference &ref, std::string &name);
150 int getLength(const eServiceReference &ref);
151 RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
153 int getInfo(const eServiceReference &ref, int w);
154 std::string getInfoString(const eServiceReference &ref,int w);
157 DEFINE_REF(eStaticServiceDVBPVRInformation);
159 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
162 m_parser.parseFile(ref.path);
165 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
167 ASSERT(ref == m_ref);
168 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
172 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
174 ASSERT(ref == m_ref);
178 if (tstools.openFile(ref.path.c_str()))
182 if (tstools.calcLen(len))
188 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
192 case iServiceInformation::sDescription:
193 return iServiceInformation::resIsString;
194 case iServiceInformation::sServiceref:
195 return iServiceInformation::resIsString;
196 case iServiceInformation::sTimeCreate:
197 if (m_parser.m_time_create)
198 return m_parser.m_time_create;
200 return iServiceInformation::resNA;
202 return iServiceInformation::resNA;
206 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
210 case iServiceInformation::sDescription:
211 return m_parser.m_description;
212 case iServiceInformation::sServiceref:
213 return m_parser.m_ref.toString();
219 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
221 if (!ref.path.empty())
223 ePtr<eServiceEvent> event = new eServiceEvent;
224 std::string filename = ref.path;
225 filename.erase(filename.length()-2, 2);
227 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
237 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
239 DECLARE_REF(eDVBPVRServiceOfflineOperations);
240 eServiceReferenceDVB m_ref;
242 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
244 RESULT deleteFromDisk(int simulate);
245 RESULT getListOfFilenames(std::list<std::string> &);
248 DEFINE_REF(eDVBPVRServiceOfflineOperations);
250 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
254 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
260 std::list<std::string> res;
261 if (getListOfFilenames(res))
264 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
266 eDebug("FATAL !! can't get background file eraser");
268 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
270 eDebug("Removing %s...", i->c_str());
272 eraser->erase(i->c_str());
274 ::unlink(i->c_str());
281 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
284 res.push_back(m_ref.path);
286 // handling for old splitted recordings (enigma 1)
291 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
293 if (stat(buf, &s) < 0)
298 res.push_back(m_ref.path + ".meta");
299 res.push_back(m_ref.path + ".ap");
300 res.push_back(m_ref.path + ".cuts");
301 std::string tmp = m_ref.path;
302 tmp.erase(m_ref.path.length()-3);
303 res.push_back(tmp + ".eit");
307 DEFINE_REF(eServiceFactoryDVB)
309 eServiceFactoryDVB::eServiceFactoryDVB()
311 ePtr<eServiceCenter> sc;
313 eServiceCenter::getPrivInstance(sc);
315 sc->addServiceFactory(eServiceFactoryDVB::id, this);
317 m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
318 m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
321 eServiceFactoryDVB::~eServiceFactoryDVB()
323 ePtr<eServiceCenter> sc;
325 eServiceCenter::getPrivInstance(sc);
327 sc->removeServiceFactory(eServiceFactoryDVB::id);
330 DEFINE_REF(eDVBServiceList);
332 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
336 eDVBServiceList::~eDVBServiceList()
340 RESULT eDVBServiceList::startQuery()
342 ePtr<iDVBChannelList> db;
343 ePtr<eDVBResourceManager> res;
346 if ((err = eDVBResourceManager::getInstance(res)) != 0)
348 eDebug("no resource manager");
351 if ((err = res->getChannelList(db)) != 0)
353 eDebug("no channel list");
357 ePtr<eDVBChannelQuery> q;
359 if (!m_parent.path.empty())
361 eDVBChannelQuery::compile(q, m_parent.path);
364 eDebug("compile query failed");
369 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
371 eDebug("startQuery failed");
378 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
380 eServiceReferenceDVB ref;
385 while (!m_query->getNextResult(ref))
389 list.sort(iListableServiceCompare(this));
394 // The first argument of this function is a format string to specify the order and
395 // the content of the returned list
396 // useable format options are
397 // R = Service Reference (as swig object .. this is very slow)
398 // S = Service Reference (as python string object .. same as ref.toString())
399 // N = Service Name (as python string object)
400 // when exactly one return value per service is selected in the format string,
401 // then each value is directly a list entry
402 // when more than one value is returned per service, then the list is a list of
404 // unknown format string chars are returned as python None values !
405 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
408 std::list<eServiceReference> tmplist;
411 if (!format || !(retcount=strlen(format)))
412 format = "R"; // just return service reference swig object ...
414 if (!getContent(tmplist, sorted))
416 int services=tmplist.size();
417 ePtr<iStaticServiceInformation> sptr;
418 eServiceCenterPtr service_center;
420 if (strchr(format, 'N'))
421 eServiceCenter::getPrivInstance(service_center);
423 ret = PyList_New(services);
424 std::list<eServiceReference>::iterator it(tmplist.begin());
426 for (int cnt=0; cnt < services; ++cnt)
428 eServiceReference &ref=*it++;
429 PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
430 for (int i=0; i < retcount; ++i)
435 case 'R': // service reference (swig)object
436 tmp = New_eServiceReference(ref);
438 case 'S': // service reference string
439 tmp = PyString_FromString(ref.toString().c_str());
441 case 'N': // service name
444 service_center->info(ref, sptr);
448 sptr->getName(ref, name);
450 tmp = PyString_FromString(name.c_str());
454 tmp = PyString_FromString("<n/a>");
467 PyTuple_SET_ITEM(tuple, i, tmp);
469 PyList_SET_ITEM(ret, cnt, tmp);
473 PyList_SET_ITEM(ret, cnt, tuple);
476 return ret ? ret : PyList_New(0);
479 RESULT eDVBServiceList::getNext(eServiceReference &ref)
484 return m_query->getNextResult((eServiceReferenceDVB&)ref);
487 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
489 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
492 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
494 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
496 ePtr<iDVBChannelList> db;
497 ePtr<eDVBResourceManager> resm;
499 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
502 if (db->getBouquet(m_parent, m_bouquet) != 0)
513 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
517 return m_bouquet->addService(ref, before);
520 RESULT eDVBServiceList::removeService(eServiceReference &ref)
524 return m_bouquet->removeService(ref);
527 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
531 return m_bouquet->moveService(ref, pos);
534 RESULT eDVBServiceList::flushChanges()
538 return m_bouquet->flushChanges();
541 RESULT eDVBServiceList::setListName(const std::string &name)
545 return m_bouquet->setListName(name);
548 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
550 ePtr<eDVBService> service;
551 int r = lookupService(service, ref);
554 // check resources...
555 ptr = new eDVBServicePlay(ref, service);
559 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
561 if (ref.path.empty())
563 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
572 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
574 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
575 if (list->startQuery())
585 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
587 /* is a listable service? */
588 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
590 if ( !ref.name.empty() ) // satellites or providers list
591 ptr = m_StaticServiceDVBInfo;
592 else // a dvb bouquet
593 ptr = m_StaticServiceDVBBouquetInfo;
595 else if (!ref.path.empty()) /* do we have a PVR service? */
596 ptr = new eStaticServiceDVBPVRInformation(ref);
597 else // normal dvb service
599 ePtr<eDVBService> service;
600 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
601 ptr = m_StaticServiceDVBInfo;
603 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
609 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
611 if (ref.path.empty())
617 ptr = new eDVBPVRServiceOfflineOperations(ref);
622 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
624 // TODO: handle the listing itself
625 // if (ref.... == -1) .. return "... bouquets ...";
626 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
628 ePtr<iDVBChannelList> db;
629 ePtr<eDVBResourceManager> res;
632 if ((err = eDVBResourceManager::getInstance(res)) != 0)
634 eDebug("no resource manager");
637 if ((err = res->getChannelList(db)) != 0)
639 eDebug("no channel list");
643 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
644 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
646 eDebug("getService failed!");
653 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
654 m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
657 m_is_pvr = !m_reference.path.empty();
659 m_timeshift_enabled = m_timeshift_active = 0;
662 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
663 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
664 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
666 m_cuesheet_changed = 0;
667 m_cutlist_enabled = 1;
669 m_subtitle_widget = 0;
671 CONNECT(m_subtitle_sync_timer.timeout, eDVBServicePlay::checkSubtitleTiming);
674 eDVBServicePlay::~eDVBServicePlay()
676 delete m_subtitle_widget;
679 void eDVBServicePlay::gotNewEvent()
683 ePtr<eServiceEvent> m_event_now, m_event_next;
684 getEvent(m_event_now, 0);
685 getEvent(m_event_next, 1);
688 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
690 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
692 m_event((iPlayableService*)this, evUpdatedEventInfo);
695 void eDVBServicePlay::serviceEvent(int event)
699 case eDVBServicePMTHandler::eventTuned:
701 ePtr<iDVBDemux> m_demux;
702 if (!m_service_handler.getDataDemux(m_demux))
704 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
705 int sid = ref.getParentServiceID().get();
707 sid = ref.getServiceID().get();
708 if ( ref.getParentTransportStreamID().get() &&
709 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
710 m_event_handler.startOther(m_demux, sid);
712 m_event_handler.start(m_demux, sid);
716 case eDVBServicePMTHandler::eventTuneFailed:
718 eDebug("DVB service failed to tune");
719 m_event((iPlayableService*)this, evTuneFailed);
722 case eDVBServicePMTHandler::eventNewProgramInfo:
724 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
725 if (m_timeshift_enabled)
726 updateTimeshiftPids();
727 if (!m_timeshift_active)
729 if (m_first_program_info && m_is_pvr)
731 m_first_program_info = 0;
734 m_event((iPlayableService*)this, evUpdatedInfo);
737 case eDVBServicePMTHandler::eventEOF:
738 m_event((iPlayableService*)this, evEOF);
740 case eDVBServicePMTHandler::eventSOF:
741 m_event((iPlayableService*)this, evSOF);
746 void eDVBServicePlay::serviceEventTimeshift(int event)
750 case eDVBServicePMTHandler::eventNewProgramInfo:
751 if (m_timeshift_active)
754 case eDVBServicePMTHandler::eventSOF:
755 m_event((iPlayableService*)this, evSOF);
757 case eDVBServicePMTHandler::eventEOF:
763 RESULT eDVBServicePlay::start()
766 /* in pvr mode, we only want to use one demux. in tv mode, we're using
767 two (one for decoding, one for data source), as we must be prepared
768 to start recording from the data demux. */
770 m_cue = new eCueSheet();
772 m_first_program_info = 1;
773 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
774 r = m_service_handler.tune(service, m_is_pvr, m_cue);
776 /* inject EIT if there is a stored one */
779 std::string filename = service.path;
780 filename.erase(filename.length()-2, 2);
782 ePtr<eServiceEvent> event = new eServiceEvent;
783 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
785 ePtr<eServiceEvent> empty;
786 m_event_handler.inject(event, 0);
787 m_event_handler.inject(empty, 1);
794 m_event(this, evStart);
795 m_event((iPlayableService*)this, evSeekableStatusChanged);
799 RESULT eDVBServicePlay::stop()
801 /* add bookmark for last play position */
805 if (!getPlayPosition(play_position))
807 /* remove last position */
808 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
810 if (i->what == 3) /* current play position */
812 m_cue_entries.erase(i);
813 i = m_cue_entries.begin();
819 m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
820 m_cuesheet_changed = 1;
824 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
826 m_service_handler_timeshift.free();
827 m_service_handler.free();
829 if (m_is_pvr && m_cuesheet_changed)
832 /* save cuesheet only when main file is accessible. */
833 if (!::stat(m_reference.path.c_str(), &s))
840 RESULT eDVBServicePlay::setTarget(int target)
842 m_is_primary = !target;
846 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
848 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
852 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
854 /* note: we check for timeshift to be enabled,
855 not neccessary active. if you pause when timeshift
856 is not active, you should activate it when unpausing */
857 if ((!m_is_pvr) && (!m_timeshift_enabled))
867 RESULT eDVBServicePlay::setSlowMotion(int ratio)
870 return m_decoder->setSlowMotion(ratio);
875 RESULT eDVBServicePlay::setFastForward(int ratio)
877 int skipmode, ffratio;
883 } else if (ratio > 0)
891 } else // if (ratio < 0)
897 if (m_skipmode != skipmode)
899 eDebug("setting cue skipmode to %d", skipmode);
901 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
904 m_skipmode = skipmode;
909 return m_decoder->setFastForward(ffratio);
912 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
914 if (m_is_pvr || m_timeshift_enabled)
924 /* TODO: when timeshift is enabled but not active, this doesn't work. */
925 RESULT eDVBServicePlay::getLength(pts_t &len)
927 ePtr<iDVBPVRChannel> pvr_channel;
929 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
932 return pvr_channel->getLength(len);
935 RESULT eDVBServicePlay::pause()
937 if (!m_is_paused && m_decoder)
940 return m_decoder->freeze(0);
945 RESULT eDVBServicePlay::unpause()
947 if (m_is_paused && m_decoder)
950 return m_decoder->unfreeze();
955 RESULT eDVBServicePlay::seekTo(pts_t to)
957 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
962 ePtr<iDVBPVRChannel> pvr_channel;
964 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
970 m_cue->seekTo(0, to);
974 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
976 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
981 ePtr<iDVBPVRChannel> pvr_channel;
983 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
988 /* HACK until we have skip-AP api */
989 if ((to > 0) && (to < 100))
997 m_cue->seekTo(mode, to);
1001 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
1003 ePtr<iDVBPVRChannel> pvr_channel;
1005 if (!m_decode_demux)
1008 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1013 /* if there is a decoder, use audio or video PTS */
1016 r = m_decoder->getPTS(0, pos);
1022 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1025 RESULT eDVBServicePlay::setTrickmode(int trick)
1028 m_decoder->setTrickmode(trick);
1032 RESULT eDVBServicePlay::isCurrentlySeekable()
1034 return m_is_pvr || m_timeshift_active;
1037 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1043 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1049 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1055 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1061 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1067 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1070 if (m_have_video_pid && // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1071 (m_timeshift_enabled || !m_is_pvr))
1073 if (!m_timeshift_enabled)
1075 /* we need enough diskspace */
1077 if (statfs(TSPATH "/.", &fs) < 0)
1079 eDebug("statfs failed!");
1083 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1085 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1095 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1106 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1112 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1118 RESULT eDVBServicePlay::radioText(ePtr<iRadioText> &ptr)
1124 RESULT eDVBServicePlay::getName(std::string &name)
1128 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1129 return i->getName(m_reference, name);
1133 m_dvb_service->getName(m_reference, name);
1137 else if (!m_reference.name.empty())
1138 eStaticServiceDVBInformation().getName(m_reference, name);
1140 name = "DVB service";
1144 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1146 return m_event_handler.getEvent(evt, nownext);
1149 int eDVBServicePlay::getInfo(int w)
1151 eDVBServicePMTHandler::program program;
1154 return resIsPyObject;
1156 if (m_service_handler.getProgramInfo(program))
1162 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1164 ePtr<eServiceEvent> evt;
1165 if (!m_event_handler.getEvent(evt, 0))
1167 ePtr<eComponentData> data;
1168 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1170 if ( data->getStreamContent() == 1 )
1172 switch(data->getComponentType())
1175 case 1: // 4:3 SD PAL
1177 case 3: // 16:9 SD PAL
1178 case 4: // > 16:9 PAL
1179 case 5: // 4:3 SD NTSC
1181 case 7: // 16:9 SD NTSC
1182 case 8: // > 16:9 NTSC
1185 case 9: // 4:3 HD PAL
1187 case 0xB: // 16:9 HD PAL
1188 case 0xC: // > 16:9 HD PAL
1189 case 0xD: // 4:3 HD NTSC
1191 case 0xF: // 16:9 HD NTSC
1192 case 0x10: // > 16:9 HD PAL
1193 return data->getComponentType();
1200 case sIsCrypted: return program.isCrypted();
1201 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1202 case sVideoType: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1203 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
1204 case sPCRPID: return program.pcrPid;
1205 case sPMTPID: return program.pmtPid;
1206 case sTXTPID: return program.textPid;
1207 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1208 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1209 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1210 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1211 case sProvider: if (!m_dvb_service) return -1; return -2;
1217 std::string eDVBServicePlay::getInfoString(int w)
1222 if (!m_dvb_service) return "";
1223 return m_dvb_service->m_provider_name;
1227 return iServiceInformation::getInfoString(w);
1230 PyObject *eDVBServicePlay::getInfoObject(int w)
1235 return m_service_handler.getCaIds();
1239 return iServiceInformation::getInfoObject(w);
1242 int eDVBServicePlay::getNumberOfTracks()
1244 eDVBServicePMTHandler::program program;
1245 if (m_service_handler.getProgramInfo(program))
1247 return program.audioStreams.size();
1250 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1252 int ret = selectAudioStream(i);
1254 if (m_decoder->start())
1260 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1262 eDVBServicePMTHandler::program program;
1264 if (m_service_handler.getProgramInfo(program))
1267 if (i >= program.audioStreams.size())
1270 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1271 info.m_description = "MPEG";
1272 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1273 info.m_description = "AC3";
1274 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1275 info.m_description = "AAC";
1276 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1277 info.m_description = "DTS";
1279 info.m_description = "???";
1281 if (program.audioStreams[i].component_tag != -1)
1283 ePtr<eServiceEvent> evt;
1284 if (!m_event_handler.getEvent(evt, 0))
1286 ePtr<eComponentData> data;
1287 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1288 info.m_language = data->getText();
1292 if (info.m_language.empty())
1293 info.m_language = program.audioStreams[i].language_code;
1298 int eDVBServicePlay::selectAudioStream(int i)
1300 eDVBServicePMTHandler::program program;
1302 if (m_service_handler.getProgramInfo(program))
1305 if ((unsigned int)i >= program.audioStreams.size())
1311 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1314 if (m_radiotext_parser)
1315 m_radiotext_parser->start(program.audioStreams[i].pid);
1317 if (m_dvb_service && !m_is_pvr)
1319 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1321 m_dvb_service->setCacheEntry(eDVBService::cAPID, program.audioStreams[i].pid);
1322 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1326 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1327 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, program.audioStreams[i].pid);
1334 int eDVBServicePlay::getCurrentChannel()
1336 return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1339 RESULT eDVBServicePlay::selectChannel(int i)
1341 if (i < LEFT || i > RIGHT || i == STEREO)
1344 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1346 m_decoder->setAudioChannel(i);
1350 std::string eDVBServicePlay::getRadioText(int x)
1352 if (m_radiotext_parser)
1356 return m_radiotext_parser->getCurrentText();
1361 void eDVBServicePlay::radioTextUpdated()
1363 m_event((iPlayableService*)this, evUpdatedRadioText);
1366 int eDVBServiceBase::getFrontendInfo(int w)
1368 eUsePtr<iDVBChannel> channel;
1369 if(m_service_handler.getChannel(channel))
1371 ePtr<iDVBFrontend> fe;
1372 if(channel->getFrontend(fe))
1374 return fe->readFrontendData(w);
1377 PyObject *eDVBServiceBase::getFrontendData(bool original)
1381 eUsePtr<iDVBChannel> channel;
1382 if(!m_service_handler.getChannel(channel))
1384 ePtr<iDVBFrontend> fe;
1385 if(!channel->getFrontend(fe))
1387 ret = fe->readTransponderData(original);
1390 ePtr<iDVBFrontendParameters> feparm;
1391 channel->getCurrentFrontendParameters(feparm);
1394 eDVBFrontendParametersSatellite osat;
1395 if (!feparm->getDVBS(osat))
1397 void PutToDict(PyObject *, const char*, long);
1398 void PutToDict(PyObject *, const char*, const char*);
1399 PutToDict(ret, "orbital_position", osat.orbital_position);
1400 const char *tmp = "UNKNOWN";
1401 switch(osat.polarisation)
1403 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1404 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1405 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1406 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1409 PutToDict(ret, "polarization", tmp);
1423 int eDVBServicePlay::getNumberOfSubservices()
1425 ePtr<eServiceEvent> evt;
1426 if (!m_event_handler.getEvent(evt, 0))
1427 return evt->getNumOfLinkageServices();
1431 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1433 ePtr<eServiceEvent> evt;
1434 if (!m_event_handler.getEvent(evt, 0))
1436 if (!evt->getLinkageService(sub, m_reference, n))
1439 sub.type=eServiceReference::idInvalid;
1443 RESULT eDVBServicePlay::startTimeshift()
1445 ePtr<iDVBDemux> demux;
1447 eDebug("Start timeshift!");
1449 if (m_timeshift_enabled)
1452 /* start recording with the data demux. */
1453 if (m_service_handler.getDataDemux(demux))
1456 demux->createTSRecorder(m_record);
1460 char templ[]=TSPATH "/timeshift.XXXXXX";
1461 m_timeshift_fd = mkstemp(templ);
1462 m_timeshift_file = templ;
1464 eDebug("recording to %s", templ);
1466 if (m_timeshift_fd < 0)
1472 m_record->setTargetFD(m_timeshift_fd);
1474 m_timeshift_enabled = 1;
1476 updateTimeshiftPids();
1482 RESULT eDVBServicePlay::stopTimeshift()
1484 if (!m_timeshift_enabled)
1489 m_timeshift_enabled = 0;
1494 close(m_timeshift_fd);
1495 eDebug("remove timeshift file");
1496 remove(m_timeshift_file.c_str());
1501 int eDVBServicePlay::isTimeshiftActive()
1503 return m_timeshift_enabled && m_timeshift_active;
1506 RESULT eDVBServicePlay::activateTimeshift()
1508 if (!m_timeshift_enabled)
1511 if (!m_timeshift_active)
1513 switchToTimeshift();
1520 PyObject *eDVBServicePlay::getCutList()
1522 PyObject *list = PyList_New(0);
1524 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1526 PyObject *tuple = PyTuple_New(2);
1527 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1528 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1529 PyList_Append(list, tuple);
1536 void eDVBServicePlay::setCutList(PyObject *list)
1538 if (!PyList_Check(list))
1540 int size = PyList_Size(list);
1543 m_cue_entries.clear();
1545 for (i=0; i<size; ++i)
1547 PyObject *tuple = PyList_GetItem(list, i);
1548 if (!PyTuple_Check(tuple))
1550 eDebug("non-tuple in cutlist");
1553 if (PyTuple_Size(tuple) != 2)
1555 eDebug("cutlist entries need to be a 2-tuple");
1558 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1559 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1561 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1564 pts_t pts = PyLong_AsLongLong(ppts);
1565 int type = PyInt_AsLong(ptype);
1566 m_cue_entries.insert(cueEntry(pts, type));
1567 eDebug("adding %08llx, %d", pts, type);
1569 m_cuesheet_changed = 1;
1571 cutlistToCuesheet();
1572 m_event((iPlayableService*)this, evCuesheetChanged);
1575 void eDVBServicePlay::setCutListEnable(int enable)
1577 m_cutlist_enabled = enable;
1578 cutlistToCuesheet();
1581 void eDVBServicePlay::updateTimeshiftPids()
1586 eDVBServicePMTHandler::program program;
1587 if (m_service_handler.getProgramInfo(program))
1591 std::set<int> pids_to_record;
1592 pids_to_record.insert(0); // PAT
1593 if (program.pmtPid != -1)
1594 pids_to_record.insert(program.pmtPid); // PMT
1596 if (program.textPid != -1)
1597 pids_to_record.insert(program.textPid); // Videotext
1599 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1600 i(program.videoStreams.begin());
1601 i != program.videoStreams.end(); ++i)
1602 pids_to_record.insert(i->pid);
1604 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1605 i(program.audioStreams.begin());
1606 i != program.audioStreams.end(); ++i)
1607 pids_to_record.insert(i->pid);
1609 std::set<int> new_pids, obsolete_pids;
1611 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1612 m_pids_active.begin(), m_pids_active.end(),
1613 std::inserter(new_pids, new_pids.begin()));
1615 std::set_difference(
1616 m_pids_active.begin(), m_pids_active.end(),
1617 pids_to_record.begin(), pids_to_record.end(),
1618 std::inserter(new_pids, new_pids.begin())
1621 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1622 m_record->addPID(*i);
1624 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1625 m_record->removePID(*i);
1629 void eDVBServicePlay::switchToLive()
1631 if (!m_timeshift_active)
1637 m_teletext_parser = 0;
1638 m_radiotext_parser = 0;
1639 m_new_subtitle_page_connection = 0;
1640 m_radiotext_updated_connection = 0;
1642 /* free the timeshift service handler, we need the resources */
1643 m_service_handler_timeshift.free();
1644 m_timeshift_active = 0;
1646 m_event((iPlayableService*)this, evSeekableStatusChanged);
1651 void eDVBServicePlay::switchToTimeshift()
1653 if (m_timeshift_active)
1658 m_teletext_parser = 0;
1659 m_radiotext_parser = 0;
1660 m_new_subtitle_page_connection = 0;
1661 m_radiotext_updated_connection = 0;
1663 m_timeshift_active = 1;
1665 m_event((iPlayableService*)this, evSeekableStatusChanged);
1667 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1668 r.path = m_timeshift_file;
1670 m_cue = new eCueSheet();
1671 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1672 updateDecoder(); /* mainly to switch off PCR */
1675 void eDVBServicePlay::updateDecoder()
1677 int vpid = -1, vpidtype = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
1679 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1681 bool defaultac3=false;
1682 std::string default_ac3;
1684 if (!ePythonConfigQuery::getConfigValue("config.av.defaultac3", default_ac3))
1685 defaultac3 = default_ac3 == "enable";
1687 eDVBServicePMTHandler::program program;
1688 if (h.getProgramInfo(program))
1689 eDebug("getting program info failed.");
1692 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1693 if (!program.videoStreams.empty())
1695 eDebugNoNewLine(" (");
1696 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1697 i(program.videoStreams.begin());
1698 i != program.videoStreams.end(); ++i)
1705 if (i != program.videoStreams.begin())
1706 eDebugNoNewLine(", ");
1707 eDebugNoNewLine("%04x", i->pid);
1709 eDebugNoNewLine(")");
1711 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1712 if (!program.audioStreams.empty())
1714 eDebugNoNewLine(" (");
1715 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1716 i(program.audioStreams.begin());
1717 i != program.audioStreams.end(); ++i)
1719 if (apid == -1 || (apidtype == eDVBAudio::aMPEG && defaultac3))
1721 if ( apid == -1 || (i->type != eDVBAudio::aMPEG) )
1727 if (i != program.audioStreams.begin())
1728 eDebugNoNewLine(", ");
1729 eDebugNoNewLine("%04x", i->pid);
1731 eDebugNoNewLine(")");
1733 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1734 pcrpid = program.pcrPid;
1735 eDebug(", and the text pid is %04x", program.textPid);
1736 tpid = program.textPid;
1741 h.getDecodeDemux(m_decode_demux);
1743 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1745 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1746 #ifdef INTERNAL_TELETEXT
1747 m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
1748 m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
1756 achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
1757 ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
1758 pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
1760 else // subservice or recording
1762 eServiceReferenceDVB ref;
1763 m_service_handler.getServiceReference(ref);
1764 eServiceReferenceDVB parent = ref.getParentServiceReference();
1769 ePtr<eDVBResourceManager> res_mgr;
1770 if (!eDVBResourceManager::getInstance(res_mgr))
1772 ePtr<iDVBChannelList> db;
1773 if (!res_mgr->getChannelList(db))
1775 ePtr<eDVBService> origService;
1776 if (!db->getService(parent, origService))
1778 ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
1779 pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
1785 m_decoder->setAC3Delay(ac3_delay == -1 ? 0 : ac3_delay);
1786 m_decoder->setPCMDelay(pcm_delay == -1 ? 0 : pcm_delay);
1788 m_decoder->setVideoPID(vpid, vpidtype);
1789 m_decoder->setAudioPID(apid, apidtype);
1790 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1792 m_decoder->setSyncPCR(pcrpid);
1795 ePtr<iDVBDemux> data_demux;
1796 if (!h.getDataDemux(data_demux))
1798 m_radiotext_parser = new eDVBRadioTextParser(data_demux);
1799 m_radiotext_parser->connectUpdatedRadiotext(slot(*this, &eDVBServicePlay::radioTextUpdated), m_radiotext_updated_connection);
1800 m_radiotext_parser->start(apid);
1805 m_decoder->setSyncPCR(-1);
1807 m_decoder->setTextPID(tpid);
1809 if (m_teletext_parser)
1810 m_teletext_parser->start(tpid);
1813 m_decoder->setTrickmode(1);
1817 if (vpid > 0 && vpid < 0x2000)
1821 std::string radio_pic;
1822 if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
1823 m_decoder->setRadioPic(radio_pic);
1826 m_decoder->setAudioChannel(achannel);
1828 // how we can do this better?
1829 // update cache pid when the user changed the audio track or video track
1830 // TODO handling of difference audio types.. default audio types..
1832 /* don't worry about non-existing services, nor pvr services */
1833 if (m_dvb_service && !m_is_pvr)
1835 if (apidtype == eDVBAudio::aMPEG)
1837 m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1838 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1842 m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1843 m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1845 m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
1846 m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
1847 m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
1848 m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
1851 m_have_video_pid = (vpid > 0 && vpid < 0x2000);
1854 void eDVBServicePlay::loadCuesheet()
1856 std::string filename = m_reference.path + ".cuts";
1858 m_cue_entries.clear();
1860 FILE *f = fopen(filename.c_str(), "rb");
1864 eDebug("loading cuts..");
1867 unsigned long long where;
1870 if (!fread(&where, sizeof(where), 1, f))
1872 if (!fread(&what, sizeof(what), 1, f))
1875 #if BYTE_ORDER == LITTLE_ENDIAN
1876 where = bswap_64(where);
1883 m_cue_entries.insert(cueEntry(where, what));
1886 eDebug("%d entries", m_cue_entries.size());
1888 eDebug("cutfile not found!");
1890 m_cuesheet_changed = 0;
1891 cutlistToCuesheet();
1892 m_event((iPlayableService*)this, evCuesheetChanged);
1895 void eDVBServicePlay::saveCuesheet()
1897 std::string filename = m_reference.path + ".cuts";
1899 FILE *f = fopen(filename.c_str(), "wb");
1903 unsigned long long where;
1906 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1908 #if BYTE_ORDER == BIG_ENDIAN
1911 where = bswap_64(i->where);
1913 what = htonl(i->what);
1914 fwrite(&where, sizeof(where), 1, f);
1915 fwrite(&what, sizeof(what), 1, f);
1921 m_cuesheet_changed = 0;
1924 void eDVBServicePlay::cutlistToCuesheet()
1928 eDebug("no cue sheet");
1933 if (!m_cutlist_enabled)
1935 m_cue->commitSpans();
1936 eDebug("cutlists were disabled");
1940 pts_t in = 0, out = 0, length = 0;
1944 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1948 if (i == m_cue_entries.end())
1951 if (i->what == 0) /* in */
1955 } else if (i->what == 1) /* out */
1957 else /* mark (2) or last play position (3) */
1965 m_cue->addSourceSpan(in, out);
1969 if (i == m_cue_entries.end())
1972 m_cue->commitSpans();
1975 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, PyObject *entry)
1977 if (m_subtitle_widget)
1978 disableSubtitles(parent);
1980 if (!m_teletext_parser)
1983 if (!PyInt_Check(entry))
1986 m_subtitle_widget = new eSubtitleWidget(parent);
1987 m_subtitle_widget->resize(parent->size()); /* full size */
1989 int page = PyInt_AsLong(entry);
1991 m_teletext_parser->setPage(page);
1996 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
1998 delete m_subtitle_widget;
1999 m_subtitle_widget = 0;
2003 PyObject *eDVBServicePlay::getSubtitleList()
2005 if (!m_teletext_parser)
2011 PyObject *l = PyList_New(0);
2013 for (std::set<int>::iterator i(m_teletext_parser->m_found_subtitle_pages.begin()); i != m_teletext_parser->m_found_subtitle_pages.end(); ++i)
2015 PyObject *tuple = PyTuple_New(2);
2017 sprintf(desc, "Page %x", *i);
2018 PyTuple_SetItem(tuple, 0, PyString_FromString(desc));
2019 PyTuple_SetItem(tuple, 1, PyInt_FromLong(*i));
2020 PyList_Append(l, tuple);
2026 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2028 if (m_subtitle_widget)
2030 m_subtitle_pages.push_back(page);
2032 checkSubtitleTiming();
2036 void eDVBServicePlay::checkSubtitleTiming()
2040 if (m_subtitle_pages.empty())
2043 eDVBTeletextSubtitlePage p = m_subtitle_pages.front();
2048 m_decoder->getPTS(0, pos);
2050 int diff = p.m_pts - pos;
2053 eDebug("[late (%d ms)]", -diff / 90);
2058 eDebug("[invalid]");
2064 m_subtitle_widget->setPage(p);
2065 m_subtitle_pages.pop_front();
2068 m_subtitle_sync_timer.start(diff / 90, 1);
2074 int eDVBServicePlay::getAC3Delay()
2077 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2079 return m_decoder->getAC3Delay();
2084 int eDVBServicePlay::getPCMDelay()
2087 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2089 return m_decoder->getPCMDelay();
2094 void eDVBServicePlay::setAC3Delay(int delay)
2097 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2099 m_decoder->setAC3Delay(delay);
2102 void eDVBServicePlay::setPCMDelay(int delay)
2105 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2107 m_decoder->setPCMDelay(delay);
2110 DEFINE_REF(eDVBServicePlay)
2112 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");