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 int eDVBServicePlay::getNumberOfSubservices()
1157 ePtr<eServiceEvent> evt;
1158 if (!m_event_handler.getEvent(evt, 0))
1159 return evt->getNumOfLinkageServices();
1163 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1165 ePtr<eServiceEvent> evt;
1166 if (!m_event_handler.getEvent(evt, 0))
1168 if (!evt->getLinkageService(sub, m_reference, n))
1171 sub.type=eServiceReference::idInvalid;
1175 RESULT eDVBServicePlay::startTimeshift()
1177 ePtr<iDVBDemux> demux;
1179 eDebug("Start timeshift!");
1181 if (m_timeshift_enabled)
1184 /* start recording with the data demux. */
1185 if (m_service_handler.getDataDemux(demux))
1188 demux->createTSRecorder(m_record);
1192 char templ[]=TSPATH "/timeshift.XXXXXX";
1193 m_timeshift_fd = mkstemp(templ);
1194 m_timeshift_file = templ;
1196 eDebug("recording to %s", templ);
1198 if (m_timeshift_fd < 0)
1204 m_record->setTargetFD(m_timeshift_fd);
1206 m_timeshift_enabled = 1;
1208 updateTimeshiftPids();
1214 RESULT eDVBServicePlay::stopTimeshift()
1216 if (!m_timeshift_enabled)
1221 m_timeshift_enabled = 0;
1226 close(m_timeshift_fd);
1227 eDebug("remove timeshift file");
1228 remove(m_timeshift_file.c_str());
1233 int eDVBServicePlay::isTimeshiftActive()
1235 return m_timeshift_enabled && m_timeshift_active;
1238 RESULT eDVBServicePlay::activateTimeshift()
1240 if (!m_timeshift_enabled)
1243 if (!m_timeshift_active)
1245 switchToTimeshift();
1252 PyObject *eDVBServicePlay::getCutList()
1254 PyObject *list = PyList_New(0);
1256 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1258 PyObject *tuple = PyTuple_New(2);
1259 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1260 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1261 PyList_Append(list, tuple);
1268 void eDVBServicePlay::setCutList(PyObject *list)
1270 if (!PyList_Check(list))
1272 int size = PyList_Size(list);
1275 m_cue_entries.clear();
1277 for (i=0; i<size; ++i)
1279 PyObject *tuple = PyList_GetItem(list, i);
1280 if (!PyTuple_Check(tuple))
1282 eDebug("non-tuple in cutlist");
1285 if (PyTuple_Size(tuple) != 2)
1287 eDebug("cutlist entries need to be a 2-tuple");
1290 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1291 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1293 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1296 pts_t pts = PyLong_AsLongLong(ppts);
1297 int type = PyInt_AsLong(ptype);
1298 m_cue_entries.insert(cueEntry(pts, type));
1299 eDebug("adding %08llx, %d", pts, type);
1301 m_cuesheet_changed = 1;
1303 cutlistToCuesheet();
1304 m_event((iPlayableService*)this, evCuesheetChanged);
1307 void eDVBServicePlay::setCutListEnable(int enable)
1309 m_cutlist_enabled = enable;
1310 cutlistToCuesheet();
1313 void eDVBServicePlay::updateTimeshiftPids()
1318 eDVBServicePMTHandler::program program;
1319 if (m_service_handler.getProgramInfo(program))
1323 std::set<int> pids_to_record;
1324 pids_to_record.insert(0); // PAT
1325 if (program.pmtPid != -1)
1326 pids_to_record.insert(program.pmtPid); // PMT
1328 if (program.textPid != -1)
1329 pids_to_record.insert(program.textPid); // Videotext
1331 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1332 i(program.videoStreams.begin());
1333 i != program.videoStreams.end(); ++i)
1334 pids_to_record.insert(i->pid);
1336 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1337 i(program.audioStreams.begin());
1338 i != program.audioStreams.end(); ++i)
1339 pids_to_record.insert(i->pid);
1341 std::set<int> new_pids, obsolete_pids;
1343 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1344 m_pids_active.begin(), m_pids_active.end(),
1345 std::inserter(new_pids, new_pids.begin()));
1347 std::set_difference(
1348 m_pids_active.begin(), m_pids_active.end(),
1349 pids_to_record.begin(), pids_to_record.end(),
1350 std::inserter(new_pids, new_pids.begin())
1353 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1354 m_record->addPID(*i);
1356 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1357 m_record->removePID(*i);
1361 void eDVBServicePlay::switchToLive()
1363 if (!m_timeshift_active)
1368 /* free the timeshift service handler, we need the resources */
1369 m_service_handler_timeshift.free();
1370 m_timeshift_active = 0;
1372 m_event((iPlayableService*)this, evSeekableStatusChanged);
1377 void eDVBServicePlay::switchToTimeshift()
1379 if (m_timeshift_active)
1385 m_timeshift_active = 1;
1387 m_event((iPlayableService*)this, evSeekableStatusChanged);
1389 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1390 r.path = m_timeshift_file;
1392 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1395 void eDVBServicePlay::updateDecoder()
1397 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1398 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1400 eDVBServicePMTHandler::program program;
1401 if (h.getProgramInfo(program))
1402 eDebug("getting program info failed.");
1405 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1406 if (!program.videoStreams.empty())
1408 eDebugNoNewLine(" (");
1409 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1410 i(program.videoStreams.begin());
1411 i != program.videoStreams.end(); ++i)
1415 if (i != program.videoStreams.begin())
1416 eDebugNoNewLine(", ");
1417 eDebugNoNewLine("%04x", i->pid);
1419 eDebugNoNewLine(")");
1421 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1422 if (!program.audioStreams.empty())
1424 eDebugNoNewLine(" (");
1425 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1426 i(program.audioStreams.begin());
1427 i != program.audioStreams.end(); ++i)
1434 if (i != program.audioStreams.begin())
1435 eDebugNoNewLine(", ");
1436 eDebugNoNewLine("%04x", i->pid);
1438 eDebugNoNewLine(")");
1440 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1441 pcrpid = program.pcrPid;
1442 eDebug(", and the text pid is %04x", program.textPid);
1443 tpid = program.textPid;
1448 h.getDecodeDemux(m_decode_demux);
1450 m_decode_demux->getMPEGDecoder(m_decoder);
1452 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1457 m_decoder->setVideoPID(vpid);
1458 m_current_audio_stream = 0;
1459 m_decoder->setAudioPID(apid, apidtype);
1460 if (!(m_is_pvr || m_timeshift_active))
1461 m_decoder->setSyncPCR(pcrpid);
1463 m_decoder->setSyncPCR(-1);
1464 m_decoder->setTextPID(tpid);
1466 // how we can do this better?
1467 // update cache pid when the user changed the audio track or video track
1468 // TODO handling of difference audio types.. default audio types..
1470 /* don't worry about non-existing services, nor pvr services */
1471 if (m_dvb_service && !m_is_pvr)
1473 if (apidtype == eDVBAudio::aMPEG)
1475 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1476 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1480 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1481 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1483 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1484 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1485 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1490 void eDVBServicePlay::loadCuesheet()
1492 std::string filename = m_reference.path + ".cuts";
1494 m_cue_entries.clear();
1496 FILE *f = fopen(filename.c_str(), "rb");
1500 eDebug("loading cuts..");
1503 unsigned long long where;
1506 if (!fread(&where, sizeof(where), 1, f))
1508 if (!fread(&what, sizeof(what), 1, f))
1511 #if BYTE_ORDER == LITTLE_ENDIAN
1512 where = bswap_64(where);
1519 m_cue_entries.insert(cueEntry(where, what));
1522 eDebug("%d entries", m_cue_entries.size());
1524 eDebug("cutfile not found!");
1526 m_cuesheet_changed = 0;
1527 cutlistToCuesheet();
1528 m_event((iPlayableService*)this, evCuesheetChanged);
1531 void eDVBServicePlay::saveCuesheet()
1533 std::string filename = m_reference.path + ".cuts";
1535 FILE *f = fopen(filename.c_str(), "wb");
1539 unsigned long long where;
1542 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1544 #if BYTE_ORDER == BIG_ENDIAN
1547 where = bswap_64(i->where);
1549 what = htonl(i->what);
1550 fwrite(&where, sizeof(where), 1, f);
1551 fwrite(&what, sizeof(what), 1, f);
1557 m_cuesheet_changed = 0;
1560 void eDVBServicePlay::cutlistToCuesheet()
1564 eDebug("no cue sheet");
1569 if (!m_cutlist_enabled)
1571 m_cue->commitSpans();
1572 eDebug("cutlists where disabled");
1576 pts_t in = 0, out = 0, length = 0;
1580 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1584 if (i == m_cue_entries.end())
1587 if (i->what == 0) /* in */
1591 } else if (i->what == 1) /* out */
1601 m_cue->addSourceSpan(in, out);
1605 if (i == m_cue_entries.end())
1608 m_cue->commitSpans();
1611 DEFINE_REF(eDVBServicePlay)
1613 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");