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 std::string tmp = m_ref.path;
255 tmp.erase(m_ref.path.length()-3);
256 res.push_back(tmp + ".eit");
260 DEFINE_REF(eServiceFactoryDVB)
262 eServiceFactoryDVB::eServiceFactoryDVB()
264 ePtr<eServiceCenter> sc;
266 eServiceCenter::getPrivInstance(sc);
268 sc->addServiceFactory(eServiceFactoryDVB::id, this);
271 eServiceFactoryDVB::~eServiceFactoryDVB()
273 ePtr<eServiceCenter> sc;
275 eServiceCenter::getPrivInstance(sc);
277 sc->removeServiceFactory(eServiceFactoryDVB::id);
280 DEFINE_REF(eDVBServiceList);
282 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
286 eDVBServiceList::~eDVBServiceList()
290 RESULT eDVBServiceList::startQuery()
292 ePtr<iDVBChannelList> db;
293 ePtr<eDVBResourceManager> res;
296 if ((err = eDVBResourceManager::getInstance(res)) != 0)
298 eDebug("no resource manager");
301 if ((err = res->getChannelList(db)) != 0)
303 eDebug("no channel list");
307 ePtr<eDVBChannelQuery> q;
309 if (!m_parent.path.empty())
311 eDVBChannelQuery::compile(q, m_parent.path);
314 eDebug("compile query failed");
319 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
321 eDebug("startQuery failed");
328 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
330 eServiceReferenceDVB ref;
332 if (!m_query || !list || !PyList_Check(list))
335 std::list<eServiceReferenceDVB> tmplist;
337 while (!m_query->getNextResult(ref))
338 tmplist.push_back(ref);
341 tmplist.sort(iListableServiceCompare(this));
343 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
344 it != tmplist.end(); ++it)
346 PyObject *refobj = New_eServiceReference(*it);
347 PyList_Append(list, refobj);
353 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
355 eServiceReferenceDVB ref;
360 while (!m_query->getNextResult(ref))
364 list.sort(iListableServiceCompare(this));
369 RESULT eDVBServiceList::getNext(eServiceReference &ref)
374 return m_query->getNextResult((eServiceReferenceDVB&)ref);
377 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
379 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
382 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
384 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
386 ePtr<iDVBChannelList> db;
387 ePtr<eDVBResourceManager> resm;
389 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
392 if (db->getBouquet(m_parent, m_bouquet) != 0)
403 RESULT eDVBServiceList::addService(eServiceReference &ref)
407 return m_bouquet->addService(ref);
410 RESULT eDVBServiceList::removeService(eServiceReference &ref)
414 return m_bouquet->removeService(ref);
417 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
421 return m_bouquet->moveService(ref, pos);
424 RESULT eDVBServiceList::flushChanges()
428 return m_bouquet->flushChanges();
431 RESULT eDVBServiceList::setListName(const std::string &name)
435 return m_bouquet->setListName(name);
438 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
440 ePtr<eDVBService> service;
441 int r = lookupService(service, ref);
444 // check resources...
445 ptr = new eDVBServicePlay(ref, service);
449 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
451 if (ref.path.empty())
453 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
462 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
464 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
465 if (list->startQuery())
475 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
477 /* is a listable service? */
478 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
480 if ( !ref.name.empty() ) // satellites or providers list
481 ptr = new eStaticServiceDVBInformation;
482 else // a dvb bouquet
483 ptr = new eStaticServiceDVBBouquetInformation;
485 else if (!ref.path.empty()) /* do we have a PVR service? */
486 ptr = new eStaticServiceDVBPVRInformation(ref);
487 else // normal dvb service
489 ePtr<eDVBService> service;
490 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
491 ptr = new eStaticServiceDVBInformation;
493 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
499 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
501 if (ref.path.empty())
507 ptr = new eDVBPVRServiceOfflineOperations(ref);
512 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
514 // TODO: handle the listing itself
515 // if (ref.... == -1) .. return "... bouquets ...";
516 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
518 ePtr<iDVBChannelList> db;
519 ePtr<eDVBResourceManager> res;
522 if ((err = eDVBResourceManager::getInstance(res)) != 0)
524 eDebug("no resource manager");
527 if ((err = res->getChannelList(db)) != 0)
529 eDebug("no channel list");
533 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
534 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
536 eDebug("getService failed!");
543 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
544 m_reference(ref), m_dvb_service(service), m_is_paused(0)
546 m_is_pvr = !ref.path.empty();
548 m_timeshift_enabled = m_timeshift_active = 0;
551 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
552 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
553 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
555 m_cuesheet_changed = 0;
556 m_cutlist_enabled = 1;
559 eDVBServicePlay::~eDVBServicePlay()
563 void eDVBServicePlay::gotNewEvent()
567 ePtr<eServiceEvent> m_event_now, m_event_next;
568 getEvent(m_event_now, 0);
569 getEvent(m_event_next, 1);
572 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
574 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
576 m_event((iPlayableService*)this, evUpdatedEventInfo);
579 void eDVBServicePlay::serviceEvent(int event)
583 case eDVBServicePMTHandler::eventTuned:
585 ePtr<iDVBDemux> m_demux;
586 if (!m_service_handler.getDataDemux(m_demux))
588 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
589 int sid = ref.getParentServiceID().get();
591 sid = ref.getServiceID().get();
592 if ( ref.getParentTransportStreamID().get() &&
593 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
594 m_event_handler.startOther(m_demux, sid);
596 m_event_handler.start(m_demux, sid);
600 case eDVBServicePMTHandler::eventTuneFailed:
602 eDebug("DVB service failed to tune");
603 m_event((iPlayableService*)this, evTuneFailed);
606 case eDVBServicePMTHandler::eventNewProgramInfo:
608 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
609 if (m_timeshift_enabled)
610 updateTimeshiftPids();
611 if (!m_timeshift_active)
613 if (m_first_program_info && m_is_pvr)
615 m_first_program_info = 0;
618 m_event((iPlayableService*)this, evUpdatedInfo);
621 case eDVBServicePMTHandler::eventEOF:
622 m_event((iPlayableService*)this, evEOF);
624 case eDVBServicePMTHandler::eventSOF:
625 m_event((iPlayableService*)this, evSOF);
630 void eDVBServicePlay::serviceEventTimeshift(int event)
634 case eDVBServicePMTHandler::eventNewProgramInfo:
635 if (m_timeshift_active)
638 case eDVBServicePMTHandler::eventSOF:
639 m_event((iPlayableService*)this, evSOF);
641 case eDVBServicePMTHandler::eventEOF:
647 RESULT eDVBServicePlay::start()
650 /* in pvr mode, we only want to use one demux. in tv mode, we're using
651 two (one for decoding, one for data source), as we must be prepared
652 to start recording from the data demux. */
653 m_cue = new eCueSheet();
655 m_first_program_info = 1;
656 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
657 r = m_service_handler.tune(service, m_is_pvr, m_cue);
659 /* inject EIT if there is a stored one */
662 std::string filename = service.path;
663 filename.erase(filename.length()-2, 2);
665 int fd = ::open( filename.c_str(), O_RDONLY );
669 int rd = ::read(fd, buf, 4096);
671 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
674 ePtr<eServiceEvent> event = new eServiceEvent;
675 ePtr<eServiceEvent> empty;
676 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
677 m_event_handler.inject(event, 0);
678 m_event_handler.inject(empty, 1);
687 m_event(this, evStart);
688 m_event((iPlayableService*)this, evSeekableStatusChanged);
692 RESULT eDVBServicePlay::stop()
694 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
696 m_service_handler_timeshift.free();
697 m_service_handler.free();
699 if (m_is_pvr && m_cuesheet_changed)
705 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
707 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
711 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
713 /* note: we check for timeshift to be enabled,
714 not neccessary active. if you pause when timeshift
715 is not active, you should activate it when unpausing */
716 if ((!m_is_pvr) && (!m_timeshift_enabled))
726 RESULT eDVBServicePlay::setSlowMotion(int ratio)
729 return m_decoder->setSlowMotion(ratio);
734 RESULT eDVBServicePlay::setFastForward(int ratio)
736 int skipmode, ffratio;
742 } else if (ratio > 0)
750 } else // if (ratio < 0)
756 if (m_skipmode != skipmode)
758 eDebug("setting cue skipmode to %d", skipmode);
760 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
763 m_skipmode = skipmode;
768 return m_decoder->setFastForward(ffratio);
771 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
773 if (m_is_pvr || m_timeshift_enabled)
783 /* TODO: when timeshift is enabled but not active, this doesn't work. */
784 RESULT eDVBServicePlay::getLength(pts_t &len)
786 ePtr<iDVBPVRChannel> pvr_channel;
788 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
791 return pvr_channel->getLength(len);
794 RESULT eDVBServicePlay::pause()
796 if (!m_is_paused && m_decoder)
799 return m_decoder->freeze(0);
804 RESULT eDVBServicePlay::unpause()
806 if (m_is_paused && m_decoder)
809 return m_decoder->unfreeze();
814 RESULT eDVBServicePlay::seekTo(pts_t to)
816 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
821 ePtr<iDVBPVRChannel> pvr_channel;
823 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
829 m_cue->seekTo(0, to);
833 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
835 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
840 ePtr<iDVBPVRChannel> pvr_channel;
842 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
847 /* HACK until we have skip-AP api */
848 if ((to > 0) && (to < 100))
856 m_cue->seekTo(mode, to);
860 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
862 ePtr<iDVBPVRChannel> pvr_channel;
867 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
872 /* if there is a decoder, use audio or video PTS */
875 r = m_decoder->getPTS(0, pos);
881 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
884 RESULT eDVBServicePlay::setTrickmode(int trick)
887 m_decoder->setTrickmode(trick);
891 RESULT eDVBServicePlay::isCurrentlySeekable()
893 return m_is_pvr || m_timeshift_active;
896 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
902 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
908 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
914 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
920 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
923 if (m_timeshift_enabled || !m_is_pvr)
925 if (!m_timeshift_enabled)
927 /* we need enough diskspace */
929 if (statfs(TSPATH "/.", &fs) < 0)
931 eDebug("statfs failed!");
935 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
937 eDebug("not enough diskspace for timeshift! (less than 1GB)");
947 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
958 RESULT eDVBServicePlay::getName(std::string &name)
962 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
963 return i->getName(m_reference, name);
967 m_dvb_service->getName(m_reference, name);
971 else if (!m_reference.name.empty())
972 eStaticServiceDVBInformation().getName(m_reference, name);
974 name = "DVB service";
978 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
980 return m_event_handler.getEvent(evt, nownext);
983 int eDVBServicePlay::getInfo(int w)
985 eDVBServicePMTHandler::program program;
987 if (m_service_handler.getProgramInfo(program))
993 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
995 ePtr<eServiceEvent> evt;
996 if (!m_event_handler.getEvent(evt, 0))
998 ePtr<eComponentData> data;
999 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1001 if ( data->getStreamContent() == 1 )
1003 switch(data->getComponentType())
1006 case 1: // 4:3 SD PAL
1008 case 3: // 16:9 SD PAL
1009 case 4: // > 16:9 PAL
1010 case 5: // 4:3 SD NTSC
1012 case 7: // 16:9 SD NTSC
1013 case 8: // > 16:9 NTSC
1016 case 9: // 4:3 HD PAL
1018 case 0xB: // 16:9 HD PAL
1019 case 0xC: // > 16:9 HD PAL
1020 case 0xD: // 4:3 HD NTSC
1022 case 0xF: // 16:9 HD NTSC
1023 case 0x10: // > 16:9 HD PAL
1024 return data->getComponentType();
1031 case sIsCrypted: return program.isCrypted;
1032 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1033 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1034 case sPCRPID: return program.pcrPid;
1035 case sPMTPID: return program.pmtPid;
1036 case sTXTPID: return program.textPid;
1037 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1038 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1039 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1040 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1041 case sProvider: if (!m_dvb_service) return -1; return -2;
1047 std::string eDVBServicePlay::getInfoString(int w)
1052 if (!m_dvb_service) return "";
1053 return m_dvb_service->m_provider_name;
1059 int eDVBServicePlay::getNumberOfTracks()
1061 eDVBServicePMTHandler::program program;
1062 if (m_service_handler.getProgramInfo(program))
1064 return program.audioStreams.size();
1067 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1069 int ret = selectAudioStream(i);
1071 if (m_decoder->start())
1077 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1079 eDVBServicePMTHandler::program program;
1081 if (m_service_handler.getProgramInfo(program))
1084 if (i >= program.audioStreams.size())
1087 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1088 info.m_description = "MPEG";
1089 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1090 info.m_description = "AC3";
1091 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1092 info.m_description = "DTS";
1094 info.m_description = "???";
1096 if (program.audioStreams[i].component_tag != -1)
1098 ePtr<eServiceEvent> evt;
1099 if (!m_event_handler.getEvent(evt, 0))
1101 ePtr<eComponentData> data;
1102 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1103 info.m_language = data->getText();
1107 if (info.m_language.empty())
1108 info.m_language = program.audioStreams[i].language_code;
1113 int eDVBServicePlay::selectAudioStream(int i)
1115 eDVBServicePMTHandler::program program;
1117 if (m_service_handler.getProgramInfo(program))
1120 if ((unsigned int)i >= program.audioStreams.size())
1126 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1129 if (m_dvb_service && !m_is_pvr)
1131 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1133 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1134 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1137 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1138 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1142 m_current_audio_stream = i;
1147 int eDVBServicePlay::getFrontendInfo(int w)
1151 eUsePtr<iDVBChannel> channel;
1152 if(m_service_handler.getChannel(channel))
1154 ePtr<iDVBFrontend> fe;
1155 if(channel->getFrontend(fe))
1157 return fe->readFrontendData(w);
1160 PyObject *eDVBServicePlay::getFrontendData(bool original)
1164 eUsePtr<iDVBChannel> channel;
1165 if(!m_service_handler.getChannel(channel))
1167 ePtr<iDVBFrontend> fe;
1168 if(!channel->getFrontend(fe))
1170 ret = fe->readTransponderData(original);
1173 ePtr<iDVBFrontendParameters> feparm;
1174 channel->getCurrentFrontendParameters(feparm);
1177 eDVBFrontendParametersSatellite osat;
1178 if (!feparm->getDVBS(osat))
1180 void PutToDict(PyObject *, const char*, long);
1181 void PutToDict(PyObject *, const char*, const char*);
1182 PutToDict(ret, "orbital_position", osat.orbital_position);
1183 const char *tmp = "UNKNOWN";
1184 switch(osat.polarisation)
1186 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1187 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1188 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1189 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1192 PutToDict(ret, "polarization", tmp);
1206 int eDVBServicePlay::getNumberOfSubservices()
1208 ePtr<eServiceEvent> evt;
1209 if (!m_event_handler.getEvent(evt, 0))
1210 return evt->getNumOfLinkageServices();
1214 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1216 ePtr<eServiceEvent> evt;
1217 if (!m_event_handler.getEvent(evt, 0))
1219 if (!evt->getLinkageService(sub, m_reference, n))
1222 sub.type=eServiceReference::idInvalid;
1226 RESULT eDVBServicePlay::startTimeshift()
1228 ePtr<iDVBDemux> demux;
1230 eDebug("Start timeshift!");
1232 if (m_timeshift_enabled)
1235 /* start recording with the data demux. */
1236 if (m_service_handler.getDataDemux(demux))
1239 demux->createTSRecorder(m_record);
1243 char templ[]=TSPATH "/timeshift.XXXXXX";
1244 m_timeshift_fd = mkstemp(templ);
1245 m_timeshift_file = templ;
1247 eDebug("recording to %s", templ);
1249 if (m_timeshift_fd < 0)
1255 m_record->setTargetFD(m_timeshift_fd);
1257 m_timeshift_enabled = 1;
1259 updateTimeshiftPids();
1265 RESULT eDVBServicePlay::stopTimeshift()
1267 if (!m_timeshift_enabled)
1272 m_timeshift_enabled = 0;
1277 close(m_timeshift_fd);
1278 eDebug("remove timeshift file");
1279 remove(m_timeshift_file.c_str());
1284 int eDVBServicePlay::isTimeshiftActive()
1286 return m_timeshift_enabled && m_timeshift_active;
1289 RESULT eDVBServicePlay::activateTimeshift()
1291 if (!m_timeshift_enabled)
1294 if (!m_timeshift_active)
1296 switchToTimeshift();
1303 PyObject *eDVBServicePlay::getCutList()
1305 PyObject *list = PyList_New(0);
1307 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1309 PyObject *tuple = PyTuple_New(2);
1310 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1311 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1312 PyList_Append(list, tuple);
1319 void eDVBServicePlay::setCutList(PyObject *list)
1321 if (!PyList_Check(list))
1323 int size = PyList_Size(list);
1326 m_cue_entries.clear();
1328 for (i=0; i<size; ++i)
1330 PyObject *tuple = PyList_GetItem(list, i);
1331 if (!PyTuple_Check(tuple))
1333 eDebug("non-tuple in cutlist");
1336 if (PyTuple_Size(tuple) != 2)
1338 eDebug("cutlist entries need to be a 2-tuple");
1341 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1342 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1344 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1347 pts_t pts = PyLong_AsLongLong(ppts);
1348 int type = PyInt_AsLong(ptype);
1349 m_cue_entries.insert(cueEntry(pts, type));
1350 eDebug("adding %08llx, %d", pts, type);
1352 m_cuesheet_changed = 1;
1354 cutlistToCuesheet();
1355 m_event((iPlayableService*)this, evCuesheetChanged);
1358 void eDVBServicePlay::setCutListEnable(int enable)
1360 m_cutlist_enabled = enable;
1361 cutlistToCuesheet();
1364 void eDVBServicePlay::updateTimeshiftPids()
1369 eDVBServicePMTHandler::program program;
1370 if (m_service_handler.getProgramInfo(program))
1374 std::set<int> pids_to_record;
1375 pids_to_record.insert(0); // PAT
1376 if (program.pmtPid != -1)
1377 pids_to_record.insert(program.pmtPid); // PMT
1379 if (program.textPid != -1)
1380 pids_to_record.insert(program.textPid); // Videotext
1382 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1383 i(program.videoStreams.begin());
1384 i != program.videoStreams.end(); ++i)
1385 pids_to_record.insert(i->pid);
1387 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1388 i(program.audioStreams.begin());
1389 i != program.audioStreams.end(); ++i)
1390 pids_to_record.insert(i->pid);
1392 std::set<int> new_pids, obsolete_pids;
1394 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1395 m_pids_active.begin(), m_pids_active.end(),
1396 std::inserter(new_pids, new_pids.begin()));
1398 std::set_difference(
1399 m_pids_active.begin(), m_pids_active.end(),
1400 pids_to_record.begin(), pids_to_record.end(),
1401 std::inserter(new_pids, new_pids.begin())
1404 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1405 m_record->addPID(*i);
1407 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1408 m_record->removePID(*i);
1412 void eDVBServicePlay::switchToLive()
1414 if (!m_timeshift_active)
1419 /* free the timeshift service handler, we need the resources */
1420 m_service_handler_timeshift.free();
1421 m_timeshift_active = 0;
1423 m_event((iPlayableService*)this, evSeekableStatusChanged);
1428 void eDVBServicePlay::switchToTimeshift()
1430 if (m_timeshift_active)
1436 m_timeshift_active = 1;
1438 m_event((iPlayableService*)this, evSeekableStatusChanged);
1440 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1441 r.path = m_timeshift_file;
1443 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1444 updateDecoder(); /* mainly to switch off PCR */
1447 void eDVBServicePlay::updateDecoder()
1449 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1450 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1452 eDVBServicePMTHandler::program program;
1453 if (h.getProgramInfo(program))
1454 eDebug("getting program info failed.");
1457 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1458 if (!program.videoStreams.empty())
1460 eDebugNoNewLine(" (");
1461 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1462 i(program.videoStreams.begin());
1463 i != program.videoStreams.end(); ++i)
1467 if (i != program.videoStreams.begin())
1468 eDebugNoNewLine(", ");
1469 eDebugNoNewLine("%04x", i->pid);
1471 eDebugNoNewLine(")");
1473 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1474 if (!program.audioStreams.empty())
1476 eDebugNoNewLine(" (");
1477 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1478 i(program.audioStreams.begin());
1479 i != program.audioStreams.end(); ++i)
1486 if (i != program.audioStreams.begin())
1487 eDebugNoNewLine(", ");
1488 eDebugNoNewLine("%04x", i->pid);
1490 eDebugNoNewLine(")");
1492 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1493 pcrpid = program.pcrPid;
1494 eDebug(", and the text pid is %04x", program.textPid);
1495 tpid = program.textPid;
1500 h.getDecodeDemux(m_decode_demux);
1502 m_decode_demux->getMPEGDecoder(m_decoder);
1504 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1509 m_decoder->setVideoPID(vpid);
1510 m_current_audio_stream = 0;
1511 m_decoder->setAudioPID(apid, apidtype);
1512 if (!(m_is_pvr || m_timeshift_active))
1513 m_decoder->setSyncPCR(pcrpid);
1515 m_decoder->setSyncPCR(-1);
1516 m_decoder->setTextPID(tpid);
1518 // how we can do this better?
1519 // update cache pid when the user changed the audio track or video track
1520 // TODO handling of difference audio types.. default audio types..
1522 /* don't worry about non-existing services, nor pvr services */
1523 if (m_dvb_service && !m_is_pvr)
1525 if (apidtype == eDVBAudio::aMPEG)
1527 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1528 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1532 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1533 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1535 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1536 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1537 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1542 void eDVBServicePlay::loadCuesheet()
1544 std::string filename = m_reference.path + ".cuts";
1546 m_cue_entries.clear();
1548 FILE *f = fopen(filename.c_str(), "rb");
1552 eDebug("loading cuts..");
1555 unsigned long long where;
1558 if (!fread(&where, sizeof(where), 1, f))
1560 if (!fread(&what, sizeof(what), 1, f))
1563 #if BYTE_ORDER == LITTLE_ENDIAN
1564 where = bswap_64(where);
1571 m_cue_entries.insert(cueEntry(where, what));
1574 eDebug("%d entries", m_cue_entries.size());
1576 eDebug("cutfile not found!");
1578 m_cuesheet_changed = 0;
1579 cutlistToCuesheet();
1580 m_event((iPlayableService*)this, evCuesheetChanged);
1583 void eDVBServicePlay::saveCuesheet()
1585 std::string filename = m_reference.path + ".cuts";
1587 FILE *f = fopen(filename.c_str(), "wb");
1591 unsigned long long where;
1594 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1596 #if BYTE_ORDER == BIG_ENDIAN
1599 where = bswap_64(i->where);
1601 what = htonl(i->what);
1602 fwrite(&where, sizeof(where), 1, f);
1603 fwrite(&what, sizeof(what), 1, f);
1609 m_cuesheet_changed = 0;
1612 void eDVBServicePlay::cutlistToCuesheet()
1616 eDebug("no cue sheet");
1621 if (!m_cutlist_enabled)
1623 m_cue->commitSpans();
1624 eDebug("cutlists where disabled");
1628 pts_t in = 0, out = 0, length = 0;
1632 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1636 if (i == m_cue_entries.end())
1639 if (i->what == 0) /* in */
1643 } else if (i->what == 1) /* out */
1653 m_cue->addSourceSpan(in, out);
1657 if (i == m_cue_entries.end())
1660 m_cue->commitSpans();
1663 DEFINE_REF(eDVBServicePlay)
1665 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");