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/components/file_eraser.h>
14 #include <lib/service/servicedvbrecord.h>
15 #include <lib/service/event.h>
16 #include <lib/dvb/metaparser.h>
17 #include <lib/dvb/tstools.h>
18 #include <lib/python/python.h>
23 #include <netinet/in.h>
25 #include <dvbsi++/event_information_section.h>
28 #error no byte order defined!
31 #define TSPATH "/media/hdd"
33 class eStaticServiceDVBInformation: public iStaticServiceInformation
35 DECLARE_REF(eStaticServiceDVBInformation);
37 RESULT getName(const eServiceReference &ref, std::string &name);
38 int getLength(const eServiceReference &ref);
41 DEFINE_REF(eStaticServiceDVBInformation);
43 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
45 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
46 if ( !ref.name.empty() )
48 if (service.getParentTransportStreamID().get()) // linkage subservice
50 ePtr<iServiceHandler> service_center;
51 if (!eServiceCenter::getInstance(service_center))
53 eServiceReferenceDVB parent = service;
54 parent.setTransportStreamID( service.getParentTransportStreamID() );
55 parent.setServiceID( service.getParentServiceID() );
56 parent.setParentTransportStreamID(eTransportStreamID(0));
57 parent.setParentServiceID(eServiceID(0));
59 ePtr<iStaticServiceInformation> service_info;
60 if (!service_center->info(parent, service_info))
62 if (!service_info->getName(parent, name))
64 // just show short name
65 unsigned int pos = name.find("\xc2\x86");
66 if ( pos != std::string::npos )
68 pos = name.find("\xc2\x87");
69 if ( pos != std::string::npos )
85 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
90 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
92 DECLARE_REF(eStaticServiceDVBBouquetInformation);
94 RESULT getName(const eServiceReference &ref, std::string &name);
95 int getLength(const eServiceReference &ref);
98 DEFINE_REF(eStaticServiceDVBBouquetInformation);
100 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
102 ePtr<iDVBChannelList> db;
103 ePtr<eDVBResourceManager> res;
106 if ((err = eDVBResourceManager::getInstance(res)) != 0)
108 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
111 if ((err = res->getChannelList(db)) != 0)
113 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
118 if ((err = db->getBouquet(ref, bouquet)) != 0)
120 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
124 if ( bouquet && bouquet->m_bouquet_name.length() )
126 name = bouquet->m_bouquet_name;
133 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
138 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
140 DECLARE_REF(eStaticServiceDVBPVRInformation);
141 eServiceReference m_ref;
142 eDVBMetaParser m_parser;
144 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
145 RESULT getName(const eServiceReference &ref, std::string &name);
146 int getLength(const eServiceReference &ref);
148 int getInfo(const eServiceReference &ref, int w);
149 std::string getInfoString(const eServiceReference &ref,int w);
152 DEFINE_REF(eStaticServiceDVBPVRInformation);
154 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
157 m_parser.parseFile(ref.path);
160 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
162 ASSERT(ref == m_ref);
163 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
167 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
169 ASSERT(ref == m_ref);
173 if (tstools.openFile(ref.path.c_str()))
177 if (tstools.calcLen(len))
183 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
187 case iServiceInformation::sDescription:
188 return iServiceInformation::resIsString;
189 case iServiceInformation::sServiceref:
190 return iServiceInformation::resIsString;
191 case iServiceInformation::sTimeCreate:
192 if (m_parser.m_time_create)
193 return m_parser.m_time_create;
195 return iServiceInformation::resNA;
197 return iServiceInformation::resNA;
201 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
205 case iServiceInformation::sDescription:
206 return m_parser.m_description;
207 case iServiceInformation::sServiceref:
208 return m_parser.m_ref.toString();
214 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
216 DECLARE_REF(eDVBPVRServiceOfflineOperations);
217 eServiceReferenceDVB m_ref;
219 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
221 RESULT deleteFromDisk(int simulate);
222 RESULT getListOfFilenames(std::list<std::string> &);
225 DEFINE_REF(eDVBPVRServiceOfflineOperations);
227 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
231 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
237 std::list<std::string> res;
238 if (getListOfFilenames(res))
241 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
243 eDebug("FATAL !! can't get background file eraser");
245 /* TODO: deferred removing.. */
246 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
248 eDebug("Removing %s...", i->c_str());
250 eraser->erase(i->c_str());
252 ::unlink(i->c_str());
259 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
262 res.push_back(m_ref.path);
264 // handling for old splitted recordings (enigma 1)
269 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
271 if (stat(buf, &s) < 0)
276 res.push_back(m_ref.path + ".meta");
277 res.push_back(m_ref.path + ".ap");
278 res.push_back(m_ref.path + ".cuts");
279 std::string tmp = m_ref.path;
280 tmp.erase(m_ref.path.length()-3);
281 res.push_back(tmp + ".eit");
285 DEFINE_REF(eServiceFactoryDVB)
287 eServiceFactoryDVB::eServiceFactoryDVB()
289 ePtr<eServiceCenter> sc;
291 eServiceCenter::getPrivInstance(sc);
293 sc->addServiceFactory(eServiceFactoryDVB::id, this);
296 eServiceFactoryDVB::~eServiceFactoryDVB()
298 ePtr<eServiceCenter> sc;
300 eServiceCenter::getPrivInstance(sc);
302 sc->removeServiceFactory(eServiceFactoryDVB::id);
305 DEFINE_REF(eDVBServiceList);
307 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
311 eDVBServiceList::~eDVBServiceList()
315 RESULT eDVBServiceList::startQuery()
317 ePtr<iDVBChannelList> db;
318 ePtr<eDVBResourceManager> res;
321 if ((err = eDVBResourceManager::getInstance(res)) != 0)
323 eDebug("no resource manager");
326 if ((err = res->getChannelList(db)) != 0)
328 eDebug("no channel list");
332 ePtr<eDVBChannelQuery> q;
334 if (!m_parent.path.empty())
336 eDVBChannelQuery::compile(q, m_parent.path);
339 eDebug("compile query failed");
344 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
346 eDebug("startQuery failed");
353 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
355 eServiceReferenceDVB ref;
360 while (!m_query->getNextResult(ref))
364 list.sort(iListableServiceCompare(this));
369 // The first argument of this function is a format string to specify the order and
370 // the content of the returned list
371 // useable format options are
372 // R = Service Reference (as swig object .. this is very slow)
373 // S = Service Reference (as python string object .. same as ref.toString())
374 // N = Service Name (as python string object)
375 // when exactly one return value per service is selected in the format string,
376 // then each value is directly a list entry
377 // when more than one value is returned per service, then the list is a list of
379 // unknown format string chars are returned as python None values !
380 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
383 std::list<eServiceReference> tmplist;
386 if (!format || !(retcount=strlen(format)))
387 format = "R"; // just return service reference swig object ...
389 if (!getContent(tmplist, sorted))
391 int services=tmplist.size();
392 ePtr<iStaticServiceInformation> sptr;
393 eServiceCenterPtr service_center;
395 if (strchr(format, 'N'))
396 eServiceCenter::getPrivInstance(service_center);
398 ret = PyList_New(services);
399 std::list<eServiceReference>::iterator it(tmplist.begin());
401 for (int cnt=0; cnt < services; ++cnt)
403 eServiceReference &ref=*it++;
404 PyObject *tuple = retcount > 1 ? PyTuple_New(retcount) : 0;
405 for (int i=0; i < retcount; ++i)
410 case 'R': // service reference (swig)object
411 tmp = New_eServiceReference(ref);
413 case 'S': // service reference string
414 tmp = PyString_FromString(ref.toString().c_str());
416 case 'N': // service name
419 service_center->info(ref, sptr);
423 sptr->getName(ref, name);
425 tmp = PyString_FromString(name.c_str());
429 tmp = PyString_FromString("<n/a>");
442 PyTuple_SET_ITEM(tuple, i, tmp);
444 PyList_SET_ITEM(ret, cnt, tmp);
448 PyList_SET_ITEM(ret, cnt, tuple);
451 return ret ? ret : PyList_New(0);
454 RESULT eDVBServiceList::getNext(eServiceReference &ref)
459 return m_query->getNextResult((eServiceReferenceDVB&)ref);
462 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
464 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
467 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
469 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
471 ePtr<iDVBChannelList> db;
472 ePtr<eDVBResourceManager> resm;
474 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
477 if (db->getBouquet(m_parent, m_bouquet) != 0)
488 RESULT eDVBServiceList::addService(eServiceReference &ref)
492 return m_bouquet->addService(ref);
495 RESULT eDVBServiceList::removeService(eServiceReference &ref)
499 return m_bouquet->removeService(ref);
502 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
506 return m_bouquet->moveService(ref, pos);
509 RESULT eDVBServiceList::flushChanges()
513 return m_bouquet->flushChanges();
516 RESULT eDVBServiceList::setListName(const std::string &name)
520 return m_bouquet->setListName(name);
523 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
525 ePtr<eDVBService> service;
526 int r = lookupService(service, ref);
529 // check resources...
530 ptr = new eDVBServicePlay(ref, service);
534 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
536 if (ref.path.empty())
538 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
547 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
549 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
550 if (list->startQuery())
560 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
562 /* is a listable service? */
563 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
565 if ( !ref.name.empty() ) // satellites or providers list
566 ptr = new eStaticServiceDVBInformation;
567 else // a dvb bouquet
568 ptr = new eStaticServiceDVBBouquetInformation;
570 else if (!ref.path.empty()) /* do we have a PVR service? */
571 ptr = new eStaticServiceDVBPVRInformation(ref);
572 else // normal dvb service
574 ePtr<eDVBService> service;
575 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
576 ptr = new eStaticServiceDVBInformation;
578 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
584 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
586 if (ref.path.empty())
592 ptr = new eDVBPVRServiceOfflineOperations(ref);
597 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
599 // TODO: handle the listing itself
600 // if (ref.... == -1) .. return "... bouquets ...";
601 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
603 ePtr<iDVBChannelList> db;
604 ePtr<eDVBResourceManager> res;
607 if ((err = eDVBResourceManager::getInstance(res)) != 0)
609 eDebug("no resource manager");
612 if ((err = res->getChannelList(db)) != 0)
614 eDebug("no channel list");
618 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
619 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
621 eDebug("getService failed!");
628 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
629 m_reference(ref), m_dvb_service(service), m_is_paused(0)
632 m_is_pvr = !m_reference.path.empty();
634 m_timeshift_enabled = m_timeshift_active = 0;
637 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
638 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
639 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
641 m_cuesheet_changed = 0;
642 m_cutlist_enabled = 1;
645 eDVBServicePlay::~eDVBServicePlay()
649 void eDVBServicePlay::gotNewEvent()
653 ePtr<eServiceEvent> m_event_now, m_event_next;
654 getEvent(m_event_now, 0);
655 getEvent(m_event_next, 1);
658 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
660 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
662 m_event((iPlayableService*)this, evUpdatedEventInfo);
665 void eDVBServicePlay::serviceEvent(int event)
669 case eDVBServicePMTHandler::eventTuned:
671 ePtr<iDVBDemux> m_demux;
672 if (!m_service_handler.getDataDemux(m_demux))
674 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
675 int sid = ref.getParentServiceID().get();
677 sid = ref.getServiceID().get();
678 if ( ref.getParentTransportStreamID().get() &&
679 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
680 m_event_handler.startOther(m_demux, sid);
682 m_event_handler.start(m_demux, sid);
686 case eDVBServicePMTHandler::eventTuneFailed:
688 eDebug("DVB service failed to tune");
689 m_event((iPlayableService*)this, evTuneFailed);
692 case eDVBServicePMTHandler::eventNewProgramInfo:
694 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
695 if (m_timeshift_enabled)
696 updateTimeshiftPids();
697 if (!m_timeshift_active)
699 if (m_first_program_info && m_is_pvr)
701 m_first_program_info = 0;
704 m_event((iPlayableService*)this, evUpdatedInfo);
707 case eDVBServicePMTHandler::eventEOF:
708 m_event((iPlayableService*)this, evEOF);
710 case eDVBServicePMTHandler::eventSOF:
711 m_event((iPlayableService*)this, evSOF);
716 void eDVBServicePlay::serviceEventTimeshift(int event)
720 case eDVBServicePMTHandler::eventNewProgramInfo:
721 if (m_timeshift_active)
724 case eDVBServicePMTHandler::eventSOF:
725 m_event((iPlayableService*)this, evSOF);
727 case eDVBServicePMTHandler::eventEOF:
733 RESULT eDVBServicePlay::start()
736 /* in pvr mode, we only want to use one demux. in tv mode, we're using
737 two (one for decoding, one for data source), as we must be prepared
738 to start recording from the data demux. */
740 m_cue = new eCueSheet();
742 m_first_program_info = 1;
743 eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
744 r = m_service_handler.tune(service, m_is_pvr, m_cue);
746 /* inject EIT if there is a stored one */
749 std::string filename = service.path;
750 filename.erase(filename.length()-2, 2);
752 int fd = ::open( filename.c_str(), O_RDONLY );
756 int rd = ::read(fd, buf, 4096);
758 if ( rd > 12 /*EIT_LOOP_SIZE*/ )
761 ePtr<eServiceEvent> event = new eServiceEvent;
762 ePtr<eServiceEvent> empty;
763 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
764 m_event_handler.inject(event, 0);
765 m_event_handler.inject(empty, 1);
774 m_event(this, evStart);
775 m_event((iPlayableService*)this, evSeekableStatusChanged);
779 RESULT eDVBServicePlay::stop()
781 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
783 m_service_handler_timeshift.free();
784 m_service_handler.free();
786 if (m_is_pvr && m_cuesheet_changed)
792 RESULT eDVBServicePlay::setTarget(int target)
794 m_is_primary = !target;
798 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
800 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
804 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
806 /* note: we check for timeshift to be enabled,
807 not neccessary active. if you pause when timeshift
808 is not active, you should activate it when unpausing */
809 if ((!m_is_pvr) && (!m_timeshift_enabled))
819 RESULT eDVBServicePlay::setSlowMotion(int ratio)
822 return m_decoder->setSlowMotion(ratio);
827 RESULT eDVBServicePlay::setFastForward(int ratio)
829 int skipmode, ffratio;
835 } else if (ratio > 0)
843 } else // if (ratio < 0)
849 if (m_skipmode != skipmode)
851 eDebug("setting cue skipmode to %d", skipmode);
853 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
856 m_skipmode = skipmode;
861 return m_decoder->setFastForward(ffratio);
864 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
866 if (m_is_pvr || m_timeshift_enabled)
876 /* TODO: when timeshift is enabled but not active, this doesn't work. */
877 RESULT eDVBServicePlay::getLength(pts_t &len)
879 ePtr<iDVBPVRChannel> pvr_channel;
881 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
884 return pvr_channel->getLength(len);
887 RESULT eDVBServicePlay::pause()
889 if (!m_is_paused && m_decoder)
892 return m_decoder->freeze(0);
897 RESULT eDVBServicePlay::unpause()
899 if (m_is_paused && m_decoder)
902 return m_decoder->unfreeze();
907 RESULT eDVBServicePlay::seekTo(pts_t to)
909 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
914 ePtr<iDVBPVRChannel> pvr_channel;
916 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
922 m_cue->seekTo(0, to);
926 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
928 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
933 ePtr<iDVBPVRChannel> pvr_channel;
935 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
940 /* HACK until we have skip-AP api */
941 if ((to > 0) && (to < 100))
949 m_cue->seekTo(mode, to);
953 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
955 ePtr<iDVBPVRChannel> pvr_channel;
960 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
965 /* if there is a decoder, use audio or video PTS */
968 r = m_decoder->getPTS(0, pos);
974 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
977 RESULT eDVBServicePlay::setTrickmode(int trick)
980 m_decoder->setTrickmode(trick);
984 RESULT eDVBServicePlay::isCurrentlySeekable()
986 return m_is_pvr || m_timeshift_active;
989 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
995 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1001 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1007 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1013 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1016 if (m_timeshift_enabled || !m_is_pvr)
1018 if (!m_timeshift_enabled)
1020 /* we need enough diskspace */
1022 if (statfs(TSPATH "/.", &fs) < 0)
1024 eDebug("statfs failed!");
1028 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1030 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1040 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1051 RESULT eDVBServicePlay::getName(std::string &name)
1055 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1056 return i->getName(m_reference, name);
1060 m_dvb_service->getName(m_reference, name);
1064 else if (!m_reference.name.empty())
1065 eStaticServiceDVBInformation().getName(m_reference, name);
1067 name = "DVB service";
1071 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1073 return m_event_handler.getEvent(evt, nownext);
1076 int eDVBServicePlay::getInfo(int w)
1078 eDVBServicePMTHandler::program program;
1081 return resIsPyObject;
1083 if (m_service_handler.getProgramInfo(program))
1089 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1091 ePtr<eServiceEvent> evt;
1092 if (!m_event_handler.getEvent(evt, 0))
1094 ePtr<eComponentData> data;
1095 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1097 if ( data->getStreamContent() == 1 )
1099 switch(data->getComponentType())
1102 case 1: // 4:3 SD PAL
1104 case 3: // 16:9 SD PAL
1105 case 4: // > 16:9 PAL
1106 case 5: // 4:3 SD NTSC
1108 case 7: // 16:9 SD NTSC
1109 case 8: // > 16:9 NTSC
1112 case 9: // 4:3 HD PAL
1114 case 0xB: // 16:9 HD PAL
1115 case 0xC: // > 16:9 HD PAL
1116 case 0xD: // 4:3 HD NTSC
1118 case 0xF: // 16:9 HD NTSC
1119 case 0x10: // > 16:9 HD PAL
1120 return data->getComponentType();
1127 case sIsCrypted: return program.isCrypted;
1128 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1129 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1130 case sPCRPID: return program.pcrPid;
1131 case sPMTPID: return program.pmtPid;
1132 case sTXTPID: return program.textPid;
1133 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1134 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1135 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1136 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1137 case sProvider: if (!m_dvb_service) return -1; return -2;
1143 std::string eDVBServicePlay::getInfoString(int w)
1148 if (!m_dvb_service) return "";
1149 return m_dvb_service->m_provider_name;
1153 return iServiceInformation::getInfoString(w);
1156 PyObject *eDVBServicePlay::getInfoObject(int w)
1161 return m_service_handler.getCaIds();
1165 return iServiceInformation::getInfoObject(w);
1168 int eDVBServicePlay::getNumberOfTracks()
1170 eDVBServicePMTHandler::program program;
1171 if (m_service_handler.getProgramInfo(program))
1173 return program.audioStreams.size();
1176 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1178 int ret = selectAudioStream(i);
1180 if (m_decoder->start())
1186 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1188 eDVBServicePMTHandler::program program;
1190 if (m_service_handler.getProgramInfo(program))
1193 if (i >= program.audioStreams.size())
1196 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1197 info.m_description = "MPEG";
1198 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1199 info.m_description = "AC3";
1200 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1201 info.m_description = "DTS";
1203 info.m_description = "???";
1205 if (program.audioStreams[i].component_tag != -1)
1207 ePtr<eServiceEvent> evt;
1208 if (!m_event_handler.getEvent(evt, 0))
1210 ePtr<eComponentData> data;
1211 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1212 info.m_language = data->getText();
1216 if (info.m_language.empty())
1217 info.m_language = program.audioStreams[i].language_code;
1222 int eDVBServicePlay::selectAudioStream(int i)
1224 eDVBServicePMTHandler::program program;
1226 if (m_service_handler.getProgramInfo(program))
1229 if ((unsigned int)i >= program.audioStreams.size())
1235 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1238 if (m_dvb_service && !m_is_pvr)
1240 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1242 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1243 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1246 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1247 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1251 m_current_audio_stream = i;
1256 int eDVBServicePlay::getFrontendInfo(int w)
1260 eUsePtr<iDVBChannel> channel;
1261 if(m_service_handler.getChannel(channel))
1263 ePtr<iDVBFrontend> fe;
1264 if(channel->getFrontend(fe))
1266 return fe->readFrontendData(w);
1269 PyObject *eDVBServicePlay::getFrontendData(bool original)
1273 eUsePtr<iDVBChannel> channel;
1274 if(!m_service_handler.getChannel(channel))
1276 ePtr<iDVBFrontend> fe;
1277 if(!channel->getFrontend(fe))
1279 ret = fe->readTransponderData(original);
1282 ePtr<iDVBFrontendParameters> feparm;
1283 channel->getCurrentFrontendParameters(feparm);
1286 eDVBFrontendParametersSatellite osat;
1287 if (!feparm->getDVBS(osat))
1289 void PutToDict(PyObject *, const char*, long);
1290 void PutToDict(PyObject *, const char*, const char*);
1291 PutToDict(ret, "orbital_position", osat.orbital_position);
1292 const char *tmp = "UNKNOWN";
1293 switch(osat.polarisation)
1295 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1296 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1297 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1298 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1301 PutToDict(ret, "polarization", tmp);
1315 int eDVBServicePlay::getNumberOfSubservices()
1317 ePtr<eServiceEvent> evt;
1318 if (!m_event_handler.getEvent(evt, 0))
1319 return evt->getNumOfLinkageServices();
1323 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1325 ePtr<eServiceEvent> evt;
1326 if (!m_event_handler.getEvent(evt, 0))
1328 if (!evt->getLinkageService(sub, m_reference, n))
1331 sub.type=eServiceReference::idInvalid;
1335 RESULT eDVBServicePlay::startTimeshift()
1337 ePtr<iDVBDemux> demux;
1339 eDebug("Start timeshift!");
1341 if (m_timeshift_enabled)
1344 /* start recording with the data demux. */
1345 if (m_service_handler.getDataDemux(demux))
1348 demux->createTSRecorder(m_record);
1352 char templ[]=TSPATH "/timeshift.XXXXXX";
1353 m_timeshift_fd = mkstemp(templ);
1354 m_timeshift_file = templ;
1356 eDebug("recording to %s", templ);
1358 if (m_timeshift_fd < 0)
1364 m_record->setTargetFD(m_timeshift_fd);
1366 m_timeshift_enabled = 1;
1368 updateTimeshiftPids();
1374 RESULT eDVBServicePlay::stopTimeshift()
1376 if (!m_timeshift_enabled)
1381 m_timeshift_enabled = 0;
1386 close(m_timeshift_fd);
1387 eDebug("remove timeshift file");
1388 remove(m_timeshift_file.c_str());
1393 int eDVBServicePlay::isTimeshiftActive()
1395 return m_timeshift_enabled && m_timeshift_active;
1398 RESULT eDVBServicePlay::activateTimeshift()
1400 if (!m_timeshift_enabled)
1403 if (!m_timeshift_active)
1405 switchToTimeshift();
1412 PyObject *eDVBServicePlay::getCutList()
1414 PyObject *list = PyList_New(0);
1416 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1418 PyObject *tuple = PyTuple_New(2);
1419 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1420 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1421 PyList_Append(list, tuple);
1428 void eDVBServicePlay::setCutList(PyObject *list)
1430 if (!PyList_Check(list))
1432 int size = PyList_Size(list);
1435 m_cue_entries.clear();
1437 for (i=0; i<size; ++i)
1439 PyObject *tuple = PyList_GetItem(list, i);
1440 if (!PyTuple_Check(tuple))
1442 eDebug("non-tuple in cutlist");
1445 if (PyTuple_Size(tuple) != 2)
1447 eDebug("cutlist entries need to be a 2-tuple");
1450 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1451 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1453 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1456 pts_t pts = PyLong_AsLongLong(ppts);
1457 int type = PyInt_AsLong(ptype);
1458 m_cue_entries.insert(cueEntry(pts, type));
1459 eDebug("adding %08llx, %d", pts, type);
1461 m_cuesheet_changed = 1;
1463 cutlistToCuesheet();
1464 m_event((iPlayableService*)this, evCuesheetChanged);
1467 void eDVBServicePlay::setCutListEnable(int enable)
1469 m_cutlist_enabled = enable;
1470 cutlistToCuesheet();
1473 void eDVBServicePlay::updateTimeshiftPids()
1478 eDVBServicePMTHandler::program program;
1479 if (m_service_handler.getProgramInfo(program))
1483 std::set<int> pids_to_record;
1484 pids_to_record.insert(0); // PAT
1485 if (program.pmtPid != -1)
1486 pids_to_record.insert(program.pmtPid); // PMT
1488 if (program.textPid != -1)
1489 pids_to_record.insert(program.textPid); // Videotext
1491 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1492 i(program.videoStreams.begin());
1493 i != program.videoStreams.end(); ++i)
1494 pids_to_record.insert(i->pid);
1496 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1497 i(program.audioStreams.begin());
1498 i != program.audioStreams.end(); ++i)
1499 pids_to_record.insert(i->pid);
1501 std::set<int> new_pids, obsolete_pids;
1503 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1504 m_pids_active.begin(), m_pids_active.end(),
1505 std::inserter(new_pids, new_pids.begin()));
1507 std::set_difference(
1508 m_pids_active.begin(), m_pids_active.end(),
1509 pids_to_record.begin(), pids_to_record.end(),
1510 std::inserter(new_pids, new_pids.begin())
1513 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1514 m_record->addPID(*i);
1516 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1517 m_record->removePID(*i);
1521 void eDVBServicePlay::switchToLive()
1523 if (!m_timeshift_active)
1529 /* free the timeshift service handler, we need the resources */
1530 m_service_handler_timeshift.free();
1531 m_timeshift_active = 0;
1533 m_event((iPlayableService*)this, evSeekableStatusChanged);
1538 void eDVBServicePlay::switchToTimeshift()
1540 if (m_timeshift_active)
1546 m_timeshift_active = 1;
1548 m_event((iPlayableService*)this, evSeekableStatusChanged);
1550 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1551 r.path = m_timeshift_file;
1553 m_cue = new eCueSheet();
1554 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1555 updateDecoder(); /* mainly to switch off PCR */
1558 void eDVBServicePlay::updateDecoder()
1560 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1561 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1563 eDVBServicePMTHandler::program program;
1564 if (h.getProgramInfo(program))
1565 eDebug("getting program info failed.");
1568 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1569 if (!program.videoStreams.empty())
1571 eDebugNoNewLine(" (");
1572 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1573 i(program.videoStreams.begin());
1574 i != program.videoStreams.end(); ++i)
1578 if (i != program.videoStreams.begin())
1579 eDebugNoNewLine(", ");
1580 eDebugNoNewLine("%04x", i->pid);
1582 eDebugNoNewLine(")");
1584 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1585 if (!program.audioStreams.empty())
1587 eDebugNoNewLine(" (");
1588 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1589 i(program.audioStreams.begin());
1590 i != program.audioStreams.end(); ++i)
1597 if (i != program.audioStreams.begin())
1598 eDebugNoNewLine(", ");
1599 eDebugNoNewLine("%04x", i->pid);
1601 eDebugNoNewLine(")");
1603 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1604 pcrpid = program.pcrPid;
1605 eDebug(", and the text pid is %04x", program.textPid);
1606 tpid = program.textPid;
1611 h.getDecodeDemux(m_decode_demux);
1613 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1615 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1620 m_decoder->setVideoPID(vpid);
1621 m_current_audio_stream = 0;
1622 m_decoder->setAudioPID(apid, apidtype);
1623 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1624 m_decoder->setSyncPCR(pcrpid);
1626 m_decoder->setSyncPCR(-1);
1627 m_decoder->setTextPID(tpid);
1629 m_decoder->setTrickmode(1);
1631 // how we can do this better?
1632 // update cache pid when the user changed the audio track or video track
1633 // TODO handling of difference audio types.. default audio types..
1635 /* don't worry about non-existing services, nor pvr services */
1636 if (m_dvb_service && !m_is_pvr)
1638 if (apidtype == eDVBAudio::aMPEG)
1640 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1641 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1645 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1646 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1648 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1649 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1650 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1655 void eDVBServicePlay::loadCuesheet()
1657 std::string filename = m_reference.path + ".cuts";
1659 m_cue_entries.clear();
1661 FILE *f = fopen(filename.c_str(), "rb");
1665 eDebug("loading cuts..");
1668 unsigned long long where;
1671 if (!fread(&where, sizeof(where), 1, f))
1673 if (!fread(&what, sizeof(what), 1, f))
1676 #if BYTE_ORDER == LITTLE_ENDIAN
1677 where = bswap_64(where);
1684 m_cue_entries.insert(cueEntry(where, what));
1687 eDebug("%d entries", m_cue_entries.size());
1689 eDebug("cutfile not found!");
1691 m_cuesheet_changed = 0;
1692 cutlistToCuesheet();
1693 m_event((iPlayableService*)this, evCuesheetChanged);
1696 void eDVBServicePlay::saveCuesheet()
1698 std::string filename = m_reference.path + ".cuts";
1700 FILE *f = fopen(filename.c_str(), "wb");
1704 unsigned long long where;
1707 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1709 #if BYTE_ORDER == BIG_ENDIAN
1712 where = bswap_64(i->where);
1714 what = htonl(i->what);
1715 fwrite(&where, sizeof(where), 1, f);
1716 fwrite(&what, sizeof(what), 1, f);
1722 m_cuesheet_changed = 0;
1725 void eDVBServicePlay::cutlistToCuesheet()
1729 eDebug("no cue sheet");
1734 if (!m_cutlist_enabled)
1736 m_cue->commitSpans();
1737 eDebug("cutlists where disabled");
1741 pts_t in = 0, out = 0, length = 0;
1745 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1749 if (i == m_cue_entries.end())
1752 if (i->what == 0) /* in */
1756 } else if (i->what == 1) /* out */
1766 m_cue->addSourceSpan(in, out);
1770 if (i == m_cue_entries.end())
1773 m_cue->commitSpans();
1776 DEFINE_REF(eDVBServicePlay)
1778 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");