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))
845 m_cue->seekTo(1, to);
849 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
851 ePtr<iDVBPVRChannel> pvr_channel;
856 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
861 /* if there is a decoder, use audio or video PTS */
864 r = m_decoder->getPTS(0, pos);
870 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
873 RESULT eDVBServicePlay::setTrickmode(int trick)
876 m_decoder->setTrickmode(trick);
880 RESULT eDVBServicePlay::isCurrentlySeekable()
882 return m_is_pvr || m_timeshift_active;
885 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
891 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
897 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
903 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
909 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
912 if (m_timeshift_enabled || !m_is_pvr)
914 if (!m_timeshift_enabled)
916 /* we need enough diskspace */
918 if (statfs(TSPATH "/.", &fs) < 0)
920 eDebug("statfs failed!");
924 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
926 eDebug("not enough diskspace for timeshift! (less than 1GB)");
936 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
947 RESULT eDVBServicePlay::getName(std::string &name)
951 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
952 return i->getName(m_reference, name);
956 m_dvb_service->getName(m_reference, name);
960 else if (!m_reference.name.empty())
961 eStaticServiceDVBInformation().getName(m_reference, name);
963 name = "DVB service";
967 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
969 return m_event_handler.getEvent(evt, nownext);
972 int eDVBServicePlay::getInfo(int w)
974 eDVBServicePMTHandler::program program;
976 if (m_service_handler.getProgramInfo(program))
982 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
984 ePtr<eServiceEvent> evt;
985 if (!m_event_handler.getEvent(evt, 0))
987 ePtr<eComponentData> data;
988 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
990 if ( data->getStreamContent() == 1 )
992 switch(data->getComponentType())
995 case 1: // 4:3 SD PAL
997 case 3: // 16:9 SD PAL
998 case 4: // > 16:9 PAL
999 case 5: // 4:3 SD NTSC
1001 case 7: // 16:9 SD NTSC
1002 case 8: // > 16:9 NTSC
1005 case 9: // 4:3 HD PAL
1007 case 0xB: // 16:9 HD PAL
1008 case 0xC: // > 16:9 HD PAL
1009 case 0xD: // 4:3 HD NTSC
1011 case 0xF: // 16:9 HD NTSC
1012 case 0x10: // > 16:9 HD PAL
1013 return data->getComponentType();
1020 case sIsCrypted: return program.isCrypted;
1021 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1022 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1023 case sPCRPID: return program.pcrPid;
1024 case sPMTPID: return program.pmtPid;
1025 case sTXTPID: return program.textPid;
1026 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1027 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1028 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1029 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1030 case sProvider: if (!m_dvb_service) return -1; return -2;
1036 std::string eDVBServicePlay::getInfoString(int w)
1041 if (!m_dvb_service) return "";
1042 return m_dvb_service->m_provider_name;
1048 int eDVBServicePlay::getNumberOfTracks()
1050 eDVBServicePMTHandler::program program;
1051 if (m_service_handler.getProgramInfo(program))
1053 return program.audioStreams.size();
1056 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1058 int ret = selectAudioStream(i);
1060 if (m_decoder->start())
1066 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1068 eDVBServicePMTHandler::program program;
1070 if (m_service_handler.getProgramInfo(program))
1073 if (i >= program.audioStreams.size())
1076 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1077 info.m_description = "MPEG";
1078 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1079 info.m_description = "AC3";
1080 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1081 info.m_description = "DTS";
1083 info.m_description = "???";
1085 if (program.audioStreams[i].component_tag != -1)
1087 ePtr<eServiceEvent> evt;
1088 if (!m_event_handler.getEvent(evt, 0))
1090 ePtr<eComponentData> data;
1091 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1092 info.m_language = data->getText();
1096 if (info.m_language.empty())
1097 info.m_language = program.audioStreams[i].language_code;
1102 int eDVBServicePlay::selectAudioStream(int i)
1104 eDVBServicePMTHandler::program program;
1106 if (m_service_handler.getProgramInfo(program))
1109 if ((unsigned int)i >= program.audioStreams.size())
1115 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1118 if (m_dvb_service && !m_is_pvr)
1120 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1122 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1123 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1126 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1127 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1131 m_current_audio_stream = i;
1136 int eDVBServicePlay::getFrontendInfo(int w)
1140 eUsePtr<iDVBChannel> channel;
1141 if(m_service_handler.getChannel(channel))
1143 ePtr<iDVBFrontend> fe;
1144 if(channel->getFrontend(fe))
1146 return fe->readFrontendData(w);
1149 int eDVBServicePlay::getNumberOfSubservices()
1151 ePtr<eServiceEvent> evt;
1152 if (!m_event_handler.getEvent(evt, 0))
1153 return evt->getNumOfLinkageServices();
1157 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1159 ePtr<eServiceEvent> evt;
1160 if (!m_event_handler.getEvent(evt, 0))
1162 if (!evt->getLinkageService(sub, m_reference, n))
1165 sub.type=eServiceReference::idInvalid;
1169 RESULT eDVBServicePlay::startTimeshift()
1171 ePtr<iDVBDemux> demux;
1173 eDebug("Start timeshift!");
1175 if (m_timeshift_enabled)
1178 /* start recording with the data demux. */
1179 if (m_service_handler.getDataDemux(demux))
1182 demux->createTSRecorder(m_record);
1186 char templ[]=TSPATH "/timeshift.XXXXXX";
1187 m_timeshift_fd = mkstemp(templ);
1188 m_timeshift_file = templ;
1190 eDebug("recording to %s", templ);
1192 if (m_timeshift_fd < 0)
1198 m_record->setTargetFD(m_timeshift_fd);
1200 m_timeshift_enabled = 1;
1202 updateTimeshiftPids();
1208 RESULT eDVBServicePlay::stopTimeshift()
1210 if (!m_timeshift_enabled)
1215 m_timeshift_enabled = 0;
1220 close(m_timeshift_fd);
1221 eDebug("remove timeshift file");
1222 remove(m_timeshift_file.c_str());
1227 int eDVBServicePlay::isTimeshiftActive()
1229 return m_timeshift_enabled && m_timeshift_active;
1232 RESULT eDVBServicePlay::activateTimeshift()
1234 if (!m_timeshift_enabled)
1237 if (!m_timeshift_active)
1239 switchToTimeshift();
1246 PyObject *eDVBServicePlay::getCutList()
1248 PyObject *list = PyList_New(0);
1250 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1252 PyObject *tuple = PyTuple_New(2);
1253 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1254 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1255 PyList_Append(list, tuple);
1262 void eDVBServicePlay::setCutList(PyObject *list)
1264 if (!PyList_Check(list))
1266 int size = PyList_Size(list);
1269 m_cue_entries.clear();
1271 for (i=0; i<size; ++i)
1273 PyObject *tuple = PyList_GetItem(list, i);
1274 if (!PyTuple_Check(tuple))
1276 eDebug("non-tuple in cutlist");
1279 if (PyTuple_Size(tuple) != 2)
1281 eDebug("cutlist entries need to be a 2-tuple");
1284 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1285 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1287 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1290 pts_t pts = PyLong_AsLongLong(ppts);
1291 int type = PyInt_AsLong(ptype);
1292 m_cue_entries.insert(cueEntry(pts, type));
1293 eDebug("adding %08llx, %d", pts, type);
1295 m_cuesheet_changed = 1;
1297 cutlistToCuesheet();
1298 m_event((iPlayableService*)this, evCuesheetChanged);
1301 void eDVBServicePlay::setCutListEnable(int enable)
1303 m_cutlist_enabled = enable;
1304 cutlistToCuesheet();
1307 void eDVBServicePlay::updateTimeshiftPids()
1312 eDVBServicePMTHandler::program program;
1313 if (m_service_handler.getProgramInfo(program))
1317 std::set<int> pids_to_record;
1318 pids_to_record.insert(0); // PAT
1319 if (program.pmtPid != -1)
1320 pids_to_record.insert(program.pmtPid); // PMT
1322 if (program.textPid != -1)
1323 pids_to_record.insert(program.textPid); // Videotext
1325 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1326 i(program.videoStreams.begin());
1327 i != program.videoStreams.end(); ++i)
1328 pids_to_record.insert(i->pid);
1330 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1331 i(program.audioStreams.begin());
1332 i != program.audioStreams.end(); ++i)
1333 pids_to_record.insert(i->pid);
1335 std::set<int> new_pids, obsolete_pids;
1337 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1338 m_pids_active.begin(), m_pids_active.end(),
1339 std::inserter(new_pids, new_pids.begin()));
1341 std::set_difference(
1342 m_pids_active.begin(), m_pids_active.end(),
1343 pids_to_record.begin(), pids_to_record.end(),
1344 std::inserter(new_pids, new_pids.begin())
1347 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1348 m_record->addPID(*i);
1350 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1351 m_record->removePID(*i);
1355 void eDVBServicePlay::switchToLive()
1357 if (!m_timeshift_active)
1362 /* free the timeshift service handler, we need the resources */
1363 m_service_handler_timeshift.free();
1364 m_timeshift_active = 0;
1366 m_event((iPlayableService*)this, evSeekableStatusChanged);
1371 void eDVBServicePlay::switchToTimeshift()
1373 if (m_timeshift_active)
1379 m_timeshift_active = 1;
1381 m_event((iPlayableService*)this, evSeekableStatusChanged);
1383 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1384 r.path = m_timeshift_file;
1386 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1389 void eDVBServicePlay::updateDecoder()
1391 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1392 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1394 eDVBServicePMTHandler::program program;
1395 if (h.getProgramInfo(program))
1396 eDebug("getting program info failed.");
1399 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1400 if (!program.videoStreams.empty())
1402 eDebugNoNewLine(" (");
1403 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1404 i(program.videoStreams.begin());
1405 i != program.videoStreams.end(); ++i)
1409 if (i != program.videoStreams.begin())
1410 eDebugNoNewLine(", ");
1411 eDebugNoNewLine("%04x", i->pid);
1413 eDebugNoNewLine(")");
1415 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1416 if (!program.audioStreams.empty())
1418 eDebugNoNewLine(" (");
1419 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1420 i(program.audioStreams.begin());
1421 i != program.audioStreams.end(); ++i)
1428 if (i != program.audioStreams.begin())
1429 eDebugNoNewLine(", ");
1430 eDebugNoNewLine("%04x", i->pid);
1432 eDebugNoNewLine(")");
1434 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1435 pcrpid = program.pcrPid;
1436 eDebug(", and the text pid is %04x", program.textPid);
1437 tpid = program.textPid;
1442 h.getDecodeDemux(m_decode_demux);
1444 m_decode_demux->getMPEGDecoder(m_decoder);
1446 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1451 m_decoder->setVideoPID(vpid);
1452 m_current_audio_stream = 0;
1453 m_decoder->setAudioPID(apid, apidtype);
1454 if (!(m_is_pvr || m_timeshift_active))
1455 m_decoder->setSyncPCR(pcrpid);
1457 m_decoder->setSyncPCR(-1);
1458 m_decoder->setTextPID(tpid);
1460 // how we can do this better?
1461 // update cache pid when the user changed the audio track or video track
1462 // TODO handling of difference audio types.. default audio types..
1464 /* don't worry about non-existing services, nor pvr services */
1465 if (m_dvb_service && !m_is_pvr)
1467 if (apidtype == eDVBAudio::aMPEG)
1469 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1470 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1474 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1475 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1477 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1478 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1479 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1484 void eDVBServicePlay::loadCuesheet()
1486 std::string filename = m_reference.path + ".cuts";
1488 m_cue_entries.clear();
1490 FILE *f = fopen(filename.c_str(), "rb");
1494 eDebug("loading cuts..");
1497 unsigned long long where;
1500 if (!fread(&where, sizeof(where), 1, f))
1502 if (!fread(&what, sizeof(what), 1, f))
1505 #if BYTE_ORDER == LITTLE_ENDIAN
1506 where = bswap_64(where);
1513 m_cue_entries.insert(cueEntry(where, what));
1516 eDebug("%d entries", m_cue_entries.size());
1518 eDebug("cutfile not found!");
1520 m_cuesheet_changed = 0;
1521 cutlistToCuesheet();
1522 m_event((iPlayableService*)this, evCuesheetChanged);
1525 void eDVBServicePlay::saveCuesheet()
1527 std::string filename = m_reference.path + ".cuts";
1529 FILE *f = fopen(filename.c_str(), "wb");
1533 unsigned long long where;
1536 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1538 #if BYTE_ORDER == BIG_ENDIAN
1541 where = bswap_64(i->where);
1543 what = htonl(i->what);
1544 fwrite(&where, sizeof(where), 1, f);
1545 fwrite(&what, sizeof(what), 1, f);
1551 m_cuesheet_changed = 0;
1554 void eDVBServicePlay::cutlistToCuesheet()
1558 eDebug("no cue sheet");
1563 if (!m_cutlist_enabled)
1565 m_cue->commitSpans();
1566 eDebug("cutlists where disabled");
1570 pts_t in = 0, out = 0, length = 0;
1574 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1578 if (i == m_cue_entries.end())
1581 if (i->what == 0) /* in */
1585 } else if (i->what == 1) /* out */
1595 m_cue->addSourceSpan(in, out);
1599 if (i == m_cue_entries.end())
1602 m_cue->commitSpans();
1605 DEFINE_REF(eDVBServicePlay)
1607 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");