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");
252 DEFINE_REF(eServiceFactoryDVB)
254 eServiceFactoryDVB::eServiceFactoryDVB()
256 ePtr<eServiceCenter> sc;
258 eServiceCenter::getPrivInstance(sc);
260 sc->addServiceFactory(eServiceFactoryDVB::id, this);
263 eServiceFactoryDVB::~eServiceFactoryDVB()
265 ePtr<eServiceCenter> sc;
267 eServiceCenter::getPrivInstance(sc);
269 sc->removeServiceFactory(eServiceFactoryDVB::id);
272 DEFINE_REF(eDVBServiceList);
274 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
278 eDVBServiceList::~eDVBServiceList()
282 RESULT eDVBServiceList::startQuery()
284 ePtr<iDVBChannelList> db;
285 ePtr<eDVBResourceManager> res;
288 if ((err = eDVBResourceManager::getInstance(res)) != 0)
290 eDebug("no resource manager");
293 if ((err = res->getChannelList(db)) != 0)
295 eDebug("no channel list");
299 ePtr<eDVBChannelQuery> q;
301 if (!m_parent.path.empty())
303 eDVBChannelQuery::compile(q, m_parent.path);
306 eDebug("compile query failed");
311 if ((err = db->startQuery(m_query, q, m_parent)) != 0)
313 eDebug("startQuery failed");
320 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
322 eServiceReferenceDVB ref;
324 if (!m_query || !list || !PyList_Check(list))
327 std::list<eServiceReferenceDVB> tmplist;
329 while (!m_query->getNextResult(ref))
330 tmplist.push_back(ref);
333 tmplist.sort(iListableServiceCompare(this));
335 for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
336 it != tmplist.end(); ++it)
338 PyObject *refobj = New_eServiceReference(*it);
339 PyList_Append(list, refobj);
345 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
347 eServiceReferenceDVB ref;
352 while (!m_query->getNextResult(ref))
356 list.sort(iListableServiceCompare(this));
361 RESULT eDVBServiceList::getNext(eServiceReference &ref)
366 return m_query->getNextResult((eServiceReferenceDVB&)ref);
369 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
371 return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
374 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
376 if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
378 ePtr<iDVBChannelList> db;
379 ePtr<eDVBResourceManager> resm;
381 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
384 if (db->getBouquet(m_parent, m_bouquet) != 0)
395 RESULT eDVBServiceList::addService(eServiceReference &ref)
399 return m_bouquet->addService(ref);
402 RESULT eDVBServiceList::removeService(eServiceReference &ref)
406 return m_bouquet->removeService(ref);
409 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
413 return m_bouquet->moveService(ref, pos);
416 RESULT eDVBServiceList::flushChanges()
420 return m_bouquet->flushChanges();
423 RESULT eDVBServiceList::setListName(const std::string &name)
427 return m_bouquet->setListName(name);
430 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
432 ePtr<eDVBService> service;
433 int r = lookupService(service, ref);
436 // check resources...
437 ptr = new eDVBServicePlay(ref, service);
441 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
443 if (ref.path.empty())
445 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
454 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
456 ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
457 if (list->startQuery())
467 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
469 /* is a listable service? */
470 if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
472 if ( !ref.name.empty() ) // satellites or providers list
473 ptr = new eStaticServiceDVBInformation;
474 else // a dvb bouquet
475 ptr = new eStaticServiceDVBBouquetInformation;
477 else if (!ref.path.empty()) /* do we have a PVR service? */
478 ptr = new eStaticServiceDVBPVRInformation(ref);
479 else // normal dvb service
481 ePtr<eDVBService> service;
482 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
483 ptr = new eStaticServiceDVBInformation;
485 /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
491 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
493 if (ref.path.empty())
499 ptr = new eDVBPVRServiceOfflineOperations(ref);
504 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
506 // TODO: handle the listing itself
507 // if (ref.... == -1) .. return "... bouquets ...";
508 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
510 ePtr<iDVBChannelList> db;
511 ePtr<eDVBResourceManager> res;
514 if ((err = eDVBResourceManager::getInstance(res)) != 0)
516 eDebug("no resource manager");
519 if ((err = res->getChannelList(db)) != 0)
521 eDebug("no channel list");
525 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
526 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
528 eDebug("getService failed!");
535 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service):
536 m_reference(ref), m_dvb_service(service), m_is_paused(0)
538 m_is_pvr = !ref.path.empty();
540 m_timeshift_enabled = m_timeshift_active = 0;
543 CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
544 CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
545 CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
547 m_cuesheet_changed = 0;
553 eDVBServicePlay::~eDVBServicePlay()
557 void eDVBServicePlay::gotNewEvent()
561 ePtr<eServiceEvent> m_event_now, m_event_next;
562 getEvent(m_event_now, 0);
563 getEvent(m_event_next, 1);
566 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
568 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
570 m_event((iPlayableService*)this, evUpdatedEventInfo);
573 void eDVBServicePlay::serviceEvent(int event)
577 case eDVBServicePMTHandler::eventTuned:
579 ePtr<iDVBDemux> m_demux;
580 if (!m_service_handler.getDataDemux(m_demux))
582 eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
583 int sid = ref.getParentServiceID().get();
585 sid = ref.getServiceID().get();
586 if ( ref.getParentTransportStreamID().get() &&
587 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
588 m_event_handler.startOther(m_demux, sid);
590 m_event_handler.start(m_demux, sid);
594 case eDVBServicePMTHandler::eventTuneFailed:
596 eDebug("DVB service failed to tune");
597 m_event((iPlayableService*)this, evTuneFailed);
600 case eDVBServicePMTHandler::eventNewProgramInfo:
602 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
603 if (m_timeshift_enabled)
604 updateTimeshiftPids();
605 if (!m_timeshift_active)
607 if (m_first_program_info && m_is_pvr)
609 m_first_program_info = 0;
612 m_event((iPlayableService*)this, evUpdatedInfo);
615 case eDVBServicePMTHandler::eventEOF:
616 m_event((iPlayableService*)this, evEOF);
618 case eDVBServicePMTHandler::eventSOF:
619 m_event((iPlayableService*)this, evSOF);
624 void eDVBServicePlay::serviceEventTimeshift(int event)
628 case eDVBServicePMTHandler::eventNewProgramInfo:
629 if (m_timeshift_active)
632 case eDVBServicePMTHandler::eventEOF:
638 RESULT eDVBServicePlay::start()
641 /* in pvr mode, we only want to use one demux. in tv mode, we're using
642 two (one for decoding, one for data source), as we must be prepared
643 to start recording from the data demux. */
644 m_cue = new eCueSheet();
645 m_first_program_info = 1;
646 r = m_service_handler.tune((eServiceReferenceDVB&)m_reference, m_is_pvr, m_cue);
647 m_event(this, evStart);
648 m_event((iPlayableService*)this, evSeekableStatusChanged);
652 RESULT eDVBServicePlay::stop()
654 stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
656 m_service_handler_timeshift.free();
657 m_service_handler.free();
659 if (m_is_pvr && m_cuesheet_changed)
665 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
667 connection = new eConnection((iPlayableService*)this, m_event.connect(event));
671 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
673 /* note: we check for timeshift to be enabled,
674 not neccessary active. if you pause when timeshift
675 is not active, you should activate it when unpausing */
676 if ((!m_is_pvr) && (!m_timeshift_enabled))
686 RESULT eDVBServicePlay::setSlowMotion(int ratio)
689 return m_decoder->setSlowMotion(ratio);
694 RESULT eDVBServicePlay::setFastForward(int ratio)
696 int skipmode, ffratio;
702 } else if (ratio > 0)
710 } else // if (ratio < 0)
716 if (m_skipmode != skipmode)
718 eDebug("setting cue skipmode to %d", skipmode);
720 m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
723 m_skipmode = skipmode;
728 return m_decoder->setFastForward(ffratio);
731 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
733 if (m_is_pvr || m_timeshift_enabled)
743 /* TODO: when timeshift is enabled but not active, this doesn't work. */
744 RESULT eDVBServicePlay::getLength(pts_t &len)
746 ePtr<iDVBPVRChannel> pvr_channel;
748 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
751 return pvr_channel->getLength(len);
754 RESULT eDVBServicePlay::pause()
756 if (!m_is_paused && m_decoder)
759 return m_decoder->freeze(0);
764 RESULT eDVBServicePlay::unpause()
766 if (m_is_paused && m_decoder)
769 return m_decoder->unfreeze();
774 RESULT eDVBServicePlay::seekTo(pts_t to)
776 eDebug("eDVBServicePlay::seekTo: jump %lld", to);
781 ePtr<iDVBPVRChannel> pvr_channel;
783 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
789 m_cue->seekTo(0, to);
793 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
795 eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
800 ePtr<iDVBPVRChannel> pvr_channel;
802 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
810 m_cue->seekTo(1, to);
814 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
816 ePtr<iDVBPVRChannel> pvr_channel;
821 if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
826 /* if there is a decoder, use audio or video PTS */
829 r = m_decoder->getPTS(0, pos);
835 return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
838 RESULT eDVBServicePlay::setTrickmode(int trick)
841 m_decoder->setTrickmode(trick);
845 RESULT eDVBServicePlay::isCurrentlySeekable()
847 return m_is_pvr || m_timeshift_active;
850 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
856 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
862 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
868 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
874 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
877 if (m_timeshift_enabled || !m_is_pvr)
879 if (!m_timeshift_enabled)
881 /* we need enough diskspace */
883 if (statfs(TSPATH "/.", &fs) < 0)
885 eDebug("statfs failed!");
889 if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
891 eDebug("not enough diskspace for timeshift! (less than 1GB)");
901 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
912 RESULT eDVBServicePlay::getName(std::string &name)
916 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
917 return i->getName(m_reference, name);
921 m_dvb_service->getName(m_reference, name);
925 else if (!m_reference.name.empty())
926 eStaticServiceDVBInformation().getName(m_reference, name);
928 name = "DVB service";
932 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
934 return m_event_handler.getEvent(evt, nownext);
937 int eDVBServicePlay::getInfo(int w)
939 eDVBServicePMTHandler::program program;
941 if (m_service_handler.getProgramInfo(program))
947 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
949 ePtr<eServiceEvent> evt;
950 if (!m_event_handler.getEvent(evt, 0))
952 ePtr<eComponentData> data;
953 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
955 if ( data->getStreamContent() == 1 )
957 switch(data->getComponentType())
960 case 1: // 4:3 SD PAL
962 case 3: // 16:9 SD PAL
963 case 4: // > 16:9 PAL
964 case 5: // 4:3 SD NTSC
966 case 7: // 16:9 SD NTSC
967 case 8: // > 16:9 NTSC
970 case 9: // 4:3 HD PAL
972 case 0xB: // 16:9 HD PAL
973 case 0xC: // > 16:9 HD PAL
974 case 0xD: // 4:3 HD NTSC
976 case 0xF: // 16:9 HD NTSC
977 case 0x10: // > 16:9 HD PAL
978 return data->getComponentType();
985 case sIsCrypted: return program.isCrypted;
986 case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
987 case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
988 case sPCRPID: return program.pcrPid;
989 case sPMTPID: return program.pmtPid;
990 case sTXTPID: return program.textPid;
991 case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
992 case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
993 case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
994 case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
995 case sProvider: if (!m_dvb_service) return -1; return -2;
1001 std::string eDVBServicePlay::getInfoString(int w)
1006 if (!m_dvb_service) return "";
1007 return m_dvb_service->m_provider_name;
1013 int eDVBServicePlay::getNumberOfTracks()
1015 eDVBServicePMTHandler::program program;
1016 if (m_service_handler.getProgramInfo(program))
1018 return program.audioStreams.size();
1021 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1023 int ret = selectAudioStream(i);
1025 if (m_decoder->start())
1031 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1033 eDVBServicePMTHandler::program program;
1035 if (m_service_handler.getProgramInfo(program))
1038 if (i >= program.audioStreams.size())
1041 if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1042 info.m_description = "MPEG";
1043 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1044 info.m_description = "AC3";
1045 else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1046 info.m_description = "DTS";
1048 info.m_description = "???";
1050 if (program.audioStreams[i].component_tag != -1)
1052 ePtr<eServiceEvent> evt;
1053 if (!m_event_handler.getEvent(evt, 0))
1055 ePtr<eComponentData> data;
1056 if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1057 info.m_language = data->getText();
1061 if (info.m_language.empty())
1062 info.m_language = program.audioStreams[i].language_code;
1067 int eDVBServicePlay::selectAudioStream(int i)
1069 eDVBServicePMTHandler::program program;
1071 if (m_service_handler.getProgramInfo(program))
1074 if ((unsigned int)i >= program.audioStreams.size())
1080 if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1083 if (m_dvb_service && !m_is_pvr)
1085 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1087 m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1088 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1091 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1092 m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1096 m_current_audio_stream = i;
1101 int eDVBServicePlay::getFrontendInfo(int w)
1105 eUsePtr<iDVBChannel> channel;
1106 if(m_service_handler.getChannel(channel))
1108 ePtr<iDVBFrontend> fe;
1109 if(channel->getFrontend(fe))
1111 return fe->readFrontendData(w);
1114 int eDVBServicePlay::getNumberOfSubservices()
1116 ePtr<eServiceEvent> evt;
1117 if (!m_event_handler.getEvent(evt, 0))
1118 return evt->getNumOfLinkageServices();
1122 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1124 ePtr<eServiceEvent> evt;
1125 if (!m_event_handler.getEvent(evt, 0))
1127 if (!evt->getLinkageService(sub, m_reference, n))
1130 sub.type=eServiceReference::idInvalid;
1134 RESULT eDVBServicePlay::startTimeshift()
1136 ePtr<iDVBDemux> demux;
1138 eDebug("Start timeshift!");
1140 if (m_timeshift_enabled)
1143 /* start recording with the data demux. */
1144 if (m_service_handler.getDataDemux(demux))
1147 demux->createTSRecorder(m_record);
1151 char templ[]=TSPATH "/timeshift.XXXXXX";
1152 m_timeshift_fd = mkstemp(templ);
1153 m_timeshift_file = templ;
1155 eDebug("recording to %s", templ);
1157 if (m_timeshift_fd < 0)
1163 m_record->setTargetFD(m_timeshift_fd);
1165 m_timeshift_enabled = 1;
1167 updateTimeshiftPids();
1173 RESULT eDVBServicePlay::stopTimeshift()
1175 if (!m_timeshift_enabled)
1180 m_timeshift_enabled = 0;
1185 close(m_timeshift_fd);
1186 eDebug("remove timeshift file");
1187 remove(m_timeshift_file.c_str());
1192 int eDVBServicePlay::isTimeshiftActive()
1194 return m_timeshift_enabled && m_timeshift_active;
1197 RESULT eDVBServicePlay::activateTimeshift()
1199 if (!m_timeshift_enabled)
1202 if (!m_timeshift_active)
1204 switchToTimeshift();
1211 PyObject *eDVBServicePlay::getCutList()
1213 PyObject *list = PyList_New(0);
1215 for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1217 PyObject *tuple = PyTuple_New(2);
1218 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1219 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1220 PyList_Append(list, tuple);
1227 void eDVBServicePlay::setCutList(PyObject *list)
1229 if (!PyList_Check(list))
1231 int size = PyList_Size(list);
1234 m_cue_entries.clear();
1236 for (i=0; i<size; ++i)
1238 PyObject *tuple = PyList_GetItem(list, i);
1239 if (!PyTuple_Check(tuple))
1241 eDebug("non-tuple in cutlist");
1244 if (PyTuple_Size(tuple) != 2)
1246 eDebug("cutlist entries need to be a 2-tuple");
1249 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1250 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1252 eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1255 pts_t pts = PyLong_AsLongLong(ppts);
1256 int type = PyInt_AsLong(ptype);
1257 m_cue_entries.insert(cueEntry(pts, type));
1258 eDebug("adding %08llx, %d", pts, type);
1260 m_cuesheet_changed = 1;
1263 void eDVBServicePlay::updateTimeshiftPids()
1268 eDVBServicePMTHandler::program program;
1269 if (m_service_handler.getProgramInfo(program))
1273 std::set<int> pids_to_record;
1274 pids_to_record.insert(0); // PAT
1275 if (program.pmtPid != -1)
1276 pids_to_record.insert(program.pmtPid); // PMT
1278 if (program.textPid != -1)
1279 pids_to_record.insert(program.textPid); // Videotext
1281 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1282 i(program.videoStreams.begin());
1283 i != program.videoStreams.end(); ++i)
1284 pids_to_record.insert(i->pid);
1286 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1287 i(program.audioStreams.begin());
1288 i != program.audioStreams.end(); ++i)
1289 pids_to_record.insert(i->pid);
1291 std::set<int> new_pids, obsolete_pids;
1293 std::set_difference(pids_to_record.begin(), pids_to_record.end(),
1294 m_pids_active.begin(), m_pids_active.end(),
1295 std::inserter(new_pids, new_pids.begin()));
1297 std::set_difference(
1298 m_pids_active.begin(), m_pids_active.end(),
1299 pids_to_record.begin(), pids_to_record.end(),
1300 std::inserter(new_pids, new_pids.begin())
1303 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1304 m_record->addPID(*i);
1306 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1307 m_record->removePID(*i);
1311 void eDVBServicePlay::switchToLive()
1313 if (!m_timeshift_active)
1318 /* free the timeshift service handler, we need the resources */
1319 m_service_handler_timeshift.free();
1320 m_timeshift_active = 0;
1322 m_event((iPlayableService*)this, evSeekableStatusChanged);
1327 void eDVBServicePlay::switchToTimeshift()
1329 if (m_timeshift_active)
1335 m_timeshift_active = 1;
1337 m_event((iPlayableService*)this, evSeekableStatusChanged);
1339 eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1340 r.path = m_timeshift_file;
1342 m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1345 void eDVBServicePlay::updateDecoder()
1347 int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1348 eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1350 eDVBServicePMTHandler::program program;
1351 if (h.getProgramInfo(program))
1352 eDebug("getting program info failed.");
1355 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1356 if (!program.videoStreams.empty())
1358 eDebugNoNewLine(" (");
1359 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1360 i(program.videoStreams.begin());
1361 i != program.videoStreams.end(); ++i)
1365 if (i != program.videoStreams.begin())
1366 eDebugNoNewLine(", ");
1367 eDebugNoNewLine("%04x", i->pid);
1369 eDebugNoNewLine(")");
1371 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1372 if (!program.audioStreams.empty())
1374 eDebugNoNewLine(" (");
1375 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1376 i(program.audioStreams.begin());
1377 i != program.audioStreams.end(); ++i)
1384 if (i != program.audioStreams.begin())
1385 eDebugNoNewLine(", ");
1386 eDebugNoNewLine("%04x", i->pid);
1388 eDebugNoNewLine(")");
1390 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1391 pcrpid = program.pcrPid;
1392 eDebug(", and the text pid is %04x", program.textPid);
1393 tpid = program.textPid;
1398 h.getDecodeDemux(m_decode_demux);
1400 m_decode_demux->getMPEGDecoder(m_decoder);
1402 m_cue->setDecodingDemux(m_decode_demux);
1407 m_decoder->setVideoPID(vpid);
1408 m_current_audio_stream = 0;
1409 m_decoder->setAudioPID(apid, apidtype);
1410 if (!(m_is_pvr || m_timeshift_active))
1411 m_decoder->setSyncPCR(pcrpid);
1413 m_decoder->setSyncPCR(-1);
1414 m_decoder->setTextPID(tpid);
1416 // how we can do this better?
1417 // update cache pid when the user changed the audio track or video track
1418 // TODO handling of difference audio types.. default audio types..
1420 /* don't worry about non-existing services, nor pvr services */
1421 if (m_dvb_service && !m_is_pvr)
1423 if (apidtype == eDVBAudio::aMPEG)
1425 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1426 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1430 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1431 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1433 m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1434 m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1435 m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1440 void eDVBServicePlay::loadCuesheet()
1442 std::string filename = m_reference.path + ".cuts";
1444 m_cue_entries.clear();
1446 FILE *f = fopen(filename.c_str(), "rb");
1450 eDebug("loading cuts..");
1453 unsigned long long where;
1456 if (!fread(&where, sizeof(where), 1, f))
1458 if (!fread(&what, sizeof(what), 1, f))
1461 #if BYTE_ORDER == LITTLE_ENDIAN
1462 where = bswap_64(where);
1469 m_cue_entries.insert(cueEntry(where, what));
1472 eDebug("%d entries", m_cue_entries.size());
1474 eDebug("cutfile not found!");
1476 m_cuesheet_changed = 0;
1479 void eDVBServicePlay::saveCuesheet()
1481 std::string filename = m_reference.path + ".cuts";
1483 FILE *f = fopen(filename.c_str(), "wb");
1487 unsigned long long where;
1490 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1492 #if BYTE_ORDER == BIG_ENDIAN
1495 where = bswap_64(i->where);
1497 what = htonl(i->what);
1498 fwrite(&where, sizeof(where), 1, f);
1499 fwrite(&what, sizeof(what), 1, f);
1505 m_cuesheet_changed = 0;
1508 DEFINE_REF(eDVBServicePlay)
1510 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");