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>
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
13 #include <lib/service/servicedvbrecord.h>
14 #include <lib/service/event.h>
15 #include <lib/dvb/metaparser.h>
16 #include <lib/dvb/tstools.h>
17 #include <lib/python/python.h>
22 #include <netinet/in.h>
24 #include <dvbsi++/event_information_section.h>
27 #error no byte order defined!
30 #define TSPATH "/media/hdd"
32 class eStaticServiceDVBInformation: public iStaticServiceInformation
34 DECLARE_REF(eStaticServiceDVBInformation);
36 RESULT getName(const eServiceReference &ref, std::string &name);
37 int getLength(const eServiceReference &ref);
40 DEFINE_REF(eStaticServiceDVBInformation);
42 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
44 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
45 if ( !ref.name.empty() )
47 if (service.getParentTransportStreamID().get()) // linkage subservice
49 ePtr<iServiceHandler> service_center;
50 if (!eServiceCenter::getInstance(service_center))
52 eServiceReferenceDVB parent = service;
53 parent.setTransportStreamID( service.getParentTransportStreamID() );
54 parent.setServiceID( service.getParentServiceID() );
55 parent.setParentTransportStreamID(eTransportStreamID(0));
56 parent.setParentServiceID(eServiceID(0));
58 ePtr<iStaticServiceInformation> service_info;
59 if (!service_center->info(parent, service_info))
61 if (!service_info->getName(parent, name))
63 // just show short name
64 unsigned int pos = name.find("\xc2\x86");
65 if ( pos != std::string::npos )
67 pos = name.find("\xc2\x87");
68 if ( pos != std::string::npos )
84 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
89 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
91 DECLARE_REF(eStaticServiceDVBBouquetInformation);
93 RESULT getName(const eServiceReference &ref, std::string &name);
94 int getLength(const eServiceReference &ref);
97 DEFINE_REF(eStaticServiceDVBBouquetInformation);
99 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
101 ePtr<iDVBChannelList> db;
102 ePtr<eDVBResourceManager> res;
105 if ((err = eDVBResourceManager::getInstance(res)) != 0)
107 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
110 if ((err = res->getChannelList(db)) != 0)
112 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
117 if ((err = db->getBouquet(ref, bouquet)) != 0)
119 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
123 if ( bouquet && bouquet->m_bouquet_name.length() )
125 name = bouquet->m_bouquet_name;
132 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
137 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
139 DECLARE_REF(eStaticServiceDVBPVRInformation);
140 eServiceReference m_ref;
141 eDVBMetaParser m_parser;
143 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
144 RESULT getName(const eServiceReference &ref, std::string &name);
145 int getLength(const eServiceReference &ref);
147 int getInfo(const eServiceReference &ref, int w);
148 std::string getInfoString(const eServiceReference &ref,int w);
151 DEFINE_REF(eStaticServiceDVBPVRInformation);
153 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
156 m_parser.parseFile(ref.path);
159 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
161 ASSERT(ref == m_ref);
162 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
166 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
168 ASSERT(ref == m_ref);
172 if (tstools.openFile(ref.path.c_str()))
176 if (tstools.calcLen(len))
182 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
186 case iServiceInformation::sDescription:
187 return iServiceInformation::resIsString;
188 case iServiceInformation::sTimeCreate:
189 if (m_parser.m_time_create)
190 return m_parser.m_time_create;
192 return iServiceInformation::resNA;
194 return iServiceInformation::resNA;
198 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
202 case iServiceInformation::sDescription:
203 return m_parser.m_description;
209 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
211 DECLARE_REF(eDVBPVRServiceOfflineOperations);
212 eServiceReferenceDVB m_ref;
214 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
216 RESULT deleteFromDisk(int simulate);
217 RESULT getListOfFilenames(std::list<std::string> &);
220 DEFINE_REF(eDVBPVRServiceOfflineOperations);
222 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
226 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
232 std::list<std::string> res;
233 if (getListOfFilenames(res))
236 /* TODO: deferred removing.. */
237 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
239 eDebug("Removing %s...", i->c_str());
240 ::unlink(i->c_str());
247 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
250 res.push_back(m_ref.path);
251 res.push_back(m_ref.path + ".meta");
252 res.push_back(m_ref.path + ".ap");
253 res.push_back(m_ref.path + ".cuts");
254 res.push_back(m_ref.path + ".eit");
258 DEFINE_REF(eServiceFactoryDVB)
260 eServiceFactoryDVB::eServiceFactoryDVB()
262 ePtr<eServiceCenter> sc;
264 eServiceCenter::getPrivInstance(sc);
266 sc->addServiceFactory(eServiceFactoryDVB::id, this);
269 eServiceFactoryDVB::~eServiceFactoryDVB()
271 ePtr<eServiceCenter> sc;
273 eServiceCenter::getPrivInstance(sc);
275 sc->removeServiceFactory(eServiceFactoryDVB::id);
278 DEFINE_REF(eDVBServiceList);
280 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
284 eDVBServiceList::~eDVBServiceList()
288 RESULT eDVBServiceList::startQuery()
290 ePtr<iDVBChannelList> db;
291 ePtr<eDVBResourceManager> res;
294 if ((err = eDVBResourceManager::getInstance(res)) != 0)
296 eDebug("no resource manager");
299 if ((err = res->getChannelList(db)) != 0)
301 eDebug("no channel list");
305 ePtr<eDVBChannelQuery> q;
307 if (!m_parent.path.empty())
309 eDVBChannelQuery::compile(q, m_parent.path);
312 eDebug("compile query failed");
317 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
319 eDebug("startQuery failed");
326 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
328 eServiceReferenceDVB ref;
330 if (!m_query || !list || !PyList_Check(list))
333 std::list<eServiceReferenceDVB> tmplist;
335 while (!m_query->getNextResult(ref))
336 tmplist.push_back(ref);
339 tmplist.sort(iListableServiceCompare(this));
341 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
342 it != tmplist.end(); ++it)
344 PyObject *refobj = New_eServiceReference(*it);
345 PyList_Append(list, refobj);
351 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
353 eServiceReferenceDVB ref;
358 while (!m_query->getNextResult(ref))
362 list.sort(iListableServiceCompare(this));
367 RESULT eDVBServiceList::getNext(eServiceReference &ref)
372 return m_query->getNextResult((eServiceReferenceDVB&)ref);
375 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
377 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
380 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
382 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
384 ePtr<iDVBChannelList> db;
385 ePtr<eDVBResourceManager> resm;
387 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
390 if (db->getBouquet(m_parent, m_bouquet) != 0)
401 RESULT eDVBServiceList::addService(eServiceReference &ref)
405 return m_bouquet->addService(ref);
408 RESULT eDVBServiceList::removeService(eServiceReference &ref)
412 return m_bouquet->removeService(ref);
415 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
419 return m_bouquet->moveService(ref, pos);
422 RESULT eDVBServiceList::flushChanges()
426 return m_bouquet->flushChanges();
429 RESULT eDVBServiceList::setListName(const std::string &name)
433 return m_bouquet->setListName(name);
436 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
438 ePtr<eDVBService> service;
439 int r = lookupService(service, ref);
442 // check resources...
443 ptr = new eDVBServicePlay(ref, service);
447 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
449 if (ref.path.empty())
451 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
460 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
462 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
463 if (list->startQuery())
473 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
475 /* is a listable service? */
476 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
478 if ( !ref.name.empty() ) // satellites or providers list
479 ptr = new eStaticServiceDVBInformation;
480 else // a dvb bouquet
481 ptr = new eStaticServiceDVBBouquetInformation;
483 else if (!ref.path.empty()) /* do we have a PVR service? */
484 ptr = new eStaticServiceDVBPVRInformation(ref);
485 else // normal dvb service
487 ePtr<eDVBService> service;
488 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
489 ptr = new eStaticServiceDVBInformation;
491 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
497 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
499 if (ref.path.empty())
505 ptr = new eDVBPVRServiceOfflineOperations(ref);
510 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
512 // TODO: handle the listing itself
513 // if (ref.... == -1) .. return "... bouquets ...";
514 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
516 ePtr<iDVBChannelList> db;
517 ePtr<eDVBResourceManager> res;
520 if ((err = eDVBResourceManager::getInstance(res)) != 0)
522 eDebug("no resource manager");
525 if ((err = res->getChannelList(db)) != 0)
527 eDebug("no channel list");
531 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
532 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
534 eDebug("getService failed!");
541 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
542 m_reference(ref), m_dvb_service(service), m_is_paused(0)
544 m_is_pvr = !ref.path.empty();
546 m_timeshift_enabled = m_timeshift_active = 0;
549 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
550 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
551 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
553 m_cuesheet_changed = 0;
554 m_cutlist_enabled = 1;
557 eDVBServicePlay::~eDVBServicePlay()
561 void eDVBServicePlay::gotNewEvent()
565 ePtr<eServiceEvent> m_event_now, m_event_next;
566 getEvent(m_event_now, 0);
567 getEvent(m_event_next, 1);
570 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
572 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
574 m_event((iPlayableService*)this, evUpdatedEventInfo);
577 void eDVBServicePlay::serviceEvent(int event)
581 case eDVBServicePMTHandler::eventTuned:
583 ePtr<iDVBDemux> m_demux;
584 if (!m_service_handler.getDataDemux(m_demux))
586 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
587 int sid = ref.getParentServiceID().get();
589 sid = ref.getServiceID().get();
590 if ( ref.getParentTransportStreamID().get() &&
591 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
592 m_event_handler.startOther(m_demux, sid);
594 m_event_handler.start(m_demux, sid);
598 case eDVBServicePMTHandler::eventTuneFailed:
600 eDebug("DVB service failed to tune");
601 m_event((iPlayableService*)this, evTuneFailed);
604 case eDVBServicePMTHandler::eventNewProgramInfo:
606 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
607 if (m_timeshift_enabled)
608 updateTimeshiftPids();
609 if (!m_timeshift_active)
611 if (m_first_program_info && m_is_pvr)
613 m_first_program_info = 0;
616 m_event((iPlayableService*)this, evUpdatedInfo);
619 case eDVBServicePMTHandler::eventEOF:
620 m_event((iPlayableService*)this, evEOF);
622 case eDVBServicePMTHandler::eventSOF:
623 m_event((iPlayableService*)this, evSOF);
628 void eDVBServicePlay::serviceEventTimeshift(int event)
632 case eDVBServicePMTHandler::eventNewProgramInfo:
633 if (m_timeshift_active)
636 case eDVBServicePMTHandler::eventEOF:
642 RESULT eDVBServicePlay::start()
645 /* in pvr mode, we only want to use one demux. in tv mode, we're using
646 two (one for decoding, one for data source), as we must be prepared
647 to start recording from the data demux. */
648 m_cue = new eCueSheet();
650 m_first_program_info = 1;
651 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
652 r = m_service_handler.tune(service, m_is_pvr, m_cue);
654 /* inject EIT if there is a stored one */
657 std::string filename = service.path;
658 filename.erase(filename.length()-2, 2);
660 int fd = ::open( filename.c_str(), O_RDONLY );
664 int rd = ::read(fd, buf, 4096);
666 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
669 ePtr<eServiceEvent> event = new eServiceEvent;
670 ePtr<eServiceEvent> empty;
671 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
672 m_event_handler.inject(event, 0);
673 m_event_handler.inject(empty, 1);
682 m_event(this, evStart);
683 m_event((iPlayableService*)this, evSeekableStatusChanged);
687 RESULT eDVBServicePlay::stop()
689 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
691 m_service_handler_timeshift.free();
692 m_service_handler.free();
694 if (m_is_pvr && m_cuesheet_changed)
700 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
702 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
706 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
708 /* note: we check for timeshift to be enabled,
709 not neccessary active. if you pause when timeshift
710 is not active, you should activate it when unpausing */
711 if ((!m_is_pvr) && (!m_timeshift_enabled))
721 RESULT eDVBServicePlay::setSlowMotion(int ratio)
724 return m_decoder->setSlowMotion(ratio);
729 RESULT eDVBServicePlay::setFastForward(int ratio)
731 int skipmode, ffratio;
737 } else if (ratio > 0)
745 } else // if (ratio < 0)
751 if (m_skipmode != skipmode)
753 eDebug("setting cue skipmode to %d", skipmode);
755 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
758 m_skipmode = skipmode;
763 return m_decoder->setFastForward(ffratio);
766 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
768 if (m_is_pvr || m_timeshift_enabled)
778 /* TODO: when timeshift is enabled but not active, this doesn't work. */
779 RESULT eDVBServicePlay::getLength(pts_t &len)
781 ePtr<iDVBPVRChannel> pvr_channel;
783 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
786 return pvr_channel->getLength(len);
789 RESULT eDVBServicePlay::pause()
791 if (!m_is_paused && m_decoder)
794 return m_decoder->freeze(0);
799 RESULT eDVBServicePlay::unpause()
801 if (m_is_paused && m_decoder)
804 return m_decoder->unfreeze();
809 RESULT eDVBServicePlay::seekTo(pts_t to)
811 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
816 ePtr<iDVBPVRChannel> pvr_channel;
818 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
824 m_cue->seekTo(0, to);
828 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
830 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
835 ePtr<iDVBPVRChannel> pvr_channel;
837 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
842 /* HACK until we have skip-AP api */
843 if ((to > 0) && (to < 100))
851 m_cue->seekTo(mode, to);
855 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
857 ePtr<iDVBPVRChannel> pvr_channel;
862 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
867 /* if there is a decoder, use audio or video PTS */
870 r = m_decoder->getPTS(0, pos);
876 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
879 RESULT eDVBServicePlay::setTrickmode(int trick)
882 m_decoder->setTrickmode(trick);
886 RESULT eDVBServicePlay::isCurrentlySeekable()
888 return m_is_pvr || m_timeshift_active;
891 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
897 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
903 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
909 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
915 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
918 if (m_timeshift_enabled || !m_is_pvr)
920 if (!m_timeshift_enabled)
922 /* we need enough diskspace */
924 if (statfs(TSPATH "/.", &fs) < 0)
926 eDebug("statfs failed!");
930 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
932 eDebug("not enough diskspace for timeshift! (less than 1GB)");
942 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
953 RESULT eDVBServicePlay::getName(std::string &name)
957 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
958 return i->getName(m_reference, name);
962 m_dvb_service->getName(m_reference, name);
966 else if (!m_reference.name.empty())
967 eStaticServiceDVBInformation().getName(m_reference, name);
969 name = "DVB service";
973 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
975 return m_event_handler.getEvent(evt, nownext);
978 int eDVBServicePlay::getInfo(int w)
980 eDVBServicePMTHandler::program program;
982 if (m_service_handler.getProgramInfo(program))
988 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
990 ePtr<eServiceEvent> evt;
991 if (!m_event_handler.getEvent(evt, 0))
993 ePtr<eComponentData> data;
994 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
996 if ( data->getStreamContent() == 1 )
998 switch(data->getComponentType())
1001 case 1: // 4:3 SD PAL
1003 case 3: // 16:9 SD PAL
1004 case 4: // > 16:9 PAL
1005 case 5: // 4:3 SD NTSC
1007 case 7: // 16:9 SD NTSC
1008 case 8: // > 16:9 NTSC
1011 case 9: // 4:3 HD PAL
1013 case 0xB: // 16:9 HD PAL
1014 case 0xC: // > 16:9 HD PAL
1015 case 0xD: // 4:3 HD NTSC
1017 case 0xF: // 16:9 HD NTSC
1018 case 0x10: // > 16:9 HD PAL
1019 return data->getComponentType();
1026 case sIsCrypted: return program.isCrypted;
1027 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1028 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1029 case sPCRPID: return program.pcrPid;
1030 case sPMTPID: return program.pmtPid;
1031 case sTXTPID: return program.textPid;
1032 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1033 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1034 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1035 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1036 case sProvider: if (!m_dvb_service) return -1; return -2;
1042 std::string eDVBServicePlay::getInfoString(int w)
1047 if (!m_dvb_service) return "";
1048 return m_dvb_service->m_provider_name;
1054 int eDVBServicePlay::getNumberOfTracks()
1056 eDVBServicePMTHandler::program program;
1057 if (m_service_handler.getProgramInfo(program))
1059 return program.audioStreams.size();
1062 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1064 int ret = selectAudioStream(i);
1066 if (m_decoder->start())
1072 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1074 eDVBServicePMTHandler::program program;
1076 if (m_service_handler.getProgramInfo(program))
1079 if (i >= program.audioStreams.size())
1082 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1083 info.m_description = "MPEG";
1084 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1085 info.m_description = "AC3";
1086 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1087 info.m_description = "DTS";
1089 info.m_description = "???";
1091 if (program.audioStreams[i].component_tag != -1)
1093 ePtr<eServiceEvent> evt;
1094 if (!m_event_handler.getEvent(evt, 0))
1096 ePtr<eComponentData> data;
1097 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1098 info.m_language = data->getText();
1102 if (info.m_language.empty())
1103 info.m_language = program.audioStreams[i].language_code;
1108 int eDVBServicePlay::selectAudioStream(int i)
1110 eDVBServicePMTHandler::program program;
1112 if (m_service_handler.getProgramInfo(program))
1115 if ((unsigned int)i >= program.audioStreams.size())
1121 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1124 if (m_dvb_service && !m_is_pvr)
1126 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1128 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1129 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1132 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1133 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1137 m_current_audio_stream = i;
1142 int eDVBServicePlay::getFrontendInfo(int w)
1146 eUsePtr<iDVBChannel> channel;
1147 if(m_service_handler.getChannel(channel))
1149 ePtr<iDVBFrontend> fe;
1150 if(channel->getFrontend(fe))
1152 return fe->readFrontendData(w);
1155 PyObject *eDVBServicePlay::getFrontendData(bool original)
1159 eUsePtr<iDVBChannel> channel;
1160 if(!m_service_handler.getChannel(channel))
1162 ePtr<iDVBFrontend> fe;
1163 if(!channel->getFrontend(fe))
1165 ret = fe->readTransponderData(original);
1168 ePtr<iDVBFrontendParameters> feparm;
1169 channel->getCurrentFrontendParameters(feparm);
1172 eDVBFrontendParametersSatellite osat;
1173 if (!feparm->getDVBS(osat))
1175 void PutToDict(PyObject *, const char*, long);
1176 void PutToDict(PyObject *, const char*, const char*);
1177 PutToDict(ret, "orbital_position", osat.orbital_position);
1178 const char *tmp = "UNKNOWN";
1179 switch(osat.polarisation)
1181 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1182 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1183 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1184 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1187 PutToDict(ret, "polarization", tmp);
1201 int eDVBServicePlay::getNumberOfSubservices()
1203 ePtr<eServiceEvent> evt;
1204 if (!m_event_handler.getEvent(evt, 0))
1205 return evt->getNumOfLinkageServices();
1209 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1211 ePtr<eServiceEvent> evt;
1212 if (!m_event_handler.getEvent(evt, 0))
1214 if (!evt->getLinkageService(sub, m_reference, n))
1217 sub.type=eServiceReference::idInvalid;
1221 RESULT eDVBServicePlay::startTimeshift()
1223 ePtr<iDVBDemux> demux;
1225 eDebug("Start timeshift!");
1227 if (m_timeshift_enabled)
1230 /* start recording with the data demux. */
1231 if (m_service_handler.getDataDemux(demux))
1234 demux->createTSRecorder(m_record);
1238 char templ[]=TSPATH "/timeshift.XXXXXX";
1239 m_timeshift_fd = mkstemp(templ);
1240 m_timeshift_file = templ;
1242 eDebug("recording to %s", templ);
1244 if (m_timeshift_fd < 0)
1250 m_record->setTargetFD(m_timeshift_fd);
1252 m_timeshift_enabled = 1;
1254 updateTimeshiftPids();
1260 RESULT eDVBServicePlay::stopTimeshift()
1262 if (!m_timeshift_enabled)
1267 m_timeshift_enabled = 0;
1272 close(m_timeshift_fd);
1273 eDebug("remove timeshift file");
1274 remove(m_timeshift_file.c_str());
1279 int eDVBServicePlay::isTimeshiftActive()
1281 return m_timeshift_enabled && m_timeshift_active;
1284 RESULT eDVBServicePlay::activateTimeshift()
1286 if (!m_timeshift_enabled)
1289 if (!m_timeshift_active)
1291 switchToTimeshift();
1298 PyObject *eDVBServicePlay::getCutList()
1300 PyObject *list = PyList_New(0);
1302 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1304 PyObject *tuple = PyTuple_New(2);
1305 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1306 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1307 PyList_Append(list, tuple);
1314 void eDVBServicePlay::setCutList(PyObject *list)
1316 if (!PyList_Check(list))
1318 int size = PyList_Size(list);
1321 m_cue_entries.clear();
1323 for (i=0; i<size; ++i)
1325 PyObject *tuple = PyList_GetItem(list, i);
1326 if (!PyTuple_Check(tuple))
1328 eDebug("non-tuple in cutlist");
1331 if (PyTuple_Size(tuple) != 2)
1333 eDebug("cutlist entries need to be a 2-tuple");
1336 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1337 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1339 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1342 pts_t pts = PyLong_AsLongLong(ppts);
1343 int type = PyInt_AsLong(ptype);
1344 m_cue_entries.insert(cueEntry(pts, type));
1345 eDebug("adding %08llx, %d", pts, type);
1347 m_cuesheet_changed = 1;
1349 cutlistToCuesheet();
1350 m_event((iPlayableService*)this, evCuesheetChanged);
1353 void eDVBServicePlay::setCutListEnable(int enable)
1355 m_cutlist_enabled = enable;
1356 cutlistToCuesheet();
1359 void eDVBServicePlay::updateTimeshiftPids()
1364 eDVBServicePMTHandler::program program;
1365 if (m_service_handler.getProgramInfo(program))
1369 std::set<int> pids_to_record;
1370 pids_to_record.insert(0); // PAT
1371 if (program.pmtPid != -1)
1372 pids_to_record.insert(program.pmtPid); // PMT
1374 if (program.textPid != -1)
1375 pids_to_record.insert(program.textPid); // Videotext
1377 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1378 i(program.videoStreams.begin());
1379 i != program.videoStreams.end(); ++i)
1380 pids_to_record.insert(i->pid);
1382 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1383 i(program.audioStreams.begin());
1384 i != program.audioStreams.end(); ++i)
1385 pids_to_record.insert(i->pid);
1387 std::set<int> new_pids, obsolete_pids;
1389 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1390 m_pids_active.begin(), m_pids_active.end(),
1391 std::inserter(new_pids, new_pids.begin()));
1393 std::set_difference(
1394 m_pids_active.begin(), m_pids_active.end(),
1395 pids_to_record.begin(), pids_to_record.end(),
1396 std::inserter(new_pids, new_pids.begin())
1399 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1400 m_record->addPID(*i);
1402 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1403 m_record->removePID(*i);
1407 void eDVBServicePlay::switchToLive()
1409 if (!m_timeshift_active)
1414 /* free the timeshift service handler, we need the resources */
1415 m_service_handler_timeshift.free();
1416 m_timeshift_active = 0;
1418 m_event((iPlayableService*)this, evSeekableStatusChanged);
1423 void eDVBServicePlay::switchToTimeshift()
1425 if (m_timeshift_active)
1431 m_timeshift_active = 1;
1433 m_event((iPlayableService*)this, evSeekableStatusChanged);
1435 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1436 r.path = m_timeshift_file;
1438 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1441 void eDVBServicePlay::updateDecoder()
1443 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1444 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1446 eDVBServicePMTHandler::program program;
1447 if (h.getProgramInfo(program))
1448 eDebug("getting program info failed.");
1451 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1452 if (!program.videoStreams.empty())
1454 eDebugNoNewLine(" (");
1455 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1456 i(program.videoStreams.begin());
1457 i != program.videoStreams.end(); ++i)
1461 if (i != program.videoStreams.begin())
1462 eDebugNoNewLine(", ");
1463 eDebugNoNewLine("%04x", i->pid);
1465 eDebugNoNewLine(")");
1467 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1468 if (!program.audioStreams.empty())
1470 eDebugNoNewLine(" (");
1471 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1472 i(program.audioStreams.begin());
1473 i != program.audioStreams.end(); ++i)
1480 if (i != program.audioStreams.begin())
1481 eDebugNoNewLine(", ");
1482 eDebugNoNewLine("%04x", i->pid);
1484 eDebugNoNewLine(")");
1486 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1487 pcrpid = program.pcrPid;
1488 eDebug(", and the text pid is %04x", program.textPid);
1489 tpid = program.textPid;
1494 h.getDecodeDemux(m_decode_demux);
1496 m_decode_demux->getMPEGDecoder(m_decoder);
1498 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1503 m_decoder->setVideoPID(vpid);
1504 m_current_audio_stream = 0;
1505 m_decoder->setAudioPID(apid, apidtype);
1506 if (!(m_is_pvr || m_timeshift_active))
1507 m_decoder->setSyncPCR(pcrpid);
1509 m_decoder->setSyncPCR(-1);
1510 m_decoder->setTextPID(tpid);
1512 // how we can do this better?
1513 // update cache pid when the user changed the audio track or video track
1514 // TODO handling of difference audio types.. default audio types..
1516 /* don't worry about non-existing services, nor pvr services */
1517 if (m_dvb_service && !m_is_pvr)
1519 if (apidtype == eDVBAudio::aMPEG)
1521 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1522 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1526 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1527 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1529 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1530 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1531 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1536 void eDVBServicePlay::loadCuesheet()
1538 std::string filename = m_reference.path + ".cuts";
1540 m_cue_entries.clear();
1542 FILE *f = fopen(filename.c_str(), "rb");
1546 eDebug("loading cuts..");
1549 unsigned long long where;
1552 if (!fread(&where, sizeof(where), 1, f))
1554 if (!fread(&what, sizeof(what), 1, f))
1557 #if BYTE_ORDER == LITTLE_ENDIAN
1558 where = bswap_64(where);
1565 m_cue_entries.insert(cueEntry(where, what));
1568 eDebug("%d entries", m_cue_entries.size());
1570 eDebug("cutfile not found!");
1572 m_cuesheet_changed = 0;
1573 cutlistToCuesheet();
1574 m_event((iPlayableService*)this, evCuesheetChanged);
1577 void eDVBServicePlay::saveCuesheet()
1579 std::string filename = m_reference.path + ".cuts";
1581 FILE *f = fopen(filename.c_str(), "wb");
1585 unsigned long long where;
1588 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1590 #if BYTE_ORDER == BIG_ENDIAN
1593 where = bswap_64(i->where);
1595 what = htonl(i->what);
1596 fwrite(&where, sizeof(where), 1, f);
1597 fwrite(&what, sizeof(what), 1, f);
1603 m_cuesheet_changed = 0;
1606 void eDVBServicePlay::cutlistToCuesheet()
1610 eDebug("no cue sheet");
1615 if (!m_cutlist_enabled)
1617 m_cue->commitSpans();
1618 eDebug("cutlists where disabled");
1622 pts_t in = 0, out = 0, length = 0;
1626 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1630 if (i == m_cue_entries.end())
1633 if (i->what == 0) /* in */
1637 } else if (i->what == 1) /* out */
1647 m_cue->addSourceSpan(in, out);
1651 if (i == m_cue_entries.end())
1654 m_cue->commitSpans();
1657 DEFINE_REF(eDVBServicePlay)
1659 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");