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/dvb/metaparser.h>
15 #include <lib/dvb/tstools.h>
16 #include <lib/python/python.h>
21 #include <netinet/in.h>
24 #error no byte order defined!
27 #define TSPATH "/media/hdd"
29 class eStaticServiceDVBInformation: public iStaticServiceInformation
31 DECLARE_REF(eStaticServiceDVBInformation);
33 RESULT getName(const eServiceReference &ref, std::string &name);
34 int getLength(const eServiceReference &ref);
37 DEFINE_REF(eStaticServiceDVBInformation);
39 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
41 eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
42 if ( !ref.name.empty() )
44 if (service.getParentTransportStreamID().get()) // linkage subservice
46 ePtr<iServiceHandler> service_center;
47 if (!eServiceCenter::getInstance(service_center))
49 eServiceReferenceDVB parent = service;
50 parent.setTransportStreamID( service.getParentTransportStreamID() );
51 parent.setServiceID( service.getParentServiceID() );
52 parent.setParentTransportStreamID(eTransportStreamID(0));
53 parent.setParentServiceID(eServiceID(0));
55 ePtr<iStaticServiceInformation> service_info;
56 if (!service_center->info(parent, service_info))
58 if (!service_info->getName(parent, name))
60 // just show short name
61 unsigned int pos = name.find("\xc2\x86");
62 if ( pos != std::string::npos )
64 pos = name.find("\xc2\x87");
65 if ( pos != std::string::npos )
81 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
86 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
88 DECLARE_REF(eStaticServiceDVBBouquetInformation);
90 RESULT getName(const eServiceReference &ref, std::string &name);
91 int getLength(const eServiceReference &ref);
94 DEFINE_REF(eStaticServiceDVBBouquetInformation);
96 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
98 ePtr<iDVBChannelList> db;
99 ePtr<eDVBResourceManager> res;
102 if ((err = eDVBResourceManager::getInstance(res)) != 0)
104 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
107 if ((err = res->getChannelList(db)) != 0)
109 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
114 if ((err = db->getBouquet(ref, bouquet)) != 0)
116 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
120 if ( bouquet && bouquet->m_bouquet_name.length() )
122 name = bouquet->m_bouquet_name;
129 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
134 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
136 DECLARE_REF(eStaticServiceDVBPVRInformation);
137 eServiceReference m_ref;
138 eDVBMetaParser m_parser;
140 eStaticServiceDVBPVRInformation(const eServiceReference &ref);
141 RESULT getName(const eServiceReference &ref, std::string &name);
142 int getLength(const eServiceReference &ref);
144 int getInfo(const eServiceReference &ref, int w);
145 std::string getInfoString(const eServiceReference &ref,int w);
148 DEFINE_REF(eStaticServiceDVBPVRInformation);
150 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
153 m_parser.parseFile(ref.path);
156 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
158 ASSERT(ref == m_ref);
159 name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
163 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
165 ASSERT(ref == m_ref);
169 if (tstools.openFile(ref.path.c_str()))
173 if (tstools.calcLen(len))
179 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
183 case iServiceInformation::sDescription:
184 return iServiceInformation::resIsString;
185 case iServiceInformation::sTimeCreate:
186 if (m_parser.m_time_create)
187 return m_parser.m_time_create;
189 return iServiceInformation::resNA;
191 return iServiceInformation::resNA;
195 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
199 case iServiceInformation::sDescription:
200 return m_parser.m_description;
206 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
208 DECLARE_REF(eDVBPVRServiceOfflineOperations);
209 eServiceReferenceDVB m_ref;
211 eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
213 RESULT deleteFromDisk(int simulate);
214 RESULT getListOfFilenames(std::list<std::string> &);
217 DEFINE_REF(eDVBPVRServiceOfflineOperations);
219 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
223 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
229 std::list<std::string> res;
230 if (getListOfFilenames(res))
233 /* TODO: deferred removing.. */
234 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
236 eDebug("Removing %s...", i->c_str());
237 ::unlink(i->c_str());
244 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
247 res.push_back(m_ref.path);
248 res.push_back(m_ref.path + ".meta");
249 res.push_back(m_ref.path + ".ap");
250 res.push_back(m_ref.path + ".cuts");
254 DEFINE_REF(eServiceFactoryDVB)
256 eServiceFactoryDVB::eServiceFactoryDVB()
258 ePtr<eServiceCenter> sc;
260 eServiceCenter::getPrivInstance(sc);
262 sc->addServiceFactory(eServiceFactoryDVB::id, this);
265 eServiceFactoryDVB::~eServiceFactoryDVB()
267 ePtr<eServiceCenter> sc;
269 eServiceCenter::getPrivInstance(sc);
271 sc->removeServiceFactory(eServiceFactoryDVB::id);
274 DEFINE_REF(eDVBServiceList);
276 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
280 eDVBServiceList::~eDVBServiceList()
284 RESULT eDVBServiceList::startQuery()
286 ePtr<iDVBChannelList> db;
287 ePtr<eDVBResourceManager> res;
290 if ((err = eDVBResourceManager::getInstance(res)) != 0)
292 eDebug("no resource manager");
295 if ((err = res->getChannelList(db)) != 0)
297 eDebug("no channel list");
301 ePtr<eDVBChannelQuery> q;
303 if (!m_parent.path.empty())
305 eDVBChannelQuery::compile(q, m_parent.path);
308 eDebug("compile query failed");
313 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
315 eDebug("startQuery failed");
322 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
324 eServiceReferenceDVB ref;
326 if (!m_query || !list || !PyList_Check(list))
329 std::list<eServiceReferenceDVB> tmplist;
331 while (!m_query->getNextResult(ref))
332 tmplist.push_back(ref);
335 tmplist.sort(iListableServiceCompare(this));
337 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
338 it != tmplist.end(); ++it)
340 PyObject *refobj = New_eServiceReference(*it);
341 PyList_Append(list, refobj);
347 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
349 eServiceReferenceDVB ref;
354 while (!m_query->getNextResult(ref))
358 list.sort(iListableServiceCompare(this));
363 RESULT eDVBServiceList::getNext(eServiceReference &ref)
368 return m_query->getNextResult((eServiceReferenceDVB&)ref);
371 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
373 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
376 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
378 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
380 ePtr<iDVBChannelList> db;
381 ePtr<eDVBResourceManager> resm;
383 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
386 if (db->getBouquet(m_parent, m_bouquet) != 0)
397 RESULT eDVBServiceList::addService(eServiceReference &ref)
401 return m_bouquet->addService(ref);
404 RESULT eDVBServiceList::removeService(eServiceReference &ref)
408 return m_bouquet->removeService(ref);
411 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
415 return m_bouquet->moveService(ref, pos);
418 RESULT eDVBServiceList::flushChanges()
422 return m_bouquet->flushChanges();
425 RESULT eDVBServiceList::setListName(const std::string &name)
429 return m_bouquet->setListName(name);
432 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
434 ePtr<eDVBService> service;
435 int r = lookupService(service, ref);
438 // check resources...
439 ptr = new eDVBServicePlay(ref, service);
443 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
445 if (ref.path.empty())
447 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
456 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
458 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
459 if (list->startQuery())
469 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
471 /* is a listable service? */
472 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
474 if ( !ref.name.empty() ) // satellites or providers list
475 ptr = new eStaticServiceDVBInformation;
476 else // a dvb bouquet
477 ptr = new eStaticServiceDVBBouquetInformation;
479 else if (!ref.path.empty()) /* do we have a PVR service? */
480 ptr = new eStaticServiceDVBPVRInformation(ref);
481 else // normal dvb service
483 ePtr<eDVBService> service;
484 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
485 ptr = new eStaticServiceDVBInformation;
487 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
493 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
495 if (ref.path.empty())
501 ptr = new eDVBPVRServiceOfflineOperations(ref);
506 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
508 // TODO: handle the listing itself
509 // if (ref.... == -1) .. return "... bouquets ...";
510 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
512 ePtr<iDVBChannelList> db;
513 ePtr<eDVBResourceManager> res;
516 if ((err = eDVBResourceManager::getInstance(res)) != 0)
518 eDebug("no resource manager");
521 if ((err = res->getChannelList(db)) != 0)
523 eDebug("no channel list");
527 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
528 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
530 eDebug("getService failed!");
537 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
538 m_reference(ref), m_dvb_service(service), m_is_paused(0)
540 m_is_pvr = !ref.path.empty();
542 m_timeshift_enabled = m_timeshift_active = 0;
545 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
546 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
547 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
549 m_cuesheet_changed = 0;
555 eDVBServicePlay::~eDVBServicePlay()
559 void eDVBServicePlay::gotNewEvent()
563 ePtr<eServiceEvent> m_event_now, m_event_next;
564 getEvent(m_event_now, 0);
565 getEvent(m_event_next, 1);
568 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
570 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
572 m_event((iPlayableService*)this, evUpdatedEventInfo);
575 void eDVBServicePlay::serviceEvent(int event)
579 case eDVBServicePMTHandler::eventTuned:
581 ePtr<iDVBDemux> m_demux;
582 if (!m_service_handler.getDataDemux(m_demux))
584 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
585 int sid = ref.getParentServiceID().get();
587 sid = ref.getServiceID().get();
588 if ( ref.getParentTransportStreamID().get() &&
589 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
590 m_event_handler.startOther(m_demux, sid);
592 m_event_handler.start(m_demux, sid);
596 case eDVBServicePMTHandler::eventTuneFailed:
598 eDebug("DVB service failed to tune");
599 m_event((iPlayableService*)this, evTuneFailed);
602 case eDVBServicePMTHandler::eventNewProgramInfo:
604 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
605 if (m_timeshift_enabled)
606 updateTimeshiftPids();
607 if (!m_timeshift_active)
609 if (m_first_program_info && m_is_pvr)
611 m_first_program_info = 0;
614 m_event((iPlayableService*)this, evUpdatedInfo);
617 case eDVBServicePMTHandler::eventEOF:
618 m_event((iPlayableService*)this, evEOF);
620 case eDVBServicePMTHandler::eventSOF:
621 m_event((iPlayableService*)this, evSOF);
626 void eDVBServicePlay::serviceEventTimeshift(int event)
630 case eDVBServicePMTHandler::eventNewProgramInfo:
631 if (m_timeshift_active)
634 case eDVBServicePMTHandler::eventEOF:
640 RESULT eDVBServicePlay::start()
643 /* in pvr mode, we only want to use one demux. in tv mode, we're using
644 two (one for decoding, one for data source), as we must be prepared
645 to start recording from the data demux. */
646 m_cue = new eCueSheet();
647 m_first_program_info = 1;
648 r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr, m_cue);
649 m_event(this, evStart);
650 m_event((iPlayableService*)this, evSeekableStatusChanged);
654 RESULT eDVBServicePlay::stop()
656 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
658 m_service_handler_timeshift.free();
659 m_service_handler.free();
661 if (m_is_pvr && m_cuesheet_changed)
667 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
669 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
673 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
675 /* note: we check for timeshift to be enabled,
676 not neccessary active. if you pause when timeshift
677 is not active, you should activate it when unpausing */
678 if ((!m_is_pvr) && (!m_timeshift_enabled))
688 RESULT eDVBServicePlay::setSlowMotion(int ratio)
691 return m_decoder->setSlowMotion(ratio);
696 RESULT eDVBServicePlay::setFastForward(int ratio)
698 int skipmode, ffratio;
704 } else if (ratio > 0)
712 } else // if (ratio < 0)
718 if (m_skipmode != skipmode)
720 eDebug("setting cue skipmode to %d", skipmode);
722 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
725 m_skipmode = skipmode;
730 return m_decoder->setFastForward(ffratio);
733 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
735 if (m_is_pvr || m_timeshift_enabled)
745 /* TODO: when timeshift is enabled but not active, this doesn't work. */
746 RESULT eDVBServicePlay::getLength(pts_t &len)
748 ePtr<iDVBPVRChannel> pvr_channel;
750 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
753 return pvr_channel->getLength(len);
756 RESULT eDVBServicePlay::pause()
758 if (!m_is_paused && m_decoder)
761 return m_decoder->freeze(0);
766 RESULT eDVBServicePlay::unpause()
768 if (m_is_paused && m_decoder)
771 return m_decoder->unfreeze();
776 RESULT eDVBServicePlay::seekTo(pts_t to)
778 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
783 ePtr<iDVBPVRChannel> pvr_channel;
785 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
791 m_cue->seekTo(0, to);
795 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
797 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
802 ePtr<iDVBPVRChannel> pvr_channel;
804 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
812 m_cue->seekTo(1, to);
816 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
818 ePtr<iDVBPVRChannel> pvr_channel;
823 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
828 /* if there is a decoder, use audio or video PTS */
831 r = m_decoder->getPTS(0, pos);
837 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
840 RESULT eDVBServicePlay::setTrickmode(int trick)
843 m_decoder->setTrickmode(trick);
847 RESULT eDVBServicePlay::isCurrentlySeekable()
849 return m_is_pvr || m_timeshift_active;
852 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
858 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
864 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
870 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
876 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
879 if (m_timeshift_enabled || !m_is_pvr)
881 if (!m_timeshift_enabled)
883 /* we need enough diskspace */
885 if (statfs(TSPATH "/.", &fs) < 0)
887 eDebug("statfs failed!");
891 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
893 eDebug("not enough diskspace for timeshift! (less than 1GB)");
903 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
914 RESULT eDVBServicePlay::getName(std::string &name)
918 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
919 return i->getName(m_reference, name);
923 m_dvb_service->getName(m_reference, name);
927 else if (!m_reference.name.empty())
928 eStaticServiceDVBInformation().getName(m_reference, name);
930 name = "DVB service";
934 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
936 return m_event_handler.getEvent(evt, nownext);
939 int eDVBServicePlay::getInfo(int w)
941 eDVBServicePMTHandler::program program;
943 if (m_service_handler.getProgramInfo(program))
949 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
951 ePtr<eServiceEvent> evt;
952 if (!m_event_handler.getEvent(evt, 0))
954 ePtr<eComponentData> data;
955 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
957 if ( data->getStreamContent() == 1 )
959 switch(data->getComponentType())
962 case 1: // 4:3 SD PAL
964 case 3: // 16:9 SD PAL
965 case 4: // > 16:9 PAL
966 case 5: // 4:3 SD NTSC
968 case 7: // 16:9 SD NTSC
969 case 8: // > 16:9 NTSC
972 case 9: // 4:3 HD PAL
974 case 0xB: // 16:9 HD PAL
975 case 0xC: // > 16:9 HD PAL
976 case 0xD: // 4:3 HD NTSC
978 case 0xF: // 16:9 HD NTSC
979 case 0x10: // > 16:9 HD PAL
980 return data->getComponentType();
987 case sIsCrypted: return program.isCrypted;
988 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
989 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
990 case sPCRPID: return program.pcrPid;
991 case sPMTPID: return program.pmtPid;
992 case sTXTPID: return program.textPid;
993 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
994 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
995 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
996 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
997 case sProvider: if (!m_dvb_service) return -1; return -2;
1003 std::string eDVBServicePlay::getInfoString(int w)
1008 if (!m_dvb_service) return "";
1009 return m_dvb_service->m_provider_name;
1015 int eDVBServicePlay::getNumberOfTracks()
1017 eDVBServicePMTHandler::program program;
1018 if (m_service_handler.getProgramInfo(program))
1020 return program.audioStreams.size();
1023 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1025 int ret = selectAudioStream(i);
1027 if (m_decoder->start())
1033 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1035 eDVBServicePMTHandler::program program;
1037 if (m_service_handler.getProgramInfo(program))
1040 if (i >= program.audioStreams.size())
1043 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1044 info.m_description = "MPEG";
1045 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1046 info.m_description = "AC3";
1047 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1048 info.m_description = "DTS";
1050 info.m_description = "???";
1052 if (program.audioStreams[i].component_tag != -1)
1054 ePtr<eServiceEvent> evt;
1055 if (!m_event_handler.getEvent(evt, 0))
1057 ePtr<eComponentData> data;
1058 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1059 info.m_language = data->getText();
1063 if (info.m_language.empty())
1064 info.m_language = program.audioStreams[i].language_code;
1069 int eDVBServicePlay::selectAudioStream(int i)
1071 eDVBServicePMTHandler::program program;
1073 if (m_service_handler.getProgramInfo(program))
1076 if ((unsigned int)i >= program.audioStreams.size())
1082 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1085 if (m_dvb_service && !m_is_pvr)
1087 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1089 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1090 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1093 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1094 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1098 m_current_audio_stream = i;
1103 int eDVBServicePlay::getFrontendInfo(int w)
1107 eUsePtr<iDVBChannel> channel;
1108 if(m_service_handler.getChannel(channel))
1110 ePtr<iDVBFrontend> fe;
1111 if(channel->getFrontend(fe))
1113 return fe->readFrontendData(w);
1116 int eDVBServicePlay::getNumberOfSubservices()
1118 ePtr<eServiceEvent> evt;
1119 if (!m_event_handler.getEvent(evt, 0))
1120 return evt->getNumOfLinkageServices();
1124 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1126 ePtr<eServiceEvent> evt;
1127 if (!m_event_handler.getEvent(evt, 0))
1129 if (!evt->getLinkageService(sub, m_reference, n))
1132 sub.type=eServiceReference::idInvalid;
1136 RESULT eDVBServicePlay::startTimeshift()
1138 ePtr<iDVBDemux> demux;
1140 eDebug("Start timeshift!");
1142 if (m_timeshift_enabled)
1145 /* start recording with the data demux. */
1146 if (m_service_handler.getDataDemux(demux))
1149 demux->createTSRecorder(m_record);
1153 char templ[]=TSPATH "/timeshift.XXXXXX";
1154 m_timeshift_fd = mkstemp(templ);
1155 m_timeshift_file = templ;
1157 eDebug("recording to %s", templ);
1159 if (m_timeshift_fd < 0)
1165 m_record->setTargetFD(m_timeshift_fd);
1167 m_timeshift_enabled = 1;
1169 updateTimeshiftPids();
1175 RESULT eDVBServicePlay::stopTimeshift()
1177 if (!m_timeshift_enabled)
1182 m_timeshift_enabled = 0;
1187 close(m_timeshift_fd);
1188 eDebug("remove timeshift file");
1189 remove(m_timeshift_file.c_str());
1194 int eDVBServicePlay::isTimeshiftActive()
1196 return m_timeshift_enabled && m_timeshift_active;
1199 RESULT eDVBServicePlay::activateTimeshift()
1201 if (!m_timeshift_enabled)
1204 if (!m_timeshift_active)
1206 switchToTimeshift();
1213 PyObject *eDVBServicePlay::getCutList()
1215 PyObject *list = PyList_New(0);
1217 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1219 PyObject *tuple = PyTuple_New(2);
1220 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1221 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1222 PyList_Append(list, tuple);
1229 void eDVBServicePlay::setCutList(PyObject *list)
1231 if (!PyList_Check(list))
1233 int size = PyList_Size(list);
1236 m_cue_entries.clear();
1238 for (i=0; i<size; ++i)
1240 PyObject *tuple = PyList_GetItem(list, i);
1241 if (!PyTuple_Check(tuple))
1243 eDebug("non-tuple in cutlist");
1246 if (PyTuple_Size(tuple) != 2)
1248 eDebug("cutlist entries need to be a 2-tuple");
1251 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1252 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1254 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1257 pts_t pts = PyLong_AsLongLong(ppts);
1258 int type = PyInt_AsLong(ptype);
1259 m_cue_entries.insert(cueEntry(pts, type));
1260 eDebug("adding %08llx, %d", pts, type);
1262 m_cuesheet_changed = 1;
1264 m_event((iPlayableService*)this, evCuesheetChanged);
1267 void eDVBServicePlay::updateTimeshiftPids()
1272 eDVBServicePMTHandler::program program;
1273 if (m_service_handler.getProgramInfo(program))
1277 std::set<int> pids_to_record;
1278 pids_to_record.insert(0); // PAT
1279 if (program.pmtPid != -1)
1280 pids_to_record.insert(program.pmtPid); // PMT
1282 if (program.textPid != -1)
1283 pids_to_record.insert(program.textPid); // Videotext
1285 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1286 i(program.videoStreams.begin());
1287 i != program.videoStreams.end(); ++i)
1288 pids_to_record.insert(i->pid);
1290 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1291 i(program.audioStreams.begin());
1292 i != program.audioStreams.end(); ++i)
1293 pids_to_record.insert(i->pid);
1295 std::set<int> new_pids, obsolete_pids;
1297 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1298 m_pids_active.begin(), m_pids_active.end(),
1299 std::inserter(new_pids, new_pids.begin()));
1301 std::set_difference(
1302 m_pids_active.begin(), m_pids_active.end(),
1303 pids_to_record.begin(), pids_to_record.end(),
1304 std::inserter(new_pids, new_pids.begin())
1307 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1308 m_record->addPID(*i);
1310 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1311 m_record->removePID(*i);
1315 void eDVBServicePlay::switchToLive()
1317 if (!m_timeshift_active)
1322 /* free the timeshift service handler, we need the resources */
1323 m_service_handler_timeshift.free();
1324 m_timeshift_active = 0;
1326 m_event((iPlayableService*)this, evSeekableStatusChanged);
1331 void eDVBServicePlay::switchToTimeshift()
1333 if (m_timeshift_active)
1339 m_timeshift_active = 1;
1341 m_event((iPlayableService*)this, evSeekableStatusChanged);
1343 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1344 r.path = m_timeshift_file;
1346 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1349 void eDVBServicePlay::updateDecoder()
1351 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1352 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1354 eDVBServicePMTHandler::program program;
1355 if (h.getProgramInfo(program))
1356 eDebug("getting program info failed.");
1359 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1360 if (!program.videoStreams.empty())
1362 eDebugNoNewLine(" (");
1363 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1364 i(program.videoStreams.begin());
1365 i != program.videoStreams.end(); ++i)
1369 if (i != program.videoStreams.begin())
1370 eDebugNoNewLine(", ");
1371 eDebugNoNewLine("%04x", i->pid);
1373 eDebugNoNewLine(")");
1375 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1376 if (!program.audioStreams.empty())
1378 eDebugNoNewLine(" (");
1379 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1380 i(program.audioStreams.begin());
1381 i != program.audioStreams.end(); ++i)
1388 if (i != program.audioStreams.begin())
1389 eDebugNoNewLine(", ");
1390 eDebugNoNewLine("%04x", i->pid);
1392 eDebugNoNewLine(")");
1394 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1395 pcrpid = program.pcrPid;
1396 eDebug(", and the text pid is %04x", program.textPid);
1397 tpid = program.textPid;
1402 h.getDecodeDemux(m_decode_demux);
1404 m_decode_demux->getMPEGDecoder(m_decoder);
1406 m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1411 m_decoder->setVideoPID(vpid);
1412 m_current_audio_stream = 0;
1413 m_decoder->setAudioPID(apid, apidtype);
1414 if (!(m_is_pvr || m_timeshift_active))
1415 m_decoder->setSyncPCR(pcrpid);
1417 m_decoder->setSyncPCR(-1);
1418 m_decoder->setTextPID(tpid);
1420 // how we can do this better?
1421 // update cache pid when the user changed the audio track or video track
1422 // TODO handling of difference audio types.. default audio types..
1424 /* don't worry about non-existing services, nor pvr services */
1425 if (m_dvb_service && !m_is_pvr)
1427 if (apidtype == eDVBAudio::aMPEG)
1429 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1430 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1434 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1435 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1437 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1438 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1439 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1444 void eDVBServicePlay::loadCuesheet()
1446 std::string filename = m_reference.path + ".cuts";
1448 m_cue_entries.clear();
1450 FILE *f = fopen(filename.c_str(), "rb");
1454 eDebug("loading cuts..");
1457 unsigned long long where;
1460 if (!fread(&where, sizeof(where), 1, f))
1462 if (!fread(&what, sizeof(what), 1, f))
1465 #if BYTE_ORDER == LITTLE_ENDIAN
1466 where = bswap_64(where);
1473 m_cue_entries.insert(cueEntry(where, what));
1476 eDebug("%d entries", m_cue_entries.size());
1478 eDebug("cutfile not found!");
1480 m_cuesheet_changed = 0;
1481 m_event((iPlayableService*)this, evCuesheetChanged);
1484 void eDVBServicePlay::saveCuesheet()
1486 std::string filename = m_reference.path + ".cuts";
1488 FILE *f = fopen(filename.c_str(), "wb");
1492 unsigned long long where;
1495 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1497 #if BYTE_ORDER == BIG_ENDIAN
1500 where = bswap_64(i->where);
1502 what = htonl(i->what);
1503 fwrite(&where, sizeof(where), 1, f);
1504 fwrite(&what, sizeof(what), 1, f);
1510 m_cuesheet_changed = 0;
1513 DEFINE_REF(eDVBServicePlay)
1515 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");