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)
1162 return m_service_handler.getCaIds();
1166 return iServiceInformation::getInfoObject(w);
1169 int eDVBServicePlay::getNumberOfTracks()
1171 eDVBServicePMTHandler::program program;
1172 if (m_service_handler.getProgramInfo(program))
1174 return program.audioStreams.size();
1177 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1179 int ret = selectAudioStream(i);
1181 if (m_decoder->start())
1187 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1189 eDVBServicePMTHandler::program program;
1191 if (m_service_handler.getProgramInfo(program))
1194 if (i >= program.audioStreams.size())
1197 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1198 info.m_description = "MPEG";
1199 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1200 info.m_description = "AC3";
1201 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1202 info.m_description = "DTS";
1204 info.m_description = "???";
1206 if (program.audioStreams[i].component_tag != -1)
1208 ePtr<eServiceEvent> evt;
1209 if (!m_event_handler.getEvent(evt, 0))
1211 ePtr<eComponentData> data;
1212 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1213 info.m_language = data->getText();
1217 if (info.m_language.empty())
1218 info.m_language = program.audioStreams[i].language_code;
1223 int eDVBServicePlay::selectAudioStream(int i)
1225 eDVBServicePMTHandler::program program;
1227 if (m_service_handler.getProgramInfo(program))
1230 if ((unsigned int)i >= program.audioStreams.size())
1236 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1239 if (m_dvb_service && !m_is_pvr)
1241 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1243 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1244 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1247 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1248 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1252 m_current_audio_stream = i;
1257 int eDVBServicePlay::getFrontendInfo(int w)
1261 eUsePtr<iDVBChannel> channel;
1262 if(m_service_handler.getChannel(channel))
1264 ePtr<iDVBFrontend> fe;
1265 if(channel->getFrontend(fe))
1267 return fe->readFrontendData(w);
1270 PyObject *eDVBServicePlay::getFrontendData(bool original)
1274 eUsePtr<iDVBChannel> channel;
1275 if(!m_service_handler.getChannel(channel))
1277 ePtr<iDVBFrontend> fe;
1278 if(!channel->getFrontend(fe))
1280 ret = fe->readTransponderData(original);
1283 ePtr<iDVBFrontendParameters> feparm;
1284 channel->getCurrentFrontendParameters(feparm);
1287 eDVBFrontendParametersSatellite osat;
1288 if (!feparm->getDVBS(osat))
1290 void PutToDict(PyObject *, const char*, long);
1291 void PutToDict(PyObject *, const char*, const char*);
1292 PutToDict(ret, "orbital_position", osat.orbital_position);
1293 const char *tmp = "UNKNOWN";
1294 switch(osat.polarisation)
1296 case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="HORIZONTAL"; break;
1297 case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="VERTICAL"; break;
1298 case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="CIRCULAR_LEFT"; break;
1299 case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="CIRCULAR_RIGHT"; break;
1302 PutToDict(ret, "polarization", tmp);
1316 int eDVBServicePlay::getNumberOfSubservices()
1318 ePtr<eServiceEvent> evt;
1319 if (!m_event_handler.getEvent(evt, 0))
1320 return evt->getNumOfLinkageServices();
1324 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1326 ePtr<eServiceEvent> evt;
1327 if (!m_event_handler.getEvent(evt, 0))
1329 if (!evt->getLinkageService(sub, m_reference, n))
1332 sub.type=eServiceReference::idInvalid;
1336 RESULT eDVBServicePlay::startTimeshift()
1338 ePtr<iDVBDemux> demux;
1340 eDebug("Start timeshift!");
1342 if (m_timeshift_enabled)
1345 /* start recording with the data demux. */
1346 if (m_service_handler.getDataDemux(demux))
1349 demux->createTSRecorder(m_record);
1353 char templ[]=TSPATH "/timeshift.XXXXXX";
1354 m_timeshift_fd = mkstemp(templ);
1355 m_timeshift_file = templ;
1357 eDebug("recording to %s", templ);
1359 if (m_timeshift_fd < 0)
1365 m_record->setTargetFD(m_timeshift_fd);
1367 m_timeshift_enabled = 1;
1369 updateTimeshiftPids();
1375 RESULT eDVBServicePlay::stopTimeshift()
1377 if (!m_timeshift_enabled)
1382 m_timeshift_enabled = 0;
1387 close(m_timeshift_fd);
1388 eDebug("remove timeshift file");
1389 remove(m_timeshift_file.c_str());
1394 int eDVBServicePlay::isTimeshiftActive()
1396 return m_timeshift_enabled && m_timeshift_active;
1399 RESULT eDVBServicePlay::activateTimeshift()
1401 if (!m_timeshift_enabled)
1404 if (!m_timeshift_active)
1406 switchToTimeshift();
1413 PyObject *eDVBServicePlay::getCutList()
1415 PyObject *list = PyList_New(0);
1417 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1419 PyObject *tuple = PyTuple_New(2);
1420 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1421 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1422 PyList_Append(list, tuple);
1429 void eDVBServicePlay::setCutList(PyObject *list)
1431 if (!PyList_Check(list))
1433 int size = PyList_Size(list);
1436 m_cue_entries.clear();
1438 for (i=0; i<size; ++i)
1440 PyObject *tuple = PyList_GetItem(list, i);
1441 if (!PyTuple_Check(tuple))
1443 eDebug("non-tuple in cutlist");
1446 if (PyTuple_Size(tuple) != 2)
1448 eDebug("cutlist entries need to be a 2-tuple");
1451 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1452 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1454 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1457 pts_t pts = PyLong_AsLongLong(ppts);
1458 int type = PyInt_AsLong(ptype);
1459 m_cue_entries.insert(cueEntry(pts, type));
1460 eDebug("adding %08llx, %d", pts, type);
1462 m_cuesheet_changed = 1;
1464 cutlistToCuesheet();
1465 m_event((iPlayableService*)this, evCuesheetChanged);
1468 void eDVBServicePlay::setCutListEnable(int enable)
1470 m_cutlist_enabled = enable;
1471 cutlistToCuesheet();
1474 void eDVBServicePlay::updateTimeshiftPids()
1479 eDVBServicePMTHandler::program program;
1480 if (m_service_handler.getProgramInfo(program))
1484 std::set<int> pids_to_record;
1485 pids_to_record.insert(0); // PAT
1486 if (program.pmtPid != -1)
1487 pids_to_record.insert(program.pmtPid); // PMT
1489 if (program.textPid != -1)
1490 pids_to_record.insert(program.textPid); // Videotext
1492 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1493 i(program.videoStreams.begin());
1494 i != program.videoStreams.end(); ++i)
1495 pids_to_record.insert(i->pid);
1497 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1498 i(program.audioStreams.begin());
1499 i != program.audioStreams.end(); ++i)
1500 pids_to_record.insert(i->pid);
1502 std::set<int> new_pids, obsolete_pids;
1504 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1505 m_pids_active.begin(), m_pids_active.end(),
1506 std::inserter(new_pids, new_pids.begin()));
1508 std::set_difference(
1509 m_pids_active.begin(), m_pids_active.end(),
1510 pids_to_record.begin(), pids_to_record.end(),
1511 std::inserter(new_pids, new_pids.begin())
1514 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1515 m_record->addPID(*i);
1517 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1518 m_record->removePID(*i);
1522 void eDVBServicePlay::switchToLive()
1524 if (!m_timeshift_active)
1530 /* free the timeshift service handler, we need the resources */
1531 m_service_handler_timeshift.free();
1532 m_timeshift_active = 0;
1534 m_event((iPlayableService*)this, evSeekableStatusChanged);
1539 void eDVBServicePlay::switchToTimeshift()
1541 if (m_timeshift_active)
1547 m_timeshift_active = 1;
1549 m_event((iPlayableService*)this, evSeekableStatusChanged);
1551 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1552 r.path = m_timeshift_file;
1554 m_cue = new eCueSheet();
1555 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1556 updateDecoder(); /* mainly to switch off PCR */
1559 void eDVBServicePlay::updateDecoder()
1561 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1562 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1564 eDVBServicePMTHandler::program program;
1565 if (h.getProgramInfo(program))
1566 eDebug("getting program info failed.");
1569 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1570 if (!program.videoStreams.empty())
1572 eDebugNoNewLine(" (");
1573 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1574 i(program.videoStreams.begin());
1575 i != program.videoStreams.end(); ++i)
1579 if (i != program.videoStreams.begin())
1580 eDebugNoNewLine(", ");
1581 eDebugNoNewLine("%04x", i->pid);
1583 eDebugNoNewLine(")");
1585 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1586 if (!program.audioStreams.empty())
1588 eDebugNoNewLine(" (");
1589 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1590 i(program.audioStreams.begin());
1591 i != program.audioStreams.end(); ++i)
1598 if (i != program.audioStreams.begin())
1599 eDebugNoNewLine(", ");
1600 eDebugNoNewLine("%04x", i->pid);
1602 eDebugNoNewLine(")");
1604 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1605 pcrpid = program.pcrPid;
1606 eDebug(", and the text pid is %04x", program.textPid);
1607 tpid = program.textPid;
1612 h.getDecodeDemux(m_decode_demux);
1614 m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
1616 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1621 m_decoder->setVideoPID(vpid);
1622 m_current_audio_stream = 0;
1623 m_decoder->setAudioPID(apid, apidtype);
1624 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1625 m_decoder->setSyncPCR(pcrpid);
1627 m_decoder->setSyncPCR(-1);
1628 m_decoder->setTextPID(tpid);
1630 m_decoder->setTrickmode(1);
1632 // how we can do this better?
1633 // update cache pid when the user changed the audio track or video track
1634 // TODO handling of difference audio types.. default audio types..
1636 /* don't worry about non-existing services, nor pvr services */
1637 if (m_dvb_service && !m_is_pvr)
1639 if (apidtype == eDVBAudio::aMPEG)
1641 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1642 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1646 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1647 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1649 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1650 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1651 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1656 void eDVBServicePlay::loadCuesheet()
1658 std::string filename = m_reference.path + ".cuts";
1660 m_cue_entries.clear();
1662 FILE *f = fopen(filename.c_str(), "rb");
1666 eDebug("loading cuts..");
1669 unsigned long long where;
1672 if (!fread(&where, sizeof(where), 1, f))
1674 if (!fread(&what, sizeof(what), 1, f))
1677 #if BYTE_ORDER == LITTLE_ENDIAN
1678 where = bswap_64(where);
1685 m_cue_entries.insert(cueEntry(where, what));
1688 eDebug("%d entries", m_cue_entries.size());
1690 eDebug("cutfile not found!");
1692 m_cuesheet_changed = 0;
1693 cutlistToCuesheet();
1694 m_event((iPlayableService*)this, evCuesheetChanged);
1697 void eDVBServicePlay::saveCuesheet()
1699 std::string filename = m_reference.path + ".cuts";
1701 FILE *f = fopen(filename.c_str(), "wb");
1705 unsigned long long where;
1708 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1710 #if BYTE_ORDER == BIG_ENDIAN
1713 where = bswap_64(i->where);
1715 what = htonl(i->what);
1716 fwrite(&where, sizeof(where), 1, f);
1717 fwrite(&what, sizeof(what), 1, f);
1723 m_cuesheet_changed = 0;
1726 void eDVBServicePlay::cutlistToCuesheet()
1730 eDebug("no cue sheet");
1735 if (!m_cutlist_enabled)
1737 m_cue->commitSpans();
1738 eDebug("cutlists where disabled");
1742 pts_t in = 0, out = 0, length = 0;
1746 std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1750 if (i == m_cue_entries.end())
1753 if (i->what == 0) /* in */
1757 } else if (i->what == 1) /* out */
1767 m_cue->addSourceSpan(in, out);
1771 if (i == m_cue_entries.end())
1774 m_cue->commitSpans();
1777 DEFINE_REF(eDVBServicePlay)
1779 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");