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::getFrontendTransponderData()
1159 eUsePtr<iDVBChannel> channel;
1160 if(!m_service_handler.getChannel(channel))
1162 ePtr<iDVBFrontend> fe;
1163 if(!channel->getFrontend(fe))
1164 ret = fe->readTransponderData();
1175 int eDVBServicePlay::getNumberOfSubservices()
1177 ePtr<eServiceEvent> evt;
1178 if (!m_event_handler.getEvent(evt, 0))
1179 return evt->getNumOfLinkageServices();
1183 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1185 ePtr<eServiceEvent> evt;
1186 if (!m_event_handler.getEvent(evt, 0))
1188 if (!evt->getLinkageService(sub, m_reference, n))
1191 sub.type=eServiceReference::idInvalid;
1195 RESULT eDVBServicePlay::startTimeshift()
1197 ePtr<iDVBDemux> demux;
1199 eDebug("Start timeshift!");
1201 if (m_timeshift_enabled)
1204 /* start recording with the data demux. */
1205 if (m_service_handler.getDataDemux(demux))
1208 demux->createTSRecorder(m_record);
1212 char templ[]=TSPATH "/timeshift.XXXXXX";
1213 m_timeshift_fd = mkstemp(templ);
1214 m_timeshift_file = templ;
1216 eDebug("recording to %s", templ);
1218 if (m_timeshift_fd < 0)
1224 m_record->setTargetFD(m_timeshift_fd);
1226 m_timeshift_enabled = 1;
1228 updateTimeshiftPids();
1234 RESULT eDVBServicePlay::stopTimeshift()
1236 if (!m_timeshift_enabled)
1241 m_timeshift_enabled = 0;
1246 close(m_timeshift_fd);
1247 eDebug("remove timeshift file");
1248 remove(m_timeshift_file.c_str());
1253 int eDVBServicePlay::isTimeshiftActive()
1255 return m_timeshift_enabled && m_timeshift_active;
1258 RESULT eDVBServicePlay::activateTimeshift()
1260 if (!m_timeshift_enabled)
1263 if (!m_timeshift_active)
1265 switchToTimeshift();
1272 PyObject *eDVBServicePlay::getCutList()
1274 PyObject *list = PyList_New(0);
1276 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1278 PyObject *tuple = PyTuple_New(2);
1279 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1280 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1281 PyList_Append(list, tuple);
1288 void eDVBServicePlay::setCutList(PyObject *list)
1290 if (!PyList_Check(list))
1292 int size = PyList_Size(list);
1295 m_cue_entries.clear();
1297 for (i=0; i<size; ++i)
1299 PyObject *tuple = PyList_GetItem(list, i);
1300 if (!PyTuple_Check(tuple))
1302 eDebug("non-tuple in cutlist");
1305 if (PyTuple_Size(tuple) != 2)
1307 eDebug("cutlist entries need to be a 2-tuple");
1310 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1311 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1313 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1316 pts_t pts = PyLong_AsLongLong(ppts);
1317 int type = PyInt_AsLong(ptype);
1318 m_cue_entries.insert(cueEntry(pts, type));
1319 eDebug("adding %08llx, %d", pts, type);
1321 m_cuesheet_changed = 1;
1323 cutlistToCuesheet();
1324 m_event((iPlayableService*)this, evCuesheetChanged);
1327 void eDVBServicePlay::setCutListEnable(int enable)
1329 m_cutlist_enabled = enable;
1330 cutlistToCuesheet();
1333 void eDVBServicePlay::updateTimeshiftPids()
1338 eDVBServicePMTHandler::program program;
1339 if (m_service_handler.getProgramInfo(program))
1343 std::set<int> pids_to_record;
1344 pids_to_record.insert(0); // PAT
1345 if (program.pmtPid != -1)
1346 pids_to_record.insert(program.pmtPid); // PMT
1348 if (program.textPid != -1)
1349 pids_to_record.insert(program.textPid); // Videotext
1351 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1352 i(program.videoStreams.begin());
1353 i != program.videoStreams.end(); ++i)
1354 pids_to_record.insert(i->pid);
1356 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1357 i(program.audioStreams.begin());
1358 i != program.audioStreams.end(); ++i)
1359 pids_to_record.insert(i->pid);
1361 std::set<int> new_pids, obsolete_pids;
1363 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1364 m_pids_active.begin(), m_pids_active.end(),
1365 std::inserter(new_pids, new_pids.begin()));
1367 std::set_difference(
1368 m_pids_active.begin(), m_pids_active.end(),
1369 pids_to_record.begin(), pids_to_record.end(),
1370 std::inserter(new_pids, new_pids.begin())
1373 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1374 m_record->addPID(*i);
1376 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1377 m_record->removePID(*i);
1381 void eDVBServicePlay::switchToLive()
1383 if (!m_timeshift_active)
1388 /* free the timeshift service handler, we need the resources */
1389 m_service_handler_timeshift.free();
1390 m_timeshift_active = 0;
1392 m_event((iPlayableService*)this, evSeekableStatusChanged);
1397 void eDVBServicePlay::switchToTimeshift()
1399 if (m_timeshift_active)
1405 m_timeshift_active = 1;
1407 m_event((iPlayableService*)this, evSeekableStatusChanged);
1409 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1410 r.path = m_timeshift_file;
1412 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1415 void eDVBServicePlay::updateDecoder()
1417 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1418 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1420 eDVBServicePMTHandler::program program;
1421 if (h.getProgramInfo(program))
1422 eDebug("getting program info failed.");
1425 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1426 if (!program.videoStreams.empty())
1428 eDebugNoNewLine(" (");
1429 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1430 i(program.videoStreams.begin());
1431 i != program.videoStreams.end(); ++i)
1435 if (i != program.videoStreams.begin())
1436 eDebugNoNewLine(", ");
1437 eDebugNoNewLine("%04x", i->pid);
1439 eDebugNoNewLine(")");
1441 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1442 if (!program.audioStreams.empty())
1444 eDebugNoNewLine(" (");
1445 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1446 i(program.audioStreams.begin());
1447 i != program.audioStreams.end(); ++i)
1454 if (i != program.audioStreams.begin())
1455 eDebugNoNewLine(", ");
1456 eDebugNoNewLine("%04x", i->pid);
1458 eDebugNoNewLine(")");
1460 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1461 pcrpid = program.pcrPid;
1462 eDebug(", and the text pid is %04x", program.textPid);
1463 tpid = program.textPid;
1468 h.getDecodeDemux(m_decode_demux);
1470 m_decode_demux->getMPEGDecoder(m_decoder);
1472 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1477 m_decoder->setVideoPID(vpid);
1478 m_current_audio_stream = 0;
1479 m_decoder->setAudioPID(apid, apidtype);
1480 if (!(m_is_pvr || m_timeshift_active))
1481 m_decoder->setSyncPCR(pcrpid);
1483 m_decoder->setSyncPCR(-1);
1484 m_decoder->setTextPID(tpid);
1486 // how we can do this better?
1487 // update cache pid when the user changed the audio track or video track
1488 // TODO handling of difference audio types.. default audio types..
1490 /* don't worry about non-existing services, nor pvr services */
1491 if (m_dvb_service && !m_is_pvr)
1493 if (apidtype == eDVBAudio::aMPEG)
1495 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1496 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1500 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1501 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1503 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1504 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1505 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1510 void eDVBServicePlay::loadCuesheet()
1512 std::string filename = m_reference.path + ".cuts";
1514 m_cue_entries.clear();
1516 FILE *f = fopen(filename.c_str(), "rb");
1520 eDebug("loading cuts..");
1523 unsigned long long where;
1526 if (!fread(&where, sizeof(where), 1, f))
1528 if (!fread(&what, sizeof(what), 1, f))
1531 #if BYTE_ORDER == LITTLE_ENDIAN
1532 where = bswap_64(where);
1539 m_cue_entries.insert(cueEntry(where, what));
1542 eDebug("%d entries", m_cue_entries.size());
1544 eDebug("cutfile not found!");
1546 m_cuesheet_changed = 0;
1547 cutlistToCuesheet();
1548 m_event((iPlayableService*)this, evCuesheetChanged);
1551 void eDVBServicePlay::saveCuesheet()
1553 std::string filename = m_reference.path + ".cuts";
1555 FILE *f = fopen(filename.c_str(), "wb");
1559 unsigned long long where;
1562 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1564 #if BYTE_ORDER == BIG_ENDIAN
1567 where = bswap_64(i->where);
1569 what = htonl(i->what);
1570 fwrite(&where, sizeof(where), 1, f);
1571 fwrite(&what, sizeof(what), 1, f);
1577 m_cuesheet_changed = 0;
1580 void eDVBServicePlay::cutlistToCuesheet()
1584 eDebug("no cue sheet");
1589 if (!m_cutlist_enabled)
1591 m_cue->commitSpans();
1592 eDebug("cutlists where disabled");
1596 pts_t in = 0, out = 0, length = 0;
1600 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1604 if (i == m_cue_entries.end())
1607 if (i->what == 0) /* in */
1611 } else if (i->what == 1) /* out */
1621 m_cue->addSourceSpan(in, out);
1625 if (i == m_cue_entries.end())
1628 m_cue->commitSpans();
1631 DEFINE_REF(eDVBServicePlay)
1633 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");